aboutsummaryrefslogtreecommitdiffstats
path: root/packages/linux/linux-mtx-2-2.4.27
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-mtx-2-2.4.27')
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/00-mtx-2.diff324
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/42-usb-ohci-fixes.patch9
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/46-otg.patch56853
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/47-au1000_eth.patch163
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/48-pptp.patch5092
-rw-r--r--packages/linux/linux-mtx-2-2.4.27/defconfig-mtx-2207
6 files changed, 62253 insertions, 395 deletions
diff --git a/packages/linux/linux-mtx-2-2.4.27/00-mtx-2.diff b/packages/linux/linux-mtx-2-2.4.27/00-mtx-2.diff
index 589446c2e9..6d1ca1c75e 100644
--- a/packages/linux/linux-mtx-2-2.4.27/00-mtx-2.diff
+++ b/packages/linux/linux-mtx-2-2.4.27/00-mtx-2.diff
@@ -2500,8 +2500,8 @@ diff -Nur linux-old/Documentation/Configure.help linux/Documentation/Configure.h
+#
+CONFIG_USBD_AU1X00_BUS=m
+CONFIG_USBD_AU1X00_SCLOCK=400
-+CONFIG_AU1000_USB_DEVICE=y
-+CONFIG_AU1X00_USB_DEVICE=y
++# CONFIG_AU1000_USB_DEVICE is not set
++# CONFIG_AU1X00_USB_DEVICE is not set
+# CONFIG_USBD_BI_REGISTER_TRACE is not set
+
+#
@@ -2605,326 +2605,6 @@ diff -Nur linux-old/Documentation/Configure.help linux/Documentation/Configure.h
MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
---- linux/drivers/net/au1000_eth.c~00-mtx-2.diff 2006-06-10 14:01:44.602796000 +0200
-+++ linux/drivers/net/au1000_eth.c 2006-06-10 13:56:07.353719250 +0200
-@@ -6,7 +6,9 @@
- * Copyright 2002 TimeSys Corp.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
-- *
-+ * Bjoern Riemer 2004
-+ * riemer@fokus.fraunhofer.de or riemer@riemer-nt.de
-+ * // fixed the link beat detection with ioctls (SIOCGMIIPHY)
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
-@@ -83,7 +85,7 @@
- static int au1000_set_config(struct net_device *dev, struct ifmap *map);
- static void set_rx_mode(struct net_device *);
- static struct net_device_stats *au1000_get_stats(struct net_device *);
--static inline void update_tx_stats(struct net_device *, u32, u32);
-+static inline void update_tx_stats(struct net_device *, u32);
- static inline void update_rx_stats(struct net_device *, u32);
- static void au1000_timer(unsigned long);
- static int au1000_ioctl(struct net_device *, struct ifreq *, int);
-@@ -656,6 +658,7 @@
- ks8995m_status,
- };
-
-+
- #ifdef CONFIG_MIPS_BOSPORUS
- struct phy_ops stub_ops = {
- stub_init,
-@@ -674,6 +677,7 @@
- {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
- {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
- {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
-+ {"Broadcom BCM5241 10/100 BaseT PHY",0x0143,0xBC31, &bcm_5201_ops,1},
- {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
- {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
- {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
-@@ -810,28 +814,39 @@
- int phy_found=0;
- #endif
-
-+#if 0
-+ if (aup && aup->mii)
-+ aup->mii->chip_info = NULL;
-+#endif
-+
-+
- /* search for total of 32 possible mii phy addresses */
- for (phy_addr = 0; phy_addr < 32; phy_addr++) {
- u16 mii_status;
- u16 phy_id0, phy_id1;
- int i;
-
-- #ifdef CONFIG_BCM5222_DUAL_PHY
-+#ifdef CONFIG_BCM5222_DUAL_PHY
- /* Mask the already found phy, try next one */
- if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
- if (au_macs[0]->phy_addr == phy_addr)
- continue;
- }
-- #endif
-+#endif
-
- mii_status = mdio_read(dev, phy_addr, MII_STATUS);
- if (mii_status == 0xffff || mii_status == 0x0000)
- /* the mii is not accessable, try next one */
- continue;
-
-+
- phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);
- phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1);
-
-+ /*printk ("mii_probe: found PHY at address 0x%X : %04X/%04X\n", phy_addr,
-+ phy_id0, phy_id1
-+ ); */
-+
- /* search our mii table for the current mii */
- for (i = 0; mii_chip_table[i].phy_id1; i++) {
- if (phy_id0 == mii_chip_table[i].phy_id0 &&
-@@ -853,7 +868,7 @@
- // values and set indicators. We need to do
- // this now since mdio_{read,write} need the
- // control and data register addresses.
-- #ifdef CONFIG_BCM5222_DUAL_PHY
-+#ifdef CONFIG_BCM5222_DUAL_PHY
- if ( mii_chip_table[i].dual_phy) {
-
- /* assume both phys are controlled
-@@ -867,11 +882,13 @@
- aup->mii->mii_data_reg = (u32 *)
- &au_macs[0]->mac->mii_data;
- }
-- #endif
-+#endif
- goto found;
- }
- }
- }
-+ return -1;
-+
- found:
-
- #ifdef CONFIG_MIPS_BOSPORUS
-@@ -1027,24 +1044,26 @@
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
-
- if (au1000_debug > 4)
-- printk(KERN_INFO "%s: reset mac, aup %x\n",
-- dev->name, (unsigned)aup);
-+ printk(KERN_INFO "%s: reset mac, aup %x, macid %d\n",
-+ dev->name, (unsigned)aup, aup->mac_id);
-+
-+ return;
-
- spin_lock_irqsave(&aup->lock, flags);
- del_timer(&aup->timer);
- hard_stop(dev);
-- #ifdef CONFIG_BCM5222_DUAL_PHY
-+#ifdef CONFIG_BCM5222_DUAL_PHY
- if (aup->mac_id != 0) {
-- #endif
-+#endif
- /* If BCM5222, we can't leave MAC0 in reset because then
- * we can't access the dual phy for ETH1 */
- *aup->enable = MAC_EN_CLOCK_ENABLE;
- au_sync_delay(2);
- *aup->enable = 0;
- au_sync_delay(2);
-- #ifdef CONFIG_BCM5222_DUAL_PHY
-+#ifdef CONFIG_BCM5222_DUAL_PHY
- }
-- #endif
-+#endif
- aup->tx_full = 0;
- for (i = 0; i < NUM_RX_DMA; i++) {
- /* reset control bits */
-@@ -1140,17 +1159,39 @@
- iflist[1].macen_addr = AU1550_MAC1_ENABLE;
- iflist[0].irq = AU1550_MAC0_DMA_INT;
- iflist[1].irq = AU1550_MAC1_DMA_INT;
-+ /*printk ("***** Au1550 Ethernet *****\n");*/
- break;
- #endif
- default:
- num_ifs = 0;
- }
-+
-+ {
-+ unsigned long pf = au_readl(SYS_PINFUNC);
-+ pf &= ~1;
-+
-+ au_writel (pf, SYS_PINFUNC);
-+ au_writel (0x10000, SYS_OUTPUTSET);
-+
-+ }
-+
-+
-+
- for(i = 0; i < num_ifs; i++) {
-+ /*printk ("*** calling au1000_probe(0x%08lX, %d, %d)\n", iflist[i].base_addr, iflist[i].irq, i);*/
- dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
-+ /*printk ("*** left au1000_probe\n");*/
-+
- iflist[i].dev = dev;
-+
-+ /*printk ("*** 1\n");*/
-+
- if (dev)
- found_one++;
- }
-+
-+ printk("Au1x Ethernet found %d ethernet devices\n", found_one);
-+
- if (!found_one)
- return -ENODEV;
- return 0;
-@@ -1194,6 +1235,7 @@
- /* Allocate the data buffers */
- aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE *
- (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr);
-+
- if (!aup->vaddr) {
- kfree(dev);
- release_region(ioaddr, MAC_IOSIZE);
-@@ -1227,6 +1269,7 @@
- setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
- aup->mac_id = 0;
- au_macs[0] = aup;
-+
- }
- else
- if (ioaddr == iflist[1].base_addr)
-@@ -1257,6 +1300,8 @@
- printk(KERN_ERR "%s: out of memory\n", dev->name);
- goto err_out;
- }
-+
-+ aup->mii->chip_info = NULL;
- aup->mii->mii_control_reg = 0;
- aup->mii->mii_data_reg = 0;
-
-@@ -1284,6 +1329,7 @@
- aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
- aup->rx_db_inuse[i] = pDB;
- }
-+
- for (i = 0; i < NUM_TX_DMA; i++) {
- pDB = GetFreeDB(aup);
- if (!pDB) {
-@@ -1383,12 +1429,17 @@
- aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
- control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
- #ifndef CONFIG_CPU_LITTLE_ENDIAN
-+ /*riemer: fix for startup without cable */
-+ if (!link)
-+ dev->flags &= ~IFF_RUNNING;
-+
- control |= MAC_BIG_ENDIAN;
- #endif
- if (link && (dev->if_port == IF_PORT_100BASEFX)) {
- control |= MAC_FULL_DUPLEX;
- }
- aup->mac->control = control;
-+ aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
- au_sync();
-
- spin_unlock_irqrestore(&aup->lock, flags);
-@@ -1541,14 +1592,11 @@
-
-
- static inline void
--update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
-+update_tx_stats(struct net_device *dev, u32 status)
- {
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
-
-- ps->tx_packets++;
-- ps->tx_bytes += pkt_len;
--
- if (status & TX_FRAME_ABORTED) {
- if (dev->if_port == IF_PORT_100BASEFX) {
- if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
-@@ -1581,7 +1629,7 @@
- ptxd = aup->tx_dma_ring[aup->tx_tail];
-
- while (ptxd->buff_stat & TX_T_DONE) {
-- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
-+ update_tx_stats(dev, ptxd->status);
- ptxd->buff_stat &= ~TX_T_DONE;
- ptxd->len = 0;
- au_sync();
-@@ -1603,6 +1651,7 @@
- static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
- {
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
-+ struct net_device_stats *ps = &aup->stats;
- volatile tx_dma_t *ptxd;
- u32 buff_stat;
- db_dest_t *pDB;
-@@ -1622,7 +1671,7 @@
- return 1;
- }
- else if (buff_stat & TX_T_DONE) {
-- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
-+ update_tx_stats(dev, ptxd->status);
- ptxd->len = 0;
- }
-
-@@ -1642,6 +1691,9 @@
- else
- ptxd->len = skb->len;
-
-+ ps->tx_packets++;
-+ ps->tx_bytes += ptxd->len;
-+
- ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
- au_sync();
- dev_kfree_skb(skb);
-@@ -1840,17 +1892,35 @@
-
- static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
-- //u16 *data = (u16 *)&rq->ifr_data;
-+/*
-+// This structure is used in all SIOCxMIIxxx ioctl calls
-+struct mii_ioctl_data {
-+ 0 u16 phy_id;
-+ 1 u16 reg_num;
-+ 2 u16 val_in;
-+ 3 u16 val_out;
-+};*/
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
-+ //struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
-
- /* fixme */
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-- //data[0] = PHY_ADDRESS;
-+ case SIOCGMIIPHY:
-+ if (!netif_running(dev))
-+ return -EINVAL;
-+ data[0] = aup->phy_addr;
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- //data[3] = mdio_read(ioaddr, data[0], data[1]);
-+ case SIOCGMIIREG:
-+ data[3] = mdio_read(dev, data[0], data[1]);
-+ //data->val_out = mdio_read(dev,data->phy_id,data->reg_num);
- return 0;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-- //mdio_write(ioaddr, data[0], data[1], data[2]);
-+ case SIOCSMIIREG:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ mdio_write(dev, data[0], data[1],data[2]);
- return 0;
- default:
- return -EOPNOTSUPP;
--- linux-old/drivers/sound/au1550_psc.c 2004-09-19 00:07:37.000000000 +0200
+++ linux/drivers/sound/au1550_psc.c 2006-04-30 20:35:58.000000000 +0200
@@ -55,14 +55,15 @@
diff --git a/packages/linux/linux-mtx-2-2.4.27/42-usb-ohci-fixes.patch b/packages/linux/linux-mtx-2-2.4.27/42-usb-ohci-fixes.patch
index 4c3058ce00..aa5a0d45f7 100644
--- a/packages/linux/linux-mtx-2-2.4.27/42-usb-ohci-fixes.patch
+++ b/packages/linux/linux-mtx-2-2.4.27/42-usb-ohci-fixes.patch
@@ -11,6 +11,15 @@
/*-------------------------------------------------------------------------*/
/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+@@ -147,7 +151,7 @@
+ ohci->complete_head = urb;
+ ohci->complete_tail = urb;
+ } else {
+- ohci->complete_head->hcpriv = urb;
++ ohci->complete_tail->hcpriv = urb;
+ ohci->complete_tail = urb;
+ }
+ }
@@ -2587,12 +2591,12 @@
hc_release_ohci (ohci);
return -ENODEV;
diff --git a/packages/linux/linux-mtx-2-2.4.27/46-otg.patch b/packages/linux/linux-mtx-2-2.4.27/46-otg.patch
new file mode 100644
index 0000000000..2004894b3e
--- /dev/null
+++ b/packages/linux/linux-mtx-2-2.4.27/46-otg.patch
@@ -0,0 +1,56853 @@
+--- linux/Makefile-otgorig 2006-09-20 16:02:57.347146612 +0200
++++ linux/Makefile 2006-09-20 16:03:35.280797278 +0200
+@@ -181,6 +181,7 @@
+ DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
+ DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
+ DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
++DRIVERS-$(CONFIG_OTG) += drivers/otg/otg_drv.o
+ DRIVERS-$(CONFIG_USB_GADGET) += drivers/usb/gadget/built-in.o
+ DRIVERS-y +=drivers/media/media.o
+ DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+--- linux/arch/mips/config-shared.in-otgorig 2006-09-20 16:09:20.671834564 +0200
++++ linux/arch/mips/config-shared.in 2006-09-20 16:09:28.068156725 +0200
+@@ -1009,6 +1009,7 @@
+ endmenu
+
+ source drivers/usb/Config.in
++source drivers/otg/Config.in
+
+ source net/bluetooth/Config.in
+
+--- linux/drivers/Makefile-otgorig 2006-09-20 16:09:47.100985766 +0200
++++ linux/drivers/Makefile 2006-09-20 16:10:25.730668535 +0200
+@@ -6,7 +6,7 @@
+ #
+
+
+-mod-subdirs := dio hil mtd sbus video macintosh usb input telephony ide \
++mod-subdirs := dio hil mtd sbus video macintosh usb otg input telephony ide \
+ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
+ fc4 net/hamradio i2c acpi bluetooth usb/gadget sensors
+
+@@ -28,6 +28,7 @@
+ subdir-$(CONFIG_MAC) += macintosh
+ subdir-$(CONFIG_PPC32) += macintosh
+ subdir-$(CONFIG_USB) += usb
++subdir-$(CONFIG_OTG) += otg
+ subdir-$(CONFIG_USB_GADGET) += usb/gadget
+ subdir-$(CONFIG_INPUT) += input
+ subdir-$(CONFIG_PHONE) += telephony
+diff -uNr linux/drivers/no-otg/Config.in linux/drivers/otg/Config.in
+--- linux/drivers/no-otg/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/Config.in 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,103 @@
++#
++# USBOTG - Top level configuration of a USB Peripheral or USB On-The-Go Peripheral Device
++#
++# Copyright (c) 2004 Belcarra
++#
++#
++
++mainmenu_option next_comment
++
++ #
++ # Enable/Disable OTG Support
++ #
++ comment 'On-The-Go and USB Peripheral Support'
++ tristate 'Support for On-The-Go and USB Peripherals ' CONFIG_OTG
++
++ if [ "$CONFIG_OTG" != "n" ]; then
++ #
++ # Select appropriate hardware platform, each config file
++ # will only offer options if the kernel is configured for
++ # that specific architecture or platform. They should define
++ # the following to enable the further configuration in this
++ # file:
++ # CONFIG_OTG_PLATFORM_OTG offer OTG configuration
++ #
++ # CONFIG_OTG_PLATFORM_USBD offer USBD configuration and
++ # function selection
++ # CONFIG_OTG_PLATFORM_HOST offer HOST configuration
++ #
++ mainmenu_option next_comment
++ comment 'Select Hardware'
++
++ # platform oriented configurations
++# source drivers/otg/config/Config.in-mainstone
++# source drivers/otg/config/Config.in-pcs-b780
++# source drivers/otg/config/Config.in-pcs-p1
++# source drivers/otg/config/Config.in-mx2ads
++# source drivers/otg/config/Config.in-omap-h2
++ source drivers/otg/config/Config.in-db1550
++# source drivers/otg/config/Config.in-mordor
++
++ # architecture specific configurations
++ source drivers/otg/config/Config.in-au1x00
++# source drivers/otg/config/Config.in-dbmx1
++# source drivers/otg/config/Config.in-lh7a400
++# source drivers/otg/config/Config.in-lubbock
++# source drivers/otg/config/Config.in-smdk2500
++# source drivers/otg/config/Config.in-strongarm
++# source drivers/otg/config/Config.in-superh
++
++ # generic drivers
++ source drivers/otg/config/Config.in-isp1301
++ source drivers/otg/config/Config.in-max3353e
++ endmenu
++
++ if [ "$CONFIG_OTG_PLATFORM_OTG" = "y" -o "$CONFIG_OTG_PLATFORM_USBD" = "y" ]; then
++
++ #
++ # Generic Options
++ #
++ mainmenu_option next_comment
++ comment 'General Support Options'
++ bool 'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEED
++ # bool 'Enable Root HUB Function' CONFIG_OTG_ROOT_HUB
++ bool 'OTG Fast Tracing' CONFIG_OTG_TRACE
++ tristate 'USB FUNCTION FS Module' CONFIG_OTG_PROCFSM
++ bool 'Disable C99 initializers' CONFIG_OTG_NOC99
++ endmenu
++
++ #
++ # Select USB Peripheral Function Drivers
++ #
++ mainmenu_option next_comment
++ comment 'Targeted Peripherals (USB Peripheral Function Drivers)'
++ source drivers/otg/functions/acm/Config.in
++ source drivers/otg/functions/mouse/Config.in
++ source drivers/otg/functions/network/Config.in
++ source drivers/otg/functions/msc/Config.in
++# source drivers/otg/functions/test/Config.in
++ endmenu
++
++ mainmenu_option next_comment
++ comment 'Traditional Device Options'
++ bool 'Built-in Minimal USB Device' CONFIG_OTG_FW_MN
++ dep_bool 'Enable Auto-Start' CONFIG_OTG_TR_AUTO $CONFIG_OTG_MN
++ endmenu
++ fi
++ #dep_tristate 'Build OTG minihost core' CONFIG_OTG_HOSTCORE $CONFIG_OTG
++ if [ "$CONFIG_OTG_PLATFORM_HOST" != "n" ]; then
++ #
++ # Host configuration
++ #
++ mainmenu_option next_comment
++ comment 'Host configuration (OTG minihost core and HCD)'
++# source drivers/otg/core/Config.in
++ source drivers/otg/ocd/Config.in
++# source drivers/otg/classes/usblan/Config.in
++ endmenu
++ fi
++
++ fi
++
++endmenu
++
+diff -uNr linux/drivers/no-otg/Config.in-orig linux/drivers/otg/Config.in-orig
+--- linux/drivers/no-otg/Config.in-orig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/Config.in-orig 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,73 @@
++#
++# OTG - configuration of a USB On-The-Go Device
++#
++# Copyright (c) 2004 Belcarra
++#
++# The otg_export script will delete all comments marked "(Testing)"
++#
++
++mainmenu_option next_comment
++
++comment 'OTG devices'
++
++tristate 'Support for USB On-The-Go Devices ' CONFIG_OTG
++
++if [ "$CONFIG_OTG" = "y" -o "$CONFIG_OTG" = "m" ]; then
++ comment ''
++ bool ' Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEED
++ bool ' Enable Root HUB Function' CONFIG_OTG_ROOT_HUB
++ comment ''
++
++ bool ' Disable PCD' CONFIG_OTG_DISABLE_PCD
++ bool ' Disable HCD' CONFIG_OTG_DISABLE_HCD
++
++ comment ''
++
++ bool ' OTG Proc FS' CONFIG_OTG_PROCFS
++ tristate ' OTG Proc FS Module' CONFIG_OTG_PROCFSM $CONFIG_OTG
++
++ comment 'On-The-Go Functions'
++
++ source drivers/otg/functions/network/Config.in
++ source drivers/otg/functions/acm/Config.in
++ source drivers/otg/functions/msc/Config.in
++
++ source drivers/otg/functions/isotest/Config.in
++ source drivers/otg/functions/mouse/Config.in
++
++ comment ''
++ comment 'On-The-Go Transceiver Controller Drivers (TCD)'
++
++ source drivers/otg/tcd/isp1301/Config.in
++
++ comment ''
++ comment 'On-The-Go Peripheral Controller Drivers (PCD)'
++
++ source drivers/otg/pcd/au1x00/Config.in
++ source drivers/otg/pcd/mx1/Config.in
++ source drivers/otg/pcd/mx2/Config.in
++ source drivers/otg/pcd/pxa/Config.in
++ source drivers/otg/pcd/sa1100/Config.in
++ source drivers/otg/pcd/lh7a400/Config.in
++ source drivers/otg/pcd/omap/Config.in
++ source drivers/otg/pcd/smdk2500/Config.in
++ source drivers/otg/pcd/superh/Config.in
++ source drivers/otg/pcd/sx2/Config.in
++ source drivers/otg/pcd/wmmx/Config.in
++
++ comment ''
++ comment 'On-The-Go Host Controller Drivers (HCD)'
++
++ source drivers/otg/hcd/omap/Config.in
++
++ comment ''
++ tristate ' OTG Fast Tracing' CONFIG_OTG_TRACE
++ comment ''
++
++ comment 'Non Current Bus Drivers (Testing)'
++ source drivers/otg/functions/pst/Config.in
++ source drivers/otg/functions/datalog/Config.in
++
++fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/FIX-MAKEFILES linux/drivers/otg/FIX-MAKEFILES
+--- linux/drivers/no-otg/FIX-MAKEFILES 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/FIX-MAKEFILES 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,23 @@
++#!/bin/sh
++
++ARG=$1
++shift
++
++[ -z "${ARG}" ] && echo Bad args && exit 1
++
++#find . -name Makefile-${ARG} | while read i
++#do
++# m=`expr $i : "\(.*\)-${ARG}"`
++# ln -sfv $i $m
++#done
++
++find . -type d | while read d
++do
++ pushd $d > /dev/null
++ if [ -s Makefile-${ARG} ] ; then
++ echo -n `pwd` ": "
++ ln -sfv Makefile-${ARG} Makefile
++ fi
++ popd >/dev/null
++done
++
+diff -uNr linux/drivers/no-otg/Kconfig linux/drivers/otg/Kconfig
+--- linux/drivers/no-otg/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/Kconfig 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,115 @@
++menu "On-The-Go and USB Peripheral Support"
++
++ config OTG
++ tristate "Support for On-The-Go and USB Peripheral Support"
++ ---help---
++ Configure all or part of the Belcarra OTG Stack
++
++
++ menu "On-The-Go Support"
++ depends on OTG
++
++ source "drivers/otg/config/Kconfig-scma11-evb"
++ #source "drivers/otg/config/Kconfig-omap-h2"
++
++ endmenu
++
++ menu "On-The-Go Support Configuration"
++ depends on OTG_PLATFORM_OTG
++
++ choice
++ depends on OTG && OTG_PLATFORM_OTG
++ prompt "On-The-Go Device Configuration"
++ config OTG_CFG_TR
++ bool "Traditional USB Peripheral"
++ ---help---
++ Compile as a Traditional USB Peripheral.
++ On-The-Go support is enabled.
++ config OTG_CFG_HO
++ bool "Host Only"
++ ---help---
++ Compile the USB Host support without the USB Peripheral
++ support. This is generally only useful for testing the
++ USB Host support and Host Controller drivers.
++ config OTG_CFG_PO
++ bool "Peripheral Only"
++ ---help---
++ Compile as a On-The-Go Peripheral-Only device. This
++ is similiar to a Traditional USB Peripheral but enables
++ On-The-Go features such as SRP.
++ config OTG_CFG_DR
++ bool "Dual Role"
++ ---help---
++ Compile as an On-The-Go Dual-Role device.
++
++ endchoice
++ endmenu
++
++ menu "Targeted Peripheral List (USB Host Class Drivers)"
++ depends on OTG_PLATFORM_OTG
++ # souce "drivers/otg/xxxx"
++ #
++ #---help---
++ #A list of USB peripherals that this device
++ #can support when it is acting as a host.
++ endmenu
++
++ menu "General Support Options"
++
++ depends on OTG_PLATFORM_OTG|| OTG_PLATFORM_USBD
++
++ # This needs to be a specific defined variable that comes
++ # from Kconfig-platform file
++ #
++ #config usb
++ # tristate 'OTG host core support (separate from native Linux host support)'
++
++ config OTG_HIGH_SPEED
++ bool 'Enable high speed descriptors'
++ depends on OTG!=n
++
++ config OTG_TRACE
++ bool 'OTG Fast Tracing'
++ depends on OTG!=n
++ ---help---
++ This option implements register trace to support
++ driver debugging.
++
++ #config OTG_ROOT_HUB
++ # bool 'Enable Root HUB Function'
++ # depends on OTG!=n
++
++ config OTG_PROCFS
++ bool 'OTG Proc FS'
++ depends on OTG!=n
++ ---help---
++ This option enables /proc/ support in various modules
++ Note: Some information previously exposed via the /proc
++ interface is now exposed via a different mechanism
++
++ config OTG_PROCFSM
++ tristate 'OTG Proc FS Module'
++ depends on OTG != n
++ ---help---
++ Build in extra support to perform various operations
++ through the /proc filesystem. Note: this module is
++ held over from the Device stack and its functions are
++ gradually being transferred to the OTG Admin API.
++
++ endmenu
++
++
++ menu "Targeted Peripherals List (USB Peripheral Function Drivers)"
++ depends on OTG_PLATFORM_OTG || OTG_PLATFORM_USBD
++ #---help---
++ #A list of USB peripheral types that this device
++ #can emulate when it is acting as a peripheral.
++ source "drivers/otg/functions/acm/Kconfig"
++ source "drivers/otg/functions/mouse/Kconfig"
++ source "drivers/otg/functions/msc/Kconfig"
++ source "drivers/otg/functions/network/Kconfig"
++ endmenu
++
++
++endmenu
++
+diff -uNr linux/drivers/no-otg/Makefile linux/drivers/otg/Makefile
+--- linux/drivers/no-otg/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/Makefile 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,132 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++TOPDIR ?= ../../..
++
++# order here may be important (determines linking order, thus module init order)
++subdir-y := otgcore functions ocd
++subdir-m := otgcore functions ocd
++subdir-n :=
++subdir- :=
++# The target object and module list name.
++
++O_TARGET := otg_drv.o
++
++# Objects that export symbols.
++
++#export-objs := usbd.o usbd-bops.o usbd-fops.o usbd-pcd.o ep0.o hub.o
++
++# Multipart objects. (core layer)
++
++
++# Optional parts of multipart objects.
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++ifeq ($(CONFIG_OTG),y)
++obj-y += otgcore/otgcore.o
++endif
++
++
++# Object files in subdirectories (There has to be a better way to do this)
++
++#=== Function drivers
++f-obj-y :=
++f-obj-m :=
++f-obj-n :=
++f-obj- :=
++
++f-obj-$(CONFIG_OTG_ACM) += functions/function_target.o
++f-obj-$(CONFIG_OTG_ISOTEST) += functions/function_target.o
++f-obj-$(CONFIG_OTG_MSC) += functions/function_target.o
++f-obj-$(CONFIG_OTG_MOUSE) += functions/function_target.o
++f-obj-$(CONFIG_OTG_NETWORK) += functions/function_target.o
++f-obj-$(CONFIG_OTG_PST) += functions/function_target.o
++
++# Remove any duplicate entries in the list by sorting (since that drops dups)
++obj-y += $(sort $(f-obj-y))
++#obj-m += $(sort $(f-obj-m))
++obj-n += $(sort $(f-obj-n))
++obj- += $(sort $(f-obj-))
++
++#=== Peripheral controller drivers
++p-obj-y :=
++p-obj-m :=
++p-obj-n :=
++p-obj- :=
++
++p-obj-$(CONFIG_OTG_AU1X00) += ocd/ocd_target.o
++p-obj-$(CONFIG_OTG_AU1550_DB1550_TR) += ocd/ocd_target.o
++
++# Remove any duplicate entries in the list by sorting (since that drops dups)
++obj-y += $(sort $(p-obj-y))
++#obj-m += $(sort $(p-obj-m))
++obj-n += $(sort $(p-obj-n))
++obj- += $(sort $(p-obj-))
++
++#=== Host controller drivers
++h-obj-y :=
++h-obj-m :=
++h-obj-n :=
++h-obj- :=
++
++
++# Remove any duplicate entries in the list by sorting (since that drops dups)
++obj-y += $(sort $(h-obj-y))
++#obj-m += $(sort $(h-obj-m))
++obj-n += $(sort $(h-obj-n))
++obj- += $(sort $(h-obj-))
++
++
++#=== Class drivers
++class-obj-y :=
++class-obj-m :=
++class-obj-n :=
++class-obj- :=
++
++#class-obj-$(CONFIG_OTG_CLASS_USBLAN) += classes/class_target.o
++
++# Remove any duplicate entries in the list by sorting (since that drops dups)
++obj-y += $(sort $(class-obj-y))
++#obj-m += $(sort $(f-obj-m))
++#obj-n += $(sort $(f-obj-n))
++#obj- += $(sort $(f-obj-))
++
++
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -Wno-format -Wall
++
+diff -uNr linux/drivers/no-otg/Makefile-l26 linux/drivers/otg/Makefile-l26
+--- linux/drivers/no-otg/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/Makefile-l26 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,7 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++obj-y +=
++obj-m += functions/ ocd/ otgcore/ core/
+diff -uNr linux/drivers/no-otg/OWNER linux/drivers/otg/OWNER
+--- linux/drivers/no-otg/OWNER 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/OWNER 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,20 @@
++OWNER: Belcarra Technologies Corp
++LICENSEE: Freescale
++
++THIS SOURCE CODE KIT IS SUPPLIED UNDER LICENSE
++
++Unless expressly modified elsewhere, the author of
++each source file included herein retains ownership
++of the identified file notwithstanding release of
++a specific version under a Public License such as
++the GNU General Public License.
++
++The line OWNER(entity) in a comment line at or near
++the top of a source file expressly asserts ownership
++of the file by that entity or person.
++
++In addition the presence of an OWNER.TXT or OWNER
++file in a directory asserts ownership of the contents
++of that directory and of the compilation thereof into
++the present and derivative kits.
++
+diff -uNr linux/drivers/no-otg/README linux/drivers/otg/README
+--- linux/drivers/no-otg/README 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/README 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,11 @@
++otg/README
++
++This is the top level of the OTG toolkit source tree.
++
++ classes Host Class drivers
++ functions Peripheral Function drivers
++ ocd OTG Controller drivers
++ otgcore OTG State Machine and USB Device stack
++ otghw Hardware related include files
++ otg Include files
++
+diff -uNr linux/drivers/no-otg/config/Config.in-au1x00 linux/drivers/otg/config/Config.in-au1x00
+--- linux/drivers/no-otg/config/Config.in-au1x00 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-au1x00 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,29 @@
++#
++# Copyright (c) 2004 Belcarra
++#
++
++# Au1x00 on DB1100, PB1100 and PB1500
++
++if [ "$CONFIG_SOC_AU1X00" = "y" -o \
++ "$CONFIG_MIPS_AU1X00" = "y" -o \
++ "$CONFIG_CPU_AU1X00" = "y" -o \
++ "$CONFIG_MIPS_AU1500" = "y" -o \
++ "$CONFIG_MIPS_AU1100" = "y" -o \
++ "$CONFIG_MIPS_AU1000" = "y" ]
++then
++ mainmenu_option next_comment
++ comment 'AMD AU1X00 Bus Interface'
++
++ dep_tristate 'DB1100/PB1100/PB1500 Development Boards Support' CONFIG_OTG_AU1X00 $CONFIG_OTG
++
++ if [ "$CONFIG_OTG_AU1X00" != "n" ]; then
++ int 'AU1X00 System Clock' CONFIG_OTG_AU1X00_SCLOCK 400
++ define_bool CONFIG_AU1000_USB_DEVICE n
++ define_bool CONFIG_AU1X00_USB_DEVICE y
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++ #else
++ # define_bool CONFIG_OTG_PLATFORM_USBD n
++ fi
++ endmenu
++fi
++
+diff -uNr linux/drivers/no-otg/config/Config.in-db1550 linux/drivers/otg/config/Config.in-db1550
+--- linux/drivers/no-otg/config/Config.in-db1550 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-db1550 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,48 @@
++#
++# Copyright (c) 2004 Belcarra
++#
++
++if [ "$CONFIG_MIPS_DB1550" = "y" -o "$CONFIG_MIPS_MTX2" ]
++then
++ mainmenu_option next_comment
++ comment 'DB1550 Development Board'
++
++ dep_tristate 'DB1550 Development Boards Support' CONFIG_OTG_DB1550 $CONFIG_OTG
++
++ #define_tristate CONFIG_OTG_AU1550
++
++ if [ "$CONFIG_OTG_DB1550" != "n" ]; then
++ int 'AU1X00 System Clock' CONFIG_OTG_AU1X00_SCLOCK 400
++ define_bool CONFIG_AU1000_USB_DEVICE n
++ define_bool CONFIG_AU1X00_USB_DEVICE n
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++ define_tristate CONFIG_OTG_AU1550 $CONFIG_OTG_DB1550
++
++ choice 'Select DB1550 Standard B or Mini A-B Port' \
++ "Mini-B-J14 CONFIG_OTG_DB1550_J14 \
++ Mini-A-B-J15 CONFIG_OTG_DB1550_J15" Mini-B-J14
++
++ if [ "$CONFIG_OTG_DB1550_J14" = "y" ]; then
++ define_bool CONFIG_OTG_PLATFORM_OTG n
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++ define_bool CONFIG_OTG_MAX3353E n
++ define_tristate CONFIG_OTG_AU1550_DB1550_TR $CONFIG_OTG_DB1550
++
++ else
++ if [ "$CONFIG_OTG_DB1550_J15" = "y" ]; then
++ define_bool CONFIG_OTG_PLATFORM_OTG y
++ define_bool CONFIG_OTG_PLATFORM_USBD n
++ define_bool CONFIG_OTG_MAX3353E y
++ define_tristate CONFIG_OTG_MAX3353E_DB1550 $CONFIG_OTG_DB1550
++ define_tristate CONFIG_OTG_AU1550_DB1550_DR $CONFIG_OTG_DB1550
++
++ # J15 is external OTG Transceiver Client
++ define_bool CONFIG_OTG_DB1550_HXOE n
++ define_bool CONFIG_OTG_DB1550_HXS y
++ define_int CONFIG_OTG_DB1550_SEOS 4
++ fi
++ fi
++ fi
++ endmenu
++fi
++
+diff -uNr linux/drivers/no-otg/config/Config.in-dbmx1 linux/drivers/otg/config/Config.in-dbmx1
+--- linux/drivers/no-otg/config/Config.in-dbmx1 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-dbmx1 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,19 @@
++#
++# Copyright (c) 2004 Belcarra
++#
++
++# MX1ADS - Motorola MX1
++
++if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then
++
++ mainmenu_option next_comment
++ comment 'Motorola MX1 Bus Interface'
++ dep_tristate 'DBMX1 Developement Board Support' CONFIG_OTG_DBMX1 $CONFIG_OTG
++
++ if [ "$CONFIG_OTG_DBMX1" != "n" ]; then
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++ else
++ define_bool CONFIG_OTG_PLATFORM_USBD n
++ fi
++ endmenu
++fi
+diff -uNr linux/drivers/no-otg/config/Config.in-isp1301 linux/drivers/otg/config/Config.in-isp1301
+--- linux/drivers/no-otg/config/Config.in-isp1301 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-isp1301 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,25 @@
++
++#
++# Copyright (c) 2004 Belcarra
++#
++# ISP 1301 TCD
++
++#if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
++# mainmenu_option next_comment
++# comment 'ISP 1301'
++#
++# #bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFSX
++# #bool 'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEEDX
++# define_bool CONFIG_OTG_TEST y
++#
++# endmenu
++#fi
++if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
++
++ mainmenu_option next_comment
++ comment 'ISP 1301'
++ bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFS
++
++ endmenu
++fi
++
+diff -uNr linux/drivers/no-otg/config/Config.in-max3353e linux/drivers/otg/config/Config.in-max3353e
+--- linux/drivers/no-otg/config/Config.in-max3353e 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-max3353e 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,25 @@
++
++#
++# Copyright (c) 2004 Belcarra
++#
++# MAX 3353E TCD
++
++#if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
++# mainmenu_option next_comment
++# comment 'MAX 3353E'
++#
++# #bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFSX
++# #bool 'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEEDX
++# define_bool CONFIG_OTG_TEST y
++#
++# endmenu
++#fi
++if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
++
++ mainmenu_option next_comment
++ comment 'MAX 3353E'
++ bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFS
++
++ endmenu
++fi
++
+diff -uNr linux/drivers/no-otg/config/Config.in-mordor linux/drivers/otg/config/Config.in-mordor
+--- linux/drivers/no-otg/config/Config.in-mordor 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Config.in-mordor 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# Copyright (c) 2004 Belcarra
++#
++
++# Au1x00 on DB1100, PB1100 and PB1500
++
++if [ "$CONFIG_AMX_MORDOR" = "y" ]
++then
++ mainmenu_option next_comment
++ comment 'AMX Mordor Board'
++
++ dep_tristate 'AMX Mordor Board Support' CONFIG_OTG_AU1550 $CONFIG_OTG
++ define_tristate CONFIG_OTG_BVD $CONFIG_OTG_AU1550
++
++ if [ "$CONFIG_OTG_AU1550" != "n" ]; then
++ int 'AU1X00 System Clock' CONFIG_OTG_AU1X00_SCLOCK 400
++ define_bool CONFIG_AU1000_USB_DEVICE n
++ define_bool CONFIG_AU1X00_USB_DEVICE n
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++
++ define_bool CONFIG_OTG_PLATFORM_OTG n
++ define_bool CONFIG_OTG_PLATFORM_USBD y
++
++ else
++ define_bool CONFIG_OTG_PLATFORM_USBD n
++ fi
++ endmenu
++fi
+diff -uNr linux/drivers/no-otg/config/Kconfig-omap-h2 linux/drivers/otg/config/Kconfig-omap-h2
+--- linux/drivers/no-otg/config/Kconfig-omap-h2 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/Kconfig-omap-h2 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,87 @@
++#
++# Copyright (c) 2004 Belcarra
++#
++
++# OMAP - TI OMAP 1610
++#
++
++# CONFIG_OTG_PLATFORM_OTG # Offer OTG Configuration
++
++# CONFIG_OTG_OMAP # Make OMAP driver
++# CONFIG_OTG_ISP1301 # Make ISP1301 driver
++
++# CONFIG_OTG_ISP1301_OMAP_H2 # Compile ISP1301 OMAP H2 driver
++
++# CONFIG_OTG_OMAP_H2 # OMAP Helen 2 board
++# CONFIG_OTG_OMAP_H2_3_WIRE # Use 3 Wire OTG Configuration
++# CONFIG_OTG_OMAP_H2_4_WIRE # Use 4 Wire OTG Configuration
++# CONFIG_OTG_OMAP_H2_DR # Compile as OTG Dual-role Device
++# CONFIG_OTG_OMAP_H2_TR # Compile as Traditional USB Peripheral
++
++config OTG_OMAP_H2
++ tristate "OMAP 1610 H2 Development Board"
++ depends on OTG && ARCH_OMAP
++ ---help---
++ This implements On-The-Go USB Support for the Helen 2 OMAP
++ Development Board.
++
++choice
++ prompt "Select Transceiver wire configuration"
++ depends on OTG && ARCH_OMAP && OTG_OMAP_H2
++ config OTG_OMAP_H2_3_WIRE
++ bool 'Enable Pin Group 1, 3 Wire Configuration'
++ depends on OMAP_H2 !=n
++ ---help---
++ The H2 board ISP1301 can be configured in either
++ the 3 wire or 4 wire configuration.
++ This enables the ISP1301 on the H2 board on Pin Group 1
++ using the 3-Wire OTG Transceiver Configuration. This
++ requires that the ISP1301 be configured for DAT_SE0.
++
++ config OTG_OMAP_H2_4_WIRE
++ bool 'Enable Pin Group 1, 4 Wire Configuration'
++ depends on OMAP_H2 !=n
++ ---help---
++ The H2 board ISP1301 can be configured in either
++ the 3 wire or 4 wire configuration.
++ This enables the ISP1301 on the H2 board on Pin Group 1
++ using the 3-Wire OTG Transceiver Configuration. This
++ requires that the ISP1301 be configured for VP_VM.
++
++endchoice
++
++config OTG_PLATFORM_OTG
++ bool
++ default OTG_OMAP_H2
++
++config OTG_OMAP_H2_TR
++ tristate
++ depends on OTG_CFG_TR
++ default OTG_OMAP_H2
++
++config OTG_OMAP_H2_HO
++ tristate
++ depends on OTG_CFG_HO
++ default OTG_OMAP_H2
++
++config OTG_OMAP_H2_PO
++ tristate
++ depends on OTG_CFG_PO
++ default OTG_OMAP_H2
++
++config OTG_OMAP_H2_DR
++ tristate
++ depends on OTG_CFG_DR
++ default OTG_OMAP_H2
++
++
++config OTG_ISP1301
++ tristate
++ depends on OTG_OMAP_H2
++ default OTG_OMAP_H2
++
++config OTG_ISP1301_OMAP_H2
++ tristate
++ depends on OTG_OMAP_H2
++ default OTG_OMAP_H2
++
+diff -uNr linux/drivers/no-otg/config/README-CONFIG.txt linux/drivers/otg/config/README-CONFIG.txt
+--- linux/drivers/no-otg/config/README-CONFIG.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/config/README-CONFIG.txt 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,106 @@
++OTG System Configuration Stuart Lynne
++Belcarra Thu Jan 13 15:45:19 PST 2005
++
++This directory contains the linux system configurations to create
++architecture or board level drivers for On-The-Go or USB Device support.
++
++There are four generic configurations available
++
++ - tr - Traditional USB Peripheral
++ - po - OTG Peripheral only
++ - dr - OTG Dual-Role device
++
++Traditional USB Peripheral
++**************************
++
++Older types of systems supported USB peripherals as a separate module. It is
++not generally possible to configure these with On-The-Go support. In most
++cases the only customization available is for detection of the Vbus (cable
++attached) and control over the D-plus pullup resistor (soft-connect.)
++
++For most of these types of systems the generated driver will be of the form:
++
++ xxx_tr
++
++Where xxx is the system architecture:
++
++ au1x00
++ lh7a400
++ mx1
++ pxa
++ sa1100
++ smdk2500
++ superh
++
++
++OTG Modes
++*********
++
++Generally new systems that support On-The-Go have (at least) the following
++components:
++
++ - USB Peripheral
++ - USB Host
++ - OTG Transceiver
++ - Charge Pump (optional)
++
++In general the combination of the above is customized at the board or
++platform level, not the architecture (chip) level. There may be up to four
++different drivers implementing various combinations of the required support.
++
++Required support:
++
++ - pcd - Peripheral Controller Driver
++ - tcd - Transceiver Controller Driver
++ - hcd - Host Controller Driver
++ - ocd - OTG Controller Driver
++
++Typically the pcd and ocd drivers will be in a single module. This module
++will be named:
++
++ xxxx_ss
++
++Where xxxx is the platform, e.g.:
++
++ mainstone
++ mx1ads
++ omap-h2
++
++And ss is the type of OTG support being compiled:
++
++ - tr - traditonal usb
++ - ho - host only
++ - po - peripheral only
++ - dr - dual-role
++
++
++
++OTG Peripheral Only (po)
++************************
++
++This mode allows for implementing a restricted mode of On-The-Go support.
++The host driver module is not configured or available.
++
++
++OTG Dual-Role Device (dr)
++*************************
++
++This mode implements the full On-The-Go stack with both USB Device and Usb
++Host support.
++
++
++Configuration File
++******************
++
++Under linux, older systems (those that support only traditional devices) will
++have a generic Config.in / Kconfig file to generate the required driver.
++
++For newer systems that support OTG type configurations there should be a
++Configuration file for each major platform supported. This will specifically
++enable defines for all of the required drivers and their options.
++
++Platform files may have several sub-types with appropriate configuration
++selectors.
++
++
++
+diff -uNr linux/drivers/no-otg/dirs linux/drivers/otg/dirs
+--- linux/drivers/no-otg/dirs 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/dirs 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,11 @@
++!if 0
++Copyright (c) 2004 Belcarra
++!endif
++
++DIRS= \
++ wince \
++ otgcore \
++ functions/mouse
++
++OPTIONAL_DIRS= \
++
+diff -uNr linux/drivers/no-otg/functions/Makefile linux/drivers/otg/functions/Makefile
+--- linux/drivers/no-otg/functions/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/Makefile 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,53 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++TOPDIR ?= ../../../..
++
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++# The target object and module list name.
++
++O_TARGET := function_target.o
++
++# Function Drivers
++subdir-$(CONFIG_OTG_ACM) += acm
++subdir-$(CONFIG_OTG_ISOTEST) += isotest
++subdir-$(CONFIG_OTG_MSC) += msc
++subdir-$(CONFIG_OTG_MOUSE) += mouse
++subdir-$(CONFIG_OTG_NETWORK) += network
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Function drivers
++ifeq ($(CONFIG_OTG_ACM),y)
++obj-y += acm/acm_fd_drv.o
++endif
++ifeq ($(CONFIG_OTG_MOUSE),y)
++obj-y += mouse/mouse_target.o
++endif
++ifeq ($(CONFIG_OTG_NETWORK),y)
++obj-y += network/network_target.o
++endif
++ifeq ($(CONFIG_OTG_MSC),y)
++obj-y += msc/msc_target.o
++endif
++ifeq ($(CONFIG_OTG_PST),y)
++obj-y += pst/pst_target.o
++endif
++ifeq ($(CONFIG_OTG_TEST),y)
++obj-y += test/test_target.o
++endif
++
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -Wno-format -Wall
++
+diff -uNr linux/drivers/no-otg/functions/Makefile-l26 linux/drivers/otg/functions/Makefile-l26
+--- linux/drivers/no-otg/functions/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/Makefile-l26 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,12 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++EXTRA_CFLAGS += -Wno-format -Wall
++# Function Drivers
++obj-$(CONFIG_OTG_ACM) += acm/
++obj-$(CONFIG_OTG_MSC) += msc/
++obj-$(CONFIG_OTG_MOUSE) += mouse/
++obj-$(CONFIG_OTG_NETWORK) += network/
++
+diff -uNr linux/drivers/no-otg/functions/acm/Config.in linux/drivers/otg/functions/acm/Config.in
+--- linux/drivers/no-otg/functions/acm/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/Config.in 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# CDC ACM Function Driver
++#
++# Copyright (C) 2003,2004 Belcarra
++#
++
++mainmenu_option next_comment
++comment "USB Peripheral Function Driver - CDC ACM"
++
++dep_tristate ' CDC ACM Function' CONFIG_OTG_ACM $CONFIG_OTG
++if [ "$CONFIG_OTG_ACM" != "n" ]; then
++ hex 'VendorID (hex value)' CONFIG_OTG_ACM_VENDORID "15ec"
++ hex 'ProductID (hex value)' CONFIG_OTG_ACM_PRODUCTID "f002"
++ hex 'bcdDevice (binary-coded decimal)' CONFIG_OTG_ACM_BCDDEVICE "0100"
++
++ string 'iManufacturer (string)' CONFIG_OTG_ACM_MANUFACTURER "Belcarra"
++ string 'iProduct (string)' CONFIG_OTG_ACM_PRODUCT_NAME "Belcarra ACM Device"
++
++ string 'iConfiguration (string)' CONFIG_OTG_ACM_DESC "Acm Cfg"
++ string 'Comm Interface iInterface (string)' CONFIG_OTG_ACM_COMM_INTF "Comm Intf"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_ACM_DATA_INTF "Data Intf"
++
++ comment ''
++ #bool 'Communications Device' CONFIG_OTG_ACM_COMM
++ #bool 'TTY Device' CONFIG_OTG_ACM_TTY
++fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/acm/Kconfig linux/drivers/otg/functions/acm/Kconfig
+--- linux/drivers/no-otg/functions/acm/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/Kconfig 2006-09-01 21:41:25.000000000 +0200
+@@ -0,0 +1,54 @@
++menu "OTG ACM Function"
++
++config OTG_ACM
++ tristate " CDC ACM Function"
++ depends on OTG
++
++menu "OTG ACM function options"
++ depends on OTG && OTG_ACM
++
++config OTG_ACM_VENDORID
++ hex "VendorID (hex value)"
++ depends on OTG_ACM && OTG
++ default "0x15ec"
++
++config OTG_ACM_PRODUCTID
++ depends on OTG_ACM && OTG
++ hex "ProductID (hex value)"
++ default "0xe003"
++config OTG_ACM_BCDDEVICE
++ depends on OTG_ACM && OTG
++ hex "bcdDevice (binary-coded decimal)"
++ default "0x0100"
++
++config OTG_ACM_MANUFACTURER
++ depends on OTG_ACM && OTG
++ string "iManufacturer (string)"
++ default "Belcarra"
++
++config OTG_ACM_PRODUCT_NAME
++ depends on OTG_ACM && OTG
++ string "iProduct (string)"
++ default "Belcarra ACM Device"
++
++config OTG_ACM_DESC
++ depends on OTG_ACM && OTG
++ string "iConfiguration (string)"
++ default "Acm Cfg"
++
++config OTG_ACM_COMM_INTF
++ depends on OTG_ACM && OTG
++ string "Comm Interface iInterface (string)"
++ default "Comm Intf"
++
++config OTG_ACM_DATA_INTF
++ depends on OTG_ACM && OTG
++ string "Data Interface iInterface (string)"
++ default "Data Intf"
++
++config OTG_ACM_TRACE
++ depends on OTG_ACM && OTG
++ bool " ACM Tracing"
++ default n
++endmenu
++endmenu
+diff -uNr linux/drivers/no-otg/functions/acm/Makefile linux/drivers/otg/functions/acm/Makefile
+--- linux/drivers/no-otg/functions/acm/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/Makefile 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,80 @@
++#
++# Function driver for a CDC ACM USB Device
++#
++# Copyright (c) 2003 Belcarra
++
++# Multipart objects.
++
++O_TARGET := acm_fd_drv.o
++list-multi := acm_fd.o tty_fd.o
++
++#modem_fd-objs := acm-fd.o modem-l24-os.o modem.o
++#obex_fd-objs := acm-fd.o obex-l24-os.o obex.o
++tty_fd-objs := acm-fd.o tty-l24-os.o tty-fd.o
++
++# Objects that export symbols.
++#export-objs := acm-fd.o
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++#obj-$(CONFIG_OTG_ACM) += modem_fd.o
++#obj-$(CONFIG_OTG_ACM) += obex_fd.o
++obj-$(CONFIG_OTG_ACM) += tty_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++ACMD=$(OTG)/functions/acm
++
++OTG_DIR=$(TOPDIR)/drivers/otg
++OTGCORE_DIR=$(OTG_DIR)/otgcore
++#USBDCORE_DIR=$(OTG_DIR)/usbdcore
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -I$(OTG_DIR) -Wno-unused -Wno-format -I$(OTGCORE_DIR)
++EXTRA_CFLAGS_nostdinc += -I$(OTG_DIR) -Wno-unused -Wno-format -I$(OTGCORE_DIR)
++
++# Link rules for multi-part drivers.
++
++modem_fd.o: $(modem_fd-objs)
++ $(LD) -r -o $@ $(modem_fd-objs)
++
++obex_fd.o: $(obex_fd-objs)
++ $(LD) -r -o $@ $(obex_fd-objs)
++
++tty_fd.o: $(tty_fd-objs)
++ $(LD) -r -o $@ $(tty_fd-objs)
++
++# dependencies:
++
++#modem.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
++#obex.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
++#tty.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
++
+diff -uNr linux/drivers/no-otg/functions/acm/Makefile-l26 linux/drivers/otg/functions/acm/Makefile-l26
+--- linux/drivers/no-otg/functions/acm/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/Makefile-l26 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,13 @@
++# Function driver for a CDC ACM OTG Device
++#
++# Copyright (c) 2004 Belcarra
++
++acm_fd-objs := acm-fd.o acm-l26-os.o
++
++obj-$(CONFIG_OTG_ACM) += acm_fd.o
++
++OTG=$(TOPDIR)/drivers/otg
++ACMD=$(OTG)/functions/acm
++USBDCORE_DIR=$(OTG)/usbdcore
++EXTRA_CFLAGS += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR)
++EXTRA_CFLAGS_nostdinc += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR)
+diff -uNr linux/drivers/no-otg/functions/acm/OBEX-TODO.txt linux/drivers/otg/functions/acm/OBEX-TODO.txt
+--- linux/drivers/no-otg/functions/acm/OBEX-TODO.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/OBEX-TODO.txt 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,16 @@
++OBEX TODO List Stuart Lynne
++Belcarra Tue Aug 24 21:36:09 PDT 2004
++
++
++1. OBEX documentation
++
++
++2. define obex requirements
++
++ - similiar to acm
++ - uses comm interface for ?
++ - impelements data/nodata inteface
++
++ - socket family interface
++ - char device interface
++
+diff -uNr linux/drivers/no-otg/functions/acm/TODO.txt linux/drivers/otg/functions/acm/TODO.txt
+--- linux/drivers/no-otg/functions/acm/TODO.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/TODO.txt 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,143 @@
++ACM TODO List Stuart Lynne
++Belcarra Wed Sep 01 19:48:38 PDT 2004
++
++
++1. The ACM driver needs to be expanded to allow it to build three ways:
++
++
++ - tty equivalent of old acm, uses linux tty layer
++ - modem present two simple char devices for data and comm interfaces
++ - obex single simple char device
++
++TTY
++ - present a single char device with TTY line discipline
++ - TIOCM calls represent "state" of emulated serial port on this
++ side of null modem
++ - notifications and line state only affect far side of null modem
++
++MODEM
++ - present two simple char device interfaces
++ - data char device will implement TIOCM ioctls
++ - comm char device will use encapsulated data over endpoint zero
++ - TIOCM calls represent state passed to/from host via notifications
++ and line state requests
++
++OBEX
++ - present a single simple char device interface
++ - no requirement for either TIOCM or TTY line discipline
++ - TIOCM calls not implemented
++
++
++
++2. The modem device must implement a virtual NULL modem and support the
++following IOCTL's.
++
++
++
++Virtual NULL Modem
++
++Peripheral to Host via Serial State Notification (write ioctls)
++
++Application TIOCM Null Modem ACM (DCE) Notificaiton Host (DTE)
++-------------------------------------------------------------------------------------------------------------
++Request to send TIOCM_RTS RTS -> CTS CTS Not Available Clear to Send (N/A)
++Data Terminal Ready TIOCM_DTR DTR -> DSR DSR bTxCarrier Data Set Ready
++ DTR -> DCD DCD bRXCarrier Carrier Detect
++Ring Indicator TIOCM_OUT1 OUT1 -> RI RI bRingSignal Ring Indicator
++Send Break TIOCM_OUT2 OUT2 -> Break Break bBreak Break Received
++-------------------------------------------------------------------------------------------------------------
++
++
++Host to Peripheral via Set Control Line State
++
++Host (DTE) Line State ACM (DCE) Null Modem TIOCM Peripheral (DTE)
++-------------------------------------------------------------------------------------------------------------
++Data Terminal Ready D0 DTR DTR -> DSR TIOCM_DSR Data Set Ready
++ DTR -> DCD TIOCM_CAR Carrier Detect
++Request To Send D1 RTS RTS -> CTS TIOCM_CTS Clear to Send
++-------------------------------------------------------------------------------------------------------------
++
++
++3. The following DEVICE REQUESTS have to be implemented and where
++possible support added to hook the results to the upper layers
++and applications.
++
++ SetCommFeature
++ GetCommFeature
++ ClearCommFeature
++
++ SendEncapsulatedCommand
++ GetEncapsulatedResponse
++
++ SetLineCoding
++ GetLineCoding
++
++ SetControlLineState
++
++ SendBreak
++
++4. The following NOTIFICATIONS need to be implemented and where
++possible hooked to appropriate indications from upper layers
++and applications.
++
++
++ RESPONSE_AVAILABLE
++ NETWORK_CONNECTION
++ SERIAL_STATE
++
++
++
++5. ACM documentation needs to be updated to reflect implementation(s).
++
++
++6. POSIX IOCTLS
++ - TIOCM*
++ - hook into flow control or set from flow control as required
++ - baudrate and other device settings
++ - CTS should disable receive urb
++
++7. COMM Interface
++ - GET / SEND Encapsulated command
++ - response available notification
++ - char device interface
++
++8. Optional TTY
++ - register as TTY device only if requested
++ - register as simple char device otherwise
++
++9. select()
++ - trackdown tty layer problem with select()
++ - sometimes fails under stress testing
++
++
++Notes..
++
++1. implementation of the comm and simple char device can probably share
++the same code base. These should queue received urbs. This will mean
++a small change in the os between acm_recv_urb() and the os specific
++layer.
++
++2. Now it is acm_os_recv_chars(), this must change to acm_os_recv_urbs().
++The acm_os_recv_urbs() function will be responsible for deallocing the
++urb when delivered.
++
++3. The various os specific functions will need to have a method to
++distinguish between the comm and data interfaces.
++
++
++
++
++10. WMC - Wireless Mobice Class
++
++ Call Management - bmCapabilities allow call management over data interface
++ ACM - bmCapabilities - 0x06, only SEND_BREAK, SET/GET LINE_CODING
++
++ NETWORK_CONNECTION, XXX_COMM_FEATURE not allowed
++
++ Call management over COMM interface optional
++
++ COMM_FEATURE - optional?
++
++
++
++
+diff -uNr linux/drivers/no-otg/functions/acm/acm-fd.c linux/drivers/otg/functions/acm/acm-fd.c
+--- linux/drivers/no-otg/functions/acm/acm-fd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/acm-fd.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,1077 @@
++/*
++ * otg/functions/acm/acm-fd.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++/*!
++ * @file otg/functions/acm/acm-fd.c
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of several pieces:
++ *
++ * 1) An OS and function specific piece that handles creating and operating
++ * a device for the given OS suitable for a specific function.
++ *
++ * 2) A set descriptors suitable for the function.
++ *
++ * 3) This acm-fd library which implements the interface to
++ * the usb peripheral and otgcore stacks.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * an ACM class driver. If the USB piece interfaces with the otgcore
++ * layer you get an ACM function driver.
++ *
++ *
++ * @ingroup ACMFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++
++static u32 max_queued_urbs;
++static u32 max_queued_bytes;
++
++// Define the low order 16 bits of an urb's memory address as it's ID for tracing.
++#define urbID(urb) (0xffff & (u32) (void *) urb)
++
++/* ******************************************************************************************* */
++
++STATIC int acm_send_int_notification(struct acm_private *acm, int , int );
++STATIC int acmfd_urb_sent_bulk (struct usbd_urb *urb, int rc);
++STATIC int acmfd_urb_sent_int (struct usbd_urb *urb, int rc);
++STATIC int acmfd_recv_urb (struct usbd_urb *urb, int rc);
++STATIC void acm_schedule_recv(struct acm_private *acm, int interface);
++
++/* ******************************************************************************************* */
++
++/*! acm_ready
++ * @param acm
++ */
++STATIC int acm_ready(struct acm_private *acm)
++{
++ TRACE_MSG5(acm->trace_tag,"CONFIGURED: %x OPENED: %x THROTTLED: %x CARRIER: %x READY: %d",
++ acm->flags & ACM_CONFIGURED, acm->flags & ACM_OPENED,
++ acm->flags & ACM_THROTTLED, acm->flags & ACM_CARRIER,
++ (acm->flags & ACM_CONFIGURED) && (acm->flags & ACM_CARRIER) ? 1 : 0);
++
++ return (acm->flags & ACM_CONFIGURED) &&
++ (acm->flags & ACM_OPENED) &&
++ !(acm->flags & ACM_THROTTLED) &&
++ ((acm->flags & ACM_LOCAL) ? 1 : (acm->flags & ACM_CARRIER) )
++ ;
++
++}
++
++/*! acm_open
++ * @param acm
++ * @param interface
++ * @return int
++ */
++STATIC int acm_open(struct acm_private *acm, int interface)
++{
++ TRACE_MSG0(acm->trace_tag,"OPEN");
++ acm->flags |= ACM_OPENED;
++ acm->flags &= ~ACM_THROTTLED;
++ acm->bmUARTState = CDC_UARTSTATE_BRXCARRIER_DCD | CDC_UARTSTATE_BTXCARRIER_DSR;
++ acm_schedule_recv(acm, interface);
++ TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ return 0;
++}
++
++/*! acm_flush
++ * @param acm
++ * @param interface
++ * @return number of urbs in queue
++ */
++STATIC void acm_flush(struct acm_private *acm, int interface)
++{
++ struct usbd_function_instance *function = acm->function;
++ unsigned long flags;
++ TRACE_MSG0(acm->trace_tag,"FLUSH");
++ RETURN_UNLESS(function);
++ local_irq_save(flags);
++ acm->bytes_received = 0;
++ acm->bytes_forwarded = 0;
++ acm->bmUARTState = CDC_UARTSTATE_BRXCARRIER_DCD | CDC_UARTSTATE_BTXCARRIER_DSR;
++ TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
++ // TBR: 20040705 use ...le32() not le16, spotted by Zhao Liang
++ acm->line_coding.dwDTERate = cpu_to_le32(0x1c200); // 115200
++ acm->line_coding.bDataBits = 0x08;
++
++ usbd_flush_endpoint_index(function, BULK_IN);
++ usbd_flush_endpoint_index(function, BULK_OUT);
++ local_irq_restore(flags);
++}
++
++/*! acm_close
++ * @param acm
++ * @param interface
++ * @return number of urbs in queue
++ */
++STATIC int acm_close(struct acm_private *acm, int interface)
++{
++ TRACE_MSG0(acm->trace_tag,"CLOSE");
++ acm->flags &= ~ACM_OPENED;
++ acm->flags &= ~ACM_THROTTLED;
++ acm_flush(acm, interface);
++ acm->bmUARTState = 0;
++ TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ return 0;
++}
++
++
++/*! acmfd_start_recv_urbs
++ * @param acm
++ * @param interface
++ * @return number of urbs in queue
++ */
++STATIC int acmfd_start_recv_urbs(struct acm_private *acm, int interface)
++{
++ /*
++ * Queue as many receive urbs as the OS layer has room for. Return
++ * the number in the queue (may be more than we queue here).
++ */
++ struct usbd_function_instance *function = acm->function;
++ unsigned long flags;
++ int num_in_queue = 0;
++
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++ TRACE_MSG1(acm->trace_tag,"START RECV: acm: %x", (int)acm);
++ TRACE_MSG2(acm->trace_tag,"START RECV: connected: %x recv_urbs: %d",
++ acm->flags & ACM_CONFIGURED, acm->recv_urbs);
++
++ local_irq_save(flags);
++ if (acm_ready(acm)) {
++
++ TRACE_MSG2(acm->trace_tag,"START RECV: throttled: %d space_avail: %d", acm->flags & ACM_THROTTLED,
++ acm->function_services->recv_space_available(acm, DATA_INTF));
++
++ while (((acm->recv_urbs + 1) * 64) < acm->function_services->recv_space_available(acm, DATA_INTF)) {
++ struct usbd_urb *urb;
++
++ BREAK_IF(!(urb = usbd_alloc_urb(function, BULK_OUT, usbd_endpoint_transferSize(function,
++ BULK_OUT, usbd_high_speed(function)), acmfd_recv_urb)));
++ acm->recv_urbs++;
++ urb->function_privdata = acm;
++ TRACE_MSG3(acm->trace_tag,"START RECV: %d urb#%p privdata#%p",acm->recv_urbs,urb,acm);
++ CONTINUE_UNLESS (usbd_start_out_urb(urb));
++ acm->recv_urbs--;
++ TRACE_MSG1(acm->trace_tag,"START RECV: %d", acm->recv_urbs);
++ usbd_free_urb(urb);
++ break;
++ }
++ if (!acm->recv_urbs)
++ acm_schedule_recv(acm, interface);
++ }
++ /* There needs to be at least one recv urb queued in order
++ * to keep driving the push to the OS layer, so return how
++ * many there are in case the OS layer must try again later.
++ */
++ num_in_queue = acm->recv_urbs;
++ local_irq_restore(flags);
++ break;
++ }
++ return(num_in_queue);
++}
++
++
++struct acm_work acm_work;
++
++/*! acmfd_start_recv
++ * @param data
++ */
++STATIC void acmfd_start_recv(void *data)
++{
++ struct acm_work *work = data;
++ struct acm_private *acm;
++ unsigned long flags;
++ int interface;
++
++ local_irq_save(flags);
++ acm = work->acm;
++ interface = work->interface;
++ work->acm = NULL;
++ work->interface = -1;
++ acm->recv_tqueue.data = NULL;
++ local_irq_restore(flags);
++ acmfd_start_recv_urbs(acm, interface);
++}
++
++
++/*! acm_schedule_recv
++ * @param acm
++ * @param interface
++ */
++void acm_schedule_recv(struct acm_private *acm, int interface)
++{
++ unsigned long flags;
++ struct acm_work *work = &acm_work;
++ TRACE_MSG1(acm->trace_tag, "sync: %d", acm->recv_tqueue.sync);
++ local_irq_save(flags);
++
++ UNLESS (acm->recv_tqueue.sync && acm->recv_tqueue.data) {
++ work->acm = acm;
++ work->interface = interface;
++ acm->recv_tqueue.routine = &acmfd_start_recv;
++ acm->recv_tqueue.data = work;
++ #if defined(LINUX24)
++ queue_task(&acm->recv_tqueue, &tq_timer);
++ #else
++ SCHEDULE_WORK(acm->recv_tqueue);
++ #endif
++ }
++
++ local_irq_restore(flags);
++}
++
++/* Transmit INTERRUPT ************************************************************************** */
++
++/*! acm_send_int_notfication
++ * Generates a response urb on the notification (INTERRUPT) endpoint.
++ * CALLED from interrupt context.
++ * @return non-zero if error
++ */
++STATIC int acm_send_int_notification(struct acm_private *acm, int bnotification, int data)
++{
++ struct usbd_function_instance *function = acm->function;
++ struct usbd_urb *urb = NULL;
++ struct cdc_notification_descriptor *notification;
++ unsigned long flags;
++ int rc = 0;
++
++ TRACE_MSG4(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d data: %04x",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED, data);
++
++ RETURN_ZERO_UNLESS((acm->flags & ACM_CONFIGURED));
++
++ local_irq_save(flags);
++
++ do {
++ BREAK_IF(!(urb = usbd_alloc_urb(function, INT_IN,
++ sizeof(struct cdc_notification_descriptor),
++ acmfd_urb_sent_int)));
++
++ urb->function_privdata = acm;
++
++ memset(urb->buffer, 0, urb->buffer_length);
++ urb->actual_length = sizeof(struct cdc_notification_descriptor);
++
++ /* fill in notification structure */
++ notification = (struct cdc_notification_descriptor *) urb->buffer;
++
++ notification->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
++ notification->bNotification = bnotification;
++
++ switch (bnotification) {
++ case CDC_NOTIFICATION_NETWORK_CONNECTION:
++ notification->wValue = data;
++ break;
++ case CDC_NOTIFICATION_SERIAL_STATE:
++ notification->wLength = cpu_to_le16(2);
++ *((unsigned short *)notification->data) = cpu_to_le16(data);
++ break;
++ }
++
++ BREAK_IF(!(rc = usbd_start_in_urb (urb)));
++
++ urb->function_privdata = NULL;
++ usbd_free_urb (urb);
++
++ TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
++
++ } while(0);
++
++ local_irq_restore(flags);
++ return(rc);
++}
++
++/* Callback functions for TX urb completion (function chosen when urb is allocated) ***********/
++
++/*! acmfd_urb_sent_bulk - called to indicate bulk URB transmit finished
++ * @param urb pointer to struct usbd_urb
++ * @param rc result
++ * @return non-zero for error
++ */
++STATIC int acmfd_urb_sent_bulk (struct usbd_urb *urb, int rc)
++{
++ struct acm_private *acm = urb->function_privdata;
++ struct usbd_function_instance *function;
++
++ TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++
++ if (!urb || !(function = urb->function_instance)) {
++ TRACE_MSG1(acm->trace_tag,"urbID#%04x --> -EINVAL",urbID(urb));
++ return(-EINVAL);
++ }
++ TRACE_MSG1(acm->trace_tag,"IN length=%d",urb->actual_length);
++
++ atomic_sub(urb->actual_length, &acm->queued_bytes);
++ atomic_dec(&acm->queued_urbs);
++ urb->function_privdata = NULL;
++ usbd_free_urb (urb);
++ if (acm->flags & ACM_OPENED)
++ acm->function_services->schedule_wakeup_writers(acm);
++ TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
++ return 0;
++}
++
++/*! acmfd_urb_sent_int - called to indicate int URB transmit finished
++ * @param urb pointer to struct usbd_urb
++ * @param rc result
++ * @return non-zero for error
++ */
++STATIC int acmfd_urb_sent_int (struct usbd_urb *urb, int rc)
++{
++ struct acm_private *acm = urb->function_privdata;
++ struct usbd_function_instance *function;
++
++ TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++ if (!urb || !(function = urb->function_instance)) {
++ TRACE_MSG1(acm->trace_tag,"urbID#%04x --> -EINVAL",urbID(urb));
++ return(-EINVAL);
++ }
++ TRACE_MSG1(acm->trace_tag,"INT length=%d",urb->actual_length);
++
++ urb->function_privdata = NULL;
++ usbd_free_urb(urb);
++ TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
++ return 0;
++}
++
++/*! acmfd_urb_sent_ep0 - called to indicate ep0 URB transmit finished
++ * @param urb pointer to struct usbd_urb
++ * @param rc result
++ * @return non-zero for error
++ */
++STATIC int acmfd_urb_sent_ep0 (struct usbd_urb *urb, int rc)
++{
++ struct acm_private *acm = urb->function_privdata;
++ struct usbd_function_instance *function;
++
++ TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++
++ RETURN_EINVAL_IF (!urb || !(function = urb->function_instance));
++
++ TRACE_MSG1(acm->trace_tag,"INT length=%d",urb->actual_length);
++
++ urb->function_privdata = NULL;
++ usbd_free_urb(urb);
++ return 0;
++}
++
++/* USB Device Functions ************************************************************************ */
++
++typedef enum mesg {
++ mesg_unknown,
++ mesg_configured,
++ mesg_reset,
++} mesg_t;
++mesg_t acm_last_mesg;
++
++char * acm_messages[3] = {
++ "",
++ "ACM Configured",
++ "ACM Reset",
++};
++
++
++/*! acmfd_check_mesg
++ * @param curr_mesg
++ */
++void acmfd_check_mesg(mesg_t curr_mesg)
++{
++ RETURN_UNLESS(acm_last_mesg != curr_mesg);
++ acm_last_mesg = curr_mesg;
++ otg_message(acm_messages[curr_mesg]);
++}
++
++
++/*! acmfd_event_handler - process a device event
++ * @param function
++ * @param event
++ * @param data
++ */
++void acmfd_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct acm_private *acm = function->privdata;
++ int i;
++
++ TRACE_MSG1(acm->trace_tag,"entered ev: %d",event);
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d ready: %d", atomic_read(&acm->used), MOD_IN_USE, acm_ready(acm));
++
++ switch (event) {
++
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(acm->trace_tag,"CONFIGURED");
++ acm->flags |= ACM_CONFIGURED;
++ acmfd_check_mesg(mesg_configured);
++ acmfd_start_recv_urbs(acm, DATA_INTF);
++ break;
++
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG0(acm->trace_tag,"RESET");
++
++ /* if configured and open then schedule hangup
++ */
++ if ((acm->flags & ACM_OPENED) && (acm->flags & ACM_CONFIGURED))
++ acm->function_services->schedule_hangup(acm);
++
++ acm->flags &= ~(ACM_CONFIGURED | ACM_CARRIER);
++ acmfd_check_mesg(mesg_reset);
++ BREAK_IF(!acm->flags & ACM_CONFIGURED);
++ TRACE_MSG0(acm->trace_tag,"RESET continue");
++ // XXX flush
++ // Release any queued urbs
++ break;
++
++ default:
++ break;
++ }
++ TRACE_MSG0(acm->trace_tag,"exited");
++}
++
++/*! acm_write_room
++ * @param acm
++ * @param interface
++ * @return non-zero if error
++ */
++STATIC int acm_write_room(struct acm_private *acm, int interface)
++{
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++ return (!acm->function || max_queued_urbs <= atomic_read(&acm->queued_urbs) ||
++ max_queued_bytes <= atomic_read(&acm->queued_bytes) ) ? 0 : acm->writesize ;
++ }
++ return 0;
++}
++
++/*! acm_chars_in_buffer
++ * @param acm
++ * @param interface
++ * @return non-zero if error
++ */
++STATIC int acm_chars_in_buffer(struct acm_private *acm, int interface)
++{
++ int rc;
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++ return atomic_read(&acm->queued_bytes);
++ }
++ return 0;
++}
++
++static int throttle_count = 0;
++static int unthrottle_count = 0;
++
++/*! acm_throttle
++ * @param acm
++ * @param interface
++ */
++STATIC void acm_throttle(struct acm_private *acm, int interface)
++{
++ switch (interface) {
++ case COMM_INTF:
++ break;
++ case DATA_INTF:
++ throttle_count += 1;
++ TRACE_MSG1(acm->trace_tag,"entered %d",throttle_count);
++ acm->flags |= ACM_THROTTLED;
++ TRACE_MSG1(acm->trace_tag,"exited %d",throttle_count);
++ break;
++ }
++}
++
++/*! acm_unthrottle
++ * @param acm
++ * @param interface
++ */
++STATIC void acm_unthrottle(struct acm_private *acm, int interface)
++{
++ switch (interface) {
++ case COMM_INTF:
++ break;
++ case DATA_INTF:
++ unthrottle_count += 1;
++ TRACE_MSG1(acm->trace_tag,"entered %d",unthrottle_count);
++ acm->flags &= ~ACM_THROTTLED;
++ TRACE_MSG1(acm->trace_tag,"exited %d",unthrottle_count);
++ UNLESS(acm->recv_urbs)
++ acm_schedule_recv(acm, interface);
++ break;
++ }
++}
++
++/*! acm_xmit_chars
++ * @param acm
++ * @param interface
++ * @param count
++ * @param from_user
++ * @param buf
++ * @return number of bytes sent.
++ */
++STATIC int acm_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
++{
++ struct usbd_function_instance *function = acm->function;
++ struct usbd_urb *urb;
++
++ RETURN_ZERO_UNLESS((acm->flags & ACM_CONFIGURED) /*&& (acm->flags & ACM_CARRIER)*/);
++
++ TRACE_MSG2(acm->trace_tag, "count: %d from_user: %d", count, from_user);
++
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++ // sanity check and are we connect
++ RETURN_ZERO_UNLESS(atomic_read(&acm->used));
++ TRACE_MSG0(acm->trace_tag,"used OK");
++ RETURN_ZERO_UNLESS (count);
++ RETURN_ZERO_UNLESS (acm->flags & ACM_CONFIGURED);
++ TRACE_MSG0(acm->trace_tag,"connected OK");
++ RETURN_ZERO_IF(max_queued_urbs <= atomic_read(&acm->queued_urbs));
++ TRACE_MSG0(acm->trace_tag,"max_queued_urbs OK");
++
++ // allocate a write urb
++ count = MIN(count, acm->writesize);
++
++ RETURN_ZERO_UNLESS ((urb = usbd_alloc_urb (function, BULK_IN, count, acmfd_urb_sent_bulk)));
++
++ if (from_user)
++ copy_from_user ((void *)urb->buffer, (void *)buf, count);
++ else
++ memcpy ((void *)urb->buffer, (void *)buf, count);
++
++ urb->function_privdata = acm;
++ urb->actual_length = count;
++ atomic_add(count, &acm->queued_bytes);
++ atomic_inc(&acm->queued_urbs);
++ usbd_start_in_urb(urb);
++ TRACE_MSG2(acm->trace_tag,"urbID#%04x --> count: %d",urbID(urb),count);
++ return count;
++ default:
++ break;
++ }
++ return 0;
++}
++
++/*! acmfd_recv_urb
++ * @param urb
++ * @param rc
++ * @return non-zero if error
++ */
++STATIC int acmfd_recv_urb (struct usbd_urb *urb, int rc)
++{
++ /* Return 0 if urb has been accepted,
++ * return 1 and expect caller to deal with urb release otherwise.
++ */
++ struct acm_private *acm = urb->function_privdata;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ acm->recv_urbs--; // this could probably be atomic operation....
++ local_irq_restore(flags);
++
++ if (RECV_CANCELLED == rc) {
++ TRACE_MSG1(acm->trace_tag,"cancelled URB=%p",urb);
++ return -EINVAL;
++ }
++ if (RECV_OK != rc) {
++ TRACE_MSG2(acm->trace_tag,"rejected URB=%p rc=%d",urb,rc);
++ usbd_free_urb(urb);
++ acm_schedule_recv(acm, DATA_INTF);
++ //acmfd_start_recv_urbs(acm, DATA_INTF);
++ return 0;
++ }
++
++ /* loopback mode
++ */
++ if (acm->flags & ACM_LOOPBACK)
++ acm_xmit_chars(acm, DATA_INTF, urb->actual_length, 0, urb->buffer);
++
++ /* acmfd_start_recv_urbs() will never queue more urbs than there is currently
++ * room in the upper layer buffer for. So we are guaranteed that any data actually
++ * received can be given to the upper layers without worrying if we will
++ * actually have room.
++ */
++ else
++ if ((rc = acm->function_services->recv_chars(acm, DATA_INTF, urb->buffer, urb->actual_length)))
++ return(rc); // XXX
++
++
++ acm->bytes_received += urb->actual_length;
++ TRACE_MSG1(acm->trace_tag,"bytes_received: %d",acm->bytes_received);
++ usbd_free_urb(urb);
++ acm_schedule_recv(acm, DATA_INTF);
++ return 0;
++
++#if 0
++ // XXX it may be reasonable to schedule here....
++ UNLESS (acmfd_start_recv_urbs(acm, DATA_INTF)) {
++ /* If start recv returns zero it means that there are no-queued urbs,
++ * and we should queue a work item to restart.
++ */
++ acm_schedule_recv(acm, DATA_INTF);
++ }
++#endif
++ return 0;
++}
++
++/*! acmfd_line_coding_urb_received - callback for sent URB
++ *
++ * Handles notification that an urb has been sent (successfully or otherwise).
++ *
++ * @param urb
++ * @param urb_rc
++ * @return non-zero for failure.
++ */
++STATIC int acmfd_line_coding_urb_received (struct usbd_urb *urb, int urb_rc)
++{
++ struct acm_private *acm = urb->function_privdata;
++ TRACE_MSG2(acm->trace_tag,"urbID#%04x rc=%d",urbID(urb),urb_rc);
++
++ RETURN_EINVAL_IF (RECV_OK != urb_rc);
++ RETURN_EINVAL_IF (urb->actual_length < sizeof(struct cdc_acm_line_coding));
++
++ RETURN_EINVAL_UNLESS (memcpy(&acm->line_coding, urb->buffer, sizeof(struct cdc_acm_line_coding)));
++
++ // something changed, copy and notify
++
++ memcpy(&acm->line_coding, urb->buffer, sizeof(struct cdc_acm_line_coding));
++
++ // XXX notify application if baudrate has changed
++
++ return -EINVAL; // caller will de-allocate
++}
++
++/*! acmfd_device_request - called to indicate urb has been received
++ * @param function
++ * @param request
++ * @return non-zero if error
++ */
++int acmfd_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct acm_private *acm = (struct acm_private *) (function->privdata);
++
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++
++ TRACE_SETUP(acm->trace_tag,request);
++
++ // verify that this is a usb class request per cdc-acm specification or a vendor request.
++ if (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR))) {
++ TRACE_MSG0(acm->trace_tag,"--> 0");
++ return(0);
++ }
++
++ // determine the request direction and process accordingly
++ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
++
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case CDC_CLASS_REQUEST_SEND_ENCAPSULATED: break;
++ case CDC_CLASS_REQUEST_SET_COMM_FEATURE: break;
++ case CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE: break;
++ case CDC_CLASS_REQUEST_SET_LINE_CODING:
++ {
++ struct usbd_urb *urb;
++ int len = le16_to_cpu(request->wLength);
++ TRACE_MSG1(acm->trace_tag,"SET_LINE_CODING wLength=%d",len);
++ if (len <= 0) {
++ TRACE_MSG0(acm->trace_tag,"(len<=0)--> 0");
++ return(0);
++ }
++
++ /* Set up an ep0 recv urb for the rest of it. */
++ UNLESS ((urb = usbd_alloc_urb_ep0(function, len, acmfd_line_coding_urb_received))) {
++ TRACE_MSG0(acm->trace_tag,"no mem for ep0 recv urb");
++ return(-ENOMEM);
++ }
++ urb->function_privdata = acm;
++ if (usbd_start_out_urb(urb)) {
++ TRACE_MSG0(acm->trace_tag,"usbd_start_out_urb() failed");
++ usbd_free_urb(urb); // de-alloc if error
++ TRACE_MSG0(acm->trace_tag,"--> -EINVAL");
++ return(-EINVAL);
++ }
++ }
++ break;
++
++ case CDC_CLASS_REQUEST_SET_CONTROL_LINE_STATE:
++ {
++ unsigned int prev_bmLineState = acm->bmLineState;
++ acm->bmLineState = le16_to_cpu(request->wValue);
++
++ // schedule writers or hangup IFF open
++ BREAK_IF(!acm->privdata);
++ TRACE_MSG3(acm->trace_tag,"set control state, bmLineState: %04x previous: %04x changed: %04x",
++ acm->bmLineState, prev_bmLineState, acm->bmLineState ^ prev_bmLineState);
++
++ // make sure there really is a state change
++ if ((acm->bmLineState ^ prev_bmLineState) & CDC_LINESTATE_D0_DTR) {
++
++ TRACE_MSG1(acm->trace_tag,"DTR state changed -> %x",
++ (acm->bmLineState & CDC_LINESTATE_D0_DTR));
++
++ if (acm->bmLineState & CDC_LINESTATE_D0_DTR) {
++ if (acm->flags & ACM_OPENED)
++ acm->function_services->schedule_wakeup_writers(acm);
++ acm->flags |= ACM_CARRIER;
++ acm_schedule_recv(acm, DATA_INTF);
++ }
++ else {
++ if (acm->flags & ACM_OPENED)
++ acm->function_services->schedule_hangup(acm);
++
++ acm->flags &= ~ACM_CARRIER;
++ acm_flush(acm, DATA_INTF);
++ }
++
++ /* wake up blocked opens */
++ acm->function_services->wakeup_opens(acm);
++
++ /* wake up blocked ioctls */
++ acm->function_services->wakeup_state(acm);
++
++ }
++
++
++
++ /* send notification if we have DCD */
++ TRACE_MSG2(acm->trace_tag,"bmUARTState: %04x privdata: %p sending (DCD|DSR) notification",
++ acm->bmUARTState, acm->privdata);
++
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ }
++ break;
++
++ case CDC_CLASS_REQUEST_SEND_BREAK: break;
++ default: break;
++ }
++ TRACE_MSG0(acm->trace_tag,"--> 0");
++ return 0;
++
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case CDC_CLASS_REQUEST_GET_ENCAPSULATED: break;
++ case CDC_CLASS_REQUEST_GET_COMM_FEATURE: break;
++ case CDC_CLASS_REQUEST_GET_LINE_CODING:
++ {
++ struct usbd_urb *urb;
++ RETURN_ENOMEM_IF (!(urb = usbd_alloc_urb_ep0(function, sizeof(struct cdc_acm_line_coding),
++ acmfd_urb_sent_ep0)));
++ urb->function_privdata = acm;
++
++ memcpy(urb->buffer, &acm->line_coding, sizeof(struct cdc_acm_line_coding));
++
++ urb->actual_length = sizeof(struct cdc_acm_line_coding);
++
++ TRACE_MSG1(acm->trace_tag,"sending line coding urb: %p",(u32)(void*)urb);
++ RETURN_ZERO_UNLESS(usbd_start_in_urb(urb));
++ usbd_free_urb(urb);
++ TRACE_MSG0(acm->trace_tag,"(send failed)--> -EINVAL");
++ }
++ return -EINVAL;
++ default: break;
++ }
++ TRACE_MSG0(acm->trace_tag,"--> 0");
++ return 0;
++
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: break;
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR: break;
++
++ default: break;
++ }
++ TRACE_MSG0(acm->trace_tag,"--> 0");
++ return 0;
++}
++
++
++/*! acmfd_function_enable
++ * @param function
++ * @return non-zero if error
++ */
++STATIC int acmfd_function_enable (struct usbd_function_instance *function)
++{
++ struct acm_private *acm = (struct acm_private *) (function->privdata);
++
++ TRACE_MSG0(acm->trace_tag,"entered");
++ TRACE_MSG1(acm->trace_tag,"INC: %d", MOD_IN_USE);
++ acm->function_services->enable(function);
++ acm->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, 0) * 24;
++
++ TRACE_MSG0(acm->trace_tag,"-> 0");
++ return 0;
++}
++
++/*! acmfd_function_disable
++ * @param function
++ */
++STATIC void acmfd_function_disable (struct usbd_function_instance *function)
++{
++ struct acm_private *acm = (struct acm_private *) (function->privdata);
++
++ TRACE_MSG0(acm->trace_tag,"entered");
++ acm->writesize = 0;
++ acm->function_services->disable(function);
++ TRACE_MSG1(acm->trace_tag,"DEC: %d", MOD_IN_USE);
++ TRACE_MSG0(acm->trace_tag,"exited");
++}
++
++
++/*! function_ops
++ */
++struct usbd_function_operations function_ops = {
++ event_handler: acmfd_event_handler,
++ device_request: acmfd_device_request,
++ function_enable: acmfd_function_enable,
++ function_disable: acmfd_function_disable,
++};
++
++/*! acm_fd_init
++ * @param acm
++ * @param usbd_module_info
++ * @param vendor_id
++ * @param product_id
++ * @param wmax_urbs
++ * @param wmax_bytes
++ * @return non-zero if error
++ */
++STATIC int acm_fd_init(struct acm_private *acm, char *usbd_module_info, u32 vendor_id, u32 product_id,
++ u32 wmax_urbs, u32 wmax_bytes)
++{
++
++ TRACE_MSG0(acm->trace_tag,"entered");
++
++ if (vendor_id)
++ acm->function_driver->idVendor = cpu_to_le16(vendor_id);
++ if (product_id)
++ acm->function_driver->idProduct = cpu_to_le16(product_id);
++ max_queued_urbs = wmax_urbs;
++ max_queued_bytes = wmax_bytes;
++
++ THROW_IF (NULL == (acm->function = usbd_register_function (acm->function_driver, "acm-fd", acm)), error);
++
++ CATCH(error) {
++ printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
++
++ if (acm->function) {
++ usbd_deregister_function (acm->function);
++ acm->function = NULL;
++ }
++ TRACE_MSG0(acm->trace_tag,"--> -EINVAL");
++ return -EINVAL;
++ }
++ TRACE_MSG0(acm->trace_tag,"--> 0");
++ return 0;
++}
++
++
++
++/*! acm_wait_task
++ * @param acm
++ * @param queue
++ */
++void acm_wait_task(struct acm_private *acm, WORK_ITEM *queue)
++{
++ TRACE_MSG1(acm->trace_tag,"entered data=%p",queue->data);
++ RETURN_IF(!queue->data);
++ queue->data = NULL;
++#if defined(LINUX24)
++ while (queue->sync) {
++ TRACE_MSG1(acm->trace_tag,"waiting for queue: %p",queue);
++ schedule_timeout(HZ);
++ }
++#else
++ while(PENDING_WORK_ITEM((*queue))){
++ TRACE_MSG1(acm->trace_tag,"waiting for queue: %p",queue);
++ SCHEDULE_TIMEOUT(1); // 1 second delay
++ }
++#endif
++ TRACE_MSG0(acm->trace_tag,"exited");
++}
++
++
++/*! acm_get_dtr
++ * Get DTR status.
++ */
++int acm_get_dtr(struct acm_private *acm)
++{
++ return (acm->bmLineState & CDC_LINESTATE_D0_DTR) ? 1 : 0;
++}
++
++/*! acm_get_dsr
++ * Get DSR status
++ */
++int acm_get_dsr(struct acm_private *acm)
++{
++ return (acm->bmUARTState & CDC_UARTSTATE_BTXCARRIER_DSR) ? 1 : 0;
++}
++
++/*! acm_get_dcd
++ * Get DCD status
++ */
++int acm_get_dcd(struct acm_private *acm)
++{
++ return (acm->bmUARTState & CDC_UARTSTATE_BRXCARRIER_DCD) ? 1 : 0;
++}
++
++/*! acm_set_dsr
++ * Set DSR status
++ * @param acm
++ * @param value
++ */
++void acm_set_dsr(struct acm_private *acm, int value)
++{
++ acm->bmUARTState &= ~CDC_UARTSTATE_BTXCARRIER_DSR;
++ acm->bmUARTState |= value ? CDC_UARTSTATE_BTXCARRIER_DSR : 0;
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++}
++
++/*! acm_set_dcd
++ * Set DCD status
++ * @param acm
++ * @param value
++ */
++void acm_set_dcd(struct acm_private *acm, int value)
++{
++ acm->bmUARTState &= ~CDC_UARTSTATE_BRXCARRIER_DCD;
++ acm->bmUARTState |= value ? CDC_UARTSTATE_BRXCARRIER_DCD : 0;
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++}
++
++/*! acm_ring
++ * Indicate Ring signal to host.
++ */
++void acm_ring(struct acm_private *acm)
++{
++ acm->bmUARTState |= CDC_UARTSTATE_BRINGSIGNAL;
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ acm->bmUARTState &= ~CDC_UARTSTATE_BRINGSIGNAL;
++}
++
++/*! acm_send_break
++ * Indicate Break signal to host.
++ */
++void acm_send_break(struct acm_private *acm)
++{
++ acm->bmUARTState |= CDC_UARTSTATE_BBREAK;
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ acm->bmUARTState &= ~CDC_UARTSTATE_BBREAK;
++}
++
++/*! acm_overrun
++ * Indicate Overrun signal to host.
++ */
++void acm_overrun(struct acm_private *acm)
++{
++ acm->bmUARTState |= CDC_UARTSTATE_BOVERRUN;
++ acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
++ acm->bmUARTState &= ~CDC_UARTSTATE_BOVERRUN;
++}
++
++/*! acm_set_local
++ * Set LOCAL status
++ * @param acm
++ * @param value
++ */
++void acm_set_local(struct acm_private *acm, int value)
++{
++ acm->flags &= ~ACM_LOCAL;
++ acm->flags |= value ? ACM_LOCAL : 0;
++}
++
++/*! acm_set_loopback
++ * Set LOOPBACK status
++ * @param acm
++ * @param value
++ */
++void acm_set_loopback(struct acm_private *acm, int value)
++{
++ acm->flags &= ~ACM_LOOPBACK;
++ acm->flags |= value ? ACM_LOOPBACK : 0;
++}
++
++
++
++/*! acm_fd_term
++ * @param acm
++ */
++STATIC void acm_fd_exit(struct acm_private *acm)
++{
++ //acm_wait_task(acm->recv_tqueue);
++ RETURN_UNLESS (acm->function);
++ usbd_deregister_function (acm->function);
++ acm->function = NULL;
++}
++
++/*!
++ * Function table exported to the OS specific upper layer.
++ */
++struct acm_usb_services acm_fd_usb_ops = {
++ .fd_init = acm_fd_init,
++ .fd_exit = acm_fd_exit,
++ .xmit_chars = acm_xmit_chars,
++ .send_int_notification = acm_send_int_notification,
++ .throttle = acm_throttle,
++ .unthrottle = acm_unthrottle,
++ .write_room = acm_write_room,
++ .chars_in_buffer = acm_chars_in_buffer,
++ .wait_task = acm_wait_task,
++ .schedule_recv = acm_schedule_recv,
++ .open = acm_open,
++ .close = acm_close,
++ .flush = acm_flush,
++ .ready = acm_ready,
++ .get_dtr = acm_get_dtr,
++ .get_dsr = acm_get_dsr,
++ .get_dcd = acm_get_dcd,
++ .set_dsr = acm_set_dsr,
++ .set_dcd = acm_set_dcd,
++ .ring = acm_ring,
++ .send_break = acm_send_break,
++ .overrun = acm_overrun,
++ .set_local = acm_set_local,
++ .set_loopback = acm_set_loopback,
++};
++
+diff -uNr linux/drivers/no-otg/functions/acm/acm-fd.h linux/drivers/otg/functions/acm/acm-fd.h
+--- linux/drivers/no-otg/functions/acm/acm-fd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/acm-fd.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,242 @@
++/*
++ * otg/functions/acm/acm-fd.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/acm/acm-fd.h
++ * @brief ACM Function Driver private defines
++ *
++ * The top and bottom halves of the driver comunication via these structures.
++ *
++ * @ingroup ACMFunction
++ */
++
++#ifndef ACM_FD_H
++#define ACM_FD_H 1
++
++typedef void (*cpy_fn)(u8 *dst, u8 *src, int len);
++
++/*! acm_usb_services
++ * Services that the acm_fd library provides.
++ */
++struct acm_usb_services {
++
++ /*! fd_init - called to initialize the acm_fd library
++ * This call initialized the acm_fd library and registers the function driver
++ * with the USB Peripheral Stack.
++ */
++ int (*fd_init)(struct acm_private *acm, char *inf, u32 vendor_id, u32 product_id, u32 wmax_urbs, u32 wmax_bytes);
++
++ /*! fd_exit - called before exiting
++ * This call will cause the function driver to be de-registered.
++ */
++ void (*fd_exit)(struct acm_private *acm);
++
++ /*! open - device open
++ * This is called the device is opened (first open only if non-exclusive opens allowed).
++ */
++ int (*open)(struct acm_private *acm, int interface);
++
++ /*! close - Device close
++ * This is called when the device closed (last close only if non-exclusive opens allowed.)
++ */
++ int (*close)(struct acm_private *acm, int interface);
++
++
++ /*! flush - flush data urbs.
++ * Cancel outstanding data urbs.
++ */
++ void (*flush)(struct acm_private *acm, int interface);
++
++ /*! schedule_recv - queue as many data receive urbs as possible
++ * This will schedule a bottom half hander that will will start as
++ * many receive data urbs as are allowed given the amount of room
++ * available in the upper layer. If no urbs are queued by the
++ * bottom half handler it will re-schedule itself.
++ */
++ void (*schedule_recv)(struct acm_private *acm, int interface);
++
++ /*! throttle - set throttle flag for specified interface
++ * Receive urbs will not be queued when throttled.
++ */
++ void (*throttle)(struct acm_private *acm, int interface);
++
++ /*! unthrottle - reset throttle flag for specified interface
++ * Receive urbs are allowed to be queued. If no urbs are queued a
++ * bottom half handler will be scheduled to queue them.
++ */
++ void (*unthrottle)(struct acm_private *acm, int interface);
++
++
++ /*! xmit_chars - send data via specified interface
++ * This will start a transmit urb to send the specified data. The
++ * number of characters sent will be returned.
++ */
++ int (*xmit_chars)(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf);
++
++ /*! write_room
++ * Return amount of data that could be queued for sending.
++ */
++ int (*write_room)(struct acm_private *acm, int interface);
++
++ /*! chars_in_buffer
++ * Return number of chars in xmit buffer.
++ */
++ int (*chars_in_buffer)(struct acm_private *acm, int interface);
++
++
++ /*! send_int_notification - send notification via interrupt endpoint
++ * This can be used to queue network, serial state change notifications.
++ */
++ int (*send_int_notification)(struct acm_private *acm, int bnotification, int data);
++
++ /*! wait_task - wait for task to complete.
++ */
++ void (*wait_task)(struct acm_private *acm, WORK_ITEM *queue);
++
++ /*! ready - return true if connected and carrier
++ */
++ int (*ready)(struct acm_private *acm);
++
++ /*! get_dtr
++ * Get DTR status.
++ */
++ int (*get_dtr)(struct acm_private *acm);
++
++ /*! get_dsr
++ * Get DSR status
++ */
++ int (*get_dsr)(struct acm_private *acm);
++
++ /*! get_dcd
++ * Get DCD status
++ */
++ int (*get_dcd)(struct acm_private *acm);
++
++ /*! set_dsr
++ * Set DSR status
++ */
++ void (*set_dsr)(struct acm_private *acm, int value);
++
++ /*! set_dcd
++ * Set DCD status
++ */
++ void (*set_dcd)(struct acm_private *acm, int value);
++
++ /*! ring
++ * Indicate Ring signal to host.
++ */
++ void (*ring)(struct acm_private *acm);
++
++ /*! send_break
++ * Indicate Break signal to host.
++ */
++ void (*send_break)(struct acm_private *acm);
++
++ /*! overrun
++ * Indicate Overrun signal to host.
++ */
++ void (*overrun)(struct acm_private *acm);
++
++
++ /*! set_local
++ * Set LOCAL status
++ */
++ void (*set_local)(struct acm_private *acm, int value);
++
++ /*! set_loopback - set loopback mode
++ * Sets LOOP flag, data received from the host will be immediately
++ * returned without passing to the upper layer.
++ */
++ void (*set_loopback)(struct acm_private *acm, int value);
++};
++
++/*! acm_function_services
++ * Services that the top level driver provides to the lower library.
++ */
++struct acm_function_services {
++ /*! enable
++ * Enable the function driver.
++ */
++ void (*enable)(struct usbd_function_instance *function);
++
++ /*! disable
++ * Disable the function driver.
++ */
++ void (*disable)(struct usbd_function_instance *function);
++
++ /*! wakeup_opens
++ * Wakeup processes waiting for DTR.
++ */
++ void (*wakeup_opens)(struct acm_private *acm);
++
++ /*! wakeup_opens
++ * Wakeup processes waiting for state change.
++ */
++ void (*wakeup_state)(struct acm_private *acm);
++
++ /*! wakeup writers
++ * Wakeup pending writes.
++ */
++ void (*schedule_wakeup_writers)(struct acm_private *acm);
++
++ /*! recv_space_available
++ * Check for amount of receive space that is available, controls
++ * amount of receive urbs that will be queued.
++ */
++ int (*recv_space_available)(struct acm_private *acm, int interface);
++
++ /*! recv_chars
++ * Process chars received on specified interface.
++ */
++ int (*recv_chars)(struct acm_private *acm, int interface, u8 *cp, int n);
++
++
++ /*! schedule_hangup
++ * Schedule a work item that will perform a hangup.
++ */
++ void (*schedule_hangup)(struct acm_private *acm);
++
++ /*! comm_feature
++ * Tell function that comm feature has changed.
++ */
++ void (*comm_feature)(struct acm_private *acm);
++
++ /*! line_coding
++ * Tell function that line coding has changed.
++ */
++ void (*line_coding)(struct acm_private *acm);
++
++ /*! control_state
++ * Tell function that control state has changed.
++ */
++ void (*control_state)(struct acm_private *acm);
++
++ /*! send_break
++ * Tell function to send a break signal.
++ */
++ void (*send_break)(struct acm_private *acm);
++
++};
++
++extern struct acm_usb_services acm_fd_usb_ops;
++extern struct usbd_function_operations function_ops;
++
++
++/*
++ * otg-trace tag.
++ */
++extern otg_tag_t acm_fd_trace_tag;
++
++#define MAX_QUEUED_BYTES 256
++#define MAX_QUEUED_URBS 10 // Max for write
++
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/acm/acm-os.h linux/drivers/otg/functions/acm/acm-os.h
+--- linux/drivers/no-otg/functions/acm/acm-os.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/acm-os.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++ * otg/functions/acm/acm-os.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @file otg/functions/acm/acm-os.h
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of two pieces:
++ * 1) An OS specific piece that handles creating and operating
++ * a serial device for the given OS.
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the otgcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * an ACM class driver. If the USB piece interfaces with the otgcore
++ * layer you get an ACM function driver.
++ *
++ * This file describes the functions exported by the various acm-*-os.c
++ * files (implementing (1)) for use in acm-fd.c (2).
++ *
++ * @ingroup ACMFunction
++ */
++
++#ifndef ACM_OS_H
++#define ACM_OS_H 1
++
++/*
++ * acm_os_recv_space_available - return the number of bytes of data
++ * the OS specific piece can accept without
++ * dropping some.
++ */
++extern int acm_os_recv_space_available(struct acm_private *acm);
++
++/*
++ * acm_os_recv_chars - receive n bytes starting at cp. This will never be
++ * more than the last call to acm_os_recv_space_available().
++ * This will be called from interrupt context.
++ */
++extern int acm_os_recv_chars(struct acm_private *acm, u8 *cp, int n);
++
++/*
++ * acm_os_wakeup_writers - wakeup any blocked writers. This is called
++ * from interrupt context, so may need to queue
++ * the actual wakeup in a "bottom half".
++ */
++extern void acm_os_wakeup_writers(struct acm_private *acm);
++
++/*
++ * acm_os_hangup - send a hangup to any readers or writers. This can be
++ * called from interrupt context, so may need to queue
++ * the actual hangup in a "bottom half".
++ */
++extern void acm_os_hangup(struct acm_private *acm);
++
++/*
++ * acm_os_wakeup_opens - wakeup any blocked opens. This is called
++ * from interrupt context, so may need to queue
++ * the actual wakeup in a "bottom half".
++ */
++extern void acm_os_wakeup_opens(struct acm_private *acm);
++
++extern void acm_os_enable(struct usbd_function_instance *function);
++extern void acm_os_disable(struct usbd_function_instance *function);
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/acm/acm.h linux/drivers/otg/functions/acm/acm.h
+--- linux/drivers/no-otg/functions/acm/acm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/acm.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ * otg/functions/acm/acm.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup ACMFunction ACM
++ * @ingroup functiongroup
++ */
++
++/*!
++ * @file otg/functions/acm/acm.h
++ * @brief ACM Function Driver private defines
++ *
++ * This is an ACM Function Driver. The upper edge is exposed
++ * to the hosting OS as a Posix type character device. The lower
++ * edge implements the USB Device Stack API.
++ *
++ * This driver implements the CDC ACM driver model and uses the CDC ACM
++ * protocols.
++ *
++ * Note that it appears to be impossible to determine the end of a receive
++ * bulk transfer larger than wMaxPacketsize. The host is free to send
++ * wMaxPacketsize chars in a single transfer. This means that we cannot
++ * queue receive urbs larger than wMaxPacketsize (typically 64 bytes.)
++ *
++ * This does not however prevent queuing transmit urbs with larger amounts
++ * of data. It is interpreted at the receiving (host) end as a series of
++ * wMaxPacketsize transfers but because there is no interpretation to the
++ * amounts of data sent it does affect anything if we treat the data as a
++ * single larger transfer.
++ *
++ * @ingroup ACMFunction
++ */
++
++
++// Endpoint indexes in acm_endpoint_requests[] and the endpoint map.
++#define BULK_OUT 0x00
++#define BULK_IN 0x01
++#define INT_IN 0x02
++#define ENDPOINTS 0x03
++
++#define COMM_INTF 0x00
++#define DATA_INTF 0x01
++
++
++
++// Most hosts don't care about BMAXPOWER, but the UUT tests want it to be 1
++#define BMAXPOWER 1
++#define BMATTRIBUTE 0
++
++#define STATIC
++//#define STATIC static
++//
++
++/*! @name ACM Flags
++ * @{
++ */
++#define ACM_OPENED (1 << 0) /*!< upper layer has opened the device port */
++#define ACM_CONFIGURED (1 << 1) /*!< device is configured */
++#define ACM_THROTTLED (1 << 2) /*!< upper layer doesn't want to receive data */
++#define ACM_CARRIER (1 << 3) /*!< host has set DTR, i.e. host has opened com device */
++#define ACM_LOOPBACK (1 << 4) /*!< upper layer wants local loopback */
++#define ACM_LOCAL (1 << 5) /*!< upper layer specified LOCAL mode */
++
++/*! @} */
++
++/*! struct acm_private
++ */
++struct acm_private {
++ struct usbd_function_instance *function;
++ struct usbd_function_driver *function_driver;
++ struct acm_function_services *function_services;
++ otg_tag_t trace_tag;
++
++ u32 flags;
++
++ int recv_urbs;
++ atomic_t used;
++ atomic_t queued_bytes;
++ atomic_t queued_urbs;
++ unsigned int writesize; // packetsize * 4
++
++ /*TBR debug receive flow control */
++ unsigned long bytes_received;
++ unsigned long bytes_forwarded;
++ /*TBR end debug */
++
++ struct cdc_acm_line_coding line_coding; // C.f. Table 50 - [GS]ET_LINE_CODING Device Request (to/from host)
++ cdc_acm_bmUARTState bmUARTState; // C.f. Table 51 - SET_CONTROL_LINE_STATE Device Request (from host)
++ cdc_acm_bmLineState bmLineState; // C.f. Table 69 - SERIAL_STATE Notification (to host)
++
++
++
++ struct tq_struct recv_tqueue;
++
++ void *privdata;
++
++};
++
++
++struct acm_work {
++ struct acm_private *acm;
++ int interface;
++};
++
+diff -uNr linux/drivers/no-otg/functions/acm/modem-l24-os.c linux/drivers/otg/functions/acm/modem-l24-os.c
+--- linux/drivers/no-otg/functions/acm/modem-l24-os.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/modem-l24-os.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,194 @@
++/*
++ * otg/functions/acm/modem-l24-os.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/acm/modem-l24-os.c
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of two pieces:
++ * 1) An OS specific piece that handles creating and operating
++ * a serial device for the given OS.
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the otgcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * an ACM class driver. If the USB piece interfaces with the otgcore
++ * layer you get an ACM function driver.
++ *
++ * This file is the OS specific piece that interfaces with Linux
++ * (kernel versions 2.4.*). It creates two simple characters devices.
++ * One for the data transport and one for the communications interface.
++ *
++ * @ingroup ACMFunction
++ */
++
++
++//#include <otg/osversion.h>
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
++
++MOD_DESCRIPTION ("Belcarra CDC-ACM Function");
++EMBED_LICENSE();
++
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <linux/capability.h>
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++// May need an ifdef here to pick up the acm_cl_usb_ops in the future.
++static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
++
++#define MDM mdm_fd_trace_tag
++otg_tag_t mdm_fd_trace_tag;
++
++/* Module Parameters ************************************************************************* */
++
++static u32 vendor_id;
++static u32 product_id;
++static u32 max_queued_urbs = MAX_QUEUED_URBS;
++static u32 max_queued_bytes = MAX_QUEUED_BYTES;
++
++MOD_PARM (vendor_id, "i");
++MOD_PARM (product_id, "i");
++MOD_PARM (max_queued_urbs, "i");
++MOD_PARM (max_queued_bytes, "i");
++
++MOD_PARM_DESC (vendor_id, "Device Vendor ID");
++MOD_PARM_DESC (product_id, "Device Product ID");
++MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
++MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
++
++
++/* ACM ***************************************************************************************** */
++
++#define ACM_TTY_MAJOR 166
++#define ACM_TTY_MINOR 0
++#define ACM_TTY_MINORS 1
++
++static struct acm_private acm_private;
++
++/* USB Simple Char Device ********************************************************************** */
++
++
++/* USB Comm Char Device ************************************************************************ */
++
++
++/* USB Module init/exit ************************************************************************ */
++/*
++ * acm_modinit - module init
++ *
++ */
++STATIC int acm_modinit (void)
++{
++ int i;
++ printk (KERN_INFO "Copyright (c) 2003-2004 sl@belcarra.com, tbr@belcarra.com\n");
++ MDM = otg_trace_obtain_tag();
++
++ // initialize private structure
++ //acm_private.tty_driver = &acm_tty_driver;
++ //acm_private.wqueue.routine = acm_wakeup_writers;
++ //acm_private.wqueue.data = &acm_private;
++ //acm_private.hqueue.routine = acm_hangup;
++ //acm_private.hqueue.data = &acm_private;
++ //acm_private.recv_tqueue.routine = &acm_start_recv;
++ //acm_private.recv_tqueue.data = &acm_private;
++
++ //init_waitqueue_head(&acm_private.open_wait);
++
++
++ // register as usb function driver
++
++ THROW_IF (usb_ops->initialize_usb_part(&acm_private,"acm_fd",vendor_id,product_id,
++ max_queued_urbs,max_queued_bytes ), error);
++
++ CATCH(error) {
++ printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
++
++ TRACE_MSG0(MDM,"--> -EINVAL");
++ return -EINVAL;
++ }
++ TRACE_MSG0(MDM,"--> 0");
++ return 0;
++}
++
++void acm_wait_task(WORK_ITEM *queue)
++{
++ TRACE_MSG1(MDM,"entered data=%p",queue->data);
++ RETURN_IF(!queue->data);
++ queue->data = NULL;
++#if defined(LINUX24)
++ while (queue->sync) {
++ TRACE_MSG1(MDM,"waiting for queue: %p",queue);
++ schedule_timeout(HZ);
++ }
++#else
++ while(PENDING_WORK_ITEM((*queue))){
++ TRACE_MSG1(MDM,"waiting for queue: %p",queue);
++ SCHEDULE_TIMEOUT(1); // 1 second delay
++ }
++#endif
++ TRACE_MSG0(MDM,"exited");
++}
++
++/* acm_modexit - module cleanup
++ */
++STATIC void acm_modexit (void)
++{
++ unsigned long flags;
++ struct usbd_urb *urb;
++ TRACE_MSG0(MDM,"entered");
++
++ // Wake up any pending opens after setting the exiting flag.
++ local_irq_save(flags);
++ acm_private.exiting = 1;
++ //if (acm_private.open_wait_count > 0) {
++ // wake_up_interruptible(&acm_private.open_wait);
++ //}
++ local_irq_restore(flags);
++
++ // verify no tasks are running
++ //acm_wait_task(&acm_private.wqueue);
++ //acm_wait_task(&acm_private.hqueue);
++
++//#if defined(LINUX24)
++// run_task_queue(&tq_timer);
++//#else
++// blk_run_queues();
++//#endif
++
++ //acm_wait_task(&acm_private.recv_tqueue);
++
++ usb_ops->terminate_usb_part(&acm_private);
++ otg_trace_invalidate_tag(MDM);
++}
++
++
++module_init (acm_modinit);
++module_exit (acm_modexit);
+diff -uNr linux/drivers/no-otg/functions/acm/modem.c linux/drivers/otg/functions/acm/modem.c
+--- linux/drivers/no-otg/functions/acm/modem.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/modem.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,263 @@
++/*
++ * otg/functions/acm/modem.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++/*!
++ * @file otg/functions/acm/modem.c
++ * @brief ACM-MODEM Descriptor Set
++ *
++ * This file is the USB specific piece that interfaces with the otgcore layer.
++ * If you're looking for the USB specific piece that interfaces with the
++ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
++ *
++ * Note: this function driver requires the following endpoints:
++ *
++ * BULK-IN
++ * BULK-OUT
++ * INTERRUPT-IN
++ *
++ * This function driver cannot be used on devices (such as the StrongArm
++ * SA1100) that do not have an interrupt endpoint.
++ *
++ * @ingroup MODEMFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++
++
++/*
++ * CDC ACM Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*! BULK OUT Data Endpoint Descriptor
++ */
++static u8 mdn_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++
++/*! BULK In Data Endpoint Descriptor
++ */
++static u8 mdn_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++
++/*! Data Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *mdn_alt_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) mdn_alt_1,
++ (struct usbd_endpoint_descriptor *) mdn_alt_2, };
++
++/*! Data Endpoint Index List
++ */
++u8 mdn_alt_indexes[] = { BULK_OUT, BULK_IN, };
++
++/*! INTERRUPT In Comm Endpoint Descriptor
++ */
++static u8 mdn_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT, 0, 0x00, 0x0a, };
++
++/*! Comm Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *mdn_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) mdn_comm_1 };
++
++
++/*! Comm Endpoint Index List
++ */
++u8 mdn_comm_indexes[] = { INT_IN, };
++
++/*! @{
++ * Class Descriptors
++ */
++static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++/*! @} */
++
++/*! ACMF Class Descriptor
++ * ACMF - c.f. Table 28
++ * currenty set to 0x2 - Support Set_Line_Coding etc,
++ *
++ * XXX Should we also set 0x4 - Supports Network_Notification?
++ */
++static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
++
++static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] =
++ { (struct usbd_generic_class_descriptor *) cdc_class_1,
++ (struct usbd_generic_class_descriptor *) cdc_class_2,
++ (struct usbd_generic_class_descriptor *) cdc_class_3,
++ (struct usbd_generic_class_descriptor *) cdc_class_4, };
++
++
++
++/* Alternate Descriptors */
++// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
++
++/*! Comm Alternate Descriptor
++ */
++static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
++
++/*! Data Alternate Descriptor
++ */
++static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
++
++
++
++/*! Comm alternate descriptions
++ */
++static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_COMM_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
++ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: cdc_comm_class_descriptors,
++ endpoint_list: mdn_comm_endpoints,
++ endpoints:sizeof (mdn_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: mdn_comm_indexes,
++ }, };
++
++/*! Data alternate descriptions
++ */
++static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
++ endpoint_list: mdn_alt_endpoints,
++ endpoints:sizeof (mdn_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: mdn_alt_indexes,
++ }, };
++
++
++/*! Interface Descriptions List */
++static struct usbd_interface_description cdc_interfaces[] = {
++ {
++ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_comm_alternate_descriptions,
++ },
++
++ {
++ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_data_alternate_descriptions,
++ },
++};
++
++
++/*! Configuration Descriptor
++ */
++static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
++
++/*! Configuration Description
++ */
++struct usbd_configuration_description mdn_description[] = {
++ { iConfiguration: CONFIG_OTG_ACM_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
++ }, };
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor mdn_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor mdn_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request mdn_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
++ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor mdn_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description mdn_device_description = {
++ device_descriptor: &mdn_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &mdn_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &mdn_otg_descriptor,
++ iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
++ iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++
++
++/*! function_driver
++ */
++struct usbd_function_driver modem_function_driver = {
++ name: "ACM-MDM",
++ fops:&function_ops,
++ device_description:&mdn_device_description,
++ bNumConfigurations:sizeof (mdn_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:mdn_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:cdc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: mdn_endpoint_requests,
++};
++
+diff -uNr linux/drivers/no-otg/functions/acm/modem.h linux/drivers/otg/functions/acm/modem.h
+--- linux/drivers/no-otg/functions/acm/modem.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/modem.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,118 @@
++/*
++ * otg/functions/acm/modem.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup MODEMFunction ACM-Modem
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/acm/modem.h
++ * @brief ACM Function Driver private defines
++ *
++ *
++ * This is an ACM Function Driver. The upper edge is exposed
++ * to the hosting OS as a Posix type character device. The lower
++ * edge implements the USB Device Stack API.
++ *
++ * These are emulated and set by the modem driver as appropriate
++ * to model a virutal serial port. The
++ *
++ * TIOCM_RNG RNG (Ring) not used
++ * TIOCM_LE DSR (Data Set Ready / Line Enable)
++ * TIOCM_DSR DSR (Data Set Ready)
++ * TIOCM_CAR DCD (Data Carrier Detect)
++ * TIOCM_CTS CTS (Clear to Send)
++ * TIOCM_CD TIOCM_CAR
++ * TIOCM_RI TIOCM_RNG
++ *
++ * These are set by the application:
++ *
++ * TIOCM_DTR DTR (Data Terminal Ready)
++ * TIOCM_RTS RTS (Request to Send)
++ *
++ * TIOCM_LOOP Set into loopback mode
++ * TIOCM_OUT1 Not used.
++ * TIOCM_OUT2 Not used.
++ *
++ *
++ * The following File and termio c_cflags are used:
++ *
++ * O_NONBLOCK don't block in modem_open()
++ * O_EXCL don't allow more than one open
++ *
++ * CLOCAL ignore DTR status
++ * CBAUD send break if set to B0
++ *
++ * Virtual NULL Modem
++ *
++ * Peripheral to Host via Serial State Notification (write ioctls)
++ *
++ * Application TIOCM Null Modem ACM (DCE) Notificaiton Host (DTE)
++ * -------------------------------------------------------------------------------------------------------------
++ * Request to send TIOCM_RTS RTS -> CTS CTS Not Available Clear to Send (N/A)
++ * Data Terminal Ready TIOCM_DTR DTR -> DSR DSR bTxCarrier Data Set Ready
++ * DTR -> DCD DCD bRXCarrier Carrier Detect
++ * Ring Indicator TIOCM_OUT1 OUT1 -> RI RI bRingSignal Ring Indicator
++ * Overrun TIOCM_OUT2 OUT2 -> Overrun Overrun bOverrun Overrun
++ * Send Break B0 B0 -> Break Break bBreak Break Received
++ * -------------------------------------------------------------------------------------------------------------
++ *
++ *
++ * Host to Peripheral via Set Control Line State
++ *
++ * Host (DTE) Line State ACM (DCE) Null Modem TIOCM Peripheral (DTE)
++ * -------------------------------------------------------------------------------------------------------------
++ * Data Terminal Ready D0 DTR DTR -> DSR TIOCM_DSR Data Set Ready
++ * DTR -> DCD TIOCM_CAR Carrier Detect
++ * Request To Send D1 RTS RTS -> CTS TIOCM_CTS Clear to Send
++ * -------------------------------------------------------------------------------------------------------------
++ *
++ *
++ * @ingroup MODEMFunction
++ */
++
++
++extern struct usbd_function_driver modem_function_driver;
++
++//#define MODEM_OPENED (1 << 0) /*!< OPENED flag */
++#define MODEMFD_CLOCAL (1 << 1) /*!< CLOCAL flag */
++//#define MODEMFD_LOOPBACK (1 << 2) /*!< LOOPBACK flag */
++#define MODEMFD_EXCLUSIVE (1 << 3) /*!< EXCLUSIVE flag */
++#define MODEMFD_THROTTLED (1 << 4) /*!< THROTTLED flag */
++
++/*! struct modem_private
++ */
++struct modem_private {
++
++ struct modem_driver *modem_driver; /*!< modem structure */
++ int modem_driver_registered; /*!< non-zero if modem_driver registered */
++ int usb_driver_registered; /*!< non-zero if usb function registered */
++
++ struct modem_struct *modem; /*!< non-null if modem open */
++ struct tq_struct wqueue; /*!< task queue for writer wakeup */
++ struct tq_struct hqueue; /*!< task queue for hangup */
++
++ u32 flags; /*!< flags */
++
++ u32 tiocm; /*!< tiocm settings */
++
++ struct serial_struct serial_struct; /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
++
++ wait_queue_head_t tiocm_wait;
++ u32 tiocgicount;
++
++ u32 c_cflag;
++
++ wait_queue_head_t open_wait; // wait queue for blocking open
++ int exiting; // True if module exiting
++};
++
++
+diff -uNr linux/drivers/no-otg/functions/acm/obex-l24-os.c linux/drivers/otg/functions/acm/obex-l24-os.c
+--- linux/drivers/no-otg/functions/acm/obex-l24-os.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/obex-l24-os.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,194 @@
++/*
++ * otg/functions/acm/obex-l24-os.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/acm/obex-l24-os.c
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of two pieces:
++ * 1) An OS specific piece that handles creating and operating
++ * a serial device for the given OS.
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the otgcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * an ACM class driver. If the USB piece interfaces with the otgcore
++ * layer you get an ACM function driver.
++ *
++ * This file is the OS specific piece that interfaces with Linux
++ * (kernel versions 2.4.*). It creates two simple characters devices.
++ * One for the data transport and one for the communications interface.
++ *
++ * @ingroup ACMFunction
++ */
++
++
++//#include <otg/osversion.h>
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
++
++MOD_DESCRIPTION ("Belcarra CDC-ACM Function");
++EMBED_LICENSE();
++
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <linux/capability.h>
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++// May need an ifdef here to pick up the acm_cl_usb_ops in the future.
++static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
++
++#define OBX obx_fd_trace_tag
++otg_tag_t obx_fd_trace_tag;
++
++/* Module Parameters ************************************************************************* */
++
++static u32 vendor_id;
++static u32 product_id;
++static u32 max_queued_urbs = MAX_QUEUED_URBS;
++static u32 max_queued_bytes = MAX_QUEUED_BYTES;
++
++MOD_PARM (vendor_id, "i");
++MOD_PARM (product_id, "i");
++MOD_PARM (max_queued_urbs, "i");
++MOD_PARM (max_queued_bytes, "i");
++
++MOD_PARM_DESC (vendor_id, "Device Vendor ID");
++MOD_PARM_DESC (product_id, "Device Product ID");
++MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
++MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
++
++
++/* ACM ***************************************************************************************** */
++
++#define ACM_TTY_MAJOR 166
++#define ACM_TTY_MINOR 0
++#define ACM_TTY_MINORS 1
++
++static struct acm_private acm_private;
++
++/* USB Simple Char Device ********************************************************************** */
++
++
++/* USB Comm Char Device ************************************************************************ */
++
++
++/* USB Module init/exit ************************************************************************ */
++/*
++ * acm_modinit - module init
++ *
++ */
++STATIC int acm_modinit (void)
++{
++ int i;
++ printk (KERN_INFO "Copyright (c) 2003-2004 sl@belcarra.com, tbr@belcarra.com\n");
++ OBX = otg_trace_obtain_tag();
++
++ // initialize private structure
++ //acm_private.tty_driver = &acm_tty_driver;
++ //acm_private.wqueue.routine = acm_wakeup_writers;
++ //acm_private.wqueue.data = &acm_private;
++ //acm_private.hqueue.routine = acm_hangup;
++ //acm_private.hqueue.data = &acm_private;
++ //acm_private.recv_tqueue.routine = &acm_start_recv;
++ //acm_private.recv_tqueue.data = &acm_private;
++
++ //init_waitqueue_head(&acm_private.open_wait);
++
++
++ // register as usb function driver
++
++ THROW_IF (usb_ops->initialize_usb_part(&acm_private,"acm_fd",vendor_id,product_id,
++ max_queued_urbs,max_queued_bytes ), error);
++
++ CATCH(error) {
++ printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
++
++ TRACE_MSG0(OBX,"--> -EINVAL");
++ return -EINVAL;
++ }
++ TRACE_MSG0(OBX,"--> 0");
++ return 0;
++}
++
++void acm_wait_task(WORK_ITEM *queue)
++{
++ TRACE_MSG1(OBX,"entered data=%p",queue->data);
++ RETURN_IF(!queue->data);
++ queue->data = NULL;
++#if defined(LINUX24)
++ while (queue->sync) {
++ TRACE_MSG1(OBX,"waiting for queue: %p",queue);
++ schedule_timeout(HZ);
++ }
++#else
++ while(PENDING_WORK_ITEM((*queue))){
++ TRACE_MSG1(OBX,"waiting for queue: %p",queue);
++ SCHEDULE_TIMEOUT(1); // 1 second delay
++ }
++#endif
++ TRACE_MSG0(OBX,"exited");
++}
++
++/* acm_modexit - module cleanup
++ */
++STATIC void acm_modexit (void)
++{
++ unsigned long flags;
++ struct usbd_urb *urb;
++ TRACE_MSG0(OBX,"entered");
++
++ // Wake up any pending opens after setting the exiting flag.
++ local_irq_save(flags);
++ acm_private.exiting = 1;
++ //if (acm_private.open_wait_count > 0) {
++ // wake_up_interruptible(&acm_private.open_wait);
++ //}
++ local_irq_restore(flags);
++
++ // verify no tasks are running
++ //acm_wait_task(&acm_private.wqueue);
++ //acm_wait_task(&acm_private.hqueue);
++
++//#if defined(LINUX24)
++// run_task_queue(&tq_timer);
++//#else
++// blk_run_queues();
++//#endif
++
++ //acm_wait_task(&acm_private.recv_tqueue);
++
++ usb_ops->terminate_usb_part(&acm_private);
++ otg_trace_invalidate_tag(OBX);
++}
++
++
++module_init (acm_modinit);
++module_exit (acm_modexit);
+diff -uNr linux/drivers/no-otg/functions/acm/obex.c linux/drivers/otg/functions/acm/obex.c
+--- linux/drivers/no-otg/functions/acm/obex.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/obex.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,263 @@
++/*
++ * otg/functions/acm/obex.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++/*!
++ * @file otg/functions/acm/obex.c
++ * @brief ACM-OBEX Descriptor Set
++ *
++ * This file is the USB specific piece that interfaces with the otgcore layer.
++ * If you're looking for the USB specific piece that interfaces with the
++ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
++ *
++ * Note: this function driver requires the following endpoints:
++ *
++ * BULK-IN
++ * BULK-OUT
++ * INTERRUPT-IN
++ *
++ * This function driver cannot be used on devices (such as the StrongArm
++ * SA1100) that do not have an interrupt endpoint.
++ *
++ * @ingroup OBEXFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++
++
++/*
++ * CDC ACM Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*! BULK OUT Data Endpoint Descriptor
++ */
++static u8 obx_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++
++/*! BULK In Data Endpoint Descriptor
++ */
++static u8 obx_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++
++/*! Data Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *obx_alt_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) obx_alt_1,
++ (struct usbd_endpoint_descriptor *) obx_alt_2, };
++
++/*! Data Endpoint Index List
++ */
++u8 obx_alt_indexes[] = { BULK_OUT, BULK_IN, };
++
++/*! INTERRUPT In Comm Endpoint Descriptor
++ */
++static u8 obx_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT, 0, 0x00, 0x0a, };
++
++/*! Comm Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *obx_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) obx_comm_1 };
++
++
++/*! Comm Endpoint Index List
++ */
++u8 obx_comm_indexes[] = { INT_IN, };
++
++/*! @{
++ * Class Descriptors
++ */
++static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++/*! @} */
++
++/*! ACMF Class Descriptor
++ * ACMF - c.f. Table 28
++ * currenty set to 0x2 - Support Set_Line_Coding etc,
++ *
++ * XXX Should we also set 0x4 - Supports Network_Notification?
++ */
++static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
++
++static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] =
++ { (struct usbd_generic_class_descriptor *) cdc_class_1,
++ (struct usbd_generic_class_descriptor *) cdc_class_2,
++ (struct usbd_generic_class_descriptor *) cdc_class_3,
++ (struct usbd_generic_class_descriptor *) cdc_class_4, };
++
++
++
++/* Alternate Descriptors */
++// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
++
++/*! Comm Alternate Descriptor
++ */
++static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
++
++/*! Data Alternate Descriptor
++ */
++static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
++
++
++
++/*! Comm alternate descriptions
++ */
++static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_COMM_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
++ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: cdc_comm_class_descriptors,
++ endpoint_list: obx_comm_endpoints,
++ endpoints:sizeof (obx_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: obx_comm_indexes,
++ }, };
++
++/*! Data alternate descriptions
++ */
++static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
++ endpoint_list: obx_alt_endpoints,
++ endpoints:sizeof (obx_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: obx_alt_indexes,
++ }, };
++
++
++/*! Interface Descriptions List */
++static struct usbd_interface_description cdc_interfaces[] = {
++ {
++ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_comm_alternate_descriptions,
++ },
++
++ {
++ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_data_alternate_descriptions,
++ },
++
++};
++
++
++/*! Configuration Descriptor
++ */
++static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
++
++/*! Configuration Description
++ */
++struct usbd_configuration_description obx_description[] = {
++ { iConfiguration: CONFIG_OTG_ACM_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
++ }, };
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor obx_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor obx_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request obx_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
++ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor obx_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description obx_device_description = {
++ device_descriptor: &obx_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &obx_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &obx_otg_descriptor,
++ iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
++ iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++
++/*! function_driver
++ */
++struct usbd_function_driver obex_function_driver = {
++ name: "ACM-OBX",
++ fops:&function_ops,
++ device_description:&obx_device_description,
++ bNumConfigurations:sizeof (obx_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:obx_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:cdc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: obx_endpoint_requests,
++};
++
+diff -uNr linux/drivers/no-otg/functions/acm/obex.h linux/drivers/otg/functions/acm/obex.h
+--- linux/drivers/no-otg/functions/acm/obex.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/obex.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,66 @@
++/*
++ * otg/functions/acm/obex.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup OBEXFunction ACM-OBEX
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/acm/obex.h
++ * @brief ACM Function Driver private defines
++ *
++ *
++ * This is an ACM Function Driver. The upper edge is exposed
++ * to the hosting OS as a Posix type character device. The lower
++ * edge implements the USB Device Stack API.
++ *
++ *
++ *
++ * @ingroup OBEXFunction
++ */
++
++
++extern struct usbd_function_driver tty_function_driver;
++
++//#define TTY_OPENED (1 << 0) /*!< OPENED flag */
++#define TTYFD_CLOCAL (1 << 1) /*!< CLOCAL flag */
++//#define TTYFD_LOOPBACK (1 << 2) /*!< LOOPBACK flag */
++#define TTYFD_EXCLUSIVE (1 << 3) /*!< EXCLUSIVE flag */
++#define TTYFD_THROTTLED (1 << 4) /*!< THROTTLED flag */
++
++/*! struct obex_private
++ */
++struct obex_private {
++
++ struct tty_driver *tty_driver; /*!< tty structure */
++ int tty_driver_registered; /*!< non-zero if tty_driver registered */
++ int usb_driver_registered; /*!< non-zero if usb function registered */
++
++ struct tty_struct *tty; /*!< non-null if tty open */
++ struct tq_struct wqueue; /*!< task queue for writer wakeup */
++ struct tq_struct hqueue; /*!< task queue for hangup */
++
++ u32 flags; /*!< flags */
++
++ u32 tiocm; /*!< tiocm settings */
++
++ struct serial_struct serial_struct; /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
++
++ wait_queue_head_t tiocm_wait;
++ u32 tiocgicount;
++
++ u32 c_cflag;
++
++ wait_queue_head_t open_wait; // wait queue for blocking open
++ int exiting; // True if module exiting
++};
++
++
+diff -uNr linux/drivers/no-otg/functions/acm/tty-fd.c linux/drivers/otg/functions/acm/tty-fd.c
+--- linux/drivers/no-otg/functions/acm/tty-fd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/tty-fd.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,263 @@
++/*
++ * otg/functions/acm/tty-fd.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++/*!
++ * @file otg/functions/acm/tty-fd.c
++ * @brief ACM-TTY Descriptor Set
++ *
++ * This file is the USB specific piece that interfaces with the otgcore layer.
++ * If you're looking for the USB specific piece that interfaces with the
++ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
++ *
++ * Note: this function driver requires the following endpoints:
++ *
++ * BULK-IN
++ * BULK-OUT
++ * INTERRUPT-IN
++ *
++ * This function driver cannot be used on devices (such as the StrongArm
++ * SA1100) that do not have an interrupt endpoint.
++ *
++ * @ingroup TTYFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++
++
++/*
++ * CDC ACM Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*! BULK OUT Data Endpoint Descriptor
++ */
++static u8 tty_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++
++/*! BULK In Data Endpoint Descriptor
++ */
++static u8 tty_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++
++/*! Data Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *tty_alt_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) tty_alt_1,
++ (struct usbd_endpoint_descriptor *) tty_alt_2, };
++
++/*! Data Endpoint Index List
++ */
++u8 tty_alt_indexes[] = { BULK_OUT, BULK_IN, };
++
++/*! INTERRUPT In Comm Endpoint Descriptor
++ */
++static u8 tty_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT, 0, 0x00, 0x0a, };
++
++/*! Comm Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *tty_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) tty_comm_1 };
++
++
++/*! Comm Endpoint Index List
++ */
++u8 tty_comm_indexes[] = { INT_IN, };
++
++/*! @{
++ * Class Descriptors
++ */
++static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++/*! @} */
++
++/*! ACMF Class Descriptor
++ * ACMF - c.f. Table 28
++ * currenty set to 0x2 - Support Set_Line_Coding etc,
++ *
++ * XXX Should we also set 0x4 - Supports Network_Notification?
++ */
++static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
++
++static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] =
++ { (struct usbd_generic_class_descriptor *) cdc_class_1,
++ (struct usbd_generic_class_descriptor *) cdc_class_2,
++ (struct usbd_generic_class_descriptor *) cdc_class_3,
++ (struct usbd_generic_class_descriptor *) cdc_class_4, };
++
++
++
++/* Alternate Descriptors */
++// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
++
++/*! Comm Alternate Descriptor
++ */
++static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
++
++/*! Data Alternate Descriptor
++ */
++static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
++
++
++
++/*! Comm alternate descriptions
++ */
++static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_COMM_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
++ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: cdc_comm_class_descriptors,
++ endpoint_list: tty_comm_endpoints,
++ endpoints:sizeof (tty_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: tty_comm_indexes,
++ }, };
++
++/*! Data alternate descriptions
++ */
++static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
++ endpoint_list: tty_alt_endpoints,
++ endpoints:sizeof (tty_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: tty_alt_indexes,
++ }, };
++
++
++/*! Interface Descriptions List */
++static struct usbd_interface_description cdc_interfaces[] = {
++ {
++ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_comm_alternate_descriptions,
++ },
++
++ {
++ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_data_alternate_descriptions,
++ },
++
++};
++
++
++/*! Configuration Descriptor
++ */
++static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
++
++/*! Configuration Description
++ */
++struct usbd_configuration_description tty_description[] = {
++ { iConfiguration: CONFIG_OTG_ACM_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
++ }, };
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor tty_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor tty_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request tty_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
++ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor tty_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description tty_device_description = {
++ device_descriptor: &tty_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &tty_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &tty_otg_descriptor,
++ iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
++ iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++/*! function_driver
++ */
++struct usbd_function_driver tty_function_driver = {
++ name: "ACM-TTY",
++ fops:&function_ops,
++ device_description:&tty_device_description,
++ bNumConfigurations:sizeof (tty_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:tty_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:cdc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: tty_endpoint_requests,
++};
++
++
++
+diff -uNr linux/drivers/no-otg/functions/acm/tty-if.c linux/drivers/otg/functions/acm/tty-if.c
+--- linux/drivers/no-otg/functions/acm/tty-if.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/tty-if.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,263 @@
++/*
++ * otg/functions/acm/tty-if.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++/*!
++ * @file otg/functions/acm/tty-if.c
++ * @brief ACM-TTY Descriptor Set
++ *
++ * This file is the USB specific piece that interfaces with the otgcore layer.
++ * If you're looking for the USB specific piece that interfaces with the
++ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
++ *
++ * Note: this function driver requires the following endpoints:
++ *
++ * BULK-IN
++ * BULK-OUT
++ * INTERRUPT-IN
++ *
++ * This function driver cannot be used on devices (such as the StrongArm
++ * SA1100) that do not have an interrupt endpoint.
++ *
++ * @ingroup TTYFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++
++
++/*
++ * CDC ACM Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*! BULK OUT Data Endpoint Descriptor
++ */
++static u8 tty_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++
++/*! BULK In Data Endpoint Descriptor
++ */
++static u8 tty_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++
++/*! Data Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *tty_alt_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) tty_alt_1,
++ (struct usbd_endpoint_descriptor *) tty_alt_2, };
++
++/*! Data Endpoint Index List
++ */
++u8 tty_alt_indexes[] = { BULK_OUT, BULK_IN, };
++
++/*! INTERRUPT In Comm Endpoint Descriptor
++ */
++static u8 tty_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT, 0, 0x00, 0x0a, };
++
++/*! Comm Endpoint Descriptor List
++ */
++static struct usbd_endpoint_descriptor *tty_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) tty_comm_1 };
++
++
++/*! Comm Endpoint Index List
++ */
++u8 tty_comm_indexes[] = { INT_IN, };
++
++/*! @{
++ * Class Descriptors
++ */
++static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
++/*! @} */
++
++/*! ACMF Class Descriptor
++ * ACMF - c.f. Table 28
++ * currenty set to 0x2 - Support Set_Line_Coding etc,
++ *
++ * XXX Should we also set 0x4 - Supports Network_Notification?
++ */
++static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
++
++static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] =
++ { (struct usbd_generic_class_descriptor *) cdc_class_1,
++ (struct usbd_generic_class_descriptor *) cdc_class_2,
++ (struct usbd_generic_class_descriptor *) cdc_class_3,
++ (struct usbd_generic_class_descriptor *) cdc_class_4, };
++
++
++
++/* Alternate Descriptors */
++// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
++
++/*! Comm Alternate Descriptor
++ */
++static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
++
++/*! Data Alternate Descriptor
++ */
++static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
++
++
++
++/*! Comm alternate descriptions
++ */
++static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_COMM_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
++ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: cdc_comm_class_descriptors,
++ endpoint_list: tty_comm_endpoints,
++ endpoints:sizeof (tty_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: tty_comm_indexes,
++ }, };
++
++/*! Data alternate descriptions
++ */
++static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_ACM_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
++ endpoint_list: tty_alt_endpoints,
++ endpoints:sizeof (tty_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_indexes: tty_alt_indexes,
++ }, };
++
++
++/*! Interface Descriptions List */
++static struct usbd_interface_description cdc_interfaces[] = {
++ {
++ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_comm_alternate_descriptions,
++ },
++
++ {
++ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_data_alternate_descriptions,
++ },
++
++};
++
++
++/*! Configuration Descriptor
++ */
++static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
++
++/*! Configuration Description
++ */
++struct usbd_configuration_description tty_description[] = {
++ { iConfiguration: CONFIG_OTG_ACM_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
++ }, };
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor tty_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor tty_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request tty_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
++ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor tty_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description tty_device_description = {
++ device_descriptor: &tty_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &tty_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &tty_otg_descriptor,
++ iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
++ iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++/*! function_driver
++ */
++struct usbd_function_driver tty_function_driver = {
++ name: "ACM-TTY",
++ fops:&function_ops,
++ device_description:&tty_device_description,
++ bNumConfigurations:sizeof (tty_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:tty_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
++ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:cdc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: tty_endpoint_requests,
++};
++
++
++
+diff -uNr linux/drivers/no-otg/functions/acm/tty-l24-os.c linux/drivers/otg/functions/acm/tty-l24-os.c
+--- linux/drivers/no-otg/functions/acm/tty-l24-os.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/tty-l24-os.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,1291 @@
++/*
++ * otg/functions/acm/tty-l24-os.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @file otg/functions/acm/tty-l24-os.c
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of two pieces:
++ *
++ * 1) An OS specific piece that handles creating and operating
++ * a serial device for the given OS.
++ *
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the otgcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get an ACM
++ * class driver. If the USB piece interfaces with the otgcore layer you get
++ * an ACM function driver.
++ *
++ * This file is the OS specific piece that interfaces with Linux (kernel
++ * versions 2.4.*). It talks to the bottom edge of the Linux tty layer.
++ *
++ * See the file acm/tty.c for USB descriptor definitions used for this
++ * function.
++ *
++ * @ingroup TTYFunction
++ */
++
++
++//#include <otg/osversion.h>
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
++
++MOD_DESCRIPTION ("Belcarra TTY Function");
++EMBED_LICENSE();
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/serial.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include <linux/capability.h>
++#include "tty.h"
++#include <otg/otg-trace.h>
++#include "acm.h"
++#include "acm-fd.h"
++#include "acm-os.h"
++
++static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
++
++#define TTY tty_fd_trace_tag
++otg_tag_t tty_fd_trace_tag;
++
++/* Module Parameters ************************************************************************* */
++
++static u32 vendor_id;
++static u32 product_id;
++static u32 max_queued_urbs = MAX_QUEUED_URBS;
++static u32 max_queued_bytes = MAX_QUEUED_BYTES;
++
++MOD_PARM (vendor_id, "i");
++MOD_PARM (product_id, "i");
++MOD_PARM (max_queued_urbs, "i");
++MOD_PARM (max_queued_bytes, "i");
++
++MOD_PARM_DESC (vendor_id, "Device Vendor ID");
++MOD_PARM_DESC (product_id, "Device Product ID");
++MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
++MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
++
++
++/* ACM ***************************************************************************************** */
++
++#define ACM_TTY_MAJOR 166
++#define ACM_TTY_MINOR 0
++#define ACM_TTY_MINORS 1
++
++extern struct acm_private acmfd_private;
++extern struct tty_private ttyfd_private;
++
++
++/* ******************************************************************************************* */
++
++#define TTY_OVERFLOW_SIZE 512
++
++u8 tty_overflow_buffer[TTY_OVERFLOW_SIZE];
++int tty_overflow_used;
++
++/* ******************************************************************************************* */
++
++/*! ttyfd_schedule
++ *
++ * Schedule a bottom half handler work item.
++ *
++ * @param queue
++ */
++STATIC void ttyfd_schedule(WORK_ITEM *queue)
++{
++ RETURN_IF(NO_WORK_DATA((*queue)) || PENDING_WORK_ITEM((*queue)));
++#if defined(LINUX24)
++ queue_task(queue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ TRACE_MSG1(TTY,"task %p scheduled and marked",queue);
++#else
++ SCHEDULE_WORK((*queue));
++ TRACE_MSG1(TTY,"task %p scheduled",queue);
++#endif
++}
++
++
++/*! ttyfd_block_until_ready
++ *
++ * Called from tty_open to implement blocking open. Wait for DTR indication
++ * from acm-fd.
++ *
++ * Called by TTY layer to open device.
++ *
++ * @param tty
++ * @param filp
++ * @param acm
++ * @returns non-zero for error
++ */
++STATIC int ttyfd_block_until_ready(struct tty_struct *tty, struct file *filp, struct acm_private *acm)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ unsigned long flags;
++ int rc = 0;
++
++ local_irq_save(flags);
++ //TRACE_MSG1(TTY,"open_wait_count: %d --> at entry", tty_private->open_wait_count);
++ //tty_private->open_wait_count += 1;
++ for (;;) {
++ /* check if the file has been closed */
++ if (tty_hung_up_p(filp)) {
++ TRACE_MSG0(TTY,"tty_hung_up_p()");
++ rc = -ERESTARTSYS;
++ break;
++ }
++ /* check for pending signals */
++ if (signal_pending(current)) {
++ TRACE_MSG0(TTY,"signal_pending()");
++ rc = -ERESTARTSYS;
++ break;
++ }
++ /* check if the module is unloading */
++ if (tty_private->exiting) {
++ TRACE_MSG0(TTY,"module exiting()");
++ rc = -ENODEV;
++ break;
++ }
++ /* check for what we want, do we have DTR?
++ */
++ if (acm->bmLineState & CDC_LINESTATE_D0_DTR) {
++ // OK, there's somebody on the other end, let's go...
++ TRACE_MSG0(TTY,"found DTR");
++ rc = 0;
++ break;
++ }
++ //TRACE_MSG1(TTY,"open_wait_count: %d sleeping...", tty_private->open_wait_count);
++
++ /* restore irqs */
++ local_irq_restore(flags);
++
++ /* sleep */
++ interruptible_sleep_on(&tty_private->open_wait);
++
++ /* lock irqs again */
++ local_irq_save(flags);
++
++ //TRACE_MSG1(TTY,"open_wait_count: %d got WAKEUP", tty_private->open_wait_count);
++ }
++ //tty_private->open_wait_count -= 1;
++ //TRACE_MSG1(TTY,"open_wait_count: %d <-- at exit", tty_private->open_wait_count);
++ local_irq_restore(flags);
++ return(rc);
++}
++
++/*! ttyfd_call_hangup
++ *
++ * Bottom half handler to safely send hangup signal to process group.
++ *
++ * @param private - point to acm_private dat structure
++ */
++STATIC void ttyfd_call_hangup(void *private)
++{
++ struct acm_private *acm = (struct acm_private *) private;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ struct tty_struct *tty = (NULL == acm) ? NULL : tty_private->tty;
++
++ TRACE_MSG5(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d c_cflag: %04x clocal: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED,
++ tty_private->c_cflag, tty_private->c_cflag & CLOCAL);
++
++
++ if (tty && !(tty_private->c_cflag & CLOCAL))
++ tty_hangup(tty);
++
++ wake_up_interruptible(&tty_private->open_wait);
++
++ TRACE_MSG0(TTY,"exited");
++}
++
++/*! ttyfd_schedule_hangup
++ *
++ * Schedule hangup bottom half handler.
++ *
++ * @param acm - point to acm_private dat structure
++ */
++void ttyfd_schedule_hangup(struct acm_private *acm)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ TRACE_MSG0(TTY, "entered");
++ ttyfd_schedule(&tty_private->hqueue);
++}
++
++
++/*! tty_open
++ *
++ * Called by TTY layer to open device.
++ *
++ * @param tty
++ * @param filp
++ * @returns non-zero for error
++ */
++STATIC int tty_open(struct tty_struct *tty, struct file *filp)
++{
++ struct acm_private *acm = &acmfd_private;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ int used;
++ int nonblocking;
++ int rc = 0;
++ unsigned long flags;
++
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++
++ TRACE_MSG2(TTY,"f_flags: %08x NONBLOCK: %x",
++ filp->f_flags, filp->f_flags & O_NONBLOCK);
++
++ nonblocking = filp->f_flags & O_NONBLOCK;
++
++ /* Lock and increment used counter, save current value.
++ * Check for exclusive open at the same time.
++ */
++ local_irq_save(flags);
++
++ /* The value of acm->used controls MOD_{INC/DEC}_USE_COUNT, so
++ * it has to be incremented unconditionally, and no early return
++ * made until after USE_COUNT has been adjusted to match.
++ */
++ used = atomic_post_inc(&acm->used);
++#ifdef MCEL
++ filp->f_flags |= O_EXCL; // QQQ Can we persuade MCEL to add this to their app?
++ if (nonblocking && !(acm->connected)) {
++ // QQQ Is MCEL actually using this "feature"? (See below for printk)
++ rc = -EINVAL;
++ }
++ else
++#endif
++#if 0
++ if (filp->f_flags & O_EXCL) {
++ /* This is intended to be an exclusive open, so
++ * make sure no one has the device open already, and
++ * set the exclusive flag so no one can open it later.
++ */
++ if (used > 0) {
++ // Someone already has it.
++ rc = -EBUSY;
++ }
++ else {
++ tty_private->flags |= TTYFD_EXCLUSIVE;
++ set_bit(TTY_EXCLUSIVE, &tty->flags);
++ }
++ }
++#if defined(LINUX24)
++ else if ((tty_private->flags & TTYFD_EXCLUSIVE) && !suser())
++#else
++ if ((tty_private->flags & TTYFD_EXCLUSIVE) && !capable(CAP_SYS_TTY_CONFIG))
++#endif
++ {
++ // Only the superuser can do a normal open of an O_EXCL tty
++ rc = -EBUSY;
++ }
++#endif
++ local_irq_restore(flags);
++
++ // OK, now it's safe to make an early return if we are failing.
++ if (rc) {
++#ifdef MCEL
++ // This can dissappear when the "feature" above does.
++ if (-EINVAL == rc)
++ //printk(KERN_INFO "\nusb cable not connected!\n");
++#endif
++ return(rc);
++ }
++ local_irq_save(flags);
++
++
++ /* To truly emulate the old dual-device approach of having a non-blocking
++ * device (e.g cu0) and a blocking device (e.g. tty0) we would need to
++ * track blocking and non-blocking opens separately. We don't. This
++ * may lead to funny behavior in the multiple open case.
++ */
++ UNLESS (used) {
++ MOD_INC_USE_COUNT;
++ TRACE_MSG1(TTY,"INC: %d", MOD_IN_USE);
++ // First open.
++ TRACE_MSG2(TTY, "FIRST OPEN nonblocking: %x exclusive: %x", nonblocking, tty_private->flags & TTYFD_EXCLUSIVE);
++ tty->driver_data = acm;
++ tty_private->tty = tty;
++ tty->low_latency = 1;
++ usb_ops->open(acm, DATA_INTF);
++ usb_ops->set_local(acm, 1);
++ }
++ local_irq_restore(flags);
++
++
++ /* All done if configured
++ */
++ RETURN_ZERO_UNLESS(usb_ops->ready(acm));
++
++ /* All done if non blocking open
++ */
++ RETURN_ZERO_IF(nonblocking);
++
++ /* Block open - wait until ready
++ */
++ TRACE_MSG0(TTY, "BLOCKING - wait until ready");
++ rc = ttyfd_block_until_ready(tty,filp,acm);
++
++ /* The tty layer calls tty_close() even if this open fails,
++ * so any cleanup (rc != 0) will be done there.
++ */
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++ return(rc);
++}
++
++/*! ttyfd_wakeup_opens
++ *
++ * Called by acm_fd to wakeup processes blocked in open waiting for DTR.
++ *
++ * @param acm - pointer to acm private data structure
++ */
++void ttyfd_wakeup_opens(struct acm_private *acm)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ TRACE_MSG0(TTY, "entered");
++ //if (tty_private->open_wait_count > 0)
++ wake_up_interruptible(&tty_private->open_wait);
++}
++
++/*! tty_close
++ *
++ * Called by TTY layer to close device.
++ *
++ * @param tty
++ * @param filp
++ * @returns non-zero for error
++ */
++STATIC void tty_close(struct tty_struct *tty, struct file *filp)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ struct usbd_function_instance *function;
++ int used;
++
++ TRACE_MSG0(TTY, "entered");
++
++ //UNLESS (acm) {
++ // printk(KERN_INFO"%s: ACM null\n", __FUNCTION__);
++ // return;
++ //}
++
++ usb_ops->close(acm, DATA_INTF);
++ tty_private = (struct tty_private *) acm->privdata;
++ function = acm->function;
++ TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
++ atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
++
++ // lock and decrement used counter, save result
++ used = atomic_pre_dec(&acm->used);
++
++ // finished unless this is the last close
++
++ RETURN_IF (used > 0);
++
++ TRACE_MSG0(TTY,"FINAL CLOSE");
++
++ tty_private->tty = NULL;
++
++ /* This should never happen if this is the last close,
++ * but it can't hurt to check.
++ */
++ //if (tty_private->open_wait_count)
++ wake_up_interruptible(&tty_private->open_wait);
++
++ if (tty_private->flags & TTYFD_EXCLUSIVE) {
++ tty_private->flags &= ~TTYFD_EXCLUSIVE;
++ if (tty)
++ clear_bit(TTYFD_EXCLUSIVE, &tty->flags);
++ }
++
++ _MOD_DEC_USE_COUNT;
++ TRACE_MSG1(TTY,"DEC: %d", MOD_IN_USE);
++ TRACE_MSG1(TTY,"LAST CLOSE r-f=%d",(acm->bytes_received-acm->bytes_forwarded));
++
++ MOD_DEC_USE_COUNT;
++
++ TRACE_MSG0(TTY,"FINISHED");
++}
++
++/* Transmit Function - called by tty layer ****************************************************** */
++
++int ttyfd_recv_space_available(struct acm_private *acm, int interface);
++int ttyfd_recv_chars(struct acm_private *acm, int interface, u8 *cp, int n);
++
++#define LOOP_BUF 16
++/*! ttyfd_loop_xmit_chars
++ *
++ * Implement data loop back, send xmit data back as received data.
++ *
++ * @param acm - pointer to acm private data structure
++ * @param interface - data interface to send on
++ * @param count - number of bytes to send
++ * @param from_user - true if from user memory space
++ * @param buf - pointer to data to send
++ * @return count - number of bytes actually sent.
++ */
++STATIC int ttyfd_loop_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
++{
++ int received = 0;
++ while (count > 0) {
++ u8 copybuf[LOOP_BUF];
++ int i;
++ int space = ttyfd_recv_space_available(acm, DATA_INTF);
++ int recv = MIN (space, LOOP_BUF);
++ recv = MIN(recv, count);
++
++ //TRACE_MSG7(TTY, "buf: %8x buf+received: %8x received: %d from_user: %d count: %d space: %d recv: %d\n",
++ // buf, buf + received, received, from_user, count, space, recv);
++
++ BREAK_UNLESS(recv);
++
++ if (from_user)
++ copy_from_user ((void *)copybuf, (void*)(buf + received), recv);
++ else
++ memcpy ((void *)copybuf, (void*)(buf + received), recv);
++
++ count -= recv;
++ received += recv;
++ TRACE_MSG3(TTY, "count: %d recv: %d received: %d", count, recv, received);
++ ttyfd_recv_chars(acm, DATA_INTF, copybuf, recv);
++ }
++ return received;
++}
++
++/*! ttyfd_overflow_send
++ *
++ * Check if there is data in overflow buffer and send if neccessary.
++ *
++ * @param acm - pointer to acm private data structure
++ * @param interface - data interface to send on
++ * @param force - force the send
++ */
++void ttyfd_overflow_send(struct acm_private *acm, int interface, int force)
++{
++ int chars_in_buffer;
++ int count;
++
++ unsigned long flags;
++ local_irq_save(flags);
++
++ chars_in_buffer = usb_ops->chars_in_buffer(acm, DATA_INTF);
++
++ TRACE_MSG3(TTY, "overflow_used: %d chars_in_buffer: %d force: %d", tty_overflow_used, chars_in_buffer, force);
++
++ if (force || !chars_in_buffer || tty_overflow_used > 200) {
++
++ count = usb_ops->xmit_chars(acm, DATA_INTF, tty_overflow_used, 0, tty_overflow_buffer);
++
++ TRACE_MSG2(TTY, "overflow_used: %d count: %d", tty_overflow_used, count);
++
++ tty_overflow_used = 0;
++
++ }
++ local_irq_restore(flags);
++}
++
++
++/*! ttyfd_overflow_xmit_chars
++ *
++ * Implement overflow buffer. The TTY layer implements echo with single
++ * character writes which can quickly exhaust the urbs allowed for sending.
++ * This results in data being lost.
++ *
++ * This function is called to accumulate small amounts of data when there is
++ * already an bulk in urb in the queue.
++ *
++ * The urb sent function calls wakeup writers which will call
++ * ttyfd_overflow_send which will send the data.
++ *
++ * @param acm - pointer to acm private data structure
++ * @param interface - data interface to send on
++ * @param count - number of bytes to send
++ * @param from_user - true if from user memory space
++ * @param buf - pointer to data to send
++ * @return count - number of bytes actually sent.
++ */
++STATIC int ttyfd_overflow_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
++{
++ unsigned long flags;
++ int overflow_room;
++ int write_room = usb_ops->write_room(acm, DATA_INTF);
++
++ TRACE_MSG2(TTY,"-> count: %d from_usr: %d", count, from_user);
++ local_irq_save(flags);
++
++ if ((overflow_room = TTY_OVERFLOW_SIZE - tty_overflow_used) > 0) {
++
++ count = MIN(overflow_room, count);
++ if (from_user)
++ copy_from_user ((void *)tty_overflow_buffer + tty_overflow_used, (void*)buf, count);
++ else
++ memcpy ((void *)tty_overflow_buffer + tty_overflow_used, (void*)buf, count);
++
++ tty_overflow_used += count;
++ }
++ else
++ count = 0;
++
++ local_irq_restore(flags);
++
++ /* start sending from overflow if neccessary
++ */
++ ttyfd_overflow_send(acm, interface, 0);
++
++ return count;
++}
++
++/*! tty_chars_in_buffer
++ *
++ * Called by TTY layer to determine amount of pending write data.
++ *
++ * @param tty - pointer to tty data structure
++ * @return amount of pending write data
++ */
++STATIC int tty_chars_in_buffer(struct tty_struct *tty)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ int rc;
++
++ //TRACE_MSG0(TTY, "entered");
++
++ rc = usb_ops->chars_in_buffer(acm, DATA_INTF);
++ TRACE_MSG1(TTY, "chars in buffer: %d", rc);
++ return rc;
++ //return(usb_ops->chars_in_buffer(acm, DATA_INTF));
++}
++
++/*! tty_write
++ *
++ * Called by TTY layer to write data.
++ * @param tty - pointer to tty data structure
++ * @param from_user - true if from user memory space
++ * @param buf - pointer to data to send
++ * @param count - number of bytes want to send.
++ * @return count - number of bytes actually sent.
++ */
++STATIC int tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ TRACE_MSG3(TTY,"-> count: %d loopback: %d from_usr: %d", count, tty_private->tiocm & TIOCM_LOOP, from_user);
++
++ /* loopback mode
++ */
++ if (tty_private->tiocm & TIOCM_LOOP)
++ return ttyfd_loop_xmit_chars(acm, DATA_INTF, count, from_user, buf);
++
++ /* overflow mode
++ */
++ if (tty_overflow_used || (tty_chars_in_buffer(tty_private->tty) && (count < 64)))
++ return ttyfd_overflow_xmit_chars(acm, DATA_INTF, count, from_user, buf);
++
++ /* straight through mode
++ */
++ return usb_ops->xmit_chars(acm, DATA_INTF, count, from_user, buf);
++
++}
++
++/*! tty_write_room
++ *
++ * Called by TTY layer get amount of write room available.
++ *
++ * @param tty - pointer to tty data structure
++ * @return amount of write room available
++ */
++STATIC int tty_write_room(struct tty_struct *tty)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ int rc;
++
++ TRACE_MSG0(TTY, "entered");
++ /* loopback mode
++ */
++ if (tty_private->tiocm & TIOCM_LOOP)
++ return ttyfd_recv_space_available(acm, DATA_INTF);
++
++ rc = usb_ops->write_room(acm, DATA_INTF) + (TTY_OVERFLOW_SIZE - tty_overflow_used);
++ TRACE_MSG1(TTY, "write room: %d", rc);
++
++ return rc;
++
++
++ //return(usb_ops->write_room(acm, DATA_INTF));
++}
++
++static int throttle_count = 0;
++static int unthrottle_count = 0;
++
++/*! tty_throttle
++ *
++ * Called by TTY layer to throttle (do not allow received data.)
++ *
++ * @return amount of write room available
++ */
++STATIC void tty_throttle(struct tty_struct *tty)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ TRACE_MSG0(TTY, "entered");
++ //tty_private->flags |= TTYFD_THROTTLED;
++ usb_ops->throttle(acm, DATA_INTF);
++}
++
++/*! tty_unthrottle
++ *
++ * Called by TTY layer to unthrottle (allow received data.)
++ *
++ * @return amount of write room available
++ */
++STATIC void tty_unthrottle(struct tty_struct *tty)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ TRACE_MSG0(TTY, "entered");
++ //tty_private->flags &= ~TTYFD_THROTTLED;
++ usb_ops->unthrottle(acm, DATA_INTF);
++
++ /* This function is called while the TTY_DONT_FLIP flag is still
++ * set, so there is no point trying to push the flip buffer. Just
++ * try to queue some recv urbs, and keep trying until we do manage
++ * to get some queued.
++ */
++ tty_schedule_flip(tty);
++}
++
++/* ********************************************************************************************** */
++
++/*! ttyfd_tiocm
++ * @param acm
++ * @param tiocm
++ * @return - computed tiocm value
++ */
++unsigned int ttyfd_tiocm(struct acm_private *acm, unsigned int tiocm)
++{
++ tiocm &= ~ ( TIOCM_DTR | TIOCM_DSR | TIOCM_CAR);
++
++ return tiocm |
++ usb_ops->get_dtr(acm) ? TIOCM_DTR : 0 |
++ usb_ops->get_dsr(acm) ? TIOCM_DSR : 0 |
++ usb_ops->get_dcd(acm) ? TIOCM_CAR : 0 ;
++}
++
++/*! tty_ioctl
++ *
++ * Used by TTY layer to execute IOCTL command.
++ *
++ * Called by TTY layer to open device.
++ *
++ * Unhandled commands must return -ENOIOCTLCMD for correct operation.
++ *
++ * @param tty
++ * @param file
++ * @param cmd
++ * @param arg
++ * @returns non-zero for error
++ */
++STATIC int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ unsigned int mask;
++ unsigned int newctrl;
++ unsigned int tiocm;
++ unsigned int saved_tiocm;
++ unsigned int changed_tiocm;
++ int rc;
++
++ //TRACE_MSG3(TTY,"entered: %8x dir: %x size: %x", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd));
++
++ switch(cmd) {
++
++ case TIOCMGET:
++ TRACE_MSG1(TTY, "TIOCMGET: tiocm: %08x", tiocm);
++ tty_private->tiocm = ttyfd_tiocm(acm, tiocm);
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &tty_private->tiocm, sizeof(int)));
++ return 0;
++
++ case TIOCMBIS:
++ case TIOCMBIC:
++ case TIOCMSET:
++ TRACE_MSG0(TTY, "TIOCMXXX: copying tiocm arguement");
++
++ TRACE_MSG1(TTY, "access: %d", access_ok(VERIFY_READ, (void *)arg, sizeof(int)));
++ RETURN_EINVAL_UNLESS(access_ok(VERIFY_READ, (void *)arg, sizeof(int)));
++
++
++ //RETURN_EINVAL_IF (copy_from_user(&tiocm, (void *)arg, sizeof(int)));
++ rc = copy_from_user((void *)&tiocm, (void *)arg, sizeof(int));
++ TRACE_MSG2(TTY, "copy_from_user: %d tiocm: %08x", rc, tiocm);
++
++ TRACE_MSG2(TTY, "tiocm: %08x mask: %08x", tiocm,
++ TIOCM_RTS | TIOCM_DTR | TIOCM_OUT1 | TIOCM_OUT2 | TIOCM_LOOP);
++
++ tiocm &= TIOCM_RTS | TIOCM_DTR | TIOCM_OUT1 | TIOCM_OUT2 | TIOCM_LOOP;
++ saved_tiocm = tty_private->tiocm;
++
++ switch (cmd) {
++ case TIOCMBIS:
++ TRACE_MSG1(TTY, "TIOCMBIS: tiocm: %08x", tiocm);
++ tty_private->tiocm |= tiocm; /* turn on flags set in tiocm */
++ break;
++ case TIOCMBIC:
++ TRACE_MSG1(TTY, "TIOCMBIC: tiocm: %08x", tiocm);
++ tty_private->tiocm &= ~tiocm; /* turn off flags set in tiocm */
++ break;
++ case TIOCMSET:
++ TRACE_MSG1(TTY, "TIOCMSET: tiocm: %08x", tiocm);
++ tty_private->tiocm = tiocm; /* set all flags as in tiocm */
++ break;
++ }
++ /* make changes
++ */
++ changed_tiocm = saved_tiocm ^ tty_private->tiocm;
++ TRACE_MSG4(TTY, "TIOCMSET: tiocm: %08x saved: %08x set: %08x changed: %d",
++ tiocm, saved_tiocm, tty_private->tiocm, changed_tiocm);
++
++ if (changed_tiocm) {
++ /* DTR -> (DSR/DCD) */
++ tiocm = tty_private->tiocm;
++ if (changed_tiocm & TIOCM_DTR) {
++ usb_ops->set_dsr(acm, tiocm & TIOCM_DTR);
++ usb_ops->set_dcd(acm, tiocm & TIOCM_DTR);
++ }
++ /* OUT1 -> Ring */
++ if (changed_tiocm & TIOCM_OUT1)
++ usb_ops->ring(acm);
++ /* OUT2 -> Overrun */
++ if (changed_tiocm & TIOCM_OUT2)
++ usb_ops->overrun(acm);
++ /* LOOPBACK */
++ if (changed_tiocm & TIOCM_OUT2)
++ usb_ops->set_loopback(acm, tiocm & TIOCM_LOOP);
++ }
++
++ return 0;
++
++ case TIOCGSERIAL:
++ TRACE_MSG0(TTY, "TIOCGSERIAL");
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &tty_private->serial_struct, sizeof(struct serial_struct)));
++ return 0;
++
++ case TIOCSSERIAL:
++ TRACE_MSG0(TTY, "TIOCSSERIAL");
++ RETURN_EFAULT_IF (copy_from_user(&tty_private->serial_struct, (void *)arg, sizeof(struct serial_struct)));
++ return 0;
++
++ case TIOCSERCONFIG:
++ case TIOCSERGETLSR: /* Get line status register */
++ case TIOCSERGSTRUCT:
++ TRACE_MSG0(TTY, "TIOCSER*");
++ return -EINVAL;
++
++ /*
++ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
++ * - mask passed in arg for lines of interest
++ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
++ * Caller should use TIOCGICOUNT to see which one it was
++ */
++ case TIOCMIWAIT:
++ TRACE_MSG0(TTY, "TIOCGMIWAIT");
++ while (1) {
++
++ saved_tiocm = tty_private->tiocm;
++
++ interruptible_sleep_on(&tty_private->tiocm_wait);
++
++ /* see if a signal did it */
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++
++ tty_private->tiocm = ttyfd_tiocm(acm, tiocm);
++ changed_tiocm = saved_tiocm ^ tty_private->tiocm;
++ RETURN_ZERO_IF ( (changed_tiocm | TIOCM_CAR) | (changed_tiocm | TIOCM_DSR) );
++ /* loop */
++ }
++ /* NOTREACHED */
++
++ /*
++ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
++ * Return: write counters to the user passed counter struct
++ * NB: both 1->0 and 0->1 transitions are counted except for
++ * RI where only 0->1 is counted.
++ */
++ case TIOCGICOUNT:
++ TRACE_MSG0(TTY, "TIOCGICOUNT");
++ if (copy_to_user((void *)arg, &tty_private->tiocgicount, sizeof(int)))
++ return -EFAULT;
++ return 0;
++
++ case TCSETS:
++ TRACE_MSG1(TTY, "TCSETS: tiocm: %08x", tiocm);
++ return -ENOIOCTLCMD;
++ case TCFLSH:
++ TRACE_MSG1(TTY, "TCFLSH: tiocm: %08x", tiocm);
++ return -ENOIOCTLCMD;
++
++ case TCGETS:
++ TRACE_MSG1(TTY, "TCGETS: tiocm: %08x", tiocm);
++ return -ENOIOCTLCMD;
++
++ default:
++ TRACE_MSG1(TTY, "unknown cmd: %08x", cmd);
++ return -ENOIOCTLCMD;
++ }
++ return -ENOIOCTLCMD;
++}
++
++/*! ttyfd_wakeup_state
++ *
++ * Called by acm_fd to wakeup processes blocked waiting for state change
++ *
++ * @param acm - pointer to acm private data structure
++ */
++void ttyfd_wakeup_state(struct acm_private *acm)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ TRACE_MSG0(TTY, "entered");
++ wake_up_interruptible(&tty_private->tiocm_wait);
++}
++
++
++/*! tty_set_termios
++ *
++ * Used by TTY layer to set termios structure according to current status.
++ *
++ * @param tty - pointer to acm private data structure
++ * @param termios_old - termios structure
++ */
++STATIC void tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
++{
++ struct acm_private *acm = tty->driver_data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ unsigned int c_cflag = tty->termios->c_cflag;
++
++ /* see if CLOCAL has changed */
++ if ((termios_old->c_cflag ^ tty->termios->c_cflag ) & CLOCAL)
++ usb_ops->set_local(acm, tty->termios->c_cflag & CLOCAL);
++
++ /* save cflags
++ */
++ tty_private->c_cflag = c_cflag;
++
++ /* send break?
++ */
++ if ((termios_old->c_cflag & CBAUD) && !(c_cflag & CBAUD))
++ usb_ops->send_break(acm);
++}
++
++/* ********************************************************************************************* */
++/*! ttyfd_wakeup_writers
++ *
++ * Bottom half handler to wakeup pending writers.
++ *
++ * @param data - pointer to acm private data structure
++ */
++STATIC void ttyfd_wakeup_writers(void *data)
++{
++ struct acm_private *acm = (struct acm_private *) data;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ struct tty_struct *tty = tty_private->tty;
++ unsigned long flags;
++
++ TRACE_MSG2(TTY,"used: %d MOD_IN_USE: %d", atomic_read(&acm->used), MOD_IN_USE);
++
++ RETURN_UNLESS(usb_ops->ready(acm));
++ RETURN_UNLESS(atomic_read(&acm->used));
++ RETURN_UNLESS(tty);
++
++ /* start sending from overflow buffer if necessary
++ */
++ ttyfd_overflow_send(acm, DATA_INTF, 0);
++
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
++ (tty->ldisc.write_wakeup)(tty);
++
++ wake_up_interruptible(&tty->write_wait);
++}
++
++/*! ttyfd_schedule_wakeup_writers
++ *
++ * Called by acm-fd to schedule a wakeup writes bottom half handler.
++ *
++ * @param acm - pointer to acm private data structure
++ */
++void ttyfd_schedule_wakeup_writers(struct acm_private *acm)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++
++ TRACE_MSG2(TTY,"used: %d MOD_IN_USE: %d", atomic_read(&acm->used), MOD_IN_USE);
++ ttyfd_schedule(&tty_private->wqueue);
++}
++
++/* ********************************************************************************************* */
++
++/*! ttyfd_recv_space_available
++ *
++ * Used by acm-fd to determine receive space available. This will determine
++ * how many receive urbs can be queued as there are never more receive urbs
++ * pending than there is currently room for data to be received.
++ *
++ * @param acm - pointer to acm private data structure
++ * @param interface - data interface to send on
++ * @return count - number of bytes available
++ */
++int ttyfd_recv_space_available(struct acm_private *acm, int interface)
++{
++ struct tty_private *tty_private;
++ struct tty_struct *tty;
++ int rc;
++
++ TRACE_MSG0(TTY, "entered");
++ RETURN_ZERO_UNLESS(acm);
++
++ tty_private = (struct tty_private *) acm->privdata;
++
++ RETURN_ZERO_UNLESS(tty_private);
++
++ RETURN_ZERO_UNLESS(tty_private->tty);
++
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++ tty = tty_private->tty;
++ rc = TTY_FLIPBUF_SIZE - tty->flip.count;
++ TRACE_MSG1(TTY, "recv space available: %d", rc);
++ return rc;
++ return(TTY_FLIPBUF_SIZE - tty->flip.count);
++ }
++ return 0;
++}
++
++/*! ttyfd_recv_chars
++ *
++ * Called by acm-fd when data has been received. This will
++ * receive n bytes starting at cp. This will never be
++ * more than the last call to ttyfd_recv_space_available().
++ * This will be called from interrupt context.
++ *
++ * @param acm - pointer to acm private data structure
++ * @param interface - data interface to send on
++ * @param n - number of bytes to send
++ * @param cp - pointer to data to send
++ * @return non-zero if error
++ */
++int ttyfd_recv_chars(struct acm_private *acm, int interface, u8 *cp, int n)
++{
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ struct tty_struct *tty = tty_private->tty;
++ unsigned long flags;
++
++ /* acm_start_recv_urbs() will never queue more urbs than there is currently
++ * room in the upper layer buffer for. So we are guaranteed that any data actually
++ * received can be given to the upper layers without worrying if we will
++ * actually have room.
++ *
++ * XXX I think that if the tty layer does get behind and we reach a point where
++ * there are no outstanding receive urbs, then we will also have been throttled
++ * so we will have an oppourtunity to queue more receive urbs when we get unthrottled.
++ *
++ * XXX If the above assumption is not true that a timer will be needed to periodically
++ * check if we can restart.
++ *
++ * YYY What can happen is that the tty_flip_buffer_push() call can fail for
++ * a variety of reasons (locked out while a read call is in progress, ldisc
++ * buffer is full, and probably others). We need to ensure that we keep
++ * trying to push the flip buffer until it does go, and there is room for
++ * more receive urbs. acm_start_recv_urbs() will queue a task to push and
++ * try again if it can't queue any now.
++ *
++ * ZZZ Yet another failure mode is to call tty_flip_buffer_push() too many
++ * times while throttled. This will result in the ldisc layer silently
++ * dropping data inside the n_tty_receive_buf() routine. (Acutal numbers
++ * for the 2.4.20 kernel this was discovered on are 128 bytes left in the
++ * ldisc buffer when throttle is called, and upto 7 64 byte urbs outstanding.
++ * The urbs will fit into the flip buffer, but NOT the ldisc buffer.) This
++ * means we must not call tty_flip_buffer_push() when throttled. We will
++ * count on the tty_unthrottle() call to kick off the final push.
++ */
++
++ {
++ int i;
++ local_irq_save(flags);
++ TRACE_MSG2(TTY, "recv: %d buffer: %x", n, cp);
++
++ for (i = 0; i < n; i += 8) {
++ TRACE_MSG8(TTY, "%02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++ }
++
++ local_irq_restore(flags);
++ }
++ switch (interface) {
++ case COMM_INTF:
++ return 0;
++ case DATA_INTF:
++
++ RETURN_EINVAL_UNLESS(tty);
++
++#define WORD_COPY 1
++#if defined(WORD_COPY)
++ local_irq_save(flags);
++ memcpy(tty->flip.char_buf_ptr,cp,n);
++ memset(tty->flip.flag_buf_ptr,TTY_NORMAL,n);
++ tty->flip.count += n;
++ tty->flip.char_buf_ptr += n;
++ tty->flip.flag_buf_ptr += n;
++ acm->bytes_forwarded += n;
++ local_irq_restore(flags);
++#else
++ int i;
++ for (i = 0; i < n; i++) {
++ /* tty_flip_char() has no lock out from any calls
++ * to tty_flip_buffer_push() that may have been queued
++ * by acm_unthrottle() or acm_start_recv_urbs(), so...
++ */
++ local_irq_save(flags);
++ tty_insert_flip_char(tty, *cp++, TTY_NORMAL);
++ local_irq_restore(flags);
++ }
++ acm->bytes_forwarded += n;
++#endif
++
++ UNLESS (test_bit(TTY_THROTTLED, &tty->flags))
++ tty_flip_buffer_push(tty);
++
++ //UNLESS (tty_private->flags & TTYFD_THROTTLED)
++ // tty_flip_buffer_push(tty);
++
++ return 0;
++ }
++ return 0;
++}
++
++/* ********************************************************************************************* */
++
++/*! ttyfd_enable
++ *
++ * Called by acm-fd when the function driver is enabled.
++ */
++void ttyfd_enable(struct usbd_function_instance *function)
++{
++ //function->privdata = &acm_private;
++ //acm_private.function = function;
++}
++
++/*! ttyfd_enable
++ *
++ * Called by acm-fd when the function driver is disabled.
++ */
++void ttyfd_disable(struct usbd_function_instance *function)
++{
++ //function->privdata = NULL;
++ //acm_private.function = NULL;
++}
++
++/* ************************************************************************** */
++
++#if defined(LINUX24)
++static int tty_refcount;
++#else
++//Maintained inside tty_driver in LINUX 2.6
++#endif
++static struct tty_struct *tty_table[ACM_TTY_MINORS];
++static struct termios *tty_termios[ACM_TTY_MINORS];
++static struct termios *tty_termios_locked[ACM_TTY_MINORS];
++
++/*! tty_driver
++ */
++static struct tty_driver tty_driver = {
++ .magic = TTY_DRIVER_MAGIC,
++ .type = TTY_DRIVER_TYPE_SERIAL,
++ .subtype = SERIAL_TYPE_NORMAL,
++ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
++ .driver_name = "acm-CDC",
++ .name = "usb/acm/%d",
++ .major = ACM_TTY_MAJOR,
++ .num = ACM_TTY_MINORS,
++ .minor_start = 0,
++
++ .open = tty_open,
++ .close = tty_close,
++ .write = tty_write,
++ .write_room = tty_write_room,
++ .ioctl = acm_tty_ioctl,
++ .throttle = tty_throttle,
++ .unthrottle = tty_unthrottle,
++ .chars_in_buffer = tty_chars_in_buffer,
++ .set_termios = tty_set_termios,
++
++#if defined(LINUX24)
++ .refcount = &tty_refcount,
++#else
++ .refcount = 0,
++#endif
++ .table = tty_table,
++ .termios = tty_termios,
++ .termios_locked = tty_termios_locked,
++};
++
++/* USB Module init/exit ************************************************************************ */
++
++struct tty_private ttyfd_private = {
++ .tty_driver = &tty_driver,
++ //.wqueue.routine = ttyfd_wakeup_writers,
++ //.wqueue.data = &acmfd_private,
++ .wqueue = {
++ .routine = ttyfd_wakeup_writers,
++ .data = &acmfd_private,
++ },
++ //.hqueue.routine = ttyfd_call_hangup,
++ //.hqueue.data = &acmfd_private,
++ .hqueue = {
++ .routine = ttyfd_call_hangup,
++ .data = &acmfd_private,
++ },
++};
++
++
++/*! tty_function_services
++ *
++ * This structure contains the list of services
++ */
++struct acm_function_services tty_function_services = {
++ .schedule_wakeup_writers = ttyfd_schedule_wakeup_writers,
++ .recv_space_available = ttyfd_recv_space_available,
++ .recv_chars = ttyfd_recv_chars,
++ .enable = ttyfd_enable,
++ .disable = ttyfd_disable,
++ .schedule_hangup = ttyfd_schedule_hangup,
++ .wakeup_opens = ttyfd_wakeup_opens,
++ .wakeup_state = ttyfd_wakeup_state,
++};
++
++struct acm_private acmfd_private = {
++ .function_driver = &tty_function_driver,
++ .function_services = &tty_function_services,
++ .privdata = &ttyfd_private,
++ // TBR: 20040705 use ...le32() not le16, spotted by Zhao Liang
++ //.line_coding.dwDTERate = __constant_cpu_to_le32(0x1c200), // 115200
++ //.line_coding.bDataBits = 0x08,
++ .line_coding = {
++ .dwDTERate = __constant_cpu_to_le32(0x1c200), // 115200
++ .bDataBits = 0x08,
++ },
++};
++
++
++/*! ttyfd_modinit - module init
++ *
++ * This is called immediately after the module is loaded or during
++ * the kernel driver initialization if linked into the kernel.
++ *
++ */
++STATIC int ttyfd_modinit (void)
++{
++ int i;
++
++ /* initialize private structures */
++ acmfd_private.trace_tag = TTY = otg_trace_obtain_tag();
++ init_waitqueue_head(&ttyfd_private.open_wait);
++ init_waitqueue_head(&ttyfd_private.tiocm_wait);
++
++ /* update init_termios and register as tty driver */
++ tty_driver.init_termios = tty_std_termios;
++ tty_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
++ tty_driver.init_termios.c_lflag &= ~(ECHO | ICANON);
++ THROW_IF(tty_register_driver(&tty_driver), error);
++ tty_register_devfs(&tty_driver, 0, ACM_TTY_MINOR);
++ ttyfd_private.tty_driver_registered++;
++
++ /* register as usb function driver via acm-fd */
++ THROW_IF (usb_ops->fd_init(&acmfd_private, "acm_fd", vendor_id, product_id, max_queued_urbs,max_queued_bytes ), error);
++
++ CATCH(error) {
++ printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
++ if (ttyfd_private.tty_driver_registered) {
++ tty_unregister_driver(&tty_driver);
++ ttyfd_private.tty_driver_registered = 0;
++ }
++ return -EINVAL;
++ }
++ return 0;
++}
++
++
++/*! ttyfd_modexit - module cleanup
++ *
++ * This is called prior to the module being unloaded.
++ */
++STATIC void ttyfd_modexit (void)
++{
++ struct acm_private *acm = &acmfd_private;
++ struct tty_private *tty_private = (struct tty_private *) acm->privdata;
++ unsigned long flags;
++ struct usbd_urb *urb;
++
++ /* Wake up any pending opens after setting the exiting flag. */
++ local_irq_save(flags);
++ ttyfd_private.exiting = 1;
++ //if (ttyfd_private.open_wait_count > 0)
++ wake_up_interruptible(&ttyfd_private.open_wait);
++ local_irq_restore(flags);
++
++ /* verify no tasks are running */
++ usb_ops->wait_task(acm, &acm->recv_tqueue);
++ usb_ops->wait_task(acm, &ttyfd_private.wqueue);
++ usb_ops->wait_task(acm, &ttyfd_private.hqueue);
++
++#if defined(LINUX24)
++ run_task_queue(&tq_timer);
++#else
++ blk_run_queues();
++#endif
++ /* de-register as tty and usb drivers */
++ if (ttyfd_private.tty_driver_registered)
++ tty_unregister_driver(&tty_driver);
++
++ /* de-register as function driver via acm-fd */
++ usb_ops->fd_exit(&acmfd_private);
++ otg_trace_invalidate_tag(TTY);
++}
++
++module_init (ttyfd_modinit);
++module_exit (ttyfd_modexit);
++
+diff -uNr linux/drivers/no-otg/functions/acm/tty-os.h linux/drivers/otg/functions/acm/tty-os.h
+--- linux/drivers/no-otg/functions/acm/tty-os.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/tty-os.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++ * otg/functions/acm/tty-os.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @file otg/functions/acm/tty-os.h
++ * @brief ACM Function Driver private defines
++ *
++ * An ACM (Abstract Control Model) driver is composed of two pieces:
++ * 1) An OS specific piece that handles creating and operating
++ * a serial device for the given OS.
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the otgcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * an ACM class driver. If the USB piece interfaces with the otgcore
++ * layer you get an ACM function driver.
++ *
++ * This file describes the functions exported by the various acm-*-os.c
++ * files (implementing (1)) for use in acm-fd.c (2).
++ *
++ * @ingroup TTYFunction
++ */
++
++#ifndef ACM_OS_H
++#define ACM_OS_H 1
++
++/*
++ * acm_os_recv_space_available - return the number of bytes of data
++ * the OS specific piece can accept without
++ * dropping some.
++ */
++extern int acm_os_recv_space_available(struct acm_private *acm);
++
++/*
++ * acm_os_recv_chars - receive n bytes starting at cp. This will never be
++ * more than the last call to acm_os_recv_space_available().
++ * This will be called from interrupt context.
++ */
++extern int acm_os_recv_chars(struct acm_private *acm, u8 *cp, int n);
++
++/*
++ * acm_os_wakeup_writers - wakeup any blocked writers. This is called
++ * from interrupt context, so may need to queue
++ * the actual wakeup in a "bottom half".
++ */
++extern void acm_os_wakeup_writers(struct acm_private *acm);
++
++/*
++ * acm_os_hangup - send a hangup to any readers or writers. This can be
++ * called from interrupt context, so may need to queue
++ * the actual hangup in a "bottom half".
++ */
++extern void acm_os_hangup(struct acm_private *acm);
++
++/*
++ * acm_os_wakeup_opens - wakeup any blocked opens. This is called
++ * from interrupt context, so may need to queue
++ * the actual wakeup in a "bottom half".
++ */
++extern void acm_os_wakeup_opens(struct acm_private *acm);
++
++extern void acm_os_enable(struct usbd_function_instance *function);
++extern void acm_os_disable(struct usbd_function_instance *function);
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/acm/tty.h linux/drivers/otg/functions/acm/tty.h
+--- linux/drivers/no-otg/functions/acm/tty.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/acm/tty.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,117 @@
++/*
++ * otg/functions/acm/tty.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup TTYFunction ACM-TTY
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/acm/tty.h
++ * @brief ACM Function Driver private defines
++ *
++ *
++ * This is an ACM Function Driver. The upper edge is exposed
++ * to the hosting OS as a Posix type character device. The lower
++ * edge implements the USB Device Stack API.
++ *
++ * These are emulated and set by the tty driver as appropriate
++ * to model a virutal serial port. The
++ *
++ * TIOCM_RNG RNG (Ring) not used
++ * TIOCM_LE DSR (Data Set Ready / Line Enable)
++ * TIOCM_DSR DSR (Data Set Ready)
++ * TIOCM_CAR DCD (Data Carrier Detect)
++ * TIOCM_CTS CTS (Clear to Send)
++ * TIOCM_CD TIOCM_CAR
++ * TIOCM_RI TIOCM_RNG
++ *
++ * These are set by the application:
++ *
++ * TIOCM_DTR DTR (Data Terminal Ready)
++ * TIOCM_RTS RTS (Request to Send)
++ *
++ * TIOCM_LOOP Set into loopback mode
++ * TIOCM_OUT1 Not used.
++ * TIOCM_OUT2 Not used.
++ *
++ *
++ * The following File and termio c_cflags are used:
++ *
++ * O_NONBLOCK don't block in tty_open()
++ * O_EXCL don't allow more than one open
++ *
++ * CLOCAL ignore DTR status
++ * CBAUD send break if set to B0
++ *
++ * Virtual NULL Modem
++ *
++ * Peripheral to Host via Serial State Notification (write ioctls)
++ *
++ * Application TIOCM Null Modem ACM (DCE) Notificaiton Host (DTE)
++ * -------------------------------------------------------------------------------------------------------------
++ * Request to send TIOCM_RTS RTS -> CTS CTS Not Available Clear to Send (N/A)
++ * Data Terminal Ready TIOCM_DTR DTR -> DSR DSR bTxCarrier Data Set Ready
++ * DTR -> DCD DCD bRXCarrier Carrier Detect
++ * Ring Indicator TIOCM_OUT1 OUT1 -> RI RI bRingSignal Ring Indicator
++ * Overrun TIOCM_OUT2 OUT2 -> Overrun Overrun bOverrun Overrun
++ * Send Break B0 B0 -> Break Break bBreak Break Received
++ * -------------------------------------------------------------------------------------------------------------
++ *
++ *
++ * Host to Peripheral via Set Control Line State
++ *
++ * Host (DTE) Line State ACM (DCE) Null Modem TIOCM Peripheral (DTE)
++ * -------------------------------------------------------------------------------------------------------------
++ * Data Terminal Ready D0 DTR DTR -> DSR TIOCM_DSR Data Set Ready
++ * DTR -> DCD TIOCM_CAR Carrier Detect
++ * Request To Send D1 RTS RTS -> CTS TIOCM_CTS Clear to Send
++ * -------------------------------------------------------------------------------------------------------------
++ *
++ *
++ * @ingroup TTYFunction
++ */
++
++extern struct usbd_function_driver tty_function_driver;
++
++//#define TTY_OPENED (1 << 0) /*! OPENED flag */
++#define TTYFD_CLOCAL (1 << 1) /*! CLOCAL flag */
++//#define TTYFD_LOOPBACK (1 << 2) /*! LOOPBACK flag */
++#define TTYFD_EXCLUSIVE (1 << 3) /*! EXCLUSIVE flag */
++#define TTYFD_THROTTLED (1 << 4) /*! THROTTLED flag */
++
++/*! @struct tty_private
++ */
++struct tty_private {
++
++ struct tty_driver *tty_driver; /*!< tty structure */
++ int tty_driver_registered; /*!< non-zero if tty_driver registered */
++ int usb_driver_registered; /*!< non-zero if usb function registered */
++
++ struct tty_struct *tty; /*!< non-null if tty open */
++ struct tq_struct wqueue; /*!< task queue for writer wakeup */
++ struct tq_struct hqueue; /*!< task queue for hangup */
++
++ u32 flags; /*!< flags */
++
++ u32 tiocm; /*!< tiocm settings */
++
++ struct serial_struct serial_struct; /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
++
++ wait_queue_head_t tiocm_wait;
++ u32 tiocgicount;
++
++ u32 c_cflag;
++
++ wait_queue_head_t open_wait; /*! wait queue for blocking open*/
++ int exiting; /*! True if module exiting */
++};
++
++
+diff -uNr linux/drivers/no-otg/functions/isotest/Config.in linux/drivers/otg/functions/isotest/Config.in
+--- linux/drivers/no-otg/functions/isotest/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/Config.in 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# Loop Function
++#
++# Copyright (C) 2003-2004 Belcarra
++# Enhanced Jan 2004 to provide greater runtime selection
++# of xmit buffer patterns from the device to the host
++#
++
++mainmenu_option next_comment
++comment "ISO Test Function"
++
++dep_tristate ' Loop Function Driver' CONFIG_OTG_ISOTEST $CONFIG_OTG
++
++if [ "$CONFIG_OTG_ISOTEST" = "y" -o "$CONFIG_OTG_ISOTEST" = "m" ]; then
++
++ hex ' idVendor (hex value)' CONFIG_OTG_ISOTEST_VENDORID "15ec"
++ hex ' idProduct (hex value)' CONFIG_OTG_ISOTEST_PRODUCTID "f004"
++ hex ' bcdDevice (binary-coded decimal)' CONFIG_OTG_ISOTEST_BCDDEVICE "0100"
++ string ' iManufacturer (string)' CONFIG_OTG_ISOTEST_MANUFACTURER ""
++ string ' iProduct (string)' CONFIG_OTG_ISOTEST_PRODUCT_NAME ""
++
++ string ' iConfiguration (string)' CONFIG_OTG_ISOTEST_DESC "ISO Test Cfg"
++ string ' Data Interface iInterface (string)' CONFIG_OTG_ISOTEST_DATA_INTF "ISO Data Intf"
++ #bool ' Runtime pattern buffer selection ' CONFIG_OTG_ISOTEST_XMIT_PATTERN "y"
++
++fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/isotest/Makefile linux/drivers/otg/functions/isotest/Makefile
+--- linux/drivers/no-otg/functions/isotest/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/Makefile 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,73 @@
++#
++# Function driver ISO Test Device
++#
++# Copyright (c) 2003 Belcarra
++
++# Multipart objects.
++
++O_TARGET := isotest_fd_drv.o
++list-multi := isotest_fd.o isotest.o
++
++isotest_fd-objs := iso.o test.o fermat.o
++isotest-objs := host.o test.o
++
++# Objects that export symbols.
++export-objs := iso.o
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_ISOTEST) += isotest_fd.o isotest.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++OTG=$(TOPDIR)/drivers/otg
++ISOD=$(OTG)/functions/isotest
++USBDCORE_DIR=$(OTG)/usbdcore
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -I$(ISOD) -I$(OTG) -Wno-unused -Wno-format
++EXTRA_CFLAGS_nostdinc += -I$(ISOD) -I$(OTG) -Wno-unused -Wno-format
++
++# Link rules for multi-part drivers.
++
++isotest_fd.o: $(isotest_fd-objs)
++ $(LD) -r -o $@ $(isotest_fd-objs)
++
++isotest.o: $(isotest-objs)
++ $(LD) -r -o $@ $(isotest-objs)
++
++# dependencies:
++
++isotest.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h test.h
++host.o: host.c test.h
++
++test.o:test.h
++
+diff -uNr linux/drivers/no-otg/functions/isotest/fermat.c linux/drivers/otg/functions/isotest/fermat.c
+--- linux/drivers/no-otg/functions/isotest/fermat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/fermat.c 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,132 @@
++/*
++ * otg/network_fd/fermat.c - Network Function Driver
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#ifdef CONFIG_OTG_ISOTEST_MODULE
++
++#include "fermat.h"
++
++#ifndef ISO_FERMAT_DEFINED
++typedef unsigned char BYTE;
++typedef struct fermat {
++ int length;
++ BYTE power[256];
++} FERMAT;
++#endif
++
++
++static int fermat_setup(FERMAT *p, int seed){
++ int i = 0;
++ unsigned long x,y;
++ y = 1;
++ do{
++ x = y;
++ p->power[i] = ( x == 256 ? 0 : x);
++ y = ( seed * x ) % 257;
++ i += 1;
++ }while( y != 1);
++ p->length = i;
++ return i;
++}
++
++static void fermat_xform(FERMAT *p, BYTE *data, int length){
++ BYTE *pw = p->power;
++ int i, j;
++ BYTE * q ;
++ for(i = 0, j=0, q = data; i < length; i++, j++, q++){
++ if(j>=p->length){
++ j = 0;
++ }
++ *q ^= pw[j];
++ }
++}
++
++static FERMAT default_fermat;
++static const int primitive_root = 5;
++void fermat_init(){
++ (void) fermat_setup(&default_fermat, primitive_root);
++}
++
++// Here are the public official versions.
++// Change the primitive_root above to another primitive root
++// if you need better scatter. Possible values are 3 and 7
++
++
++void fermat_encode(BYTE *data, int length){
++ fermat_xform(&default_fermat, data, length);
++}
++
++void fermat_decode(BYTE *data, int length){
++ fermat_xform(&default_fermat, data, length);
++}
++
++
++// Note: the seed must be a "primitive root" of 257. This means that
++// the return value of the setup routine must be 256 (otherwise the
++// seed is not a primitive root. The routine will still work fine
++// but will be less pseudo-random.
++
++#undef TEST
++#if TEST
++#include <stdio.h>
++#include <memory.h>
++
++// Use FERMAT in two ways: to encode, and to generate test data.
++
++main(){
++ //Note 3, 5, and 7 are primitive roots of 257
++ // 11 is not a primitive root
++ FERMAT three, five, seven;
++
++ FERMAT three2;
++ printf("Cycle lengths: 3,5,7 %d %d %d \n",
++ fermat_setup(&three, 3),
++ fermat_setup(&five, 5),
++ fermat_setup(&seven, 7));
++ three2=three; // Copy data from three
++ fermat_xform(&three,three2.power,three2.length);
++ fermat_xform(&five,three2.power,three2.length);
++ fermat_xform(&seven,three2.power,three2.length);
++ fermat_xform(&seven,three2.power,three2.length);
++ fermat_xform(&five,three2.power,three2.length);
++ fermat_xform(&three,three2.power,three2.length);
++
++ //At this stage, three2 and three should be identical
++ if(memcpy(&three,&three2,sizeof(FERMAT))){
++ printf("Decoded intact\n");
++ }
++
++ fermat_init();
++ fermat_encode(three2.power,256);
++
++}
++#endif
++
++#endif /* CONFIG_OTG_ISOTEST */
++
+diff -uNr linux/drivers/no-otg/functions/isotest/fermat.h linux/drivers/otg/functions/isotest/fermat.h
+--- linux/drivers/no-otg/functions/isotest/fermat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/fermat.h 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,38 @@
++/*
++ * otg/network_fd/fermat.h - Network Function Driver
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ */
++
++#ifndef ISO_FERMAT_DEFINED
++#define ISO_FERMAT_DEFINED 1
++typedef unsigned char BYTE;
++typedef struct fermat {
++ int length;
++ BYTE power[256];
++} FERMAT;
++
++void fermat_init(void);
++void fermat_encode(BYTE *data, int length);
++void fermat_decode(BYTE *data, int length);
++#endif
++
+diff -uNr linux/drivers/no-otg/functions/isotest/host.c linux/drivers/otg/functions/isotest/host.c
+--- linux/drivers/no-otg/functions/isotest/host.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/host.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,840 @@
++/*
++ * otg/isotest_fd/host.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * USB ISO Test
++ *
++ *
++ * Copyright (c) 2003, 2004 sl@belcarra.com
++ *
++ */
++
++//#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h>
++//#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++//#include <linux/poll.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/fcntl.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++#include <linux/usb.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++
++#include <linux/vmalloc.h>
++
++#include <asm/atomic.h>
++#include <asm/io.h>
++
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
++#include <asm/dma.h>
++#include <asm/mach/dma.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/types.h>
++#endif
++
++#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++#include <asm/au1000.h>
++#include <asm/au1000_dma.h>
++#include <asm/mipsregs.h>
++#endif
++
++#if defined(CONFIG_ARCH_SAMSUNG)
++#include <asm/arch/timers.h>
++#include <asm/arch/hardware.h>
++#endif
++
++#include "test.h"
++
++
++/* Use our own dbg macro */
++#undef dbg
++#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
++
++#define MIN(a,b) (((a) < (b))?(a):(b))
++#define MAX(a,b) (((a) > (b))?(a):(b))
++
++#define THROW(x) goto x
++#define CATCH(x) while(0) x:
++#define THROW_IF(e, x) if (e) { goto x; }
++#define BREAK_IF(x) if (x) { break; }
++#define CONTINUE_IF(x) if (x) { continue; }
++#define RETURN_IF(y) if (y) { return; }
++#define RETURN_ZERO_IF(y) if (y) { return 0; }
++#define RETURN_NULL_IF(y) if (y) { return NULL; }
++
++
++/* Version Information */
++#define DRIVER_VERSION "v0.9"
++#define DRIVER_AUTHOR "sl@belcarra.com"
++#define DRIVER_DESC "USB ISO Test"
++
++/* Define these values to match your device */
++
++#ifdef CONFIG_OTG_ISOTEST_VENDORID
++ #undef USB_ISOTEST_VENDOR_ID
++ #define USB_ISOTEST_VENDOR_ID CONFIG_OTG_ISOTEST_VENDORID
++#else
++ #define USB_ISOTEST_VENDOR_ID 0xfff0
++#endif
++
++#ifdef CONFIG_OTG_ISOTEST_PRODUCTID
++ #undef USB_ISOTEST_PRODUCT_ID
++ #define USB_ISOTEST_PRODUCT_ID CONFIG_OTG_ISOTEST_PRODUCTID
++#else
++ #define USB_ISOTEST_PRODUCT_ID 0xfff1
++#endif
++
++/* Module paramaters */
++//MODULE_PARM(debug, "i");
++//MODULE_PARM_DESC(debug, "Debug enabled or not");
++
++static int send;
++MODULE_PARM(send, "i");
++MODULE_PARM_DESC(send, "send test");
++
++static int recv;
++MODULE_PARM(recv, "i");
++MODULE_PARM_DESC(recv, "recv test");
++
++static u32 vendor_id; // no default
++static u32 product_id; // no default
++
++
++MODULE_PARM_DESC(vendor_id, "User specified USB idVendor");
++MODULE_PARM_DESC(product_id, "User specified USB idProduct");
++MODULE_PARM(vendor_id, "i");
++MODULE_PARM(product_id, "i");
++
++
++/* table of devices that work with this driver */
++static struct usb_device_id isotest_table [] = {
++ { USB_DEVICE(USB_ISOTEST_VENDOR_ID, USB_ISOTEST_PRODUCT_ID) },
++ { }, /* extra entry */
++ { }, /* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE (usb, isotest_table);
++
++/* ********************************************************************************************* */
++
++
++/* ********************************************************************************************* */
++/*
++struct iso_test_data {
++
++ // sender info
++ u32 sender_id;
++ time_t send_time;
++ u32 send_crc;
++
++ // loop info
++ u32 recv_id;
++ time_t recv_time;
++ u32 recv_crc;
++
++ // payload
++ u32 size;
++ u8 data[0];
++};
++*/
++
++#define IN_URBS 10
++#define OUT_URBS 10
++
++
++
++
++/* Structure to hold all of our device specific stuff */
++struct usb_isotest {
++ struct usb_device * udev; /* save off the usb device pointer */
++ struct usb_interface * interface; /* the interface for this device */
++
++ u8 closing;
++ u8 num_interrupt_in; /* number of interrupt in endpoints we have */
++ u8 num_iso_in; /* number of iso in endpoints we have */
++ u8 num_iso_out; /* number of iso out endpoints we have */
++
++ int iso_in_size; /* the size of the receive buffer */
++ struct urb * iso_in_urbs[IN_URBS]; /* the urb used to send data */
++ u8 iso_in_endpointAddr; /* the address of the iso in endpoint */
++ int in_urbs;
++
++ int iso_out_size; /* the size of the send buffer */
++ struct urb * iso_out_urbs[OUT_URBS]; /* the urb used to send data */
++ u8 iso_out_endpointAddr; /* the address of the iso out endpoint */
++ int out_urbs;
++
++ struct semaphore sem; /* locks this structure */
++ struct tq_struct iso_bh;
++ wait_queue_head_t iso_wq;
++
++ struct isotest_stats stats;
++
++ int first;
++};
++
++
++/* local function prototypes */
++
++static void * isotest_probe (struct usb_device *, unsigned int , const struct usb_device_id *);
++static void isotest_disconnect (struct usb_device *, void *);
++
++
++void isotest_schedule_bh(struct usb_isotest *isotest);
++
++
++/* ISO OUT - Transmit ************************************************************************** */
++
++
++#if 1
++static void isotest_iso_out_free_urb(struct urb *urb)
++{
++ struct usb_isotest *isotest;
++ int i;
++ unsigned long flags;
++
++ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
++
++ RETURN_IF(!urb);
++
++ if (urb->transfer_buffer) {
++ kfree(urb->transfer_buffer);
++ }
++
++ isotest = (struct usb_isotest *)urb->context;
++ usb_free_urb(urb);
++
++ RETURN_IF(!isotest);
++
++ local_irq_save (flags);
++ for (i = 0; i < OUT_URBS; i++) {
++ CONTINUE_IF(isotest->iso_out_urbs[i] != urb);
++ //printk(KERN_INFO"%s: zeroing %d urb: %p\n", __FUNCTION__, i, urb);
++ isotest->iso_out_urbs[i] = NULL;
++ break;
++ }
++ local_irq_restore (flags);
++}
++#endif
++
++static int iso_transfer_count;
++
++int iso_out_submit(struct usb_isotest *isotest, struct urb *urb)
++{
++ int i;
++ int j;
++ int rc = 0;
++
++ //printk(KERN_INFO"%s: transfer: %d size: %d frames: %x\n", __FUNCTION__,
++ // iso_transfer_count, urb->transfer_buffer_length, urb->number_of_packets);
++
++ RETURN_ZERO_IF(isotest->closing);
++
++ urb->dev = isotest->udev;
++
++ iso_transfer_count++;
++
++ for (j = urb->transfer_buffer_length, i = 0; i < urb->number_of_packets; i++) {
++
++ int send = MIN(isotest->iso_out_size, j);
++
++ u8 *cp = urb->transfer_buffer + (isotest->iso_out_size * i);
++
++ j -= send;
++
++ urb->iso_frame_desc[i].offset = i * isotest->iso_out_size;
++ urb->iso_frame_desc[i].length = send;
++
++ // iso_transfer_count
++ *cp++ = cpu_to_le16(iso_transfer_count) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_count) >> 8) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_count) >> 16) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_count) >> 24) & 0xff;
++
++ // iso transfer length
++ *cp++ = cpu_to_le16(urb->transfer_buffer_length) & 0xff;
++ *cp++ = (cpu_to_le16(urb->transfer_buffer_length) >> 8) & 0xff;
++
++ // iso frame size
++ *cp++ = cpu_to_le16(isotest->iso_out_size) & 0xff;
++ *cp++ = (cpu_to_le16(isotest->iso_out_size) >> 8) & 0xff;
++
++ // total frames
++ *cp++ = cpu_to_le16(urb->number_of_packets) & 0xff;
++ *cp++ = (cpu_to_le16(urb->number_of_packets) >> 8) & 0xff;
++
++ // this packet number
++ *cp++ = cpu_to_le16(i+1) & 0xff;
++ *cp++ = (cpu_to_le16(i+1) >> 8) & 0xff;
++
++ }
++
++ //printk(KERN_INFO"%s: submitting\n", __FUNCTION__);
++
++ RETURN_ZERO_IF(!(rc = usb_submit_urb(urb)));
++ printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
++
++ return rc;
++}
++
++void isotest_iso_out_complete (struct urb *urb)
++{
++ struct usb_isotest *isotest = (struct usb_isotest *)urb->context;
++ int rc;
++
++ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
++
++ RETURN_IF(!urb);
++
++ if (urb->status /* && (urb->status != -ENOENT) && (urb->status != -ECONNRESET)*/) {
++ //printk(KERN_INFO"%s: - nonzero write iso status received: %d\n", __FUNCTION__, urb->status);
++ }
++
++ iso_out_submit(isotest, urb);
++}
++
++
++#define ISO_SEND_TOTAL 1000
++#define ISO_SEND_TRANSFERS 1200
++
++static int out_count;
++
++struct urb *iso_out_start(struct usb_isotest *isotest)
++{
++ struct urb * urb = NULL;
++ int rc = 0;
++ int i;
++ int j;
++
++
++ int size = ((ISO_SEND_TOTAL % isotest->iso_out_size) < 20) ? ISO_SEND_TOTAL + 20 : ISO_SEND_TOTAL;
++ int frames = (size / isotest->iso_out_size) + 1;
++
++ //RETURN_NULL_IF(out_count-- <= 0);
++
++ //printk(KERN_INFO"%s: %d %02x\n", __FUNCTION__, out_count, isotest->iso_out_endpointAddr);
++
++
++ //printk(KERN_INFO"%s: frames: %x packet: %d size: %d\n", __FUNCTION__, frames, isotest->iso_out_size, size);
++
++ // allocate urb and buffer, fill buffer with some data
++ THROW_IF(!(urb = usb_alloc_urb(frames + 1)), error);
++
++ THROW_IF (!(urb->transfer_buffer = kmalloc(size, GFP_ATOMIC)), error);
++
++ for (i = 0; i < size; i++) {
++ unsigned char *cp = urb->transfer_buffer + i;
++ *cp = i % 256;
++ }
++
++ //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
++
++ urb->hcpriv = NULL;
++ urb->context = isotest;
++ urb->transfer_flags = USB_ISO_ASAP;
++ urb->complete = isotest_iso_out_complete;
++ urb->pipe = usb_sndisocpipe(isotest->udev, isotest->iso_out_endpointAddr);
++
++ urb->transfer_buffer_length = size;
++
++ urb->number_of_packets = frames;
++
++ THROW_IF((rc = iso_out_submit(isotest, urb)), error);
++
++ //printk(KERN_INFO"%s: OK frames: %d\n", __FUNCTION__, frames);
++
++ CATCH(error) {
++ printk(KERN_INFO"%s: FAILED rc: %d\n", __FUNCTION__, rc);
++ //isotest_iso_out_free_urb(urb);
++ return NULL;
++ }
++ return urb;
++}
++
++/* ISO IN - Receive **************************************************************************** */
++
++static int in_count = 5;
++static int in_submitted;
++static int in_resubmitted;
++static long in_completed;
++static long in_total_received;
++
++#if 0
++static void isotest_iso_in_free_urb(struct urb *urb)
++{
++ struct usb_isotest *isotest;
++ int i;
++ unsigned long flags;
++
++ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
++
++ RETURN_IF(!urb);
++
++ if (urb->transfer_buffer) {
++ kfree(urb->transfer_buffer);
++ }
++
++ isotest = (struct usb_isotest *)urb->context;
++ usb_free_urb(urb);
++
++ RETURN_IF(!isotest);
++
++ local_irq_save (flags);
++ for (i = 0; i < IN_URBS; i++) {
++ CONTINUE_IF(isotest->iso_in_urbs[i] != urb);
++ //printk(KERN_INFO"%s: clearing %d urb: %p\n", __FUNCTION__, i, urb);
++ isotest->iso_in_urbs[i] = NULL;
++ break;
++ }
++ local_irq_restore (flags);
++}
++#endif
++
++struct urb *iso_in_start(struct usb_isotest *isotest);
++
++int iso_in_submit(struct usb_isotest *isotest, struct urb *urb)
++{
++ int i;
++ int j;
++ int rc = 0;
++
++ //printk(KERN_INFO"%s: %p\n", __FUNCTION__, urb->complete);
++
++ RETURN_ZERO_IF(isotest->closing);
++
++ urb->dev = isotest->udev;
++ urb->actual_length = 0;
++
++ for (j = urb->transfer_buffer_length, i = 0; i < urb->number_of_packets; i++) {
++
++ int send = MIN(isotest->iso_in_size, j);
++ j -= send;
++ urb->iso_frame_desc[i].offset = i * isotest->iso_in_size;
++ urb->iso_frame_desc[i].length = send;
++ }
++
++ RETURN_ZERO_IF(!(rc = usb_submit_urb(urb)));
++ printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
++
++ //isotest_iso_in_free_urb(urb);
++ return rc;
++}
++
++
++/**
++ * isotest_iso_in_complete
++ */
++void isotest_iso_in_complete (struct urb *urb)
++{
++ struct usb_isotest *isotest = (struct usb_isotest *)urb->context;
++ int i;
++ int rc;
++ int status;
++
++ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
++
++ RETURN_IF(!urb);
++
++ if (isotest->closing) {
++ //printk(KERN_INFO"%s: urb: %p pre urbs: %d\n", __FUNCTION__, urb, isotest->in_urbs);
++ if (urb->transfer_buffer) {
++ kfree(urb->transfer_buffer);
++ }
++ usb_free_urb(urb);
++ isotest->in_urbs--;
++ //printk(KERN_INFO"%s: urb: %p pre urbs: %d\n", __FUNCTION__, urb, isotest->in_urbs);
++ return;
++ }
++ status = urb->status;
++
++ if (status /* && (status != -ENOENT) && (status != -ECONNRESET)*/) {
++ //printk(KERN_INFO"%s: - urb: %p nonzero write iso status received: %x\n", __FUNCTION__, urb, status);
++ }
++
++ else if (urb->actual_length) {
++ //printk(KERN_INFO"%s: urb: %p lenght: %d\n", __FUNCTION__, urb, urb->actual_length);
++ in_completed++;
++ in_total_received += urb->actual_length;
++
++ //printk(KERN_INFO"%s: ", __FUNCTION__);
++ for (i = 0; i < urb->number_of_packets; i++) {
++
++ iso_trace_recv_data(&isotest->stats,
++ urb->transfer_buffer + urb->iso_frame_desc[i].offset,
++ urb->iso_frame_desc[i].actual_length, 0);
++
++ // printk("%d:%d:%x ", i,
++ // urb->iso_frame_desc[i].actual_length,
++ // urb->iso_frame_desc[i].status);
++
++
++ }
++ //printk("\n");
++ }
++
++ THROW_IF((rc = iso_in_submit(isotest, urb)), error);
++
++ in_resubmitted++;
++
++ CATCH(error) {
++ printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
++ }
++}
++
++
++struct urb *iso_in_start(struct usb_isotest *isotest)
++{
++ struct urb * urb = NULL;
++ int frames = (ISO_SEND_TOTAL + isotest->iso_in_size) / isotest->iso_in_size;
++ int iso_transfer_size;
++ int rc = 0;
++
++
++ //RETURN_NULL_IF(in_count-- <= 0);
++
++ //printk(KERN_INFO"%s: %d %02x\n", __FUNCTION__, in_count, isotest->iso_in_endpointAddr);
++
++ //iso_transfer_size = ((ISO_SEND_TOTAL % isotest->iso_in_size) > 20) ?
++ // ISO_SEND_TOTAL :
++ // ISO_SEND_TOTAL + (20 - (ISO_SEND_TOTAL % isotest->iso_in_size));
++
++ iso_transfer_size = frames * isotest->iso_in_size;
++
++ THROW_IF(!(urb = usb_alloc_urb(frames + 1)), error);
++ THROW_IF (!(urb->transfer_buffer = kmalloc(iso_transfer_size, GFP_ATOMIC)), error);
++ memset(urb->transfer_buffer, 0, isotest->iso_in_size);
++
++ urb->hcpriv = NULL;
++ urb->context = isotest;
++ urb->transfer_flags = USB_ISO_ASAP;
++ urb->complete = isotest_iso_in_complete;
++ urb->pipe = usb_rcvisocpipe(isotest->udev, isotest->iso_in_endpointAddr);
++
++ urb->transfer_buffer_length = iso_transfer_size;
++ urb->number_of_packets = frames;
++
++ THROW_IF((rc = iso_in_submit(isotest, urb)), error);
++ in_submitted++;
++ isotest->in_urbs++;
++ //printk(KERN_INFO"%s: new urbs: %d\n", __FUNCTION__, isotest->in_urbs);
++ return urb;
++
++ CATCH(error) {
++ printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
++ //isotest_iso_in_free_urb(urb);
++ return NULL;
++ }
++}
++
++
++
++
++/* ********************************************************************************************* */
++
++void isotest_schedule_bh(struct usb_isotest *isotest)
++{
++ unsigned long flags;
++
++ //RETURN_IF(!isotest->iso_bh.data);
++
++ // schedule more data
++ local_irq_save (flags);
++ if (isotest->iso_bh.data && !isotest->iso_bh.sync) {
++ MOD_INC_USE_COUNT;
++ queue_task(&isotest->iso_bh, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ local_irq_restore (flags);
++}
++
++
++static void bottomhalf(void *data)
++{
++ int i;
++ unsigned long flags;
++ struct usb_isotest *isotest = (struct usb_isotest *) data;
++
++ if (isotest->first) {
++ //sleep_on_timeout(&isotest->iso_wq, 200);
++ udelay(100);
++ isotest->first = 0;
++ }
++
++ THROW_IF(!isotest, error);
++
++ if (isotest->closing) {
++ struct urb *urb;
++ //printk(KERN_INFO"%s: closing\n", __FUNCTION__);
++
++ // unlink outstanding urbs, this has side-effect of calling completion routing
++ local_irq_save (flags);
++ for (i = 0; i < IN_URBS; i++) {
++ CONTINUE_IF(!(urb = isotest->iso_in_urbs[i]));
++ //printk(KERN_INFO"%s: unlinking: %d IN urb: %p\n", __FUNCTION__, i, urb);
++ isotest->iso_in_urbs[i] = NULL;
++ urb->transfer_flags |= USB_ASYNC_UNLINK;
++ usb_unlink_urb(urb);
++ }
++ local_irq_restore (flags);
++
++ local_irq_save (flags);
++ for (i = 0; i < OUT_URBS; i++) {
++ CONTINUE_IF(!(urb = isotest->iso_out_urbs[i]));
++ //printk(KERN_INFO"%s: unlinking: %d OUT urb: %p\n", __FUNCTION__, i, urb);
++ isotest->iso_out_urbs[i] = NULL;
++ urb->transfer_flags |= USB_ASYNC_UNLINK;
++ usb_unlink_urb(urb);
++ }
++ local_irq_restore (flags);
++
++ // tell disconnect that we are finished
++ isotest->iso_bh.data = NULL;
++
++ }
++ else {
++
++ //printk(KERN_INFO"%s: normal\n", __FUNCTION__);
++
++ if (send && out_count) {
++ local_irq_save (flags);
++ for (i = 0; i < OUT_URBS; i++) {
++ CONTINUE_IF(isotest->iso_out_urbs[i]);
++ isotest->iso_out_urbs[i] = iso_out_start(isotest);
++ //printk(KERN_INFO"%s: starting: %d OUT urb: %p\n", __FUNCTION__, i, isotest->iso_out_urbs[i]);
++ }
++ local_irq_restore (flags);
++ }
++
++ if (recv && in_count) {
++ local_irq_save (flags);
++ for (i = 0; i < IN_URBS; i++) {
++ CONTINUE_IF(isotest->iso_in_urbs[i]);
++ isotest->iso_in_urbs[i] = iso_in_start(isotest);
++ //printk(KERN_INFO"%s: starting: %d IN urb: %p\n", __FUNCTION__, i, isotest->iso_in_urbs[i]);
++ }
++ local_irq_restore (flags);
++ }
++ }
++
++ CATCH(error) {
++ printk(KERN_ERR"%s: isotest NULL\n", __FUNCTION__);
++ }
++ MOD_DEC_USE_COUNT;
++}
++
++/* ********************************************************************************************* */
++
++/* usb specific object needed to register this driver with the usb subsystem */
++static struct usb_driver isotest_driver = {
++ name: "isotest",
++ probe: isotest_probe,
++ disconnect: isotest_disconnect,
++ id_table: isotest_table,
++};
++
++/**
++ * isotest_probe
++ *
++ * Called by the usb core when a new device is connected that it thinks
++ * this driver might be interested in.
++ */
++static void * isotest_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++{
++ struct usb_isotest *isotest = NULL;
++ struct usb_interface *interface;
++ struct usb_device_descriptor *device = &udev->descriptor;
++ struct usb_interface_descriptor *interface_descriptor;
++ int i;
++
++ printk(KERN_INFO"%s: %04x %04x\n", __FUNCTION__, device->idVendor, device->idProduct);
++
++ // See if the device offered us matches what we can accept
++ //if ((device->idVendor != vendor_id) || (device->idProduct != product_id)) {
++ // printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
++ // return NULL;
++ //}
++
++ // allocate memory for our device state and intialize it
++ if (!(isotest = kmalloc (sizeof(struct usb_isotest), GFP_KERNEL))) {
++ printk(KERN_INFO"%s: Out of memory\n", __FUNCTION__);
++ return NULL;
++ }
++
++ memset (isotest, 0x00, sizeof (*isotest));
++ init_MUTEX (&isotest->sem);
++ init_waitqueue_head(&isotest->iso_wq);
++
++ isotest->udev = udev;
++ isotest->first = 1;
++ isotest->closing = 0;
++ isotest->in_urbs = 0;
++ isotest->interface = interface = &udev->actconfig->interface[ifnum];
++ isotest->iso_bh.routine = bottomhalf;
++ isotest->iso_bh.data = (void *)isotest;
++ interface_descriptor = &interface->altsetting[0];
++
++ // set up the endpoint information and check out the endpoints
++
++ for (i = 0; i < interface_descriptor->bNumEndpoints; ++i) {
++
++ struct usb_endpoint_descriptor *endpoint = &interface_descriptor->endpoint[i];
++
++ //printk(KERN_INFO"%s: looking at %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
++
++ if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x01)) {
++
++ //printk(KERN_INFO"%s: found ISO IN %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
++ isotest->iso_in_size = endpoint->wMaxPacketSize;
++ isotest->iso_in_endpointAddr = endpoint->bEndpointAddress;
++ }
++
++ if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x01)) {
++
++ //printk(KERN_INFO"%s: found ISO OUT %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
++
++ isotest->iso_out_size = endpoint->wMaxPacketSize;
++ isotest->iso_out_endpointAddr = endpoint->bEndpointAddress;
++ }
++ }
++
++ out_count = ISO_SEND_TRANSFERS;
++
++ // let the user know what node this device is now attached to
++ //printk(KERN_INFO"%s: USB TEST device now attached to ISOTEST\n", __FUNCTION__);
++
++ isotest_schedule_bh(isotest);
++
++ return isotest;
++}
++
++/**
++ * isotest_disconnect
++ *
++ * Called by the usb core when the device is removed from the system.
++ */
++static void isotest_disconnect(struct usb_device *udev, void *ptr)
++{
++ struct usb_isotest *isotest;
++
++ printk(KERN_INFO"%s: in_submitted: %d in_resubmitted: %d in_completed: %ld in_total: %ld\n",
++ __FUNCTION__, in_submitted, in_resubmitted, in_completed, in_total_received);
++
++ RETURN_IF(!(isotest = (struct usb_isotest *)ptr));
++
++ // set flag to say we are closing
++ isotest->closing = 1;
++ isotest_schedule_bh(isotest);
++
++ while (isotest->iso_bh.data) {
++ isotest_schedule_bh(isotest);
++ printk(KERN_INFO"%s: waiting for bh\n", __FUNCTION__);
++ sleep_on_timeout(&isotest->iso_wq, 20);
++ }
++
++ while (isotest->in_urbs) {
++ printk(KERN_INFO"%s: waiting for urbs\n", __FUNCTION__);
++ sleep_on_timeout(&isotest->iso_wq, 20);
++ }
++
++ kfree(isotest);
++
++ printk(KERN_INFO"%s: USB ISOTEST now disconnected\n", __FUNCTION__);
++}
++
++
++/* ********************************************************************************************* */
++
++void iso_start_in(int count)
++{
++
++}
++
++void iso_start_out(int count)
++{
++
++}
++
++
++/**
++ * isotest_init
++ */
++static int isotest_init(void)
++{
++ int result;
++
++ printk(KERN_INFO"%s:\n", __FUNCTION__);
++
++ if (vendor_id && product_id) {
++ int i;
++ for (i = 0; i < (sizeof(isotest_table) / sizeof(struct usb_device_id) - 1); i++) {
++
++ if ((isotest_table[i].idVendor == vendor_id) && isotest_table[i].idProduct == product_id ) {
++ printk(KERN_INFO"%s: vendor_id: %04x product_id: %04x already in table\n",
++ __FUNCTION__, vendor_id, product_id);
++ break;
++ }
++ printk(KERN_INFO"%s: vendor_id: %04x product_id: %04x\n",
++ __FUNCTION__, isotest_table[i].idVendor, isotest_table[i].idProduct);
++ }
++ if (!isotest_table[i].idVendor && !isotest_table[i].idProduct) {
++ printk(KERN_INFO"%s: inserting vendor_id: %04x product_id: %04x into table\n",
++ __FUNCTION__, vendor_id, product_id);
++
++ isotest_table[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
++ isotest_table[i].idVendor = vendor_id;
++ isotest_table[i].idProduct = product_id;
++ isotest_table[i].bDeviceClass = 0;
++ isotest_table[i].bDeviceSubClass = 0;
++ }
++ }
++
++ iso_trace_init("isotest_host");
++
++ /* register this driver with the USB subsystem */
++ result = usb_register(&isotest_driver);
++ if (result < 0) {
++ printk(KERN_INFO"%s: usb_register failed for the "__FILE__" driver. Error number %d\n", KERN_INFO, result);
++ return -1;
++ }
++
++ printk(KERN_INFO "%s: " DRIVER_DESC " " DRIVER_VERSION "\n", __FUNCTION__);
++ return 0;
++}
++
++
++/**
++ * isotest_exit
++ */
++static void isotest_exit(void)
++{
++ /* deregister this driver with the USB subsystem */
++ usb_deregister(&isotest_driver);
++
++ iso_trace_exit("isotest_host");
++}
++
++
++module_init (isotest_init);
++module_exit (isotest_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
++MODULE_LICENSE("PRIVATE");
++#endif
++
+diff -uNr linux/drivers/no-otg/functions/isotest/iso.c linux/drivers/otg/functions/isotest/iso.c
+--- linux/drivers/no-otg/functions/isotest/iso.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/iso.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,620 @@
++/*
++ * otg/isotest_fd/iso.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_DESCRIPTION ("USB Device Serial Function");
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
++MODULE_LICENSE("GPL");
++#endif
++
++#include <linux/init.h>
++#include <linux/list.h>
++#include <asm/uaccess.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++
++#include "usbp-chap9.h"
++#include <usbp-mem.h>
++#include <usbp-func.h>
++#include <usbp-admin.h>
++
++USBD_MODULE_INFO ("isotest_fd 2.0-beta");
++
++#include "test.h"
++#include "fermat.h"
++
++struct usb_isotest {
++ int interface;
++ struct usbd_function_instance *function;
++ rwlock_t rwlock;
++
++ int open;
++ int closing;
++ struct tq_struct iso_bh;
++ wait_queue_head_t iso_wq;
++};
++
++#define ISO_OUT 0x00
++#define ISO_IN 0x01
++
++#define ENDPOINTS 0x02
++
++
++u8 isotest_requested_endpoints[ENDPOINTS+1] = {
++ USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS,
++ USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS,
++ 0,
++};
++
++#define ISO_OUT_PKTSIZE 90
++#define ISO_IN_PKTSIZE 90
++#define isotest_requested_transferSizes xfer_sizes
++
++u16 xfer_sizes[ENDPOINTS+1] = {
++ ISO_OUT_PKTSIZE,
++ ISO_IN_PKTSIZE,
++ 0,
++};
++
++
++
++/* Module Parameters ************************************************************************* */
++// override vendor ID
++static u32 vendor_id;
++MODULE_PARM (vendor_id, "i");
++MODULE_PARM_DESC (vendor_id, "vendor id");
++
++// override product ID
++static u32 product_id;
++MODULE_PARM (product_id, "i");
++MODULE_PARM_DESC (product_id, "product id");
++
++MODULE_PARM (xfer_sizes, "3-3h");
++MODULE_PARM_DESC (xfer_sizes, "Requested transfer sizes for each endpoint; default 90 for iso in and out");
++
++// packet sizes
++static u32 in = ISO_IN_PKTSIZE;
++MODULE_PARM (in, "i");
++MODULE_PARM_DESC (in, "in size");
++
++static u32 out = ISO_OUT_PKTSIZE;
++MODULE_PARM (out, "i");
++MODULE_PARM_DESC (out, "out size");
++
++static int fermat=0;
++MODULE_PARM (fermat, "i");
++MODULE_PARM_DESC (fermat, "Apply randomization to buffer");
++
++static int custom=0;
++MODULE_PARM (custom, "i");
++MODULE_PARM_DESC (custom, "Supply custom pattern via xmit_pattern parameter");
++
++static int print_all=0;
++MODULE_PARM (print_all, "i");
++MODULE_PARM_DESC (print_all, "Print all buffers, not just the first");
++
++#define ZERO4 0,0,0,0
++#define ZERO16 ZERO4,ZERO4,ZERO4,ZERO4
++#define ZERO64 ZERO16,ZERO16,ZERO16,ZERO16
++static u8 xmit_pattern[256]={1,0xE,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe, ZERO16,ZERO16,ZERO16,ZERO64,ZERO64,ZERO64};
++MODULE_PARM(xmit_pattern,"1-256b");
++MODULE_PARM_DESC(xmit_pattern, "pattern to be transmitted, count, size, payload; size is "
++ "the size of the payload following. count is the number of times to repeat the pattern (0=infinite)");
++static struct {
++ int count;
++ int size;
++ u8 *payload_start, *payload_end;
++ u8 *current;
++ int total_size;
++ int sent;
++} xps; // Transmit pattern state
++
++static void xmit_pattern_state_init(void);
++static u8 xmit_pattern_next(void);
++static void fill_xmit_buffer(u32 size, u8*buffer);
++
++static void xmit_pattern_state_init(){
++ xps.count = xmit_pattern[0];
++ xps.size = xmit_pattern[1];
++ xps.payload_start = xmit_pattern+2;
++ xps.payload_end = xps.payload_start + xps.size;
++ xps.current = xps.payload_start;
++ xps.sent = 0;
++ xps.total_size = xps.count * xps.size;
++}
++
++static u8 xmit_pattern_next(){
++
++ // current always points at the next character to send
++ u8 next_value = *xps.current++;
++
++ xps.sent += 1;
++
++ if (xps.current >= xps.payload_end)
++ xps.current = xps.payload_start; //Rewind buffer
++
++ // if Total pattern has been sent; rewind
++ if (xps.sent >= xps.total_size){
++ xmit_pattern_state_init();
++ }
++
++ return next_value;
++}
++
++static void fill_xmit_buffer(u32 size, u8 *buffer)
++{
++ u8 * limit = buffer + size;
++ xmit_pattern_state_init();
++ while(buffer < limit){
++ *buffer++ = xmit_pattern_next();
++ }
++}
++
++static void fill_xmit_buffer_default(u32 size, u8 * buffer){
++ int j;
++ for(j = 0; j < size; j++){
++ buffer[j] = j & 0xff;
++ }
++}
++
++static void print_buffer(u32 size, u8 * buffer){
++ // Print up to 16 bytes of the buffer, first time called only
++ static int first = 1;
++ int n = ( size >=16 ? 16 : size);
++ int j;
++ if((first) || (print_all)){
++ char *prefix = first? "\n" : "";
++ printk(KERN_INFO "%sxmit buffer:", prefix);
++ for( j=0 ; j < n; j++){
++ printk("%02x",buffer[j]);
++ }
++ printk("\n");
++ first = 0;
++ }
++}
++
++
++
++/* ************************************************************************** */
++
++static struct isotest_stats isotest_stats;
++static struct usb_isotest isotest;
++
++
++/* Classes descriptors
++ */
++
++static u8 isotest_ep_1[7] = { 0x07, USB_DT_ENDPOINT, 0, ISOCHRONOUS, ISO_OUT_PKTSIZE&0xff, (ISO_OUT_PKTSIZE>>8)&0xff, 0x00};
++static u8 isotest_ep_2[7] = { 0x07, USB_DT_ENDPOINT, 0, ISOCHRONOUS, ISO_IN_PKTSIZE&0xff, (ISO_IN_PKTSIZE>>8)&0xff, 0x00};
++
++static struct usbd_endpoint_descriptor *isotest_data_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) &isotest_ep_1,
++ (struct usbd_endpoint_descriptor *) &isotest_ep_2 };
++
++u8 isotest_data_indexes [] = { ISO_OUT, ISO_IN, };
++
++
++/* Alternate descriptors
++ */
++static u8 isotest_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE, 0x00, 0x00, 0x01, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
++ 0x00, 0x00, 0x00, 0x00,
++};
++
++
++/* Alternate descriptions
++ */
++static struct usbd_alternate_description isotest_data_alternate_descriptions[] = {
++ { iInterface:CONFIG_OTG_ISOTEST_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&isotest_data_alternate_descriptor,
++ endpoints:sizeof (isotest_data_endpoints) / sizeof(u8 *),
++ endpoint_list: isotest_data_endpoints,
++ endpoint_indexes: isotest_data_indexes,
++ },
++};
++
++
++/* Interface descriptions
++ */
++static struct usbd_interface_description isotest_interfaces[] = {
++ { alternates:sizeof (isotest_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++alternate_list:isotest_data_alternate_descriptions,
++ },
++};
++
++
++/* Configuration descriptions
++ */
++static u8 isotest_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (isotest_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++
++struct usbd_configuration_description isotest_description[] = {
++ { iConfiguration:CONFIG_OTG_ISOTEST_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)isotest_configuration_descriptor,
++ },
++};
++
++/* Device Description
++ */
++static struct usbd_device_descriptor isotest_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x00,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++static struct usbd_device_qualifier_descriptor isotest_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x00,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++static struct usbd_endpoint_request iso_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS, ISO_OUT_PKTSIZE, ISO_OUT_PKTSIZE * 4, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS, ISO_IN_PKTSIZE, ISO_OUT_PKTSIZE * 4, },
++ { 1, },
++};
++
++static struct usbd_otg_descriptor iso_otg_descriptor = {
++bLength : sizeof(struct usbd_otg_descriptor),
++bDescriptorType: USB_DT_OTG,
++bmAttributes: 0,
++};
++
++struct usbd_device_description isotest_device_description = {
++ device_descriptor: &isotest_device_descriptor,
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &isotest_device_qualifier_descriptor,
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &iso_otg_descriptor,
++ iManufacturer: CONFIG_OTG_ISOTEST_MANUFACTURER,
++ iProduct: CONFIG_OTG_ISOTEST_PRODUCT_NAME,
++ #if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++ #endif
++};
++
++void iso_start_in(int count);
++void iso_start_out(int count);
++
++void schedule_bh(void)
++{
++ unsigned long flags;
++
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++
++ local_irq_save (flags);
++ if (!isotest.iso_bh.sync) {
++ MOD_INC_USE_COUNT;
++ queue_task(&isotest.iso_bh, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ local_irq_restore (flags);
++
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++}
++
++
++int isotest_urb_sent (struct usbd_urb *urb, int rc);
++int isotest_recv_urb (struct usbd_urb *urb, int rc);
++
++/* Transmit Function *************************************************************************** */
++
++static int out_count;
++static int in_count;
++static int send_size = 1000;
++static int iso_transfer_in_count;
++
++static int isotest_xmit_data (void)
++{
++ int i;
++ int j;
++ int frames;
++ int size = ((send_size % in) < 20) ? send_size + 20 : send_size;
++ struct usbd_urb *urb;
++ struct usbd_function_instance *function = isotest.function;
++
++ //printk(KERN_INFO"%s: open: %d in_count: %d\n", __FUNCTION__, isotest.open, in_count);
++
++ RETURN_ZERO_IF(!isotest.open);
++
++ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb (isotest.function, ISO_IN, size, isotest_urb_sent)));
++
++ frames = (size / in) + 1;
++
++ iso_transfer_in_count++;
++
++ for (i = 0; i < frames; i++) {
++
++ u8 *cp = urb->buffer + (i * in);
++ if(custom){
++ (void) fill_xmit_buffer(in, cp);
++ } else {
++ (void) fill_xmit_buffer_default(in,cp);
++ }
++ if(fermat){
++ fermat_encode(cp, in);
++ }
++ print_buffer(in, cp);
++
++ // iso_transfer_count
++ *cp++ = cpu_to_le16(iso_transfer_in_count) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 8) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 16) & 0xff;
++ *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 24) & 0xff;
++
++ // iso transfer length
++ *cp++ = cpu_to_le16(size) & 0xff;
++ *cp++ = (cpu_to_le16(size) >> 8) & 0xff;
++
++ // iso frame size
++ *cp++ = cpu_to_le16(in) & 0xff;
++ *cp++ = (cpu_to_le16(in) >> 8) & 0xff;
++
++ // total frames
++ *cp++ = cpu_to_le16(frames) & 0xff;
++ *cp++ = (cpu_to_le16(frames) >> 8) & 0xff;
++
++ // this packet number
++ *cp++ = cpu_to_le16(i+1) & 0xff;
++ *cp++ = (cpu_to_le16(i+1) >> 8) & 0xff;
++
++ }
++ urb->actual_length = size;
++
++ // push it down into the usb-device layer
++ //printk(KERN_INFO"%s: sending: %p length: %d\n", __FUNCTION__, urb, urb->actual_length);
++ return usbd_start_in_urb (urb);
++}
++
++
++/* isotest_urb_sent - called to indicate URB transmit finished
++ * @urb: pointer to struct usbd_urb
++ * @rc: result
++ */
++int isotest_urb_sent (struct usbd_urb *urb, int rc)
++{
++ //printk(KERN_INFO"%s: sent: %p status: %d\n", __FUNCTION__, urb, urb->status);
++
++ usbd_free_urb (urb);
++
++ //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
++ schedule_bh();
++ return 0;
++}
++
++
++/* USB Device Functions ************************************************************************ */
++
++/* isotest_event_handler - process a device event
++ *
++ */
++void isotest_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ int i;
++ switch (event) {
++
++ case DEVICE_RESET:
++ case DEVICE_DESTROY:
++ if (isotest.open)
++ usbd_disable_irq(NULL);
++
++ isotest.open = 0;
++ break;
++
++ case DEVICE_CONFIGURED:
++ isotest.open = 1;
++ for (i = 0; i < 2; i++) {
++ struct usbd_urb *urb;
++ BREAK_IF(!(urb = usbd_alloc_urb (function, ISO_OUT,
++ usbd_endpoint_transferSize(
++ function, ISO_OUT,usbd_high_speed(function)),
++ isotest_recv_urb
++ )));
++ if (usbd_start_out_urb(urb))
++ usbd_free_urb(urb);
++ }
++ iso_start_in(100);
++ break;
++
++ case DEVICE_BUS_INACTIVE:
++ break;
++
++ case DEVICE_BUS_ACTIVITY:
++ break;
++
++ default:
++ break;
++ }
++}
++
++
++/* isotest_recv_urb - called to indicate URB has been received
++ * @urb - pointer to struct usbd_urb
++ *
++ * Return non-zero if we failed and urb is still valid (not disposed)
++ */
++int isotest_recv_urb (struct usbd_urb *urb, int rc)
++{
++ //struct usbd_device_instance *device = urb->device;
++#if 0
++ printk(KERN_INFO"%s: urb: %p length: %d framenum: %04x %d\n", __FUNCTION__,
++ urb, urb->actual_length, urb->framenum, urb->framenum);
++#endif
++ iso_trace_recv_data(&isotest_stats, urb->buffer, urb->actual_length, 0);
++
++ // start_recv urb
++ return (usbd_start_out_urb (urb));
++}
++
++
++/* ********************************************************************************************* */
++
++void iso_start_in(int count)
++{
++ in_count = count;
++ //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
++ schedule_bh();
++}
++
++void iso_start_out(int count)
++{
++ out_count = count;
++ //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
++ schedule_bh();
++}
++
++static void
++bottomhalf(void *data)
++{
++ //printk(KERN_INFO"%s: closing: %d\n", __FUNCTION__, isotest.closing);
++ if (isotest.closing)
++ isotest.iso_bh.data = NULL;
++
++ else if (isotest.open)
++ isotest_xmit_data ();
++
++ MOD_DEC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++}
++
++
++/* ********************************************************************************************* */
++
++static int isotest_function_enable (struct usbd_function_instance *function)
++{
++ //printk(KERN_INFO"%s:\n", __FUNCTION__);
++ MOD_INC_USE_COUNT;
++
++ //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
++ isotest.closing = 0;
++ schedule_bh();
++ return 0;
++}
++
++static void isotest_function_disable (struct usbd_function_instance *function)
++{
++ isotest.closing = 1;
++ while (isotest.iso_bh.data) {
++ //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
++ schedule_bh();
++ //printk(KERN_INFO"%s: waiting\n", __FUNCTION__);
++ sleep_on_timeout(&isotest.iso_wq, 20);
++ }
++ MOD_DEC_USE_COUNT;
++}
++
++
++struct usbd_function_operations function_ops = {
++ event_handler:isotest_event_handler,
++ function_enable: isotest_function_enable,
++ function_disable: isotest_function_disable,
++};
++
++struct usbd_function_driver function_driver = {
++ name:"ISO Test Function",
++ fops:&function_ops,
++ device_description:&isotest_device_description,
++ bNumConfigurations:sizeof (isotest_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:isotest_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_BCDDEVICE),
++ bNumInterfaces:sizeof (isotest_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:isotest_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: iso_endpoint_requests,
++};
++
++
++/*
++ * isotest_modinit - module init
++ *
++ */
++static int isotest_modinit (void)
++{
++ printk (KERN_INFO "vendor_id: %04x product_id: %04x in: %02x out: %02x\n",
++ vendor_id, product_id, in, out);
++
++ if (vendor_id)
++ function_driver.idVendor = cpu_to_le16(vendor_id);
++
++ if (product_id)
++ function_driver.idProduct = cpu_to_le16(product_id);
++
++
++ isotest_ep_1[4] = out&0xff;
++ isotest_ep_1[5] = (out>>8)&0xff;
++ isotest_ep_2[4] = in&0xff;
++ isotest_ep_2[5] = (in>>8)&0xff;
++
++ // XXX should this be the endpoint request structure?
++ iso_endpoint_requests[0].fs_requestedTransferSize = out;
++ iso_endpoint_requests[1].fs_requestedTransferSize = in;
++
++ iso_trace_init("isotest_fd");
++ if(fermat){
++ fermat_init();
++ }
++
++ isotest.iso_bh.routine = bottomhalf;
++ isotest.iso_bh.data = (void *)&isotest;
++ init_waitqueue_head(&isotest.iso_wq);
++
++ // register us with the usb device support layer
++ RETURN_EINVAL_IF (usbd_register_function (&function_driver, "isotest", NULL));
++
++ // return
++ return 0;
++}
++
++
++/* isotest_modexit - module cleanup
++ */
++static void isotest_modexit (void)
++{
++ usbd_deregister_function (&function_driver);
++ iso_trace_exit("isotest_fd");
++}
++
++module_init (isotest_modinit);
++module_exit (isotest_modexit);
++
+diff -uNr linux/drivers/no-otg/functions/isotest/iso_fermat linux/drivers/otg/functions/isotest/iso_fermat
+--- linux/drivers/no-otg/functions/isotest/iso_fermat 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/iso_fermat 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,34 @@
++#!/bin/sh
++XFER=$1
++PATTERN=$2
++if [ -z "$PATTERN" ]
++then
++ PATTERN="0x1,0x8,1,2,3,4,5,6,7,8"
++fi
++echo "Using PATTERN='$PATTERN'"
++set -x
++
++insmod /tmp/usbdcore.o
++insmod /tmp/usbdprocfs.o
++
++insmod /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=0 fermat=1 custom=0
++
++insmod /tmp/au1x00_bi.o
++echo "enable" > /proc/usbd-switch
++
++
++set +x
++echo -n "INSERT CABLE"
++sleep 15
++echo -n "; REMOVE CABLE AND PRESS RETURN"
++read junk
++set -x
++cp /proc/isotest_fd client
++cp /proc/isotest_host host
++echo "disable" > /proc/usbd-switch
++
++rmmod au1x00_bi
++rmmod isotest_fd
++rmmod usbdprocfs
++rmmod usbdcore
++
+diff -uNr linux/drivers/no-otg/functions/isotest/iso_one linux/drivers/otg/functions/isotest/iso_one
+--- linux/drivers/no-otg/functions/isotest/iso_one 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/iso_one 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,34 @@
++#!/bin/sh
++XFER=$1
++PATTERN=$2
++if [ -z "$PATTERN" ]
++then
++ PATTERN="0x1,0x1,0xFF"
++fi
++echo "Using PATTERN='$PATTERN'"
++set -x
++
++insmod /tmp/usbdcore.o
++insmod /tmp/usbdprocfs.o
++
++insmod /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=1 fermat=0 custom=1
++
++insmod /tmp/au1x00_bi.o
++echo "enable" > /proc/usbd-switch
++
++
++set +x
++echo -n "INSERT CABLE"
++sleep 15
++echo -n "; REMOVE CABLE AND PRESS RETURN"
++read junk
++set -x
++cp /proc/isotest_fd client
++cp /proc/isotest_host host
++echo "disable" > /proc/usbd-switch
++
++rmmod au1x00_bi
++rmmod isotest_fd
++rmmod usbdprocfs
++rmmod usbdcore
++
+diff -uNr linux/drivers/no-otg/functions/isotest/iso_zero linux/drivers/otg/functions/isotest/iso_zero
+--- linux/drivers/no-otg/functions/isotest/iso_zero 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/iso_zero 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,34 @@
++#!/bin/sh
++XFER=$1
++PATTERN=$2
++if [ -z "$PATTERN" ]
++then
++ PATTERN="0x1,0x1,0x00"
++fi
++echo "Using PATTERN='$PATTERN'"
++set -x
++
++insmod /tmp/usbdcore.o
++insmod /tmp/usbdprocfs.o
++
++insmod /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=1 fermat=0 custom=1
++
++insmod /tmp/au1x00_bi.o
++echo "enable" > /proc/usbd-switch
++
++
++set +x
++echo -n "INSERT CABLE"
++sleep 15
++echo -n "; REMOVE CABLE AND PRESS RETURN"
++read junk
++set -x
++cp /proc/isotest_fd client
++cp /proc/isotest_host host
++echo "disable" > /proc/usbd-switch
++
++rmmod au1x00_bi
++rmmod isotest_fd
++rmmod usbdprocfs
++rmmod usbdcore
++
+diff -uNr linux/drivers/no-otg/functions/isotest/iso_zero_silent linux/drivers/otg/functions/isotest/iso_zero_silent
+--- linux/drivers/no-otg/functions/isotest/iso_zero_silent 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/iso_zero_silent 2006-09-01 21:41:26.000000000 +0200
+@@ -0,0 +1,34 @@
++#!/bin/sh
++XFER=$1
++PATTERN=$2
++if [ -z "$PATTERN" ]
++then
++ PATTERN="0x1,0x1,0x00"
++fi
++echo "Using PATTERN='$PATTERN'"
++set -x
++
++insmod /tmp/usbdcore.o
++insmod /tmp/usbdprocfs.o
++
++insmod /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=0 fermat=0 custom=1
++
++insmod /tmp/au1x00_bi.o
++echo "enable" > /proc/usbd-switch
++
++
++set +x
++echo -n "INSERT CABLE"
++sleep 15
++echo -n "; REMOVE CABLE AND PRESS RETURN"
++read junk
++set -x
++cp /proc/isotest_fd client
++cp /proc/isotest_host host
++echo "disable" > /proc/usbd-switch
++
++rmmod au1x00_bi
++rmmod isotest_fd
++rmmod usbdprocfs
++rmmod usbdcore
++
+diff -uNr linux/drivers/no-otg/functions/isotest/test.c linux/drivers/otg/functions/isotest/test.c
+--- linux/drivers/no-otg/functions/isotest/test.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/test.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,456 @@
++/*
++ * otg/isotest_fd/test.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h>
++//#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++//#include <linux/poll.h>
++#include <linux/init.h>
++
++#include <asm/system.h>
++#include <asm/atomic.h>
++//#include <linux/interrupt.h>
++//#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <linux/proc_fs.h>
++#include <linux/vmalloc.h>
++
++#include <asm/io.h>
++#include <asm/string.h>
++
++#include <linux/proc_fs.h>
++
++#include <linux/netdevice.h>
++#include <linux/cache.h>
++
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
++#include <asm/dma.h>
++#include <asm/mach/dma.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/types.h>
++#endif
++
++#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++#include <asm/au1000.h>
++#include <asm/au1000_dma.h>
++#include <asm/mipsregs.h>
++#endif
++
++#if defined(CONFIG_ARCH_SAMSUNG)
++#include <asm/arch/timers.h>
++#include <asm/arch/hardware.h>
++#endif
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include "test.h"
++
++
++int iso_trace_first;
++int iso_trace_next;
++iso_trace_t *iso_traces;
++
++
++/* ******************************************************************************************* */
++
++void dump_stats(struct isotest_stats *stats)
++{
++ if (stats->errors || ((stats->ok % 100) == 99)) {
++ TRACE_ISO(stats->iso_transfer_number, stats->total_frames,
++ stats->received, stats->errors, stats->missed, stats->skipped, stats->ok);
++ }
++ if (stats->errors) {
++ memset(stats, 0, sizeof(struct isotest_stats));
++ }
++ else {
++ stats->ok++;
++ stats->iso_transfer_number++;
++ stats->last_packet = 0;
++ }
++}
++
++u16 getu16(u8 **cp)
++{
++ u16 val = 0;
++
++ val = *(*cp)++;
++ val |= *(*cp)++ << 8;
++
++ return val;
++}
++
++u16 getu32(u8 **cp)
++{
++ u32 val = 0;
++
++ val = *(*cp)++;
++ val |= *(*cp)++ << 8;
++ val |= *(*cp)++ << 16;
++ val |= *(*cp)++ << 24;
++
++ return val;
++}
++
++static int iso_in_received;
++
++void iso_trace_recv_data (struct isotest_stats *stats, u8 *cp, int length, int framenum)
++{
++ //struct usb_device_instance *device = urb->device;
++
++ u16 iso_transfer_number;
++ u16 total_size;
++ u16 packet_size;
++ u16 total_frames;
++ u16 this_packet;
++ u8 frames;
++
++
++ iso_transfer_number = getu32(&cp);
++ total_size = getu16(&cp);
++ packet_size = getu16(&cp);
++ total_frames = getu16(&cp);
++ this_packet = getu16(&cp);
++
++
++ // did we miss the end of the last ISO transfer?
++ if (stats->iso_transfer_number && (stats->iso_transfer_number != iso_transfer_number)) {
++ stats->errors++;
++ stats->missed++;
++ //printk(KERN_INFO"%s: ERROR bad iso number: %x %x %x %x %x expecting: %x\n", __FUNCTION__, iso_transfer_number,
++ // total_size, packet_size, total_frames, this_packet, stats->iso_transfer_number);
++ dump_stats(stats);
++ return;
++ }
++
++ if (!stats->iso_transfer_number) {
++ stats->framenum = framenum;
++ stats->iso_transfer_number = iso_transfer_number;
++ stats->total_frames = total_frames;
++ }
++
++ // is this the packet we are expecting?
++ if (stats->last_packet && ((stats->last_packet + 1) != this_packet)) {
++ stats->errors++;
++ stats->missed++;
++ //printk(KERN_INFO"%s: ERROR bad packet: %x %x %x %x %x expecting: %x\n", __FUNCTION__, iso_transfer_number,
++ // total_size, packet_size, total_frames, this_packet, stats->last_packet + 1);
++ }
++
++ // did we miss a frame?
++ frames = (stats->framenum < framenum) ? (framenum - stats->framenum) : (stats->framenum - framenum);
++
++ if (frames > 1) {
++ stats->errors++;
++ stats->skipped++;
++ //printk(KERN_INFO"%s: SKIPPED %x %x %x %x %x\n", __FUNCTION__, iso_transfer_number,
++ // total_size, packet_size, total_frames, this_packet);
++ }
++
++ // update stats
++ stats->received++;
++ stats->last_packet = this_packet;
++
++ // last packet?
++ if (stats->total_frames == this_packet)
++ dump_stats(stats);
++}
++
++
++
++/* Proc Filesystem *************************************************************************** */
++
++/* *
++ * iso_trace_proc_read - implement proc file system read.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Standard proc file system read function.
++ */
++static ssize_t iso_trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int oindex;
++ int previous;
++
++ MOD_INC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++ // get a page, max 4095 bytes of data...
++ if (!(page = get_free_page (GFP_KERNEL))) {
++ MOD_DEC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++ return -ENOMEM;
++ }
++
++ len = 0;
++ oindex = index = (*pos)++;
++
++ if (index == 0) {
++ //len += sprintf ((char *) page + len, " uS Exp Rcv Err Miss Skip OK\n");
++ //len += sprintf ((char *) page + len, " uS Exp Rcv Err Miss Skip Xfers\n");
++ len += sprintf ((char *) page + len, " uS Tr Exp Rcv Err Miss Skip Xfers\n");
++
++// uS Exp Rcv Err Miss Skip Xfers
++// uS Tr Exp Rcv Err Miss Skip Xfers
++// 0 | 100 9 900 0 0 0 99
++
++ }
++
++ index += iso_trace_first;
++ if (index >= TRACE_MAX) {
++ index -= TRACE_MAX;
++ }
++ previous = (index) ? (index - 1) : (TRACE_MAX - 1);
++
++ //printk(KERN_INFO"first: %d next: %d index: %d %d prev: %d\n", iso_trace_first, iso_trace_next, oindex, index, previous);
++
++ if (
++ ((iso_trace_first < iso_trace_next) && (index >= iso_trace_first) && (index < iso_trace_next)) ||
++ ((iso_trace_first > iso_trace_next) && ((index < iso_trace_next) || (index >= iso_trace_first)))
++ )
++ {
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++ u32 ticks = 0;
++#elif defined(CONFIG_ARCH_SAMSUNG)
++ u32 ticks = 0;
++#else
++ u64 jifs = 0;
++#endif
++ iso_trace_t *p = iso_traces + index;
++ //unsigned char *cp;
++ //int skip = 0;
++
++ if (oindex > 0) {
++ iso_trace_t *o = iso_traces + previous;
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
++ /*
++ * oscr is 3.6864 Mhz free running counter,
++ *
++ * 1/3.6864 = .2712
++ * 60/221 = .2714
++ *
++ */
++ if (o->ocsr) {
++ ticks = (p->ocsr > o->ocsr) ? (p->ocsr - o->ocsr) : (o->ocsr - p->ocsr) ;
++ ticks = (ticks * 60) / 221;
++ }
++
++#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++ /*
++ * cp0_count is incrementing timer at system clock
++ */
++ if (o->cp0_count) {
++ //ticks = (p->cp0_count > o->cp0_count) ?
++ // (p->cp0_count - o->cp0_count) : (o->cp0_count - p->cp0_count) ;
++ ticks = (p->cp0_count - o->cp0_count) ;
++ ticks = ticks / CONFIG_OTG_AU1X00_SCLOCK;
++ }
++
++#elif defined(CONFIG_ARCH_SAMSUNG)
++ /*
++ * tcnt1 is a count-down timer running at the system bus clock
++ * The divisor must be set as a configuration value, typically 66 or 133.
++ */
++ if (o->tcnt1) {
++ ticks = (p->tcnt1 < o->tcnt1) ? (o->tcnt1 - p->tcnt1) : (p->tcnt1 - o->tcnt1) ;
++ ticks /= CONFIG_OTG_SMDK2500_BCLOCK;
++ }
++#else
++ if (o->jiffies) {
++ jifs = p->jiffies - iso_traces[previous].jiffies;
++ }
++#endif
++
++ //if (o->interrupts != p->interrupts) {
++ // skip++;
++ //}
++ }
++
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++ len += sprintf ((char *) page + len, "%9d ", ticks);
++#elif defined(CONFIG_ARCH_SAMSUNG)
++ //len += sprintf ((char *) page + len, "%8u ", p->jiffies);
++ //len += sprintf ((char *) page + len, "%8u ", p->tcnt0);
++ len += sprintf ((char *) page + len, "%8u ", p->tcnt1);
++ if (ticks > 1024*1024) {
++ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
++ }
++ else {
++ len += sprintf ((char *) page + len, "%8d ", ticks);
++ }
++#else
++ if (jifs > 1024) {
++ len += sprintf ((char *) page + len, "%4dK", (int)jifs>>20);
++ }
++ else {
++ len += sprintf ((char *) page + len, "%4d ", (int)jifs);
++ }
++#endif
++
++ len += sprintf ((char *) page + len, "| %8d", p->iso_transfer_number);
++ len += sprintf ((char *) page + len, "%6d", p->expected);
++ len += sprintf ((char *) page + len, "%6d", p->received);
++ len += sprintf ((char *) page + len, "%6d", p->errors);
++ len += sprintf ((char *) page + len, "%6d", p->missed);
++ len += sprintf ((char *) page + len, "%6d", p->skipped);
++ len += sprintf ((char *) page + len, "%6d", p->ok);
++ len += sprintf ((char *) page + len, "\n");
++ }
++
++#if 1
++ if ((len > count) ) {
++ printk(KERN_INFO"%s: ((len > count) count=%d len=%d\n", __FUNCTION__, count, len);
++ len = -EINVAL;
++ }
++
++#else
++ if ((len > count) || (len == 0)) {
++ printk(KERN_INFO"%s: ((len > count) || (len == 0)) count=%d len=%d\n", __FUNCTION__, count, len);
++ len = -EINVAL;
++ }
++#endif
++ else if (len > 0 && copy_to_user (buf, (char *) page, len)) {
++ printk(KERN_INFO"%s: (len > 0 && copy_to_user (buf, (char *) page, len) \n", __FUNCTION__);
++ len = -EFAULT;
++ }
++ free_page (page);
++ MOD_DEC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++ return len;
++}
++
++void iso_start_in(int count);
++void iso_start_out(int count);
++
++/* *
++ * iso_trace_proc_write - implement proc file system write.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Proc file system write function, used to signal monitor actions complete.
++ * (Hotplug script (or whatever) writes to the file to signal the completion
++ * of the script.) An ugly hack.
++ */
++static ssize_t iso_trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
++{
++ //struct usb_device_instance *device;
++ size_t n = count;
++ char command[64];
++ char *cp = command;
++ int i = 0;
++
++ MOD_INC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++ //printk(KERN_DEBUG "%s: count=%u\n",__FUNCTION__,count);
++ while ((n > 0) && (i < 64)) {
++ // Not too efficient, but it shouldn't matter
++ if (copy_from_user (cp++, buf + (count - n), 1)) {
++ count = -EFAULT;
++ break;
++ }
++ *cp = '\0';
++ i++;
++ n -= 1;
++ //printk(KERN_DEBUG "%s: %u/%u %02x\n",__FUNCTION__,count-n,count,c);
++ }
++ if (!strncmp (command, "in", 2)) {
++ iso_start_in (10);
++ }
++ else if (!strncmp (command, "out", 3)) {
++ iso_start_out (10);
++ }
++ // XXX need to be able to set serial number here
++ MOD_DEC_USE_COUNT;
++ //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
++ return (count);
++}
++
++static struct file_operations iso_trace_proc_operations_functions = {
++read:iso_trace_proc_read,
++write:iso_trace_proc_write,
++};
++
++#if defined(CONFIG_ARCH_SAMSUNG)
++#endif
++
++/**
++ * iso_trace_init
++ *
++ * Return non-zero if not successful.
++ */
++int iso_trace_init (char *name)
++{
++ printk(KERN_INFO"%s:\n", __FUNCTION__);
++ if (!(iso_traces = vmalloc(sizeof(iso_trace_t) * TRACE_MAX))) {
++ printk(KERN_ERR"%s: malloc failed %p %d\n", __FUNCTION__, iso_traces, sizeof(iso_trace_t) * TRACE_MAX);
++ return -EINVAL;
++ }
++ memset(iso_traces, 0, sizeof(iso_trace_t) * TRACE_MAX);
++
++ {
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry (name, 0, 0)) == NULL) {
++ printk(KERN_INFO"BITRACE PROC FS failed\n");
++ }
++ else {
++ p->proc_fops = &iso_trace_proc_operations_functions;
++ }
++ }
++#if defined(CONFIG_ARCH_SAMSUNG)
++ *(volatile u32 *)TMOD |= 0x3 << 3;
++#endif
++ printk(KERN_INFO"%s: OK\n", __FUNCTION__);
++ return 0;
++}
++
++/**
++ * udc_release_io - release UDC io region
++ */
++void iso_trace_exit (char *name)
++{
++ {
++ unsigned long flags;
++ local_irq_save (flags);
++ remove_proc_entry (name, NULL);
++ if (iso_traces) {
++ iso_trace_t *p = iso_traces;
++ iso_traces = 0;
++ vfree(p);
++ }
++ local_irq_restore (flags);
++ }
++}
++
++
++/* End of FILE */
++
+diff -uNr linux/drivers/no-otg/functions/isotest/test.h linux/drivers/otg/functions/isotest/test.h
+--- linux/drivers/no-otg/functions/isotest/test.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/isotest/test.h 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,129 @@
++/*
++ * otg/isotest_fd/test.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++
++#if defined(CONFIG_ARCH_SAMSUNG)
++#ifndef CONFIG_OTG_SMDK2500_BCLOCK
++#define CONFIG_OTG_SMDK2500_BCLOCK 66
++#endif
++#endif
++
++#define NUSBD_FRAMENUM 0xB0200038
++
++
++struct isotest_stats {
++
++ u16 count;
++
++ u16 iso_transfer_number;
++ u16 total_size;
++ u16 packet_size;
++ u16 total_frames;
++ u16 last_packet;
++
++
++ u16 framenum;
++ u16 received;
++ u16 missed;
++ u16 skipped;
++ u16 errors;
++
++ u32 ok;
++
++};
++
++
++
++
++
++typedef struct iso_trace_types {
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
++ u32 ocsr;
++#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++ u32 cp0_count;
++#elif defined(CONFIG_ARCH_SAMSUNG)
++ u32 tcnt1;
++#else
++ u64 jiffies;
++#endif
++ u16 iso_transfer_number;
++
++ u16 expected;
++ u16 received;
++ u16 errors;
++ u16 missed;
++ u16 skipped;
++
++ u32 ok;
++
++} iso_trace_t;
++
++
++#define TRACE_MAX 3000
++
++extern int iso_trace_first;
++extern int iso_trace_next;
++
++extern iso_trace_t *iso_traces;
++
++static __inline__ iso_trace_t *ISO_TRACE_NEXT(void)
++{
++ iso_trace_t *p;
++
++ p = iso_traces + iso_trace_next;
++
++#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
++ p->ocsr = OSCR;
++#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++ p->cp0_count = read_c0_count();
++#elif defined(CONFIG_ARCH_SAMSUNG)
++ p->tcnt1 = *(volatile u32 *)TCNT1;
++#else
++ p->jiffies = jiffies;
++#endif
++//#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
++// p->iso_transfer_number = au_readl(NUSBD_FRAMENUM);
++//#endif
++
++ iso_trace_next++;
++ iso_trace_next = (iso_trace_next == TRACE_MAX) ? 0 : iso_trace_next;
++
++ if (iso_trace_next == iso_trace_first) {
++ iso_trace_first++;
++ iso_trace_first = (iso_trace_first == TRACE_MAX) ? 0 : iso_trace_first;
++ }
++
++ return p;
++}
++
++static __inline__ void TRACE_ISO(u16 iso_transfer_number, u16 expected, u16 received, u16 errors, u16 missed, u16 skipped, u32 ok)
++{
++ iso_trace_t *p = NULL;
++
++ //printk(KERN_INFO"%s: %d %d %d %d %d first: %d next: %d traces: %p\n", __FUNCTION__,
++ // expected, received, errors, missed, skipped, iso_trace_first, iso_trace_next, traces);
++
++ if (!iso_traces) return;
++
++ p = ISO_TRACE_NEXT();
++ p->iso_transfer_number = iso_transfer_number;
++ p->expected = expected;
++ p->received = received;
++ p->errors = errors;
++ p->missed = missed;
++ p->skipped = skipped;
++ p->ok = ok;
++}
++
++void iso_trace_recv_data (struct isotest_stats *stats, u8 *cp, int length, int framenum);
++int iso_trace_init (char *str);
++void iso_trace_exit (char *str);
++
+diff -uNr linux/drivers/no-otg/functions/mouse/Config.in linux/drivers/otg/functions/mouse/Config.in
+--- linux/drivers/no-otg/functions/mouse/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/Config.in 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# Mouse Function Driver
++#
++# Copyright (C) 2003 Belcarra
++#
++
++
++mainmenu_option next_comment
++
++comment "USB Peripheral Function Driver - Random Mouse"
++dep_tristate ' Mouse Function' CONFIG_OTG_MOUSE $CONFIG_OTG
++
++if [ "$CONFIG_OTG_MOUSE" != "n" ]; then
++ hex 'VendorID (hex value)' CONFIG_OTG_MOUSE_VENDORID "15ec"
++ hex 'ProductID (hex value)' CONFIG_OTG_MOUSE_PRODUCTID "f003"
++ hex 'bcdDevice (binary-coded decimal)' CONFIG_OTG_MOUSE_BCDDEVICE "0100"
++
++ string 'iManufacturer (string)' CONFIG_OTG_MOUSE_MANUFACTURER "Belcarra"
++ #string 'iProduct (string)' CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra Mouse"
++
++ string 'iConfiguration (string)' CONFIG_OTG_MOUSE_DESC "Mouse Cfg"
++ string 'Comm Interface iInterface (string)' CONFIG_OTG_MOUSE_COMM_INTF "Comm Intf"
++ bool 'Mouse BH Test' CONFIG_OTG_MOUSE_BH
++ int 'Number of packets (zero is continous ' CONFIG_OTG_MOUSE_PACKETS "10"
++ int 'Polling Interval ' CONFIG_OTG_MOUSE_INTERVAL "1"
++
++fi
++endmenu
+diff -uNr linux/drivers/no-otg/functions/mouse/Kconfig linux/drivers/otg/functions/mouse/Kconfig
+--- linux/drivers/no-otg/functions/mouse/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/Kconfig 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,74 @@
++menu "OTG Random Mouse function"
++ depends on OTG
++
++config OTG_MOUSE
++ tristate " Random Mouse Function"
++ depends on OTG
++ ---help---
++ This implements a simple Mouse driver that sends HID packets with
++ small random movements. This is a good function for initial testing
++ of Peripheral Controller Drivers as it provides for a complicated
++ enumeration but a simple uni-directional (send Interrupt only) data
++ transport.
++
++menu "OTG Random Mouse function options"
++ depends on OTG && OTG_MOUSE
++
++config OTG_MOUSE_VENDORID
++ hex "VendorID (hex value)"
++ depends on OTG && OTG_MOUSE
++ default "0x15ec"
++
++config OTG_MOUSE_PRODUCTID
++ hex "ProductID (hex value)"
++ depends on OTG && OTG_MOUSE
++ default "0xf003"
++
++config OTG_MOUSE_BCDDEVICE
++ hex "bcdDevice (binary-coded decimal)"
++ depends on OTG && OTG_MOUSE
++ default "0x0100"
++
++config OTG_MOUSE_MANUFACTURER
++ string "iManufacturer (string)"
++ depends on OTG && OTG_MOUSE
++ default "Belcarra"
++
++config OTG_MOUSE_PRODUCT_NAME
++ string "iProduct (string)"
++ depends on OTG && OTG_MOUSE
++ default "Random Mouse Class - Interrupt"
++
++config OTG_MOUSE_COMM_INTF
++ string "MOUSE Bulk Only iInterface (string)"
++ depends on OTG && OTG_MOUSE
++ default "MOUSE Data Intf"
++
++config OTG_MOUSE_DESC
++ string "Data Interface iConfiguration (string)"
++ depends on OTG && OTG_MOUSE
++ default "MOUSE Configuration"
++
++config OTG_MOUSE_BH
++ bool " MOUSE BH Test"
++ depends on OTG && OTG_MOUSE
++ default n
++ ---help---
++ Implement the Mouse send packet in a bottom half handler,
++ this will delay responses to test the PCD works correctly
++ when the host polls before a send data urb is queued.
++
++
++config OTG_MOUSE_PACKETS
++ int "Number of packets (zero is continous)"
++ depends on OTG && OTG_MOUSE
++ default 10
++ ---help---
++ Number of Mouse packets to send, will run
++ forever if set to zero.
++
++
++endmenu
++
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/mouse/Makefile linux/drivers/otg/functions/mouse/Makefile
+--- linux/drivers/no-otg/functions/mouse/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/Makefile 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,81 @@
++#
++# Function driver for a Mouse USB Device
++#
++# Copyright (c) 2003 Belcarra
++
++# Multipart objects.
++
++O_TARGET := mouse_target.o
++#list-multi := mouse_fd.o cmouse_fd.o
++list-multi := mouse_fd.o
++
++mouse_fd-objs := mouse-fd.o mouse-l24.o
++#cmouse_fd-objs := mouse-cf.o mouse-if.o cmouse-l24.o
++#cmouse_fd-objs := mouse-if.o cmouse-l24.o
++
++# Objects that export symbols.
++#export-objs := mouse.o
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_MOUSE) += mouse_fd.o
++#obj-$(CONFIG_OTG_MOUSE) += cmouse_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++#MOUSED=$(OTG)/functions/mouse
++
++OTG_WARNINGS=-Wno-unused -Wno-format
++OTG=$(TOPDIR)/drivers/otg
++OTG_INCLUDES=-I$(OTG)
++OTG_EXTRA=$(OTG_INCLUDES) $(OTG_WARNINGS)
++OTGCORE_DIR=$(OTG)/otgcore
++##USBDCORE_DIR=$(OTG)/usbdcore
++include $(TOPDIR)/Rules.make
++#EXTRA_CFLAGS += -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
++#EXTRA_CFLAGS_nostdinc += -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
++EXTRA_CFLAGS += $(OTG_EXTRA)
++EXTRA_CFLAGS_nostdinc += $(OTG_EXTRA)
++
++# Link rules for multi-part drivers.
++
++mouse_fd.o: $(mouse_fd-objs)
++ $(LD) -r -o $@ $(mouse_fd-objs)
++
++#cmouse_fd.o: $(cmouse_fd-objs)
++# $(LD) -r -o $@ $(cmouse_fd-objs)
++
++# dependencies:
++
++#mouse.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
++
++
+diff -uNr linux/drivers/no-otg/functions/mouse/Makefile-l26 linux/drivers/otg/functions/mouse/Makefile-l26
+--- linux/drivers/no-otg/functions/mouse/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/Makefile-l26 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,14 @@
++# Function driver for a Random Mouse
++#
++# Copyright (c) 2004 Belcarra
++
++mouse_fd-objs := mouse-fd.o mouse-l24.o
++
++obj-$(CONFIG_OTG_MOUSE) += mouse_fd.o
++
++OTG=$(TOPDIR)/drivers/otg
++ACMD=$(OTG)/functions/mouse
++OTGCORE_DIR=$(OTG)/otgcore
++USBDCORE_DIR=$(OTG)/usbdcore
++EXTRA_CFLAGS += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
++EXTRA_CFLAGS_nostdinc += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+diff -uNr linux/drivers/no-otg/functions/mouse/cmouse-l24.c linux/drivers/otg/functions/mouse/cmouse-l24.c
+--- linux/drivers/no-otg/functions/mouse/cmouse-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/cmouse-l24.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,199 @@
++/*
++ * otg/functions/mouse/cmouse-l24.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/mouse/cmouse-l24.c
++ * @brief Mouse Function Driver Linux 2.4 initialization
++ *
++ *
++ * This file contains the Linux 2.4 module init and exit functions
++ * to load and unload the Random Mouse Function.
++ *
++ * Notes
++ *
++ * This driver does not export any upper edge functionality to
++ * for the user or applications to use. It simply sends a configurable
++ * number of data packets to the USB Host when configured. Each data
++ * packet contains the equivalent of a small mouse report which will
++ * cause the mouse cursor to move on the host.
++ *
++ * To use simply load with something like:
++ *
++ * insmod cmouse_fd.o vendor_id=0xffff product_id=0xffff
++ *
++ * And attach to a Windows box. Windows should recognize as a mouse and
++ * immediately start receiving a stream of data.
++ *
++ * To terminate simply unplug.
++ *
++ *
++ * 1. The mouse driver is product name is hard coded to a string that will
++ * generate a string descriptor that is 32 bytes long. This will test
++ * most UDC's ep0 ZLP handling as it is a multiple of the most common
++ * UDC endpoint zero size. (An option can be added later to allow for
++ * 64 byte ep0 packetsize.)
++ *
++ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report
++ * to being generated by a bottom half handler. This will verify that
++ * the bus interface driver properly handles the case of a delayed
++ * CONTROL READ. I.e. when the usbd_device_request() function returns
++ * zero for successful completion but there is no tx_urb containing the
++ * requested data. The bus interface driver must setup the conditions for
++ * ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
++ * until the tx_urb is started later.
++ *
++ * 3. The CONFIG_OTG_MOUSE_PACKETS option is used to set the number of
++ * mouse data reports to send. Set to zero for a continous stream
++ * of data.
++ *
++ * @ingroup MouseFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++
++#include "cmouse.h"
++
++
++/* Module Parameters ******************************************************** */
++/* !
++ * @name XXXXX MODULE Parameters
++ */
++/* ! @{ */
++
++MOD_AUTHOR ("sl@belcarra.com");
++EMBED_LICENSE();
++MOD_DESCRIPTION ("Belcarra Random Walk MOUSE Function");
++
++static u32 vendor_id; /*!< override built-in vendor ID */
++static u32 product_id; /*!< override built-in product ID */
++
++MOD_PARM (vendor_id, "i");
++MOD_PARM (product_id, "i");
++
++MOD_PARM_DESC (vendor_id, "Device Vendor ID");
++MOD_PARM_DESC (product_id, "Device Product ID");
++
++otg_tag_t MOUSE;
++/* ! *} */
++
++/* USB Module init/exit ***************************************************** */
++
++struct mouse_private mouse_private;
++
++char *mouse_interface_list[2] = {
++ "mouse-random-interface",
++ NULL,
++};
++
++/*!
++ * mouse_modinit() - module init
++ *
++ * This is called by the Linux kernel; either when the module is loaded
++ * if compiled as a module, or during the system intialization if the
++ * driver is linked into the kernel.
++ *
++ * This function will parse module parameters if required and then register
++ * the mouse driver with the USB Device software.
++ *
++ * If the CONFIG_OTG_MOUSE_BH option is enabled it will also setup the mouse
++ * bottom half handler.
++ *
++ */
++static int mouse_modinit (void)
++{
++ struct usbd_function_instance *mfi;
++ printk (KERN_INFO "%s: vendor_id: %04x product_id: %04x\n", __FUNCTION__, vendor_id, product_id);
++
++ #if !defined(OTG_C99)
++ mouse_global_init();
++ mouse_ops_init();
++ #endif /* defined(OTG_C99) */
++
++ MOUSE = otg_trace_obtain_tag();
++ TRACE_MSG2(MOUSE, "vendor_id: %04x product_id: %04x",vendor_id, product_id);
++
++ if (vendor_id)
++ mouse_composite_driver.idVendor = cpu_to_le16(vendor_id);
++ if (product_id)
++ mouse_composite_driver.idProduct = cpu_to_le16(product_id);
++
++ mouse_hid.wItemLength = cpu_to_le16(0x34); // XXX mips compiler bug.....
++
++ // register as usb function driver
++ TRACE_MSG2(MOUSE, "%s %d", mouse_interface_driver.name, mouse_interface_driver.endpointsRequested);
++ THROW_UNLESS ((mouse_private.interface =
++ usbd_register_interface (&mouse_interface_driver, "mouse-random-interface", NULL)), error);
++
++ TRACE_MSG2(MOUSE, "%s %d", mouse_interface_driver.name, mouse_interface_driver.endpointsRequested);
++
++ THROW_UNLESS ((mouse_private.composite =
++ usbd_register_composite (&mouse_composite_driver, "mouse-random-cf",
++ mouse_interface_list, NULL)), error);
++
++ #ifdef CONFIG_OTG_MOUSE_BH
++ mouse_private.notification_bh.routine = mouse_hid_bh;
++ mouse_private.notification_bh.data = NULL;
++ #endif
++ CATCH(error) {
++ if (mouse_private.interface) {
++ usbd_deregister_function (mouse_private.interface);
++ mouse_private.interface = NULL;
++ }
++ if (mouse_private.composite) {
++ usbd_deregister_function (mouse_private.composite);
++ mouse_private.composite = NULL;
++ }
++ otg_trace_invalidate_tag(MOUSE);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++module_init (mouse_modinit);
++
++#if OTG_EPILOGUE
++/*!
++ * mouse_modexit() - module init
++ *
++ * This is called by the Linux kernel; when the module is being unloaded
++ * if compiled as a module. This function is never called if the
++ * driver is linked into the kernel.
++ *
++ * @param void
++ * @return void
++ */
++static void mouse_modexit (void)
++{
++ #ifdef CONFIG_OTG_MOUSE_BH
++ while (PENDING_WORK_ITEM(mouse_private.notification_bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++ #endif
++ if (mouse_private.interface) {
++ usbd_deregister_function (mouse_private.interface);
++ mouse_private.interface = NULL;
++ }
++ if (mouse_private.composite) {
++ usbd_deregister_function (mouse_private.composite);
++ mouse_private.composite = NULL;
++ }
++
++ otg_trace_invalidate_tag(MOUSE);
++}
++
++module_exit (mouse_modexit);
++#endif
++
+diff -uNr linux/drivers/no-otg/functions/mouse/cmouse.h linux/drivers/otg/functions/mouse/cmouse.h
+--- linux/drivers/no-otg/functions/mouse/cmouse.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/cmouse.h 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * otg/functions/mouse/mouse.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup MouseFunction Random Mouse
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/mouse/mouse.h
++ * @brief Mouse Function Driver private defines
++ *
++ *
++ * This is a test USB HID Function Driver designed to test and
++ * verify that INTERRUPT IN endpoints work properly.
++ *
++ *
++ * @ingroup MouseFunction
++ */
++
++
++/*!
++ * The mouse_private structure is used to collect all of the mouse driver
++ * global variables into one place.
++ */
++struct mouse_private {
++ struct usbd_function_instance *interface; /*!< function instance for this module */
++ struct usbd_function_instance *composite; /*!< function instance for this module */
++
++#ifdef CONFIG_OTG_MOUSE_BH
++ struct WORK_STRUCT notification_bh;
++#endif /* CONFIG_OTG_MOUSE_BH */
++ int usb_driver_registered; /*!< non-zero if usb function registered */
++ unsigned char connected; /*!< non-zero if connected to host (configured) */
++ unsigned int writesize; /*!< packetsize * 4 */
++ struct usbd_urb *tx_urb; /*!< saved copy of current tx urb */
++ int wLength;
++ int x;
++ int y;
++ int last_x;
++ int last_y;
++ int n;
++};
++
++extern struct mouse_private mouse_private;
++extern struct usbd_function_driver mouse_interface_driver;
++extern struct usbd_function_driver mouse_composite_driver;
++extern struct hid_descriptor mouse_hid;
++
++#ifndef OTG_C99
++extern void mouse_global_init(void);
++#endif /* OTG_C99 */
++
++#define MOUSE mouse_trace_tag
++extern otg_tag_t MOUSE;
++
+diff -uNr linux/drivers/no-otg/functions/mouse/getmouse.c linux/drivers/otg/functions/mouse/getmouse.c
+--- linux/drivers/no-otg/functions/mouse/getmouse.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/getmouse.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,107 @@
++/*
++ *
++ *
++ * 3.2. Non-Canonical Input Processing
++ *
++ * In non-canonical input processing mode, input is not assembled into lines and
++ * input processing (erase, kill, delete, etc.) does not occur. Two parameters
++ * control the behavior of this mode: c_cc[VTIME] sets the character timer, and
++ * c_cc[VMIN] sets the minimum number of characters to receive before satisfying
++ * the read.
++ *
++ * If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before
++ * the read is satisfied. As TIME is zero, the timer is not used.
++ *
++ * If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be
++ * satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1
++ * s). If TIME is exceeded, no character will be returned.
++ *
++ * If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read
++ * will be satisfied if MIN characters are received, or the time between two
++ * characters exceeds TIME. The timer is restarted every time a character is
++ * received and only becomes active after the first character has been received.
++ *
++ * If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of
++ * characters currently available, or the number of characters requested will be
++ * returned. According to Antonino (see contributions), you could issue a fcntl
++ * (fd, F_SETFL, FNDELAY); before reading to get the same result.
++ *
++ * By modifying newtio.c_cc[VTIME] and newtio.c_cc[VMIN] all modes described
++ * above can be tested.
++ *
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <termios.h>
++#include <stdio.h>
++
++#define BAUDRATE B1200
++#define MODEMDEVICE "/dev/ttyS0"
++#define _POSIX_SOURCE 1 /* POSIX compliant source */
++#define FALSE 0
++#define TRUE 1
++
++volatile int STOP=FALSE;
++
++main()
++{
++ int fd,c, res;
++ struct termios oldtio,newtio;
++ unsigned char buf[255];
++
++ int bytes;
++ unsigned char mouse[3];
++
++ fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
++ if (fd <0) {perror(MODEMDEVICE); exit(-1); }
++
++ tcgetattr(fd,&oldtio); /* save current port settings */
++
++ bzero(&newtio, sizeof(newtio));
++ newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
++ newtio.c_iflag = IGNPAR;
++ newtio.c_oflag = 0;
++
++ /* set input mode (non-canonical, no echo,...) */
++ newtio.c_lflag = 0;
++
++ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
++ newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
++
++ tcflush(fd, TCIFLUSH);
++ tcsetattr(fd,TCSANOW,&newtio);
++
++
++ bytes = 0;
++ while (STOP==FALSE) { /* loop for input */
++ unsigned char c;
++
++ res = read(fd,buf,1); /* returns after 5 chars have been input */
++ buf[res]=0; /* so we can printf... */
++ //fprintf(stderr, ":%02x:%d\n", buf[0], res);
++ //if (buf[0]=='z') STOP=TRUE;
++
++ c = buf[0];
++
++ if ( c & 0x40 ) {
++ bytes = 1;
++ mouse[0] = c;
++ }
++ else if (bytes == 1) {
++ bytes = 2;
++ mouse[1] = c;
++ }
++ else if (bytes == 2) {
++ bytes = 0;
++ mouse[2] = c;
++ fprintf(stderr, "%02x %02x %02x\n", mouse[0], mouse[1], mouse[2]);
++ //printf("%c%c%c", mouse[0], mouse[1], mouse[2]);
++ }
++ }
++ tcsetattr(fd,TCSANOW,&oldtio);
++}
++
++
++/* End of FILE */
+diff -uNr linux/drivers/no-otg/functions/mouse/mouse-ce42.c linux/drivers/otg/functions/mouse/mouse-ce42.c
+--- linux/drivers/no-otg/functions/mouse/mouse-ce42.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/mouse-ce42.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ * otg/functions/mouse/mouse-ce42.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <sl@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ *
++ * This is a test USB HID Function Driver designed to test and
++ * verify that INTERRUPT IN endpoints work properly.
++ *
++ * This emulates a simple USB mouse and generates a constant stream
++ * of small random mouse movements.
++ *
++ * To use simply load with something like:
++ *
++ * insmod mouse_fd.o vendor_id=0xffff product_id=0xffff
++ *
++ * And attach to a Windows box. Windows should recognize as a mouse and
++ * immediately start receiving a stream of data.
++ *
++ * To terminate simply unplug.
++ *
++ * The mouse driver has several other characteristics to allow testing of
++ * other features of the bus interface driver:
++ *
++ * - ep0 ZLP handling
++ *
++ * - ep0 delayed CONTROL READ
++ *
++ *
++ * Notes
++ *
++ * 1. The mouse driver is product name is hard coded to a string that will
++ * generate a string descriptor that is 32 bytes long. This will test
++ * most UDC's ep0 ZLP handling as it is a multiple of the most common
++ * UDC endpoint zero size. (An option can be added later to allow for
++ * 64 byte ep0 packetsize.)
++ *
++ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report
++ * to being generated by a bottom half handler. This will verify that
++ * the bus interface driver properly handles the case of a delayed
++ * CONTROL READ. I.e. when the usbd_device_requesdevice_requesdevice_request
++ * zero for successful completion but there is no tx_urb containing the
++ * requested data. The bus interface driver must setup the conditions for
++ * ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
++ * until the tx_urb is started later.
++ */
++
++
++
++#include "otg/usbp-chap9.h"
++#include <otg/usbp-mem.h>
++#include <otg/usbp-func.h>
++
++/*
++ * mouse_modinit - module init
++ *
++ */
++static int mouse_modinit (void)
++{
++
++ // register as usb function driver
++ THROW_IF (NULL == (mouse_private.function = usbd_register_function (&mouse_function_driver, "mouse", NULL)), error);
++#ifdef CONFIG_OTG_MOUSE_BH
++ mouse_private.notification_bh.routine = mouse_hid_bh;
++ mouse_private.notification_bh.data = NULL;
++#endif
++ CATCH(error) {
++ if (mouse_private.function) {
++ usbd_deregister_function (mouse_private.function);
++ mouse_private.function = NULL;
++ }
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/* mouse_modexit - module cleanup
++ */
++static void mouse_modexit (void)
++{
++ if (mouse_private.function) {
++ usbd_deregister_function (mouse_private.function);
++ mouse_private.function = NULL;
++ }
++}
++
+diff -uNr linux/drivers/no-otg/functions/mouse/mouse-fd.c linux/drivers/otg/functions/mouse/mouse-fd.c
+--- linux/drivers/no-otg/functions/mouse/mouse-fd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/mouse-fd.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,826 @@
++/*
++ * otg/functions/mouse/mouse-fd.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/mouse/mouse-fd.c
++ * @brief Mouse Function Driver protocol implementation.
++ *
++ * This file implements the Mouse HID protocols and will generate
++ * random mouse data on the INTERRUPT endpoint.
++ *
++ * The primary purpose of this driver is to demonstrate how to
++ * implement a simple function driver and to provide a simple
++ * uni-directional driver for testing USB Device peripheral drivers.
++ *
++ * The mouse driver has several other characteristics to allow testing of
++ * other features of USB Device peripheral drivers:
++ *
++ * - ep0 ZLP handling
++ *
++ * - ep0 delayed CONTROL READ
++ *
++ * To verify that ep0 ZLP processing is being handling correctly this
++ * driver has a hard coded Product name that is returned as a 32 byte
++ * string. This forces most any implementations that have an endpoint
++ * zero packetsize of 8, 16 or 32 to send a Zero Length Packet to
++ * terminate the string transfer when the Product name is requested
++ * by the host.
++ *
++ * The delayed CONTROL READ test verifies that that USB Device peripheral
++ * drivers will correctly NAK until data is provide for device requests.
++ * This is done by (optionally) delaying the HID report via a bottom half
++ * handler. The device request returns normally and the peripheral driver
++ * must properly recognize that while the device request had a non-zero
++ * wLength field, there is currently no queued urb.
++ *
++ * When the bottom half handler is scheduled the HID report urb will be
++ * queued on endpoint zero and then returned to the host.
++ *
++ *
++ * @ingroup MouseFunction
++ */
++
++#include <linux/config.h>
++#include <otg/otg-compat.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#include "mouse.h"
++
++struct mouse_private mouse_private;
++
++/*
++ * ep0 testing.... ensure that this is exactly 16 bytes
++ */
++#undef CONFIG_OTG_MOUSE_PRODUCT_NAME
++#define CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra Mouse"
++
++/*!
++ * @name Mouse Descriptors
++ *
++ * MouseHIDReport
++ * MOUSE Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*!
++ * Mouse Descriptors
++ * @{
++ */
++
++#define BULK_INT 0x00 /*!< Interrupt endpoint number */
++#define ENDPOINTS 0x01 /*!< Number of endpoints required */
++
++/*! List of required endpoint numbers
++ */
++static u8 mouse_indexes[] = { BULK_INT, };
++
++/*! List of requested endpoints
++ */
++static struct usbd_endpoint_request mouse_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++/*! This is the HID report returned for the HID Device Request.
++ * There is no pre-defined descriptor type for this.
++ */
++static char MouseHIDReport[52] = {
++ 0x05, 0x01, /*!< USAGE_PAGE (Generic Desktop) */
++ 0x09, 0x02, /*!< USAGE (Mouse) */
++ 0xa1, 0x01, /*!< COLLECTION (Application) */
++ 0x09, 0x01, /*!< USAGE (Pointer) */
++ 0xa1, 0x00, /*!< COLLECTION (Physical) */
++ 0x05, 0x09, /*!< USAGE_PAGE (Button) */
++ 0x19, 0x01, /*!< USAGE_MINIMUM (Button 1) */
++ 0x29, 0x03, /*!< USAGE_MAXIMUM (Button 3) */
++ 0x15, 0x00, /*!< LOGICAL_MINIMUM (0) */
++ 0x25, 0x01, /*!< LOGICAL_MAXIMUM (1) */
++ 0x95, 0x03, /*!< REPORT_COUNT (3) */
++ 0x75, 0x01, /*!< REPORT_SIZE (1) */
++ 0x81, 0x02, /*!< INPUT (Data,Var,Abs) */
++ 0x95, 0x01, /*!< REPORT_COUNT (1) */
++ 0x75, 0x05, /*!< REPORT_SIZE (5) */
++ 0x81, 0x03, /*!< INPUT (Cnst,Var,Abs) */
++ 0x05, 0x01, /*!< USAGE_PAGE (Generic Desktop) */
++ 0x09, 0x30, /*!< USAGE (X) */
++ 0x09, 0x31, /*!< USAGE (Y) */
++ 0x09, 0x38, /*!< USAGE (WHEEL) */
++ 0x15, 0x81, /*!< LOGICAL_MINIMUM (-127) */
++ 0x25, 0x7f, /*!< LOGICAL_MAXIMUM (127) */
++ 0x75, 0x08, /*!< REPORT_SIZE (8) */
++ 0x95, 0x03, /*!< REPORT_COUNT (3) */
++ 0x81, 0x06, /*!< INPUT (Data,Var,Rel) */
++ 0xc0, /*!< END_COLLECTION */
++ 0xc0 /*!< END_COLLECTION */
++};
++
++#if !defined(OTG_C99)
++/*! This is the interrupt endpoint descriptor.
++ */
++static struct usbd_endpoint_descriptor mouse_data;
++
++/*! The list of endpoint descriptors
++ */
++static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
++
++
++/*! This is the HID desccriptor.
++ */
++struct hid_descriptor mouse_hid;
++
++/*! List of class descriptors
++ */
++static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = {
++ (struct usbd_generic_class_descriptor *)&mouse_hid, };
++
++
++/*! Data Interface Alternate description
++ */
++static struct usbd_interface_descriptor mouse_data_alternate_descriptor;
++
++/*! Interface Descriptions
++ */
++static struct usbd_alternate_description mouse_data_alternate_descriptions[1];
++
++/*! List of Interface description(s)
++ */
++static struct usbd_interface_description mouse_interfaces[1];
++
++/*! Configuration description(s)
++ */
++static struct usbd_configuration_descriptor mouse_configuration_descriptor;
++
++/*! Mouse Configuration Description
++ */
++struct usbd_configuration_description mouse_configuration_description[1];
++
++/*! Device Description
++ */
++static struct usbd_device_descriptor mouse_device_descriptor;
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Description
++ */
++static struct usbd_device_qualifier_descriptor mouse_device_qualifier_descriptor;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor mouse_otg_descriptor;
++
++/*! Device Description
++ */
++struct usbd_device_description mouse_device_description;
++
++void mouse_global_init(void)
++{
++
++ /*! This is the interrupt endpoint descriptor.
++ */
++ ZERO(mouse_data);
++ mouse_data.bLength = 0x07;
++ mouse_data.bDescriptorType = USB_DT_ENDPOINT;
++ mouse_data.bEndpointAddress = USB_DIR_IN;
++ mouse_data.bmAttributes = INTERRUPT;
++ mouse_data.wMaxPacketSize = __constant_cpu_to_le16(0x10);
++#if defined (CONFIG_OTG_MOUSE_INTERVAL)
++ mouse_data.bInterval = CONFIG_OTG_MOUSE_INTERVAL;
++#else
++ mouse_data.bInterval = 0x01;
++#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
++
++
++ /*! This is the HID desccriptor.
++ */
++ ZERO(mouse_hid);
++ mouse_hid.bLength = 0x09;
++ mouse_hid.bDescriptorType = 0x21;
++ mouse_hid.bcdHID = __constant_cpu_to_le16(0x110);
++ mouse_hid.bCountryCode = 0x00;
++ mouse_hid.bNumDescriptors = 0x01;
++ mouse_hid.bReportType = 0x22;
++ mouse_hid.wItemLength = __constant_cpu_to_le16(0x34);
++
++
++ /*! Data Interface Alternate description
++ */
++ ZERO(mouse_data_alternate_descriptor);
++ mouse_data_alternate_descriptor.bLength = 0x09;
++ mouse_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
++ mouse_data_alternate_descriptor.bInterfaceNumber = 0x00;
++ mouse_data_alternate_descriptor.bAlternateSetting = 0x00;
++ mouse_data_alternate_descriptor.bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor);
++ mouse_data_alternate_descriptor.bInterfaceClass = 0x03;
++ mouse_data_alternate_descriptor.bInterfaceSubClass = 0x01;
++ mouse_data_alternate_descriptor.bInterfaceProtocol = 0x02;
++ mouse_data_alternate_descriptor.iInterface = 0x00;
++
++ /*! Interface Descriptions
++ */
++ ZERO(mouse_data_alternate_descriptions);
++ mouse_data_alternate_descriptions[0].iInterface = "Random Mouse Interface - Interrupt";
++ mouse_data_alternate_descriptions[0].interface_descriptor = &mouse_data_alternate_descriptor;
++ mouse_data_alternate_descriptions[0].classes =
++ sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *);
++ mouse_data_alternate_descriptions[0].class_list = mouse_hid_descriptors;
++ mouse_data_alternate_descriptions[0].endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *);
++ mouse_data_alternate_descriptions[0].endpoint_list = mouse_default;
++ mouse_data_alternate_descriptions[0].endpoint_indexes = mouse_indexes;
++
++ /*! List of Interface description(s)
++ */
++ ZERO(mouse_interfaces);
++ mouse_interfaces[0].alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
++ mouse_interfaces[0].alternate_list = mouse_data_alternate_descriptions;
++
++
++ /*! Configuration description(s)
++ */
++ ZERO(mouse_configuration_descriptor);
++ mouse_configuration_descriptor.bLength = 0x09;
++ mouse_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
++ mouse_configuration_descriptor.wTotalLength = 0x00;
++ mouse_configuration_descriptor.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
++ mouse_configuration_descriptor.bConfigurationValue = 0x01;
++ mouse_configuration_descriptor.iConfiguration = 0x00;
++ mouse_configuration_descriptor.bmAttributes = 0;
++ mouse_configuration_descriptor.bMaxPower = 0;
++
++ /*! Mouse Configuration Description
++ */
++ ZERO(mouse_configuration_description);
++ mouse_configuration_description[0].configuration_descriptor = &mouse_configuration_descriptor;
++ mouse_configuration_description[0].iConfiguration = "USB Random Mouse Configuration";
++ mouse_configuration_description[0].bNumInterfaces =
++ sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
++ mouse_configuration_description[0].interface_list = mouse_interfaces;
++
++ /*! Device Description
++ */
++ ZERO(mouse_device_descriptor);
++ mouse_device_descriptor.bLength = sizeof(struct usbd_device_descriptor);
++ mouse_device_descriptor.bDescriptorType = USB_DT_DEVICE;
++ mouse_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
++ mouse_device_descriptor.bDeviceClass = 0x00;
++ mouse_device_descriptor.bDeviceSubClass = 0x00;
++ mouse_device_descriptor.bDeviceProtocol = 0x00;
++ mouse_device_descriptor.bMaxPacketSize0 = 0x00;
++ mouse_device_descriptor.idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID);
++ mouse_device_descriptor.idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID);
++ mouse_device_descriptor.bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE);
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++ /*! High Speed Device Description
++ */
++ ZERO(mouse_device_qualifier_descriptor);
++ mouse_device_qualifier_descriptor.bLength = sizeof(struct usbd_device_qualifier_descriptor);
++ mouse_device_qualifier_descriptor.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
++ mouse_device_qualifier_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
++ mouse_device_qualifier_descriptor.bDeviceClass = 0x00;
++ mouse_device_qualifier_descriptor.bDeviceSubClass = 0x00;
++ mouse_device_qualifier_descriptor.bDeviceProtocol = 0x00;
++ mouse_device_qualifier_descriptor.bMaxPacketSize0 = 0x00;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++ /*! OTG Descriptor
++ */
++ ZERO(mouse_otg_descriptor);
++ mouse_otg_descriptor.bLength = sizeof(struct usbd_otg_descriptor);
++ mouse_otg_descriptor.bDescriptorType = USB_DT_OTG;
++ mouse_otg_descriptor.bmAttributes = 0;
++
++ /*! Device Description
++ */
++ ZERO(mouse_device_description);
++ mouse_device_description.device_descriptor = &mouse_device_descriptor;
++#ifdef CONFIG_OTG_HIGH_SPEED
++ mouse_device_description.device_qualifier_descriptor = &mouse_device_qualifier_descriptor;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ mouse_device_description.otg_descriptor = &mouse_otg_descriptor;
++ mouse_device_description.iManufacturer = CONFIG_OTG_MOUSE_MANUFACTURER;
++ mouse_device_description.iProduct = CONFIG_OTG_MOUSE_PRODUCT_NAME;
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ mouse_device_description.iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR;
++#endif
++}
++
++#else /* defined(OTG_C99) */
++
++/*! This is the interrupt endpoint descriptor.
++ */
++static struct usbd_endpoint_descriptor mouse_data = {
++ .bLength = 0x07,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = INTERRUPT,
++ .wMaxPacketSize = __constant_cpu_to_le16(0x10),
++#if defined (CONFIG_OTG_MOUSE_INTERVAL)
++ .bInterval = CONFIG_OTG_MOUSE_INTERVAL,
++#else
++ .bInterval = 0x01,
++#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
++};
++
++/*! The list of endpoint descriptors
++ */
++static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
++
++/*! This is the HID desccriptor.
++ */
++struct hid_descriptor mouse_hid = {
++ .bLength = 0x09,
++ .bDescriptorType = 0x21,
++ .bcdHID = __constant_cpu_to_le16(0x110),
++ .bCountryCode = 0x00,
++ .bNumDescriptors = 0x01,
++ .bReportType = 0x22,
++ .wItemLength = __constant_cpu_to_le16(0x34),
++};
++
++/*! List of class descriptors
++ */
++static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = {
++ (struct usbd_generic_class_descriptor *)&mouse_hid, };
++
++
++/*! Data Interface Alternate description
++ */
++static struct usbd_interface_descriptor mouse_data_alternate_descriptor = {
++ .bLength = 0x09,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x00,
++ .bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor),
++ .bInterfaceClass = 0x03,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0x00,
++};
++
++/*! Interface Descriptions
++ */
++static struct usbd_alternate_description mouse_data_alternate_descriptions[] = {
++ { .iInterface = "Random Mouse Interface - Interrupt",
++ .interface_descriptor = &mouse_data_alternate_descriptor,
++ .classes = sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ .class_list = mouse_hid_descriptors,
++ .endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *),
++ .endpoint_list = mouse_default,
++ .endpoint_indexes = mouse_indexes,
++ },
++};
++
++/*! List of Interface description(s)
++ */
++static struct usbd_interface_description mouse_interfaces[] = {
++ { .alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ .alternate_list = mouse_data_alternate_descriptions,},
++};
++
++
++/*! Configuration description(s)
++ */
++static struct usbd_configuration_descriptor mouse_configuration_descriptor = {
++ .bLength = 0x09,
++ .bDescriptorType = USB_DT_CONFIGURATION,
++ .wTotalLength = 0x00,
++ .bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description),
++ .bConfigurationValue = 0x01,
++ .iConfiguration = 0x00,
++ .bmAttributes = 0,
++ .bMaxPower = 0,
++};
++
++/*! Mouse Configuration Description
++ */
++struct usbd_configuration_description mouse_configuration_description[] = {
++ { .configuration_descriptor = &mouse_configuration_descriptor,
++ .iConfiguration = "USB Random Mouse Configuration",
++ },
++};
++
++/*! Device Description
++ */
++static struct usbd_device_descriptor mouse_device_descriptor = {
++ .bLength = sizeof(struct usbd_device_descriptor),
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
++ .bDeviceClass = 0x00,
++ .bDeviceSubClass = 0x00,
++ .bDeviceProtocol = 0x00,
++ .bMaxPacketSize0 = 0x00,
++ .idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID),
++ .idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID),
++ .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Description
++ */
++static struct usbd_device_qualifier_descriptor mouse_device_qualifier_descriptor = {
++ .bLength = sizeof(struct usbd_device_qualifier_descriptor),
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++ .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
++ .bDeviceClass = 0x00,
++ .bDeviceSubClass = 0x00,
++ .bDeviceProtocol = 0x00,
++ .bMaxPacketSize0 = 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor mouse_otg_descriptor = {
++ .bLength = sizeof(struct usbd_otg_descriptor),
++ .bDescriptorType = USB_DT_OTG,
++ .bmAttributes = 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description mouse_device_description = {
++ .device_descriptor = &mouse_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ .device_qualifier_descriptor = &mouse_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ .otg_descriptor = &mouse_otg_descriptor,
++ .iManufacturer = CONFIG_OTG_MOUSE_MANUFACTURER,
++ .iProduct = CONFIG_OTG_MOUSE_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ .iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++#endif /* defined(OTG_C99) */
++
++
++/*! @} */
++
++static int mouse_count;
++
++/* MOUSE ***************************************************************************************** */
++/* Transmit Function *************************************************************************** */
++
++int get_xy[8] = {
++ 0, 0, 1, 1,
++ 0, 0, -1, -1,
++};
++
++/*!
++ * mouse_send() - send a mouse data urb with random data
++ * @param function
++ * @return void
++ */
++void mouse_send(struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ int new_x = 0;
++ int new_y = 0;
++ u8 random;
++
++ memset(mouse->tx_urb->buffer, 0, 4);
++ if (!mouse->n) {
++
++ get_random_bytes(&random, 1);
++
++ mouse->last_x = MAX(-4, MIN(4, mouse->last_x + get_xy[random & 0x7]));
++ mouse->last_y = MAX(-4, MIN(4, mouse->last_y + get_xy[(random >> 3) & 0x7]));
++ mouse->n = (random>>6) & 0x3;
++
++ new_x = mouse->x + mouse->last_x;
++ new_y = mouse->y + mouse->last_y;
++
++ mouse->tx_urb->buffer[1] = mouse->last_x;
++ mouse->x = new_x;
++ mouse->tx_urb->buffer[2] = mouse->last_y;
++ mouse->y = new_y;
++ mouse->tx_urb->actual_length = 4;
++
++ }
++ else if ((mouse->n)&1) {
++ mouse->n--;
++ }
++ else {
++ mouse->n--;
++ mouse->tx_urb->buffer[1] = mouse->last_x;
++ mouse->x = new_x;
++ mouse->tx_urb->buffer[2] = mouse->last_y;
++ mouse->y = new_y;
++ }
++ usbd_start_in_urb(mouse->tx_urb);
++}
++
++/*!
++ * mouse_urb_sent() - called to indicate URB transmit finished
++ * This function is the callback function for sent urbs.
++ * It simply queues up another urb until the packets to be sent
++ * configuration parameter is reached (or forever if zero.)
++ * @param urb The urb to be sent.
++ * @param rc result
++ * @return int Return non-zero for failure.
++ */
++int mouse_urb_sent (struct usbd_urb *urb, int rc)
++{
++ struct mouse_private *mouse = &mouse_private;
++ struct usbd_function_instance *function = mouse->function;
++
++ RETURN_ZERO_IF(usbd_get_device_status(function) == USBD_CLOSING);
++ RETURN_ZERO_IF(usbd_get_device_status(function) != USBD_OK);
++ RETURN_ZERO_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
++ TRACE_MSG1(MOUSE, "mouse_count: %d", mouse_count);
++ #ifdef CONFIG_OTG_MOUSE_PACKETS
++ RETURN_ZERO_IF (CONFIG_OTG_MOUSE_PACKETS && (mouse_count++ > CONFIG_OTG_MOUSE_PACKETS));
++ #endif /* CONFIG_OTG_MOUSE_PACKETS */
++ mouse_send(function); // re-send
++ return 0;
++}
++
++/* USB Device Functions ************************************************************************ */
++
++typedef enum mesg {
++ mesg_unknown,
++ mesg_configured,
++ mesg_reset,
++} mesg_t;
++mesg_t mouse_last_mesg;
++
++char * mouse_messages[3] = {
++ "",
++ "Mouse Configured",
++ "Mouse Reset",
++};
++
++void mouse_check_mesg(mesg_t curr_mesg)
++{
++ RETURN_UNLESS(mouse_last_mesg != curr_mesg);
++ mouse_last_mesg = curr_mesg;
++ otg_message(mouse_messages[curr_mesg]);
++}
++
++/*!
++ * mouse_event_handler() - process a device event
++ * This function is called to process USB Device Events.
++ *
++ * The DEVICE_CONFIGURED event causes the mouse_send() to be called
++ * to start the data flow.
++ *
++ * The DEVICE_RESET or DEVICE_DE_CONFIGURED events cause the outstanding
++ * transmit urb to be cancelled.
++ *
++ * @param function the function instance
++ * @param event the event
++ * @param data
++ * @return void
++ *
++ */
++void mouse_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct mouse_private *mouse = &mouse_private;
++
++ switch (event) {
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(MOUSE, "Mouse Configured");
++ mouse_check_mesg(mesg_configured);
++ mouse_count = 0;
++ mouse->connected = 1;
++ if (!(mouse->tx_urb = usbd_alloc_urb (function, BULK_INT, 4, mouse_urb_sent)))
++ printk(KERN_INFO"%s: alloc failed\n", __FUNCTION__);
++ mouse_send(function); // start sending
++ break;
++
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG0(MOUSE, "Mouse De-Configured");
++ mouse_check_mesg(mesg_reset);
++ BREAK_IF(!mouse->connected);
++ mouse->connected = 0;
++ if (mouse->tx_urb) {
++ usbd_free_urb (mouse->tx_urb);
++ mouse->tx_urb = NULL;
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++/*! copy_report()
++ * This function copies the Mouse HID report into the provided URB.
++ * @param urb Destination
++ * @param data Source
++ * @param size Amount of data to copy.
++ * @param max_buf Size of buffer
++ * @return Non-zero if error.
++ *
++ */
++static int copy_report (struct usbd_urb *urb, void *data, int size, int max_buf)
++{
++ int available;
++ int length;
++
++ RETURN_EINVAL_IF (!urb);
++ RETURN_EINVAL_IF (!data);
++ RETURN_EINVAL_IF (!(length = size));
++ RETURN_EINVAL_IF ((available = max_buf - urb->actual_length) <= 0);
++
++ length = (length < available) ? length : available;
++ memcpy (urb->buffer + urb->actual_length, data, length);
++ urb->actual_length += length;
++ return 0;
++}
++
++/*!
++ * mouse_send_hid() - send an EP0 urb containing HID report
++ * This is called to send the Mouse HID report.
++ */
++static int mouse_send_hid (void *data)
++{
++ struct mouse_private *mouse = &mouse_private;
++ struct usbd_function_instance *function = mouse->function;
++ struct usbd_urb *urb = usbd_alloc_urb_ep0(function, mouse->wLength, NULL);
++ int wMaxPacketSize = usbd_endpoint_zero_wMaxPacketSize(urb->function_instance, 0);
++
++ TRACE_MSG1(MOUSE, "Send Hid wLength: %d", mouse->wLength);
++ RETURN_EINVAL_IF (copy_report(urb, MouseHIDReport, sizeof(MouseHIDReport), mouse->wLength));
++ RETURN_EINVAL_UNLESS (wMaxPacketSize);
++
++ if (!(urb->actual_length % wMaxPacketSize) && (urb->actual_length < mouse->wLength))
++ urb->flags |= USBD_URB_SENDZLP;
++
++ RETURN_ZERO_IF(!usbd_start_in_urb(urb));
++ usbd_free_urb(urb);
++ return -EINVAL;
++}
++
++#ifdef CONFIG_OTG_MOUSE_BH
++/*!
++ * mouse_hid_bh() - Bottom half handler to send a HID report
++ * @param data
++ */
++static void mouse_hid_bh (void *data)
++{
++ struct usbd_function_instance *function = mouse_private.function;
++ mouse_send_hid(function);
++}
++
++/*! mouse_schedule_bh - schedule a call for mouse_hid_bh
++ * @param void
++ */
++static int mouse_schedule_bh (void)
++{
++ TRACE_MSG0(MOUSE, "Scheduling");
++ return (!schedule_task (&mouse_private.notification_bh)) ? EINVAL : 0;
++}
++#endif /* CONFIG_OTG_MOUSE_BH */
++
++/*!
++ * mouse_device_request - called to indicate urb has been received
++ * @param function
++ * @param request
++ */
++int mouse_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ /* verify that this is a usb class request per cdc-mouse specification or a vendor request.
++ * determine the request direction and process accordingly
++ */
++
++ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
++
++ case USB_REQ_HOST2DEVICE:
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR:
++ return 0;
++
++ case USB_REQ_DEVICE2HOST :
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
++
++ switch (request->bRequest) {
++ case USB_REQ_GET_DESCRIPTOR:
++ switch (le16_to_cpu(request->wValue)>>8) {
++ case HID_REPORT:
++ mouse_private.wLength = request->wLength;
++ #ifdef CONFIG_OTG_MOUSE_BH
++ return mouse_schedule_bh();
++ #else
++ return mouse_send_hid(function);
++ #endif
++ }
++ default: break;
++ }
++ break;
++
++ default:
++ break;
++ }
++ return -EINVAL;
++}
++
++
++/*! mouse_function_enable - called by USB Device Core to enable the driver
++ * @param function The function instance for this driver to use.
++ * @return non-zero if error.
++ */
++static int mouse_function_enable (struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ mouse->function = function;
++ mouse->n = 0;
++ mouse->x = 0;
++ mouse->y = 0;
++ mouse->last_x = 0;
++ mouse->last_y = 0;
++ mouse->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_INT, 0);
++ return 0;
++}
++
++/*! mouse_function_disable - called by the USB Device Core to disable the driver
++ * @param function The function instance for this driver
++ */
++static void mouse_function_disable (struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ mouse->function = NULL;
++ mouse->writesize = 0;
++ mouse->function = NULL;
++}
++
++/* ********************************************************************************************* */
++#if !defined(OTG_C99)
++/*! function_ops - operations table for the USB Device Core
++ */
++static struct usbd_function_operations mouse_function_ops;
++
++/*! mouse_function_driver - USB Device Core function driver definition
++ */
++struct usbd_function_driver mouse_function_driver;
++
++void mouse_ops_init(void)
++{
++ /*! function_ops - operations table for the USB Device Core
++ */
++ ZERO(mouse_function_ops);
++ mouse_function_ops.event_handler = mouse_event_handler; /*! called for each USB Device Event */
++ mouse_function_ops.device_request = mouse_device_request; /*! called for each received device request */
++ mouse_function_ops.function_enable = mouse_function_enable; /*! called to enable the function driver */
++ mouse_function_ops.function_disable = mouse_function_disable; /*! called to disable the function driver */
++
++ /*! function_driver - USB Device Core function driver definition
++ */
++ ZERO(mouse_function_driver);
++ mouse_function_driver.name = "mouse-random"; /*! driver name */
++ mouse_function_driver.fops = &mouse_function_ops; /*! operations table */
++ mouse_function_driver.device_description = &mouse_device_description; /*! mouse device description */
++ mouse_function_driver.bNumConfigurations =
++ sizeof (mouse_configuration_description) / sizeof (struct usbd_configuration_description);
++ mouse_function_driver.configuration_description =
++ mouse_configuration_description; /*! mouse configuration description */
++ mouse_function_driver.idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID);
++ mouse_function_driver.idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID);
++ mouse_function_driver.bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE);
++
++
++ mouse_function_driver.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
++ mouse_function_driver.interface_list = mouse_interfaces;
++ mouse_function_driver.endpointsRequested = ENDPOINTS;
++ mouse_function_driver.requestedEndpoints = mouse_endpoint_requests;
++}
++#else /* defined(OTG_C99) */
++/*! function_ops - operations table for the USB Device Core
++ */
++static struct usbd_function_operations mouse_function_ops = {
++ .event_handler = mouse_event_handler, /*!< called for each USB Device Event */
++ .device_request = mouse_device_request, /*!< called for each received device request */
++ .function_enable = mouse_function_enable, /*!< called to enable the function driver */
++ .function_disable = mouse_function_disable, /*!< called to disable the function driver */
++};
++
++/*! mouse_function_driver - USB Device Core function driver definition
++ */
++struct usbd_function_driver mouse_function_driver = {
++ .name = "mouse-random", /*!< driver name */
++ .fops = &mouse_function_ops, /*!< operations table */
++ .device_description = &mouse_device_description, /*!< mouse device description */
++ .bNumConfigurations = sizeof (mouse_configuration_description) / sizeof (struct usbd_configuration_description),
++ .configuration_description = mouse_configuration_description, /*!< mouse configuration description */
++ .idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID),
++ .idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID),
++ .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE),
++ .bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description),
++ .interface_list = mouse_interfaces,
++ .endpointsRequested = ENDPOINTS,
++ .requestedEndpoints = mouse_endpoint_requests,
++};
++#endif /* defined(OTG_C99) */
++
+diff -uNr linux/drivers/no-otg/functions/mouse/mouse-if.c linux/drivers/otg/functions/mouse/mouse-if.c
+--- linux/drivers/no-otg/functions/mouse/mouse-if.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/mouse-if.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,499 @@
++/*
++ * otg/functions/mouse/mouse-if.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/mouse/mouse-if.c
++ * @brief Mouse Interface Function Driver protocol implementation.
++ *
++ * This file implements the Mouse HID protocols and will generate
++ * random mouse data on the INTERRUPT endpoint.
++ *
++ * The primary purpose of this driver is to demonstrate how to
++ * implement a simple function driver and to provide a simple
++ * uni-directional driver for testing USB Device peripheral drivers.
++ *
++ * The mouse driver has several other characteristics to allow testing of
++ * other features of USB Device peripheral drivers:
++ *
++ * - ep0 ZLP handling
++ *
++ * - ep0 delayed CONTROL READ
++ *
++ * To verify that ep0 ZLP processing is being handling correctly this
++ * driver has a hard coded Product name that is returned as a 32 byte
++ * string. This forces most any implementations that have an endpoint
++ * zero packetsize of 8, 16 or 32 to send a Zero Length Packet to
++ * terminate the string transfer when the Product name is requested
++ * by the host.
++ *
++ * The delayed CONTROL READ test verifies that that USB Device peripheral
++ * drivers will correctly NAK until data is provide for device requests.
++ * This is done by (optionally) delaying the HID report via a bottom half
++ * handler. The device request returns normally and the peripheral driver
++ * must properly recognize that while the device request had a non-zero
++ * wLength field, there is currently no queued urb.
++ *
++ * When the bottom half handler is scheduled the HID report urb will be
++ * queued on endpoint zero and then returned to the host.
++ *
++ *
++ * @ingroup MouseFunction
++ */
++
++#include <linux/config.h>
++#include <otg/otg-compat.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#include "mouse.h"
++
++
++/*
++ * ep0 testing.... ensure that this is exactly 16 bytes
++ */
++#undef CONFIG_OTG_MOUSE_PRODUCT_NAME
++#define CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra Mouse"
++
++/*!
++ * @name Mouse Descriptors
++ *
++ * MouseHIDReport
++ * MOUSE Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++/*!
++ * Mouse Descriptors
++ * @{
++ */
++
++#define BULK_INT 0x00 /*!< Interrupt endpoint number */
++#define ENDPOINTS 0x01 /*!< Number of endpoints required */
++
++/*! List of required endpoint numbers
++ */
++static u8 mouse_indexes[] = { BULK_INT, };
++
++/*! List of requested endpoints
++ */
++static struct usbd_endpoint_request mouse_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++#if !defined(OTG_C99)
++/*! This is the interrupt endpoint descriptor.
++ */
++static struct usbd_endpoint_descriptor mouse_data;
++
++/*! The list of endpoint descriptors
++ */
++static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
++
++
++/*! List of class descriptors
++ */
++static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = {
++ (struct usbd_generic_class_descriptor *)&mouse_hid, };
++
++
++/*! Data Interface Alternate description
++ */
++static struct usbd_interface_descriptor mouse_data_alternate_descriptor;
++
++/*! Interface Descriptions
++ */
++static struct usbd_alternate_description mouse_data_alternate_descriptions[1];
++
++/*! List of Interface description(s)
++ */
++static struct usbd_interface_description mouse_interfaces[1];
++
++
++void mouse_if_global_init(void)
++{
++
++ /*! This is the interrupt endpoint descriptor.
++ */
++ ZERO(mouse_data);
++ mouse_data.bLength = 0x07;
++ mouse_data.bDescriptorType = USB_DT_ENDPOINT;
++ mouse_data.bEndpointAddress = USB_DIR_IN;
++ mouse_data.bmAttributes = INTERRUPT;
++ mouse_data.wMaxPacketSize = __constant_cpu_to_le16(0x10);
++#if defined (CONFIG_OTG_MOUSE_INTERVAL)
++ mouse_data.bInterval = CONFIG_OTG_MOUSE_INTERVAL;
++#else
++ mouse_data.bInterval = 0x01;
++#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
++
++
++ /*! Data Interface Alternate description
++ */
++ ZERO(mouse_data_alternate_descriptor);
++ mouse_data_alternate_descriptor.bLength = 0x09;
++ mouse_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
++ mouse_data_alternate_descriptor.bInterfaceNumber = 0x00;
++ mouse_data_alternate_descriptor.bAlternateSetting = 0x00;
++ mouse_data_alternate_descriptor.bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor);
++ mouse_data_alternate_descriptor.bInterfaceClass = 0x03;
++ mouse_data_alternate_descriptor.bInterfaceSubClass = 0x01;
++ mouse_data_alternate_descriptor.bInterfaceProtocol = 0x02;
++ mouse_data_alternate_descriptor.iInterface = 0x00;
++
++ /*! Interface Descriptions
++ */
++ ZERO(mouse_data_alternate_descriptions);
++ mouse_data_alternate_descriptions[0].iInterface = "Random Mouse Interface - Interrupt";
++ mouse_data_alternate_descriptions[0].interface_descriptor = &mouse_data_alternate_descriptor;
++ mouse_data_alternate_descriptions[0].classes =
++ sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *);
++ mouse_data_alternate_descriptions[0].class_list = mouse_hid_descriptors;
++ mouse_data_alternate_descriptions[0].endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *);
++ mouse_data_alternate_descriptions[0].endpoint_list = mouse_default;
++ mouse_data_alternate_descriptions[0].endpoint_indexes = mouse_indexes;
++
++ /*! List of Interface description(s)
++ */
++ ZERO(mouse_interfaces);
++ mouse_interfaces[0].alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
++ mouse_interfaces[0].alternate_list = mouse_data_alternate_descriptions;
++
++
++#else /* defined(OTG_C99) */
++
++/*! This is the interrupt endpoint descriptor.
++ */
++static struct usbd_endpoint_descriptor mouse_data = {
++ .bLength = 0x07,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = INTERRUPT,
++ .wMaxPacketSize = __constant_cpu_to_le16(0x10),
++#if defined (CONFIG_OTG_MOUSE_INTERVAL)
++ .bInterval = CONFIG_OTG_MOUSE_INTERVAL,
++#else
++ .bInterval = 0x01,
++#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
++};
++
++/*! The list of endpoint descriptors
++ */
++static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
++
++
++/*! List of class descriptors
++ */
++static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = {
++ (struct usbd_generic_class_descriptor *)&mouse_hid, };
++
++
++/*! Data Interface Alternate description
++ */
++static struct usbd_interface_descriptor mouse_data_alternate_descriptor = {
++ .bLength = 0x09,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x00,
++ .bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor),
++ .bInterfaceClass = 0x03,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0x00,
++};
++
++/*! Interface Descriptions
++ */
++static struct usbd_alternate_description mouse_data_alternate_descriptions[] = {
++ { .iInterface = "Random Mouse Interface - Interrupt",
++ .interface_descriptor = &mouse_data_alternate_descriptor,
++ .classes = sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ .class_list = mouse_hid_descriptors,
++ .endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *),
++ .endpoint_list = mouse_default,
++ .endpoint_indexes = mouse_indexes,
++ },
++};
++
++/*! List of Interface description(s)
++ */
++static struct usbd_interface_description mouse_interfaces[] = {
++ { .alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ .alternate_list = mouse_data_alternate_descriptions,},
++};
++
++#endif /* defined(OTG_C99) */
++
++/*! @} */
++
++static int mouse_count;
++
++/* MOUSE ***************************************************************************************** */
++/* Transmit Function *************************************************************************** */
++
++int get_xy[8] = {
++ 0, 0, 1, 1,
++ 0, 0, -1, -1,
++};
++
++/*!
++ * mouse_send() - send a mouse data urb with random data
++ * @param function
++ * @return void
++ */
++void mouse_send(struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ int new_x = 0;
++ int new_y = 0;
++ u8 random;
++
++ memset(mouse->tx_urb->buffer, 0, 4);
++ if (!mouse->n) {
++
++ get_random_bytes(&random, 1);
++
++ mouse->last_x = MAX(-4, MIN(4, mouse->last_x + get_xy[random & 0x7]));
++ mouse->last_y = MAX(-4, MIN(4, mouse->last_y + get_xy[(random >> 3) & 0x7]));
++ mouse->n = (random>>6) & 0x3;
++
++ new_x = mouse->x + mouse->last_x;
++ new_y = mouse->y + mouse->last_y;
++
++ mouse->tx_urb->buffer[1] = mouse->last_x;
++ mouse->x = new_x;
++ mouse->tx_urb->buffer[2] = mouse->last_y;
++ mouse->y = new_y;
++ mouse->tx_urb->actual_length = 4;
++
++ }
++ else if ((mouse->n)&1) {
++ mouse->n--;
++ }
++ else {
++ mouse->n--;
++ mouse->tx_urb->buffer[1] = mouse->last_x;
++ mouse->x = new_x;
++ mouse->tx_urb->buffer[2] = mouse->last_y;
++ mouse->y = new_y;
++ }
++ usbd_start_in_urb(mouse->tx_urb);
++}
++
++/*!
++ * mouse_urb_sent() - called to indicate URB transmit finished
++ * This function is the callback function for sent urbs.
++ * It simply queues up another urb until the packets to be sent
++ * configuration parameter is reached (or forever if zero.)
++ * @param urb The urb to be sent.
++ * @param rc result
++ * @return int Return non-zero for failure.
++ */
++int mouse_urb_sent (struct usbd_urb *urb, int rc)
++{
++ struct mouse_private *mouse = &mouse_private;
++ struct usbd_function_instance *function = mouse->function;
++
++ RETURN_ZERO_IF(usbd_get_device_status(function) == USBD_CLOSING);
++ RETURN_ZERO_IF(usbd_get_device_status(function) != USBD_OK);
++ RETURN_ZERO_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
++ TRACE_MSG1(MOUSE, "mouse_count: %d", mouse_count);
++ #ifdef CONFIG_OTG_MOUSE_PACKETS
++ RETURN_ZERO_IF (CONFIG_OTG_MOUSE_PACKETS && (mouse_count++ > CONFIG_OTG_MOUSE_PACKETS));
++ #endif /* CONFIG_OTG_MOUSE_PACKETS */
++ mouse_send(function); // re-send
++ return 0;
++}
++
++/* USB Device Functions ************************************************************************ */
++
++typedef enum mesg {
++ mesg_unknown,
++ mesg_configured,
++ mesg_reset,
++} mesg_t;
++static mesg_t mouse_last_mesg;
++
++static char * mouse_messages[3] = {
++ "",
++ "Mouse-if Configured",
++ "Mouse-if Reset",
++};
++
++static void mouse_check_mesg(mesg_t curr_mesg)
++{
++ RETURN_UNLESS(mouse_last_mesg != curr_mesg);
++ mouse_last_mesg = curr_mesg;
++ otg_message(mouse_messages[curr_mesg]);
++}
++
++/*!
++ * mouse_event_handler() - process a device event
++ * This function is called to process USB Device Events.
++ *
++ * The DEVICE_CONFIGURED event causes the mouse_send() to be called
++ * to start the data flow.
++ *
++ * The DEVICE_RESET or DEVICE_DE_CONFIGURED events cause the outstanding
++ * transmit urb to be cancelled.
++ *
++ * @param function the function instance
++ * @param event the event
++ * @param data
++ * @return void
++ *
++ */
++static void mouse_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct mouse_private *mouse = &mouse_private;
++
++ switch (event) {
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(MOUSE, "Mouse-if Configured");
++ mouse_check_mesg(mesg_configured);
++ mouse_count = 0;
++ mouse->connected = 1;
++ if (!(mouse->tx_urb = usbd_alloc_urb (function, BULK_INT, 4, mouse_urb_sent)))
++ printk(KERN_INFO"%s: alloc failed\n", __FUNCTION__);
++ mouse_send(function); // start sending
++ break;
++
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG0(MOUSE, "Mouse-if De-Configured");
++ mouse_check_mesg(mesg_reset);
++ BREAK_IF(!mouse->connected);
++ mouse->connected = 0;
++ if (mouse->tx_urb) {
++ usbd_free_urb (mouse->tx_urb);
++ mouse->tx_urb = NULL;
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++#ifdef CONFIG_OTG_MOUSE_BH
++/*!
++ * mouse_hid_bh() - Bottom half handler to send a HID report
++ * @param data
++ */
++static void mouse_hid_bh (void *data)
++{
++ struct usbd_function_instance *function = mouse_private.function;
++ mouse_send_hid(function);
++}
++
++/*! mouse_schedule_bh - schedule a call for mouse_hid_bh
++ * @param void
++ */
++static int mouse_schedule_bh (void)
++{
++ TRACE_MSG0(MOUSE, "Scheduling");
++ return (!schedule_task (&mouse_private.notification_bh)) ? EINVAL : 0;
++}
++#endif /* CONFIG_OTG_MOUSE_BH */
++
++/*!
++ * mouse_device_request - called to indicate urb has been received
++ * @param function
++ * @param request
++ */
++static int mouse_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ return -EINVAL;
++}
++
++
++/*! mouse_function_enable - called by USB Device Core to enable the driver
++ * @param function The function instance for this driver to use.
++ * @return non-zero if error.
++ */
++static int mouse_function_enable (struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ mouse->function = function;
++ mouse->n = 0;
++ mouse->x = 0;
++ mouse->y = 0;
++ mouse->last_x = 0;
++ mouse->last_y = 0;
++ mouse->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_INT, 0);
++ return 0;
++}
++
++/*! mouse_function_disable - called by the USB Device Core to disable the driver
++ * @param function The function instance for this driver
++ */
++static void mouse_function_disable (struct usbd_function_instance *function)
++{
++ struct mouse_private *mouse = &mouse_private;
++ mouse->function = NULL;
++ mouse->writesize = 0;
++ mouse->function = NULL;
++}
++
++/* ********************************************************************************************* */
++#if !defined(OTG_C99)
++/*! function_ops - operations table for the USB Device Core
++ */
++static struct usbd_function_operations mouse_function_ops;
++
++/*! mouse_interfacedriver - USB Device Core function driver definition
++ */
++struct usbd_function_driver mouse_interfacedriver;
++
++void mouse_if_ops_init(void)
++{
++ /*! function_ops - operations table for the USB Device Core
++ */
++ ZERO(mouse_function_ops);
++ mouse_function_ops.event_handler = mouse_event_handler; /*! called for each USB Device Event */
++ mouse_function_ops.device_request = mouse_device_request; /*! called for each received device request */
++ mouse_function_ops.function_enable = mouse_function_enable; /*! called to enable the function driver */
++ mouse_function_ops.function_disable = mouse_function_disable; /*! called to disable the function driver */
++
++ /*! function_driver - USB Device Core function driver definition
++ */
++ ZERO(mouse_interfacedriver);
++ mouse_interface_driver.name = "mouse-random-if-driver-noc99"; /*! driver name */
++ mouse_interface_driver.fops = &mouse_function_ops; /*! operations table */
++
++ mouse_function_driver.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
++ mouse_function_driver.interface_list = mouse_interfaces;
++ mouse_interface_driver.endpointsRequested = ENDPOINTS;
++ mouse_interface_driver.requestedEndpoints = mouse_endpoint_requests;
++
++}
++#else /* defined(OTG_C99) */
++/*! function_ops - operations table for the USB Device Core
++ */
++static struct usbd_function_operations mouse_function_ops = {
++ .event_handler = mouse_event_handler, /*!< called for each USB Device Event */
++ .device_request = mouse_device_request, /*!< called for each received device request */
++ .function_enable = mouse_function_enable, /*!< called to enable the function driver */
++ .function_disable = mouse_function_disable, /*!< called to disable the function driver */
++};
++
++/*! mouse_interface_driver - USB Device Core function driver definition
++ */
++struct usbd_function_driver mouse_interface_driver = {
++ .name = "mouse-random-if-driver", /*!< driver name */
++ .fops = &mouse_function_ops, /*!< operations table */
++ .endpointsRequested = ENDPOINTS,
++ .requestedEndpoints = mouse_endpoint_requests,
++};
++#endif /* defined(OTG_C99) */
++
+diff -uNr linux/drivers/no-otg/functions/mouse/mouse-l24.c linux/drivers/otg/functions/mouse/mouse-l24.c
+--- linux/drivers/no-otg/functions/mouse/mouse-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/mouse-l24.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,175 @@
++/*
++ * otg/functions/mouse/mouse-l24.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/mouse/mouse-l24.c
++ * @brief Mouse Function Driver Linux 2.4 initialization
++ *
++ *
++ * This file contains the Linux 2.4 module init and exit functions
++ * to load and unload the Random Mouse Function.
++ *
++ * Notes
++ *
++ * This driver does not export any upper edge functionality to
++ * for the user or applications to use. It simply sends a configurable
++ * number of data packets to the USB Host when configured. Each data
++ * packet contains the equivalent of a small mouse report which will
++ * cause the mouse cursor to move on the host.
++ *
++ * To use simply load with something like:
++ *
++ * insmod mouse_fd.o vendor_id=0xffff product_id=0xffff
++ *
++ * And attach to a Windows box. Windows should recognize as a mouse and
++ * immediately start receiving a stream of data.
++ *
++ * To terminate simply unplug.
++ *
++ *
++ * 1. The mouse driver is product name is hard coded to a string that will
++ * generate a string descriptor that is 32 bytes long. This will test
++ * most UDC's ep0 ZLP handling as it is a multiple of the most common
++ * UDC endpoint zero size. (An option can be added later to allow for
++ * 64 byte ep0 packetsize.)
++ *
++ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report
++ * to being generated by a bottom half handler. This will verify that
++ * the bus interface driver properly handles the case of a delayed
++ * CONTROL READ. I.e. when the usbd_device_request() function returns
++ * zero for successful completion but there is no tx_urb containing the
++ * requested data. The bus interface driver must setup the conditions for
++ * ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
++ * until the tx_urb is started later.
++ *
++ * 3. The CONFIG_OTG_MOUSE_PACKETS option is used to set the number of
++ * mouse data reports to send. Set to zero for a continous stream
++ * of data.
++ *
++ * @ingroup MouseFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++
++#include "mouse.h"
++
++
++/* Module Parameters ******************************************************** */
++/* !
++ * @name XXXXX MODULE Parameters
++ */
++/* ! @{ */
++
++MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++EMBED_LICENSE();
++MOD_DESCRIPTION ("Belcarra Random Walk MOUSE Function");
++
++static u32 vendor_id; /*!< override built-in vendor ID */
++static u32 product_id; /*!< override built-in product ID */
++
++MOD_PARM (vendor_id, "i");
++MOD_PARM (product_id, "i");
++
++MOD_PARM_DESC (vendor_id, "Device Vendor ID");
++MOD_PARM_DESC (product_id, "Device Product ID");
++
++otg_tag_t MOUSE;
++/* ! *} */
++
++/* USB Module init/exit ***************************************************** */
++
++/*!
++ * mouse_modinit() - module init
++ *
++ * This is called by the Linux kernel; either when the module is loaded
++ * if compiled as a module, or during the system intialization if the
++ * driver is linked into the kernel.
++ *
++ * This function will parse module parameters if required and then register
++ * the mouse driver with the USB Device software.
++ *
++ * If the CONFIG_OTG_MOUSE_BH option is enabled it will also setup the mouse
++ * bottom half handler.
++ *
++ */
++static int mouse_modinit (void)
++{
++ struct usbd_function_instance *mfi;
++ printk (KERN_INFO "%s: vendor_id: %04x product_id: %04x\n", __FUNCTION__, vendor_id, product_id);
++
++ #if !defined(OTG_C99)
++ mouse_global_init();
++ mouse_ops_init();
++ #endif /* defined(OTG_C99) */
++
++ MOUSE = otg_trace_obtain_tag();
++ TRACE_MSG2(MOUSE, "vendor_id: %04x product_id: %04x",vendor_id, product_id);
++
++ if (vendor_id)
++ mouse_function_driver.idVendor = cpu_to_le16(vendor_id);
++ if (product_id)
++ mouse_function_driver.idProduct = cpu_to_le16(product_id);
++
++ mouse_hid.wItemLength = cpu_to_le16(0x34); // XXX mips compiler bug.....
++
++ // register as usb function driver
++ THROW_UNLESS ((mouse_private.function = usbd_register_function (&mouse_function_driver, "mouse", NULL)), error);
++ #ifdef CONFIG_OTG_MOUSE_BH
++ mouse_private.notification_bh.routine = mouse_hid_bh;
++ mouse_private.notification_bh.data = NULL;
++ #endif
++ CATCH(error) {
++ if (mouse_private.function) {
++ usbd_deregister_function (mouse_private.function);
++ mouse_private.function = NULL;
++ }
++ otg_trace_invalidate_tag(MOUSE);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++module_init (mouse_modinit);
++
++#if OTG_EPILOGUE
++/*!
++ * mouse_modexit() - module init
++ *
++ * This is called by the Linux kernel; when the module is being unloaded
++ * if compiled as a module. This function is never called if the
++ * driver is linked into the kernel.
++ *
++ * @param void
++ * @return void
++ */
++static void mouse_modexit (void)
++{
++ #ifdef CONFIG_OTG_MOUSE_BH
++ while (PENDING_WORK_ITEM(mouse_private.notification_bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++ #endif
++ if (mouse_private.function) {
++ usbd_deregister_function (mouse_private.function);
++ mouse_private.function = NULL;
++ }
++
++ otg_trace_invalidate_tag(MOUSE);
++}
++
++module_exit (mouse_modexit);
++#endif
++
+diff -uNr linux/drivers/no-otg/functions/mouse/mouse.h linux/drivers/otg/functions/mouse/mouse.h
+--- linux/drivers/no-otg/functions/mouse/mouse.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/mouse/mouse.h 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,63 @@
++/*
++ * otg/functions/mouse/mouse.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup MouseFunction Random Mouse
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/mouse/mouse.h
++ * @brief Mouse Function Driver private defines
++ *
++ *
++ * This is a test USB HID Function Driver designed to test and
++ * verify that INTERRUPT IN endpoints work properly.
++ *
++ *
++ * @ingroup MouseFunction
++ */
++
++
++/*!
++ * The mouse_private structure is used to collect all of the mouse driver
++ * global variables into one place.
++ */
++struct mouse_private {
++ struct usbd_function_instance *function; /*!< function instance for this module */
++#ifdef CONFIG_OTG_MOUSE_BH
++ struct WORK_STRUCT notification_bh;
++#endif /* CONFIG_OTG_MOUSE_BH */
++ int usb_driver_registered; /*!< non-zero if usb function registered */
++ unsigned char connected; /*!< non-zero if connected to host (configured) */
++ unsigned int writesize; /*!< packetsize * 4 */
++ struct usbd_urb *tx_urb; /*!< saved copy of current tx urb */
++ int wLength;
++ int x;
++ int y;
++ int last_x;
++ int last_y;
++ int n;
++};
++
++extern struct mouse_private mouse_private;
++extern struct usbd_function_driver mouse_function_driver;
++extern struct usbd_function_driver mouse_interface_driver;
++extern struct usbd_function_driver mouse_composite_driver;
++extern struct hid_descriptor mouse_hid;
++
++#ifndef OTG_C99
++extern void mouse_global_init(void);
++#endif /* OTG_C99 */
++
++#define MOUSE mouse_trace_tag
++extern otg_tag_t MOUSE;
++
+diff -uNr linux/drivers/no-otg/functions/msc/Config.in linux/drivers/otg/functions/msc/Config.in
+--- linux/drivers/no-otg/functions/msc/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/Config.in 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,25 @@
++#
++# Mass Storage Class Function Drivers
++#
++# Copyright (C) 2003 Belcarra
++#
++
++
++mainmenu_option next_comment
++
++comment "Mass Storage Function "
++dep_tristate ' Mass Storage Function' CONFIG_OTG_MSC $CONFIG_OTG
++
++if [ "$CONFIG_OTG_MSC" = "y" -o "$CONFIG_OTG_MSC" = "m" ]; then
++ hex 'VendorID (hex value)' CONFIG_OTG_MSC_VENDORID "15ec"
++ hex 'ProductID (hex value)' CONFIG_OTG_MSC_PRODUCTID "f006"
++ hex 'bcdDevice (binary-coded decimal)' CONFIG_OTG_MSC_BCDDEVICE "0100"
++
++ string 'iManufacturer (string)' CONFIG_OTG_MSC_MANUFACTURER "Belcarra"
++ string 'iProduct (string)' CONFIG_OTG_MSC_PRODUCT_NAME "Mass Storage Class - Bulk Only"
++ string 'MSC Bulk Only iInterface (string)' CONFIG_OTG_MSC_INTF "MSC BO Data Intf"
++ string 'Data Interface iConfiguration (string)' CONFIG_OTG_MSC_DESC "MSC BO Configuration"
++
++fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/msc/Kconfig linux/drivers/otg/functions/msc/Kconfig
+--- linux/drivers/no-otg/functions/msc/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/Kconfig 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,52 @@
++menu "OTG Mass Storage function"
++ depends on OTG
++
++config OTG_MSC
++ tristate " Mass Storage Function"
++ depends on OTG
++
++menu "OTG Mass Storage function options"
++ depends on OTG && OTG_MSC
++
++config OTG_MSC_VENDORID
++ hex "VendorID (hex value)"
++ depends on OTG && OTG_MSC
++ default "Ox15ec"
++
++config OTG_MSC_PRODUCTID
++ hex "ProductID (hex value)"
++ depends on OTG && OTG_MSC
++ default "Oxf006"
++
++config OTG_MSC_BCDDEVICE
++ hex "bcdDevice (binary-coded decimal)"
++ depends on OTG && OTG_MSC
++ default "Ox0100"
++
++config OTG_MSC_MANUFACTURER
++ string "iManufacturer (string)"
++ depends on OTG && OTG_MSC
++ default "Belcarra"
++
++config OTG_MSC_PRODUCT_NAME
++ string "iProduct (string)"
++ depends on OTG && OTG_MSC
++ default "Mass Storage Class - Bulk Only"
++
++config OTG_MSC_INTF
++ string "MSC Bulk Only iInterface (string)"
++ depends on OTG && OTG_MSC
++ default "MSC BO Data Intf"
++
++config OTG_MSC_DESC
++ string "Data Interface iConfiguration (string)"
++ depends on OTG && OTG_MSC
++ default "MSC BO Configuration"
++
++config OTG_MSC_REGISTER_TRACE
++ bool " MSC Tracing"
++ depends on OTG && OTG_MSC
++ default n
++endmenu
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/msc/Makefile linux/drivers/otg/functions/msc/Makefile
+--- linux/drivers/no-otg/functions/msc/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/Makefile 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,68 @@
++#
++# Function driver for a Mass Storage USB Device
++#
++# Copyright (c) 2003 Belcarra
++
++# Multipart objects.
++
++O_TARGET := msc_target.o
++list-multi := msc_fd.o
++
++#msc_fd-objs := msc.o crc.o
++msc_fd-objs := msc-fd.o crc.o msc-linux.o msc-bo.o msc-io-l24.o
++
++# Objects that export symbols.
++#export-objs := msc.o
++export-objs := msc-fd.o msc-linux.o msc-bo.o
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_MSC) += msc_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++MSCD=$(OTG)/functions/msc
++
++OTG=$(TOPDIR)/drivers/otg
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -I$(OTG) -Wno-unused -Wno-format
++EXTRA_CFLAGS_nostdinc += -I$(OTG) -Wno-unused -Wno-format
++
++# Link rules for multi-part drivers.
++
++msc_fd.o: $(msc_fd-objs)
++ $(LD) -r -o $@ $(msc_fd-objs)
++
++# dependencies:
++
++mass.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
++
+diff -uNr linux/drivers/no-otg/functions/msc/TODO.txt linux/drivers/otg/functions/msc/TODO.txt
+--- linux/drivers/no-otg/functions/msc/TODO.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/TODO.txt 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,118 @@
++MSC TODO List Stuart Lynne
++Belcarra Mon Oct 25 00:51:12 PDT 2004
++
++
++1. MSC documentation
++
++ - requirements and specifications
++ - comparison to mass storage specification, bulk-only and rbc
++ - implementation specifics
++ - rbc/spc commands
++ - sense keys
++ - control and usage
++
++2. PSC requirements
++
++ - notification to PSM layer for addroot and deleteroot
++
++
++3. expunge non Belcarra code and header files
++
++
++4. Insertion emulation
++
++ i. If not connected,
++ - do bdget(),
++ - do blkdev_get()
++ - set flags appropriately.
++
++ ii. If connected,
++ - ensure that there are no active requests (sleep if neccessary)
++ - do bdget()
++ - do blkdev_get()
++ - ensure that overlapped requests from the host while
++ doing the open will not cause problems
++
++5. Removal emulation
++
++ i. If not connected
++ - reset flags appropriately
++
++ ii. If connected,
++ - wait for any active requests to complete (sleep if necessary),
++ - reset flags
++ - ensure that overlapped requests from host while
++ resetting the flags will not cause problems
++ - wait for acknowledgement from host
++
++
++Note that all of the above must take place in the thread of execution of
++the ioctl call (i.e. a normal user thread or process.)
++
++The ioctl should not complete until all of the above is complete OR
++cannot complete and you return an error.
++
++
++6. ioctls
++
++Finish ioctl implementation.
++
++ start start using block device (major, minor specified)
++ stop stop using block device
++ status return current connection status
++ connect wait for connection
++ disconnect wait for dis-connection
++ connected return zero if connected, error otherwise
++ disconnected return zero if dis-connected, error otherwise
++
++
++7. tests
++
++Get the tests in the scripts directory working.
++
++These should verify the following:
++
++ 1. connect/disconnect while started/stopped
++ 2. start/stop while connected/disconnected
++
++
++Or as two matrixes:
++
++ Connected Disconnected
++ Start
++ Stop
++
++
++ Started Stopped
++ Connect
++ DisConnect
++
++
++All valid combinations of starting, stopping, connecting and disconnecting
++must be verified.
++
++
++
++8. Windows
++
++Get Windows test applicatoin working.
++
++9. Compatibility
++
++Test against:
++
++ WinXP
++ Win2k
++ Linux 2.4
++ (Linux 2.6)
++ (WinME)
++
++
++
++10. code review
++
++ - review other drivers to verify we have implemented all required
++ rbc/spc-2 commands and sense codes
++
++11. prevent removal
++
+diff -uNr linux/drivers/no-otg/functions/msc/crc.c linux/drivers/otg/functions/msc/crc.c
+--- linux/drivers/no-otg/functions/msc/crc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/crc.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++ * otg/msc_fd/crc.c - crc table
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++
++#include <otg/otg-compat.h>
++
++//#include <usbd-chap9.h>
++//#include <usbd-mem.h>
++//#include <usbd.h>
++//#include <usbd-func.h>
++
++#include "crc.h"
++
++unsigned int *msc_crc32_table;
++
++/**
++ * Generate the crc32 table
++ *
++ * return non-zero if malloc fails
++ */
++int make_crc_table(void)
++{
++ unsigned int n;
++ if (msc_crc32_table) return 0;
++ if (!(msc_crc32_table = (unsigned int *)ckmalloc(256*4, GFP_KERNEL))) return -EINVAL;
++ for (n = 0; n < 256; n++) {
++ int k;
++ unsigned int c = n;
++ for (k = 0; k < 8; k++) {
++ c = (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1);
++ }
++ msc_crc32_table[n] = c;
++ }
++ return 0;
++}
++
++void free_crc_table(void)
++{
++ if (msc_crc32_table) {
++ lkfree(msc_crc32_table);
++ msc_crc32_table = NULL;
++ }
++}
++
++unsigned int crc32_compute(unsigned char *src, int len, unsigned int val)
++{
++ for (; len-- > 0; val = COMPUTE_FCS (val, *src++));
++ return val;
++}
++
+diff -uNr linux/drivers/no-otg/functions/msc/crc.h linux/drivers/otg/functions/msc/crc.h
+--- linux/drivers/no-otg/functions/msc/crc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/crc.h 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * otg/msc_fd/crc.c - crc table
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ * Ted Powell <ted@belcarra.com>
++ *
++ *
++ */
++
++
++extern unsigned int *msc_crc32_table;
++
++#define CRC32_INIT 0xffffffff // Initial FCS value
++#define CRC32_GOOD 0xdebb20e3 // Good final FCS value
++
++#define CRC32_POLY 0xedb88320 // Polynomial for table generation
++
++#define COMPUTE_FCS(val, c) (((val) >> 8) ^ msc_crc32_table[((val) ^ (c)) & 0xff])
++
++int make_crc_table(void);
++void free_crc_table(void);
++unsigned int crc32_compute(unsigned char *src, int len, unsigned int val);
++
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc-bo.c linux/drivers/otg/functions/msc/msc-bo.c
+--- linux/drivers/no-otg/functions/msc/msc-bo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-bo.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,176 @@
++/*
++ * otg/function/msc/msc-bo.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/msc/msc-bo.c
++ * @brief Mass Storage Driver private defines
++ *
++ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
++ *
++ *
++ * @ingroup MSCFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include <linux/blkdev.h>
++
++
++#include "msc-scsi.h"
++#include "msc.h"
++#include "msc-fd.h"
++#include "crc.h"
++
++//#include "rbc.h"
++
++/*!
++ * Mass Storage Class - Bulk Only
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++static u8 msc_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++static u8 msc_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++static struct usbd_endpoint_descriptor *msc_default[] = {
++ (struct usbd_endpoint_descriptor *) msc_data_1,
++ (struct usbd_endpoint_descriptor *) msc_data_2, };
++u8 msc_indexes[] = { BULK_OUT, BULK_IN, };
++
++
++/*! Endpoint, Interface, Configuration and Device descriptions and descriptors
++ */
++static u8 msc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE,
++ 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor), // bNumEndpoints
++ MASS_STORAGE_CLASS,
++ MASS_STORAGE_SUBCLASS_SCSI,
++ MASS_STORAGE_PROTO_BULK_ONLY,
++ 0x00,
++};
++
++static struct usbd_alternate_description msc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_MSC_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&msc_data_alternate_descriptor,
++ endpoints:sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: msc_default,
++ endpoint_indexes: msc_indexes,
++ },
++};
++
++
++struct usbd_interface_description msc_interfaces[] = {
++ { alternates:sizeof (msc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:msc_data_alternate_descriptions,},
++};
++
++u8 msc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++struct usbd_configuration_description msc_description[] = {
++ { iConfiguration: CONFIG_OTG_MSC_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)msc_configuration_descriptor,
++ },
++};
++
++
++static struct usbd_device_descriptor msc_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: 0x00,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++static struct usbd_device_qualifier_descriptor msc_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: 0x00,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++
++
++static struct usbd_endpoint_request msc_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
++ { 0, },
++};
++
++struct usbd_otg_descriptor msc_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++struct usbd_device_description msc_device_description = {
++ device_descriptor: &msc_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &msc_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &msc_otg_descriptor,
++ iManufacturer: CONFIG_OTG_MSC_MANUFACTURER,
++ iProduct: CONFIG_OTG_MSC_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++extern struct usbd_function_operations msc_function_ops;
++
++struct usbd_function_driver msc_function_driver = {
++ name: "msc-bulkonly",
++ fops:&msc_function_ops,
++ device_description:&msc_device_description,
++ bNumConfigurations:sizeof (msc_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:msc_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
++ bNumInterfaces:sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:msc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: msc_endpoint_requests,
++};
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc-fd.c linux/drivers/otg/functions/msc/msc-fd.c
+--- linux/drivers/no-otg/functions/msc/msc-fd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-fd.c 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,1233 @@
++/*
++ * otg/function/msc/msc.-fd.cc
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @file otg/functions/msc/msc-fd.c
++ * @brief Mass Storage Driver private defines
++ *
++ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
++ *
++ *
++ * Notes:
++ *
++ * 1. Currently we only support the Bulk Only model. Microsoft states that
++ * further support for the mass storage driver will only be done for devices
++ * that conform to the Bulk Only model.
++ *
++ * 2. Multiple LUN's are not supported, but in theory they could be.
++ *
++ * 3. Error handling should be done with STALL but using ZLP seems to also
++ * work. ZLP is usually easier to implement (except possibly on the SA1100.)
++ * We may need to make STALL an option if we find devices (perhaps SA1100)
++ * that cannot reliaby send a ZLP on BULK-IN endpoint.
++ *
++ *
++ * 4. WinXP will match the following:
++ *
++ * USB: Class_08&SubClass_02&Prot_50
++ * USB: Class_08&SubClass_05&Prot_50
++ * USB: Class_08&SubClass_06&Prot_50
++ *
++ * SubClass 02 is MMC or SFF8020I
++ * SubClass 05 is SFF or SFF8070I
++ * SubClass 06 is SCSI
++ *
++ * From the Windows USB Storage FAQ:
++ *
++ * RBC not supported
++ *
++ * SubClass = 6 (SCSI)
++ * CDBs SHOULD NOT be padded to 12 bytes
++ * ModeSense/ModeSelect SHOULD NOT be translated from 1ah/15h to 5ah/55h
++ * should be used for FLASH
++ *
++ * SubClass !=6
++ * CDBs SHOULD be padded to 12 bytes
++ * ModeSense/ModeSelect SHOULD be translated from 1ah/15h to 5ah/55h
++ *
++ * We are using the former, SubClass = 6, and implement the required SCSI operations.
++ *
++ *
++ * TODO
++ *
++ *
++ *
++ * TODO FIXME Bus Interface Notes
++ *
++ * 1. The bus interface driver must correctly implement NAK'ing if not rcv_urb is
++ * present (see au1x00.c or wmmx.c for examples.)
++ *
++ * 2. The bus interface driver must implement USBD_URB_SENDZLP flag (see au1x00.c
++ * for example.)
++ *
++ * @ingroup MSCFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include <linux/blkdev.h>
++
++
++#include "msc-scsi.h"
++#include "msc.h"
++#include "msc-fd.h"
++#include "crc.h"
++
++
++/* Module Parameters ************************************************************************* */
++
++
++#define DEVICE_EJECTED 0x0001 // MEDIA_EJECTED
++#define DEVICE_INSERTED 0x0002 // MEDIA_INSERT
++
++#define DEVICE_OPEN 0x0004 // WR_PROTECT_OFF
++#define DEVICE_WRITE_PROTECTED 0x0008 // WR_PROTECT_ON
++
++#define DEVICE_CHANGE_ON 0x0010 // MEDIA_CHANGE_ON
++
++#define DEVICE_PREVENT_REMOVAL 0x0020
++
++
++#define DEF_NUMBER_OF_HEADS 0x10
++#define DEF_SECTORS_PER_TRACK 0x20
++
++
++
++/* MSC ******************************************************************************************** */
++
++extern struct msc_private msc_private;
++
++int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
++static int msc_recv_urb (struct usbd_urb *urb, int rc);
++
++otg_tag_t msc_fd_trace_tag;
++
++/* Sense Key *********************************************************************************** */
++
++/*! set_sense_data - set sensedata in msc private struture
++ * @param msc
++ * @param sensedata
++ * @param info
++ *
++ * This saves sense data. Sense data indicates what type of error
++ * has occurred and will be returned to the host when a request sense
++ * command is sent.
++ */
++void set_sense_data(struct msc_private *msc, u32 sensedata, u32 info)
++{
++ TRACE_SENSE(sensedata, info);
++ msc->sensedata = sensedata;
++ msc->info = info;
++}
++
++/* Check blockdev ****************************************************************************** */
++
++/*! msc_check_blockdev_name - check current status of the block device
++ *
++ * Check if the block device is operational, either generate a failed CSW
++ * or a ZLP if not ready.
++ *
++ * Returns non-zero if the block device is not available for I/O operations
++ * and a failed CSW has already been sent.
++ */
++int msc_check_blockdev_name(struct msc_private *msc, int zlp, char *name)
++{
++ if (msc->block_dev_state & DEVICE_EJECTED) {
++ TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_EJECTED");
++ ((SENDZLP == zlp) ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
++ (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++ return -EINVAL;
++ }
++ if (msc->block_dev_state & DEVICE_CHANGE_ON) {
++ msc->block_dev_state &= ~DEVICE_CHANGE_ON;
++ TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_CHANGE_ON");
++ ((SENDZLP == zlp) ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
++ (msc, SCSI_SENSEKEY_NOT_READY_TO_READY_CHANGE, msc->lba, USB_MSC_FAILED);
++ return -EINVAL;
++ }
++ //TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_INSERTED");
++ return 0;
++}
++
++/* Generic start recv urb and send csw ********************************************************* */
++
++/*! msc_start_recv - queue a receive urb
++ *
++ * Ensure that size is a multiple of the endpoint packetsize.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size)
++{
++ struct usbd_urb *rcv_urb = NULL;
++ int wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
++ if ((size % wMaxPacketSize))
++ size = ((size + wMaxPacketSize) / wMaxPacketSize) * wMaxPacketSize;
++
++ RETURN_EINVAL_UNLESS((rcv_urb = usbd_alloc_urb (function, BULK_OUT, size, msc_recv_urb)));
++ rcv_urb->function_privdata = msc;
++ msc->rcv_urb_finished = NULL;
++ RETURN_ZERO_UNLESS(usbd_start_out_urb(rcv_urb));
++ TRACE_MSG0(MSC,"START RECV URB ERROR");
++ usbd_free_urb(rcv_urb);
++ return -EINVAL;
++}
++
++/*! msc_start_sending - start sending a new data or csw urb
++ *
++ * Generate a CSW (Command Status Wrapper) to send to the the host.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status)
++{
++ COMMAND_STATUS_WRAPPER *csw;
++ int length = sizeof(COMMAND_STATUS_WRAPPER);
++ struct usbd_urb *tx_urb;
++
++ //TRACE_MSG1(MSC,"START SENDING CSW %08x", status);
++
++ msc->command_state = MSC_STATUS;
++
++ RETURN_EINVAL_UNLESS((tx_urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)));
++
++ tx_urb->actual_length = length;
++ tx_urb->function_privdata = msc;
++
++ // fill in CSW and queue the urb
++ csw = (COMMAND_STATUS_WRAPPER *) tx_urb->buffer;
++ csw->dCSWSignature = CSW_SIGNATURE;
++ csw->dCSWTag = msc->command.dCBWTag;
++ csw->dCSWDataResidue = msc->command.dCBWDataTransferLength - msc->data_transferred_in_bytes;
++ csw->bCSWStatus = status;
++
++ TRACE_MSG2(MSC,"START SENDING CSW status: %02x data residue: %d", status, csw->dCSWDataResidue);
++
++ RETURN_ZERO_UNLESS(usbd_start_in_urb (tx_urb));
++ TRACE_MSG0(MSC,"START SENDING CSW FAILED");
++ usbd_free_urb (tx_urb);
++ return -EINVAL;
++}
++
++/*! msc_start_sending_csw_failed - starting sending a CSW showing failure
++ *
++ * Sets sensedata and generates a CSW with status set to USB_MSC_FAILED.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status)
++{
++ TRACE_MSG2(MSC, "sensedata: %x status: %x", sensedata, status);
++ set_sense_data(msc, sensedata, info);
++ return msc_start_sending_csw(msc->function, msc, status);
++}
++
++
++/* ********************************************************************************************* */
++
++/*! msc_alloc_urb - allocate an urb for returning a query
++ *
++ * Returns NULL if there is an error in the USB layer.
++ */
++struct usbd_urb * msc_alloc_urb(struct msc_private *msc, int length)
++{
++ struct usbd_function_instance *function;
++ struct usbd_urb *urb;
++
++ THROW_IF(!(function = msc->function), error);
++ THROW_IF(!(urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
++ return urb;
++ CATCH(error) {
++ msc->command_state = MSC_READY;
++ return NULL;
++ }
++}
++
++/*! msc_dispatch_query_urb - dispatch an urb containing query data
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status)
++{
++ int rc;
++ unsigned long flags;
++
++ TRACE_MSG1(MSC,"DISPATCH URB len: %d", length);
++
++ // save information in msc and urb
++ //
++ urb->function_privdata = msc;
++ urb->actual_length = msc->TransferLength_in_bytes = length;
++
++ // dispatch urb
++ local_irq_save(flags);
++ if ((rc = usbd_start_in_urb (urb))) {
++
++ TRACE_MSG0(MSC,"DISPATCH URB FAILED");
++ usbd_free_urb (urb);
++
++ // stall?
++ msc->command_state = MSC_READY;
++ local_irq_restore(flags);
++ return -EINVAL;
++ }
++ msc->command_state = MSC_QUERY;
++ msc->status = status;
++ local_irq_restore(flags);
++ return 0;
++}
++
++/*! msc_dispatch_query_urb_zlp - send a ZLP
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status)
++{
++ struct usbd_urb *urb;
++ TRACE_MSG2(MSC, "sensedata: %x status: %x", sensedata, status);
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1)));
++ set_sense_data(msc, sensedata, info);
++ urb->flags |= USBD_URB_SENDZLP;
++ return msc_dispatch_query_urb(urb, msc, 0, status);
++}
++
++/* READ 10 COMMAND - read and send data to the host ******************************************** */
++extern int msc_scsi_read_10(struct msc_private *msc, char *name, int op);
++extern int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc);
++
++/* WRITE 10 - receive data from host and write to block device ********************************* */
++extern int msc_scsi_write_10(struct msc_private *msc, char *name, int op);
++extern void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc);
++
++/* SCSI Commands ******************************************************************************* */
++
++/*! msc_scsi_inquiry - process an inquiry
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_inquiry(struct msc_private *msc, char *name, int op)
++{
++ SCSI_INQUIRY_COMMAND *command = (SCSI_INQUIRY_COMMAND *)&msc->command.CBWCB;
++ SCSI_INQUIRY_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_INQUIRY_DATA);
++
++ /*
++ * C.f. SPC2 7.3 INQUIRY command
++ * C.f. Table 46 - Standard INQUIRY data format
++ *
++ * C.f. Table 47 - Peripheral Qualifier
++ *
++ * 000b The specified peripheral device type is currently connected to this
++ * logical unit.....
++ * 001b The device server is capable of of supporting the peripheral device
++ * type on this logical unit. However, the physical device is not currently
++ * connected to this logical unit.....
++ * 010b Reserved
++ * 011b The device server is not capable of supporting a physical device on
++ * this logical unit....
++ *
++ */
++
++ TRACE_MSG4(MSC,"INQUIRY EnableVPD: %02x LogicalUnitNumber: %02x PageCode: %02x AllocLen: %02x",
++ command->EnableVPD, command->LogicalUnitNumber, command->PageCode, command->AllocationLength);
++
++ // XXX THROW_IF(msc->command_state != MSC_READY, error);
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_INQUIRY_DATA *)urb->buffer;
++ data->PeripheralQaulifier = msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON) ? 0x1 : 0;
++ data->PeripheralDeviceType = 0x00;
++ data->RMB = 0x1;
++ data->ResponseDataFormat = 0x1;
++ data->AdditionalLength = 0x1f;
++
++ strncpy(data->VendorInformation, CONFIG_OTG_MSC_MANUFACTURER, strlen(CONFIG_OTG_MSC_MANUFACTURER));
++ strncpy(data->ProductIdentification, CONFIG_OTG_MSC_PRODUCT_NAME, strlen(CONFIG_OTG_MSC_PRODUCT_NAME));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/*! msc_scsi_read_format_capacity - process a query
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_FORMAT_CAPACITY_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_READ_FORMAT_CAPACITY_DATA);
++ u32 block_num = msc->capacity;
++ u32 block_len;
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_READ_FORMAT_CAPACITY_DATA *) urb->buffer;
++
++ data->CapacityListHeader.CapacityListLength = sizeof(data->CurrentMaximumCapacityDescriptor);
++
++ data->CurrentMaximumCapacityDescriptor.NumberofBlocks = block_num;
++ data->CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
++ memcpy(data->CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len, sizeof(block_len));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/*! msc_read_capacity - process a read_capacity command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_capacity(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_CAPACITY_COMMAND *command = (SCSI_READ_CAPACITY_COMMAND *)&msc->command.CBWCB;
++ SCSI_READ_CAPACITY_DATA *data;
++ struct usbd_urb *urb;
++ int length = 8;
++ u32 lba;
++
++ /*
++ * C.f. RBC 5.3
++ */
++ lba = be32_to_cpu(command->LogicalBlockAddress);
++
++ TRACE_MSG1(MSC,"READ CAPACITY LBA: %d", lba);
++
++ if ((command->PMI > 1) || (!command->PMI && lba)) {
++ TRACE_MSG1(MSC,"READ CAPACITY PMI: %d", command->PMI);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, lba, USB_MSC_FAILED);
++ }
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_READ_CAPACITY_DATA *) urb->buffer;
++
++ data->LastLogicalBlockAddress = cpu_to_be32(msc->capacity);
++ data->BlockLengthInBytes = cpu_to_be32(msc->block_size);
++
++ TRACE_MSG2(MSC,"RECV READ CAPACITY lba: %x block_size: %x",
++ be32_to_cpu(data->LastLogicalBlockAddress), be32_to_cpu(data->BlockLengthInBytes));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++
++/*! msc_scsi_request_sense - process a request_sense command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_request_sense(struct msc_private *msc, char *name, int op)
++{
++ SCSI_REQUEST_SENSE_COMMAND* command = (SCSI_REQUEST_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_REQUEST_SENSE_DATA *data;
++
++ /*
++ * C.f. SPC2 7.20 REQUEST SENSE command
++ */
++
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_REQUEST_SENSE_DATA);
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_REQUEST_SENSE_DATA *) urb->buffer;
++ memset(command, 0x0, length);
++ data->ErrorCode = SCSI_ERROR_CURRENT;
++ data->SenseKey = msc->sensedata >> 16;
++ data->AdditionalSenseLength = 0xa; /* XXX is this needed */
++ data->AdditionalSenseCode = msc->sensedata >> 8;
++ data->AdditionalSenseCodeQualifier = msc->sensedata;
++ data->Valid = 1;
++
++ set_sense_data(msc, SCSI_SENSEKEY_NO_SENSE, 0);
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/*! msc_scsi_mode_sense - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
++{
++ SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_MODE_SENSE_DATA *data;
++ int length = sizeof(SCSI_MODE_SENSE_DATA);
++
++ struct usbd_urb *urb;
++ u8 *cp;
++
++ TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x",
++ command->DBD, command->PageControl, command->PageCode, 0);
++ length = 8;
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ cp = (u8 *) urb->buffer;
++ memset(cp, 0x0, length);
++
++ cp[0] = 0;
++ cp[1] = 0;
++ cp[2] = 0; // 0x80 is writeprotect
++ cp[3] = 0x08;
++ cp[4] = 0;
++ cp[5] = 0;
++ cp[6] = 0;
++ cp[7] = 0;
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/*! msc_scsi_mode_sense - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * XXX this doesn't work, need to re-implement and add these pages.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int new_msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
++{
++
++ /*
++ * C.f. SPC2 7.8.1 MODE SENSE(6) command
++ */
++
++ static READ_WRITE_ERROR_RECOVERY_PAGE page_01 = {
++ PageCode:0x01,
++ PageLength:0x0A,
++ ReadRetryCount:0x03,
++ WriteRetryCount:0x80,
++ };
++ static FLEXIBLE_DISK_PAGE page_05 = {
++ PageCode:0x05,
++ PageLength:0x1E,
++ TransferRate:__constant_cpu_to_be16(0xFA00),
++ NumberofHeads:0xA0,
++ SectorsperTrack:0x00,
++ DataBytesperSector:__constant_cpu_to_be16(0x0002),
++ NumberofCylinders:__constant_cpu_to_be16(0x0000),
++ MotorOnDelay:0x05,
++ MotorOffDelay:0x1E,
++ MediumRotationRate:__constant_cpu_to_be16(0x6801),
++ };
++ static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
++ PageCode:0x1B,
++ PageLength:0x0A,
++ TLUN:0x01,
++ };
++ static TIMER_AND_PROTECT_PAGE page_1c = {
++ PageCode:0x1c,
++ PageLength:0x06,
++ InactivityTimeMultiplier:0x0A,
++ };
++
++ SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_MODE_SENSE_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_MODE_SENSE_DATA);
++
++
++ TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x",
++ command->DBD, command->PageControl, command->PageCode, 0);
++
++
++ if (msc->block_dev_state & DEVICE_EJECTED) {
++ u16 sector = htons((unsigned short)msc->block_size);
++ u16 cylinder = 0;
++ page_05.NumberofHeads = 0;
++ page_05.SectorsperTrack = 0;
++ memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++ }
++ else {
++ u16 sector = htons((unsigned short)msc->block_size);
++ u32 size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
++ u16 cylinder = htons(msc->capacity / size);
++ page_05.NumberofHeads = DEF_NUMBER_OF_HEADS;
++ page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK;
++ memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++ }
++
++ if (SCSI_MODEPAGE_CONTROL_CURRENT != command->PageControl) {
++ TRACE_MSG2(MSC,"MODE SENSE - requeested other than CONTROL_CURRENT: %d %d",
++ command->PageControl, command->PageCode);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
++ }
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++ data = (SCSI_MODE_SENSE_DATA *) urb->buffer;
++
++ data->ModeParameterHeader.WriteProtect = msc->block_dev_state & DEVICE_WRITE_PROTECTED ? 1 : 0;
++
++ switch (command->PageCode) {
++ case SCSI_MODEPAGE_ERROR_RECOVERY:
++ TRACE_MSG0(MSC, "MODEPAGE ERROR_RECOVERY");
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_01, sizeof(page_01));
++ break;
++ case SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE:
++ TRACE_MSG0(MSC, "MODEPAGE FLEXIBLE_DISK_PAGE");
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_05, sizeof(page_05));
++ break;
++ case SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS:
++ TRACE_MSG0(MSC, "MODEPAGE REMOVABLE_BLOCK_ACCESS");
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_1b, sizeof(page_1b));
++ break;
++ case SCSI_MODEPAGE_INFORMATION_EXCEPTIONS:
++ TRACE_MSG0(MSC, "MODEPAGE INFORMATION_EXCEPTIONS");
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_1c, sizeof(page_1c));
++ break;
++ case SCSI_MODEPAGE_ALL_SUPPORTED:
++ TRACE_MSG0(MSC, "MODEPAGE ALL_SUPPORTED");
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages.ModeAllPages.ReadWriteErrorRecoveryPage, &page_01, sizeof(page_01));
++ memcpy(&data->ModePages.ModeAllPages.FlexibleDiskPage, &page_05, sizeof(page_05));
++ memcpy(&data->ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage, &page_1b, sizeof(page_1b));
++ memcpy(&data->ModePages.ModeAllPages.TimerAndProtectPage, &page_1c, sizeof(page_1c));
++ break;
++ case SCSI_MODEPAGE_CACHING:
++ // see file_storage.c for an example if we want to support this
++ TRACE_MSG0(MSC, "MODEPAGE CACHING (not supported)");
++ break;
++ }
++
++ TRACE_MSG2(MSC,"LENGTH: %d %d", msc->command.dCBWDataTransferLength, length);
++
++ /*
++ * XXX verify that length is <= 256 bytes, return CHECK_CONDITION if it is
++ */
++ length = MIN(msc->command.dCBWDataTransferLength, length);
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++
++/*! msc_scsi_test_unit_ready - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_test_unit_ready(struct msc_private *msc, char *name, int op)
++{
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/*! msc_scsi_prevent_allow - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_prevent_allow(struct msc_private *msc, char *name, int op)
++{
++ SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND*)&msc->command.CBWCB;
++
++ /*
++ * C.f. SPC2 7.12 Table 78 PREVENT ALLOW MEDIA REMOVAL Prevent Field
++ *
++ * 00b Medium removal shall be allowed from both the data transport
++ * element and the attached medium changer (if any).
++ * 01b Medium removal shall be prohibited from the data transport
++ * element but allowed from the attached medium changer (if any).
++ * 10b Medium removal shall be allowed for the data transport element
++ * but prohibited for the attached medium changer.
++ * 11b Medium remval shall be prohibited from both the data transport
++ * element and the attached medium changer
++ *
++ * Prevention shall terminate after 00b or 10b, after a SYNC CACHE or hard reset.
++ */
++
++ // XXX TODO
++ // this is from storageproto.c, shouldn't we implement something?
++ if (command->Prevent)
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
++
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/*! msc_scsi_start_stop - process a request_sense command
++ *
++ * C.f. RBC 5.4 and 5.4.2
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_start_stop(struct msc_private *msc, char *name, int op)
++{
++ SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)&msc->command.CBWCB;
++
++ TRACE_MSG4(MSC,"START STOP: Immed: %d Power: %x LoEj: %d Start: %d",
++ command->IMMED, command->PowerConditions, command->LoEj, command->Start);
++ /*
++ * C.f. 5.4
++ *
++ * IMMED - if set return status immediately after command validation, otherwise
++ * return status as soon operation is completed.
++ *
++ * C.f. 5.4.1 Table 8 POWER CONDITIONS
++ *
++ * 0 - M - no change in power condition
++ * 1 - M - place device in active condition
++ * 2 - M - place device in idle condition
++ * 3 - M - place device in Standby condition
++ * 4 - - reserved
++ * 5 - M - place device in Sleep condition
++ * 6 - - reserved
++ * 7 - 0 - Device Control
++ *
++ * C.f. 5.4.2 Table 9 START STOP control bit definitions
++ *
++ * Power Load/Eject Start
++ * 1-7 x x LoEj and Start Ignored
++ * 0 0 0 Stop the medium
++ * 0 0 1 Make the medium ready
++ * 0 1 0 Unload the medium
++ * 0 1 1 Load the medium
++ *
++ */
++ // XXX TODO
++ // this is from storageproto.c, shouldn't we implement something?
++
++ if (command->Start && command->LoEj)
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
++
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++/*! msc_scsi_verify - process a verify command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_verify(struct msc_private *msc, char *name, int op)
++{
++ SCSI_VERIFY_COMMAND *command = (SCSI_VERIFY_COMMAND *)&msc->command.CBWCB;
++
++ /*
++ * C.f. RBC 5.7 VERIFY command
++ */
++ // XXX This actually should use the read_10 function and when
++ // finished reading simply send the following
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/*! msc_scsi_mode_select - process a select command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_mode_select(struct msc_private *msc, char *name, int op)
++{
++ //SCSI_MODE_SELECT_COMMAND *command = (SCSI_MODE_SELECT_COMMAND *)&msc->command.CBWCB;
++
++ /*
++ * C.f. SPC2 7.6 MODE SELECT(6) command
++ */
++
++ // if less than correct amount of data return USB_MSC_PHASE_ERROR - see MV
++ //
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++/*! msc_private_pcs - process a private command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_cmd_private_pcs(struct msc_private *msc, char *name, int op)
++{
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++}
++
++/*! msc_cmd_unknown - process an unknown command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_cmd_unknown(struct msc_private *msc, char *name, int op)
++{
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++}
++
++struct rbc_dispatch {
++ u8 op;
++ char *name;
++ int (*rbc_command) (struct msc_private *, char *, int op);
++ int device_check;
++};
++
++/*! Command cross reference
++ *
++ * This is the list of commands observed from each host OS. It is necessarily
++ * incomplete in that we not have reached some condition necessary to have
++ * other commands used.
++ * Win2k WinXP
++ * SCSI_TEST_UNIT_READY yes yes
++ * SCSI_READ_10 yes yes
++ * SCSI_WRITE_10 yes yes
++ * SCSI_READ_CAPACITY yes yes
++ * SCSI_VERIFY yes
++ * SCSI_INQUIRY yes yes
++ * SCSI_MODE_SENSE yes
++ * SCSI_READ_FORMAT_CAPACITY yes yes
++ * SCSI_REQUEST_SENSE
++ * SCSI_PREVENT_ALLOW_MEDIA_REMOVAL
++ * SCSI_START_STOP
++ * SCSI_MODE_SELECT
++ * SCSI_FORMAT_UNIT
++ *
++ */
++
++struct rbc_dispatch rbc_dispatch_table[] = {
++ { SCSI_TEST_UNIT_READY, "SCSI_TEST_UNIT_READY", msc_scsi_test_unit_ready, NOZLP },
++ { SCSI_READ_10, "SCSI_READ_10", msc_scsi_read_10, SENDZLP },
++ { SCSI_WRITE_10, "SCSI_WRITE_10", msc_scsi_write_10, NOZLP },
++ { SCSI_READ_CAPACITY, "SCSI_READ_CAPACITY", msc_scsi_read_capacity, SENDZLP },
++ { SCSI_VERIFY, "SCSI_VERIFY", msc_scsi_verify, NOCHK },
++ { SCSI_INQUIRY, "SCSI_INQUIRY", msc_scsi_inquiry, NOCHK },
++ { SCSI_MODE_SENSE, "SCSI_MODE_SENSE", msc_scsi_mode_sense, NOCHK },
++ { SCSI_READ_FORMAT_CAPACITY, "SCSI_READ_FORMAT_CAPACITY", msc_scsi_read_format_capacity, SENDZLP },
++ { SCSI_REQUEST_SENSE, "SCSI_REQUEST_SENSE", msc_scsi_request_sense, NOCHK },
++ { SCSI_PREVENT_ALLOW_MEDIA_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIA_REMOVAL", msc_scsi_prevent_allow, NOZLP },
++ { SCSI_START_STOP, "SCSI_START_STOP", msc_scsi_start_stop, NOZLP },
++ { SCSI_MODE_SELECT, "SCSI_MODE_SELECT", msc_scsi_mode_select, NOCHK },
++ { SCSI_FORMAT_UNIT, "SCSI_FORMAT_UNIT", msc_cmd_unknown, NOCHK },
++
++ { SCSI_READ_6, "SCSI_READ_6", msc_cmd_unknown, NOCHK },
++ { SCSI_WRITE_6, "SCSI_WRITE_6", msc_cmd_unknown, NOCHK },
++ { SCSI_RESERVE, "SCSI_RESERVE", msc_cmd_unknown, NOCHK },
++ { SCSI_RELEASE, "SCSI_RELEASE", msc_cmd_unknown, NOCHK },
++ { SCSI_SEND_DIAGNOSTIC, "SCSI_SEND_DIAGNOSTIC", msc_cmd_unknown, NOCHK },
++ { SCSI_SYNCHRONIZE_CACHE, "SCSI_SYNCHRONIZE_CACHE", msc_cmd_unknown, NOCHK },
++ { SCSI_MODE_SENSE_10, "SCSI_MODE_SENSE_10", msc_cmd_unknown, NOCHK },
++ { SCSI_REZERO_UNIT, "SCSI_REZERO_UNIT", msc_cmd_unknown, NOCHK },
++ { SCSI_SEEK_10, "SCSI_SEEK_10", msc_cmd_unknown, NOCHK },
++ { SCSI_WRITE_AND_VERIFY, "SCSI_WRITE_AND_VERIFY", msc_cmd_unknown, NOCHK },
++ { SCSI_WRITE_12, "SCSI_WRITE_12", msc_cmd_unknown, NOCHK },
++ { SCSI_READ_12, "SCSI_READ_12", msc_cmd_unknown, NOCHK },
++
++ { SCSI_PRIVATE_PCS, "SCSI_PRIVATE_PCS", msc_cmd_private_pcs, NOCHK },
++
++ { 0xff, "SCSI_UNKNOWN", msc_cmd_unknown, NOCHK },
++};
++
++
++/*! msc_recv_command - process a new CBW
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++void msc_recv_command(struct usbd_urb *urb, struct msc_private *msc)
++{
++ COMMAND_BLOCK_WRAPPER *command = (COMMAND_BLOCK_WRAPPER *)urb->buffer;
++ u8 op = command->CBWCB[0];
++ struct rbc_dispatch *dispatch;
++
++ /*
++ * c.f. section 6.2 - Valid and Meaningful CBW
++ * c.f. section 6.2.1 - Valid CBW
++ *
++ * The CBW was received after the device had sent a CSW or after a
++ * reset XXX check that we only set MSC_READY after reset or sending
++ * CSW.
++ *
++ * The CBW is 31 (1Fh) bytes in length and the bCBWSignature is
++ * equal to 43425355h.
++ */
++ THROW_IF(31 != urb->actual_length, error);
++ THROW_IF(CBW_SIGNATURE != le32_to_cpu(command->dCBWSignature), error);
++
++ /*
++ * c.f. section 6.2.2 - Meaningful CBW
++ *
++ * no reserved bits are set
++ * the bCBWLUN contains a valid LUN supported by the device
++ * both bCBWCBlength and the content of the CBWCB are in accordance with bInterfaceSubClass
++ */
++
++ // XXX checklun etc
++
++ /*
++ * Success
++ */
++ memcpy(&msc->command, command, sizeof(COMMAND_BLOCK_WRAPPER));
++ msc->data_transferred_in_bytes = msc->TransferLength_in_blocks = msc->TransferLength_in_bytes = 0;
++
++ TRACE_TAG(command->dCBWTag, urb->framenum);
++ usbd_free_urb(urb);
++ urb = NULL;
++
++ /*
++ * Search using the opcode to find the dispatch function to use and
++ * call it.
++ */
++ for (dispatch = rbc_dispatch_table; dispatch->op != 0xff; dispatch++) {
++ CONTINUE_UNLESS ((dispatch->op == op));
++
++ TRACE_CBW(dispatch->name, dispatch->op, dispatch->device_check);
++ TRACE_RECV(&(command->CBWCB[1]));
++
++ /* Depending on the command we may need to check if the device is available
++ * and either fail or send a ZLP if it is not
++ */
++ if (dispatch->device_check)
++ RETURN_IF (msc_check_blockdev_name(msc, dispatch->device_check, dispatch->name));
++
++ /* Call the specific function that implements the specified command
++ */
++ if (dispatch->rbc_command(msc, dispatch->name, op))
++ TRACE_MSG0(MSC,"COMMAND ERROR");
++ return;
++ }
++
++ /* FALL THROUGH if no match is found */
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"RECV CBW ERROR");
++ if (urb)
++ usbd_free_urb(urb);
++
++ /* XXX which of these do we stall?
++ */
++ usbd_halt_endpoint(urb->function_instance, BULK_IN);
++ usbd_halt_endpoint(urb->function_instance, BULK_OUT);
++ }
++ msc_cmd_unknown(msc, "CMD_UNKNOWN", op);
++}
++
++
++/* Sent Function - process a sent urb ********************************************************** */
++
++/*! msc_urb_sent - called to indicate URB transmit finished
++ * @param tx_urb: pointer to struct usbd_urb
++ * @param rc: result
++ *
++ * This is called when an urb is sent. Depending on current state
++ * it may:
++ *
++ * - continue sending data
++ * - send a CSW
++ * - start a recv for a CBW
++ *
++ * This is called from BOTTOM HALF context.
++ *
++ * @return non-zero if urb was not disposed of.
++ */
++int msc_urb_sent (struct usbd_urb *tx_urb, int rc)
++{
++ struct usbd_function_instance *function;
++ struct msc_private *msc = &msc_private;
++
++ RETURN_EINVAL_IF(!(function = tx_urb->function_instance));
++ RETURN_EINVAL_IF(usbd_get_device_status(function) == USBD_CLOSING);
++ RETURN_EINVAL_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
++
++ switch (msc->command_state) {
++ case MSC_DATA_IN_READ:
++ case MSC_DATA_IN_READ_FINISHED:
++ TRACE_MSG0(MSC,"URB SENT READ");
++ return msc_in_read_10_urb_sent(tx_urb, msc);
++
++ case MSC_QUERY:
++ // finished, send CSW
++ TRACE_MSG0(MSC,"URB SENT QUERY");
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ break;
++
++ case MSC_STATUS:
++ default:
++ // sent a CSW need to receive the next CBW
++ TRACE_MSG0(MSC,"URB SENT STATUS");
++ msc->command_state = MSC_READY;
++ msc_start_recv_urb(msc->function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
++ break;
++ }
++ usbd_free_urb (tx_urb);
++ return 0;
++}
++
++
++/* Receive Function - receiving an urb ********************************************************* */
++
++/*! msc_recv_urb - process a received urb
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++static int msc_recv_urb (struct usbd_urb *rcv_urb, int rc)
++{
++ struct msc_private *msc = &msc_private;
++
++ RETURN_EINVAL_IF(!msc->connected);
++
++ //TRACE_MSG2(MSC, "RECV URB length: %d state: %d", rcv_urb->actual_length, msc->command_state);
++
++ switch(msc->command_state) {
++
++ // ready to start a new transaction
++ case MSC_READY:
++ msc_recv_command(rcv_urb, msc);
++ return 0;
++
++ // we think we are receiving data
++ case MSC_DATA_OUT_WRITE:
++ case MSC_DATA_OUT_WRITE_FINISHED:
++ msc_recv_out_blocks(rcv_urb, msc);
++ return 0;
++
++ // we think we are sending data
++ case MSC_DATA_IN_READ:
++ case MSC_DATA_IN_READ_FINISHED:
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++ break;
++
++ // we think we are sending status
++ case MSC_STATUS:
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++ break;
++
++ // we don't think
++ case MSC_UNKNOWN:
++ default:
++ TRACE_MSG0(MSC,"RECV URB ERROR");
++ usbd_halt_endpoint(rcv_urb->function_instance, BULK_OUT);
++ }
++ // let caller dispose of urb
++ return -EINVAL;
++}
++
++/* USB Device Functions ************************************************************************ */
++
++
++static void msc_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ TRACE_MSG0(MSC,"--");
++}
++
++static void msc_set_configuration (struct usbd_function_instance *function, int wValue)
++{
++ TRACE_MSG1(MSC,"wValue: %02x", wValue);
++
++}
++
++static void msc_set_interface (struct usbd_function_instance *function, int wIndex, int wValue)
++{
++ TRACE_MSG2(MSC,"wIndex: %02x wValue: %02x", wIndex, wValue);
++
++}
++
++static void msc_endpoint_cleared (struct usbd_function_instance *function, int bEndpointAddress)
++{
++ TRACE_MSG1(MSC,"bEndpointAddress: %02x", bEndpointAddress);
++
++}
++
++/* USB Device Functions ************************************************************************ */
++/*! msc_event_handler - process a device event
++ *
++ * This function is called when an USBD event occurs.
++ *
++ * This is called from INTERRUPT context.
++ */
++void msc_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ unsigned long flags;
++ struct msc_private *msc = &msc_private;
++ int connected;
++ switch (event) {
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(MSC,"EVENT CONFIGURED");
++ msc->connected = 1;
++ msc->command_state = MSC_READY;
++ msc_start_recv_urb(function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
++ #if 0
++ local_irq_save(flags);
++ if (msc->io_state & MSC_IOCTL_WAITING) {
++ msc->io_state &= ~MSC_IOCTL_WAITING;
++ TRACE_MSG0(MSC, "WAKEUP");
++ }
++ local_irq_restore(flags);
++ #endif
++ wake_up_interruptible(&msc->ioctl_wq);
++ break;
++
++ case DEVICE_BUS_INACTIVE:
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG2(MSC,"EVENT RESET: connected %d msc->io_state", msc->connected, msc->io_state);
++ connected = msc->connected;
++ msc->connected = 0;
++ #if 0
++ local_irq_save(flags);
++ if (msc->io_state & MSC_IOCTL_WAITING) {
++ msc->io_state &= ~MSC_IOCTL_WAITING;
++ TRACE_MSG0(MSC, "WAKEUP");
++ wake_up_interruptible(&msc->ioctl_wq);
++ }
++ local_irq_restore(flags);
++ #endif
++ wake_up_interruptible(&msc->ioctl_wq);
++ BREAK_UNLESS(connected);
++
++ // XXX we should have a semaphore to protect this
++ BREAK_UNLESS (msc->rcv_urb_finished);
++ usbd_free_urb (msc->rcv_urb_finished);
++ msc->rcv_urb_finished = NULL;
++ break;
++
++ default:
++ TRACE_MSG0(MSC,"EVENT IGNORED");
++ break;
++ }
++}
++
++/*! msc_device_request - called to indicate urb has been received
++ *
++ * This function is called when a SETUP packet has been received that
++ * should be handled by the function driver. It will not be called to
++ * process the standard chapter nine defined requests.
++ *
++ * Return non-zero for failure.
++ */
++int msc_device_handler (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct msc_private *msc = &msc_private;
++ struct usbd_urb *urb;
++
++ TRACE_MSG0(MSC,"RECV SETUP");
++
++ // verify that this is a usb class request per cdc-acm specification or a vendor request.
++ RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
++
++ // determine the request direction and process accordingly
++ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
++
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case MSC_BULKONLY_RESET:
++ // XXX TODO FIXME
++ return 0;
++ }
++
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case MSC_BULKONLY_GETMAXLUN:
++ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, 1, NULL)));
++ urb->buffer[0] = 0;
++ urb->actual_length = 1;
++ RETURN_ZERO_IF(!usbd_start_in_urb(urb));
++ usbd_free_urb(urb);
++ return -EINVAL;
++ }
++ default:
++ break;
++ }
++ return -EINVAL;
++}
++
++/*! msc_function_enable - this is called by the USBD core layer
++ *
++ * This is called to initialize the function when a bus interface driver
++ * is loaded.
++ */
++static int msc_function_enable (struct usbd_function_instance *function)
++{
++ struct msc_private *msc = &msc_private;
++
++ MOD_INC_USE_COUNT;
++
++ // XXX TODO need to verify that serial number is minimum of 12
++
++ msc->function = function;
++ msc->command_state = MSC_READY;
++
++ return 0;
++}
++
++/*! msc_function_disable - this is called by the USBD core layer
++ *
++ * This is called to close the function when a bus interface driver
++ * is unloaded.
++ */
++static void msc_function_disable (struct usbd_function_instance *function)
++{
++ struct msc_private *msc = &msc_private;
++
++ TRACE_MSG0(MSC,"FUNCTION EXIT");
++
++ msc->function = NULL;
++
++ MOD_DEC_USE_COUNT;
++}
++
++/* ********************************************************************************************* */
++struct usbd_function_operations msc_function_ops = {
++ event_handler: msc_event_handler,
++ device_request: msc_device_request,
++ function_enable: msc_function_enable,
++ function_disable: msc_function_disable,
++ endpoint_cleared: msc_device_request,
++ endpoint_cleared: msc_set_configuration,
++ endpoint_cleared: msc_set_interface,
++ endpoint_cleared: msc_endpoint_cleared,
++};
++
++/* ********************************************************************************************* */
+diff -uNr linux/drivers/no-otg/functions/msc/msc-fd.h linux/drivers/otg/functions/msc/msc-fd.h
+--- linux/drivers/no-otg/functions/msc/msc-fd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-fd.h 2006-09-01 21:41:27.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * otg/msc_fd/msc.h - Mass Storage Class
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++#ifndef MSC_FD_H
++#define MSC_FD_H 1
++
++extern int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status);
++extern int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status);
++extern int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status);
++extern int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status);
++extern int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size);
++
++#define NOCHK 0
++#define NOZLP 1
++#define SENDZLP 2
++
++#if 1
++static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
++{
++ TRACE_MSG2(MSC, "--> SENSE: %06x INFO: %08x", sense, info);
++}
++static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "<-- rlba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "--> slba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "--> tlba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
++{
++ TRACE_MSG2(MSC, "--> TAG: %8x FRAME: %03x", tag, frame);
++}
++static __inline__ void TRACE_CBW(char *msg, int val, int check)
++{
++ TRACE_MSG3(MSC, " --> %s %02x check: %d", msg, val, check);
++}
++static __inline__ void TRACE_RECV(unsigned char *cp)
++{
++ TRACE_MSG8(MSC, "<-- recv [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++}
++static __inline__ void TRACE_SENT(unsigned char *cp)
++{
++ TRACE_MSG8(MSC, "--> sent [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++}
++
++#endif
++
++
++#endif /* MSC_H */
+diff -uNr linux/drivers/no-otg/functions/msc/msc-io-l24.c linux/drivers/otg/functions/msc/msc-io-l24.c
+--- linux/drivers/no-otg/functions/msc/msc-io-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-io-l24.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,272 @@
++/*
++ * otg/function/msc/msc-io-l24.c - MSC IO
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/msc/msc-io-l24.c
++ * @brief
++ *
++ * NOTES
++ *
++ * TODO
++ *
++ * 1. implement prevent removal command.
++ *
++ * @ingroup MSCFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/devfs_fs_kernel.h>
++
++#include "msc-scsi.h"
++#include "msc.h"
++#include "msc-fd.h"
++#include "crc.h"
++#include "msc-io.h"
++
++extern void msc_open_blockdev (struct msc_private *msc);
++extern void msc_close_blockdev (struct msc_private *msc);
++extern int msc_connection_blockdev (struct msc_private *msc);
++extern struct msc_private msc_private;
++
++#define DEVICE_EJECTED 0x0001 //MEDIA_EJECTED
++#define DEVICE_INSERTED 0x0002 //MEDIA_INSERT
++#define DEVICE_MOUNTED 0x0001 //DEVICE_MOUNTED
++#define DEVICE_UNMOUNTED 0x0002 //DEVICE_UNMOUNTED
++
++extern u32 major;
++extern u32 minor;
++#if 0
++void msc_io_wait(struct msc_private *msc, u32 flag)
++{
++ unsigned long flags;
++ msc->io_state |= MSC_IOCTL_WAITING | flag;
++ TRACE_MSG1(MSC, "SLEEPING io_state: %x", msc->io_state);
++ interruptible_sleep_on(&msc->ioctl_wq);
++}
++
++void msc_io_wakup(struct msc_private *msc)
++{
++ unsigned long flags;
++ local_irq_save(flags);
++ if (msc->io_state & MSC_IOCTL_WAITING) {
++ msc->io_state &= ~MSC_IOCTL_WAITING;
++ TRACE_MSG0(MSC, "WAKEUP");
++ wake_up_interruptible(&msc->ioctl_wq);
++ }
++ local_irq_restore(flags);
++}
++#endif
++/*! msc_io_ioctl_internal
++ */
++int msc_io_ioctl_internal(unsigned int cmd, unsigned long arg)
++{
++ int i;
++ int len;
++ int flag;
++
++ static char func_buf[32];
++ struct otgmsc_mount mount;
++ struct msc_private *msc = &msc_private;
++ unsigned long flags;
++
++ TRACE_MSG2(MSC, "cmd: %d connect: %d", cmd, msc->connected);
++ memset(&mount, 0, sizeof(mount));
++ switch (cmd) {
++
++ /* Mount - make the specified major/minof device available for use
++ * by the USB Host, this does not require an active connection.
++ */
++ case OTGMSC_START:
++ TRACE_MSG0(MSC, "Mounting the device");
++ RETURN_EINVAL_IF(copy_from_user(&mount, (void *)arg, _IOC_SIZE(cmd)));
++
++ TRACE_MSG3(MSC, "major=%d minor=%d state=%d", mount.major, mount.minor, msc->block_dev_state);
++ major = mount.major;
++ minor = mount.minor;
++
++ //msc->io_state = MSC_INACTIVE;
++ msc_open_blockdev (msc);
++ RETURN_EAGAIN_UNLESS(msc->command_state == MSC_READY);
++
++ mount.status = (msc->block_dev_state == DEVICE_INSERTED) ? DEVICE_MOUNTED : DEVICE_UNMOUNTED;
++
++ TRACE_MSG1(MSC, "Device is mounted status: %d", mount.status);
++
++ // XXX Need to copy result back to user space
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
++ TRACE_MSG0(MSC, "Device mounted");
++ return 0;
++
++ /* Umount - make the currently mounted device unavailable to the USB Host,
++ * if there is pending block i/o block until it has finished.
++ * Note that if the driver is unloaded the waiting ioctl process
++ * must be woken up and informed with error code.
++ */
++ case OTGMSC_STOP:
++
++ TRACE_MSG0(MSC, "Unmounting the device");
++
++ RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
++
++ if (msc->command_state != MSC_READY) {
++ TRACE_MSG0(MSC, "SLEEPING");
++ interruptible_sleep_on(&msc->ioctl_wq);
++ TRACE_MSG0(MSC, "AWAKE");
++ }
++
++ RETURN_EAGAIN_UNLESS(msc->command_state == MSC_INACTIVE);
++
++ // XXX Need to copy result back to user space
++ msc->major = mount.major;
++ msc->minor = mount.minor;
++ msc_close_blockdev(msc);
++ mount.status = DEVICE_UNMOUNTED;
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
++ TRACE_MSG0(MSC, "Device unmounted");
++ return 0;
++
++
++ /* Status - return the current mount status.
++ */
++ case OTGMSC_STATUS:
++ TRACE_MSG0(MSC, "Mount status");
++ RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
++ if (msc->block_dev_state == DEVICE_EJECTED)
++ mount.status = DEVICE_UNMOUNTED;
++ else
++ mount.status = DEVICE_MOUNTED;
++
++ // XXX Need to copy result back to user space
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
++ return 0;
++
++ /* Wait_Connect - if not already connected wait until connected,
++ * Note that if the driver is unloaded the waiting ioctl process
++ * must be woken up and informed with error code.
++ */
++ case OTGMSC_WAIT_CONNECT:
++ TRACE_MSG1(MSC, "Wait for connect: connected: %d", msc->connected);
++ local_irq_save(flags);
++
++ if (msc->connected == 0) {
++ TRACE_MSG0(MSC, "SLEEPING");
++ interruptible_sleep_on (&msc->ioctl_wq);
++ TRACE_MSG0(MSC, "AWAKE");
++ }
++ RETURN_EAGAIN_UNLESS(msc->connected);
++
++ RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
++ TRACE_MSG0(MSC, "Device connected");
++ return 0;
++
++ /* Wait_DisConnect - if not already disconnected wait until disconnected,
++ * Note that if the driver is unloaded the waiting ioctl process
++ * must be woken up and informed with error code.
++ */
++ case OTGMSC_WAIT_DISCONNECT:
++ TRACE_MSG1(MSC, "Wait for disconnect: connected: %d", msc->connected);
++
++ if (msc->connected == 1) {
++ TRACE_MSG0(MSC, "SLEEPING");
++ interruptible_sleep_on (&msc->ioctl_wq);
++ TRACE_MSG0(MSC, "AWAKE");
++ }
++ RETURN_EAGAIN_IF(msc->connected);
++ RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
++ RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
++ TRACE_MSG0(MSC, "Device disconnected");
++ return 0;
++
++ default:
++ TRACE_MSG1(MSC, "Unknown command: %x", cmd);
++ TRACE_MSG1(MSC, "OTGMSC_START: %x", OTGMSC_START);
++ TRACE_MSG1(MSC, "OTGMSC_WRITEPROTECT: %x", OTGMSC_WRITEPROTECT);
++ TRACE_MSG1(MSC, "OTGMSC_STOP: %x", OTGMSC_STOP);
++ TRACE_MSG1(MSC, "OTGMSC_STATUS: %x", OTGMSC_STATUS);
++ TRACE_MSG1(MSC, "OTGMSC_WAIT_CONNECT: %x", OTGMSC_WAIT_CONNECT);
++ TRACE_MSG1(MSC, "OTGMSC_WAIT_DISCONNECT: %x", OTGMSC_WAIT_DISCONNECT);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++
++
++/*! msc_io_ioctl
++ */
++int msc_io_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ int i;
++ int len;
++ int flag;
++
++ //printk(KERN_INFO"%s: cmd: %08x arg: %08x\n", __FUNCTION__, cmd, arg);
++ TRACE_MSG6(MSC, "cmd: %08x arg: %08x type: %02d nr: %02d dir: %02d size: %02d",
++ cmd, arg, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
++
++ RETURN_EINVAL_UNLESS (_IOC_TYPE(cmd) == OTGMSC_MAGIC);
++ RETURN_EINVAL_UNLESS (_IOC_NR(cmd) <= OTGMSC_MAXNR);
++
++ RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_READ) && !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)));
++ RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_WRITE) && !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)));
++
++ return msc_io_ioctl_internal(cmd, arg);
++}
++
++
++
++int msc_io_proc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ return msc_io_ioctl(inode, filp, cmd, arg);
++}
++
++
++static struct file_operations msc_io_proc_switch_functions = {
++ ioctl:msc_io_proc_ioctl,
++};
++
++
++/* msc_io_init_l24 - initialize
++ */
++int msc_io_init_l24(void)
++{
++ struct proc_dir_entry *message = NULL;
++
++ THROW_IF (!(message = create_proc_entry ("msc_io", 0666, 0)), error);
++ message->proc_fops = &msc_io_proc_switch_functions;
++ CATCH(error) {
++ printk(KERN_ERR"%s: creating /proc/msc_io failed\n", __FUNCTION__);
++ if (message)
++ remove_proc_entry("msc_io", NULL);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/* msc_io_exit_l24 - exit
++ */
++void msc_io_exit_l24(void)
++{
++ remove_proc_entry("msc_io", NULL);
++}
++
++
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc-io.h linux/drivers/otg/functions/msc/msc-io.h
+--- linux/drivers/no-otg/functions/msc/msc-io.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-io.h 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * otg/functions/msc/msc-io.h - Mass Storage Class
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/functions/msc/msc-io.h
++ * @brief Mass Storage Driver private defines
++ *
++ * OTGMSC_START - make specified major/minor device available to USB Host
++ * OTGMSC_WRITEPROTECT - set or reset write protect flag
++ *
++ * OTGMSC_STOP - remove access to current device, block until pending I/O finished
++ * OTGMSC_STATUS - remove current USB connection status (connected or disconnected)
++ * OTGMSC_WAIT_CONNECT - wait until device is connected (may return immediately if already connected)
++ * OTGMSC_WAIT_DISCONNECT - wait until device is disconnected (may return immediately if already disconnected)
++ *
++ * @ingroup MSCFunction
++ */
++
++//#ifndef MSC_H
++//#define MSC_H 1
++
++#define MSC_IO "/proc/msc_io"
++
++struct otgmsc_mount {
++ int major;
++ int minor;
++ int lun;
++ int writeprotect;
++ int result;
++ int status;
++};
++
++#define OTGMSC_MAGIC 'M'
++#define OTGMSC_MAXNR 10
++
++#define OTGMSC_START _IOWR(OTGMSC_MAGIC, 1, struct otgmsc_mount)
++#define OTGMSC_WRITEPROTECT _IOWR(OTGMSC_MAGIC, 2, struct otgmsc_mount)
++
++#define OTGMSC_STOP _IOR(OTGMSC_MAGIC, 1, struct otgmsc_mount)
++#define OTGMSC_STATUS _IOR(OTGMSC_MAGIC, 2, struct otgmsc_mount)
++#define OTGMSC_WAIT_CONNECT _IOR(OTGMSC_MAGIC, 3, struct otgmsc_mount)
++#define OTGMSC_WAIT_DISCONNECT _IOR(OTGMSC_MAGIC, 4, struct otgmsc_mount)
++
++
++#define MSC_CONNECTED 0x01
++#define MSC_DISCONNECTED 0x02
++#define MSC_WRITEPROTECTED 0x04
++
++//#endif /* MSC_H */
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc-linux.c linux/drivers/otg/functions/msc/msc-linux.c
+--- linux/drivers/no-otg/functions/msc/msc-linux.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-linux.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,935 @@
++/*
++ * otg/function/msc/msc-linux.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++
++/*!
++ * @file otg/functions/msc/msc-linux.c
++ * @brief Mass Storage Driver private defines
++ *
++ *
++ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
++ *
++ * To use simply load with something like:
++ *
++ * insmod msc_fd.o vendor_id=0xffff product_id=0xffff
++ *
++ * Notes:
++ *
++ * 1. Currently block I/O is done a page at a time. I have not determined if
++ * it is possible to dispatch a multiple page generic request. It should at
++ * least be possible to queue page requests.
++ *
++ * 2. Currently for READ operations we have a maximum of one outstanding
++ * read block I/O and send urb. These are allowed to overlap so that we can
++ * continue to read data while sending data to the host.
++ *
++ * 3. Currently for WRITE operations we have a maximum of one outstanding
++ * recv urb and one outstanding write block I/O. These are allowed to
++ * overlap so that we can continue to receive data from the host while
++ * waiting for writing to complete.
++ *
++ * 4. It would be possible to allow multiple writes to be pending, to the
++ * limit of the page cache, if desired.
++ *
++ * 5. It should be possible to allow multiple outstanding reads to be
++ * pending, to the limit of the page cache, but this potentially could
++ * require dealing with out of order completions of the reads. Essentially a
++ * list of completed buffer heads would be required to hold any completed
++ * buffer heads that cannot be sent prior to another, earlier request being
++ * completed.
++ *
++ * 6. Currently ioctl calls are available to start and stop device i/o.
++ *
++ * 7. The driver can optionally generate trace messages showing each sectors
++ * CRC as read or written with LBA. These can be compared by user programs to
++ * ensure that the correct data was read and/or written.
++ *
++ *
++ * TODO
++ *
++ * 1. error handling for block io, e.g. what if using with removable block
++ * device (like CF card) and it is removed.
++ *
++ * 2. Currently we memcpy() data from between the urb buffer and buffer
++ * head page. It should be possible to simply use the page buffer for the
++ * urb.
++ *
++ * 3. Should we offer using fileio as an option? This would allow direct access
++ * to a block device image stored in a normal file or direct access to (for example)
++ * ram disks. It would require implementing a separate file I/O kernel thread to
++ * do the actual I/O.
++ *
++ * 4. It may be interesting to support use of SCSI block device and pass the
++ * scsi commands directly to that. This would allow vendor commands for real
++ * devices to be passed through and executed with results being properly
++ * returned to the host. [This is the intended design for the mass storage
++ * specification.]
++ *
++ *
++ * TODO FIXME Bus Interface Notes
++ *
++ *
++ * @ingroup MSCFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include <linux/blkdev.h>
++
++
++#include "msc-scsi.h"
++#include "msc.h"
++#include "msc-fd.h"
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++#include "crc.h"
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++#include "msc-io.h"
++
++
++//#include "rbc.h"
++
++
++/* Module Parameters ************************************************************************* */
++
++u32 vendor_id;
++u32 product_id;
++
++u32 major;
++u32 minor;
++
++MODULE_PARM (vendor_id, "i");
++MODULE_PARM (product_id, "i");
++MODULE_PARM (major, "i");
++MODULE_PARM (minor, "i");
++
++MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
++MODULE_PARM_DESC (product_id, "Device Product ID");
++MODULE_PARM_DESC (major, "Device Major");
++MODULE_PARM_DESC (minor, "Device Minor");
++
++
++#define DEVICE_EJECTED 0x0001 // MEDIA_EJECTED
++#define DEVICE_INSERTED 0x0002 // MEDIA_INSERT
++
++#define DEVICE_OPEN 0x0004 // WR_PROTECT_OFF
++#define DEVICE_WRITE_PROTECTED 0x0008 // WR_PROTECT_ON
++
++#define DEVICE_CHANGE_ON 0x0010 // MEDIA_CHANGE_ON
++
++#define DEVICE_PREVENT_REMOVAL 0x0020
++
++
++#define DEF_NUMBER_OF_HEADS 0x10
++#define DEF_SECTORS_PER_TRACK 0x20
++
++
++DECLARE_MUTEX(msc_sem);
++
++
++/* MSC ******************************************************************************************** */
++
++struct msc_private msc_private;
++
++int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
++
++
++/* Block Device ******************************************************************************** */
++
++/*! msc_open_blockdev - open the block device specified in msc->major, msc->minor
++ *
++ * Sets appropriate fields to show current status of block device.
++ *
++ * XXX TODO - this needs to be tested against RO and absent devices.
++ *
++ */
++void msc_open_blockdev(struct msc_private *msc)
++{
++ int rc;
++
++ down(&msc_sem);
++ msc->block_dev_state = DEVICE_EJECTED;
++
++ TRACE_MSG2(MSC, "OPEN BLOCKDEV: Major: %x Minor: %x", major, minor);
++
++ /*
++ * Check device information and verify access to the block device.
++ */
++ THROW_IF (!major, ejected);
++
++ msc->dev = MKDEV(major, minor);
++
++ THROW_IF (!(msc->bdev = bdget(kdev_t_to_nr(msc->dev))), ejected);
++
++ if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
++
++ TRACE_MSG0(MSC,"OPEN BLOCKDEV: cannot open RW");
++ THROW_IF ((rc = blkdev_get(msc->bdev, FMODE_READ, 0, BDEV_RAW)), ejected);
++ msc->block_dev_state |= DEVICE_WRITE_PROTECTED;
++ }
++
++ msc->io_state = MSC_INACTIVE;
++ msc->block_dev_state &= ~DEVICE_EJECTED;
++ msc->block_dev_state |= DEVICE_INSERTED | DEVICE_CHANGE_ON;
++
++ TRACE_MSG1(MSC,"OPEN BLOCKDEV: opened block_dev_state: %x", msc->block_dev_state);
++
++ /*
++ * Note that capacity must return the LBA of the last addressable block
++ * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
++ *
++ * The blk_size array contains the number of addressable blocks or N,
++ * capacity is therefore N-1.
++ */
++
++ msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
++ msc->block_size = get_hardsect_size(msc->dev);
++ msc->max_blocks = PAGE_SIZE / msc->block_size;
++
++ TRACE_MSG2(MSC,"blk_size: %x %d",
++ blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1,
++ blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1);
++
++ TRACE_MSG2(MSC,"capacity: %x %d", msc->capacity, msc->capacity);
++ TRACE_MSG2(MSC,"block_size: %x %d", msc->block_size, msc->block_size);
++ TRACE_MSG2(MSC,"max_blocks: %x %d", msc->max_blocks, msc->max_blocks);
++
++ /* setup generic buffer_head
++ * XXX do we need two pages? it should be possible to have a single page
++ * for both read and write, in fact do we need a read_bh and write_bh?
++ * XXX ensure the page (or pages) get deallocated
++ */
++ msc->write_pending = msc->read_pending = 0;
++ msc->write_bh.b_rdev = msc->read_bh.b_rdev = msc->dev;
++ msc->write_bh.b_private = msc->read_bh.b_private = msc;
++ msc->read_bh.b_page = alloc_page(GFP_NOIO); // XXX ensure that this gets de-allocated
++ msc->write_bh.b_page = alloc_page(GFP_NOIO); // XXX ensure that this gets de-allocated
++ msc->read_bh.b_data = page_address(msc->read_bh.b_page);
++ msc->write_bh.b_data = page_address(msc->write_bh.b_page);
++
++ CATCH(ejected) {
++ TRACE_MSG1(MSC,"OPEN BLOCKDEV: EJECTED block_dev_state: %x", msc->block_dev_state);
++ printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor);
++ }
++ up(&msc_sem);
++}
++
++/*! msc_close_blockdev - close the device for host
++ */
++
++void msc_close_blockdev(struct msc_private *msc)
++{
++
++ RETURN_IF(msc->block_dev_state == DEVICE_EJECTED);
++
++ down(&msc_sem);
++ msc->block_dev_state = DEVICE_EJECTED;
++ if (msc->bdev)
++ blkdev_put(msc->bdev, BDEV_RAW);
++
++ // XXX this should be a wait for read_bh/write_bh to go to NULL
++ //while (msc->read_bh.b_data || msc->write_bh.b_data) {
++ while (msc->read_pending || msc->write_pending) {
++ printk(KERN_INFO"%s: sleeping on read or write bh\n", __FUNCTION__);
++ sleep_on_timeout(&msc->msc_wq, 20);
++ }
++ __free_page((void *)&msc->read_bh.b_page);
++ msc->read_bh.b_page = NULL;
++ __free_page((void *)&msc->write_bh.b_page);
++ msc->write_bh.b_page = NULL;
++ up(&msc_sem);
++}
++
++
++/* READ 10 COMMAND - read and send data to the host ******************************************** */
++
++int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc);
++void msc_block_read_finished(struct buffer_head *bh, int flag);
++
++
++/*! msc_scsi_read_10 - process a read(10) command
++ *
++ * We have received a READ(10) CBW, if transfer length is non-zero
++ * initiate a generic block i/o otherwise send a CSW.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_10(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_10_COMMAND *command = (SCSI_READ_10_COMMAND *)&msc->command.CBWCB;
++
++ /*
++ * save the CBW information and setup for transmitting data read from the block device
++ */
++ msc->lba = be32_to_cpu(command->LogicalBlockAddress);
++ msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
++ msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
++ msc->command_state = MSC_DATA_IN_READ;
++ msc->io_state = MSC_INACTIVE;
++
++ /*
++ * Start reading blocks to send or simply send the CSW if the host
++ * didn't actually ask for a non-zero length.
++ */
++ return (msc->TransferLength_in_blocks) ? msc_start_reading_block_data(msc->function, msc) :
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/*! msc_start_reading_block_data - start reading data
++ *
++ * Generate a generic block io request to read some data to transmit.
++ *
++ * This function is initially called by msc_scsi_read_10() but can also be called
++ * by msc_urb_sent() if the amount of data requested was too large.
++ *
++ * The function msc_block_read_finished() will be called to actually send the data
++ * to the host when the I/O request is complete.
++ *
++ */
++int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc)
++{
++ int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
++ unsigned long flags;
++
++ TRACE_MSG3(MSC,"START READING BLOCK DATA lba: %x blocks: %d %d ",
++ msc->lba, msc->TransferLength_in_blocks, TransferLength_in_blocks);
++
++ /* ensure that device state is ok
++ */
++ if (msc->block_dev_state != DEVICE_INSERTED) {
++ TRACE_MSG0(MSC,"START READ MEDIA NOT PRESENT");
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++ }
++
++ // XXX an ioctl has requested that pending io be aborted
++ local_irq_save(flags);
++ if (msc->io_state & MSC_ABORT_IO) {
++ msc->io_state &= ~MSC_ABORT_IO;
++ TRACE_MSG0(MSC,"BLOCK READ ABORTED");
++ local_irq_restore(flags);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ }
++ local_irq_restore(flags);
++
++ /* sanity check lba against capacity
++ */
++ if (msc->lba >= msc->capacity) {
++ TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ }
++
++ /* setup buffer head - msc_block_read_finished() will be called when block i/o is finished
++ */
++ msc->read_bh.b_end_io = msc_block_read_finished;
++ msc->read_bh.b_size = TransferLength_in_blocks * msc->block_size;
++ msc->read_bh.b_rsector = msc->lba;
++ msc->read_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
++ msc->io_state |= MSC_BLOCKIO_PENDING;
++ msc->read_pending=1;
++
++ memset(msc->read_bh.b_data, 0x0, msc->read_bh.b_size);
++
++ generic_make_request(READ, &msc->read_bh);
++ generic_unplug_device(blk_get_queue(msc->read_bh.b_rdev));
++ return 0;
++}
++
++
++/*! msc_block_read_finished - called by generic request
++ *
++ * Called when block i/o read is complete, send the data to the host if possible.
++ *
++ * The function msc_urb_sent() will be called when the data is sent to
++ * either send additional data or the CSW as appropriate.
++ *
++ * If more data is required then call msc_start_reading_block_data() to
++ * issue another block i/o to get more data.
++ *
++ * These means that there can be two outstanding actions when this
++ * function completes:
++ *
++ * 1. a transmit urb may be pending, sending the most recently
++ * read data to the host
++ * 2. another block i/o may be pending to read additional data
++ *
++ * This leads to a race condition, if the block i/o finished before the urb
++ * transmit, then we must simply exit. The msc_in_read_10_urb_sent()
++ * function will ensure that this is restarted.
++ */
++void msc_block_read_finished(struct buffer_head *bh, int uptodate)
++{
++ //struct msc_private *msc = bh->b_private;
++ //int TransferLength_in_blocks = bh->b_size / msc->block_size;
++
++ struct msc_private *msc;
++ int TransferLength_in_blocks;
++
++ struct usbd_function_instance *function;
++ struct usbd_urb *tx_urb;
++ unsigned long flags;
++ int rc;
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ u32 crc;
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++ int i;
++
++ msc = bh->b_private;
++ TransferLength_in_blocks = bh->b_size / msc->block_size;
++
++ TRACE_MSG1(MSC,"BLOCK READ FINISHED size: %x", bh->b_size);
++
++ #if 0
++ local_irq_save(flags);
++ if (msc->io_state & MSC_IOCTL_WAITING) {
++ wake_up_interruptible(&msc->ioctl_wq);
++ msc->io_state &= ~MSC_IOCTL_WAITING;
++ }
++ local_irq_restore(flags);
++ #endif
++
++ wake_up_interruptible(&msc->ioctl_wq);
++
++ /*
++ * Race condition here, if we have not finished sending the
++ * previous tx_urb then we want to simply exit and let
++ * msc_in_read_10_urb_sent() call us again.
++ *
++ * Ensure that we do not reset BLOCKIO flags if SEND PENDING and
++ * that we do reset BLOCKIO if not SEND PENDING
++ */
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++ if (msc->io_state & MSC_SEND_PENDING) {
++ TRACE_MSG0(MSC,"BLOCK READ SEND PENDING");
++ msc->io_state |= MSC_BLOCKIO_FINISHED;
++ msc->uptodate = uptodate;
++ local_irq_restore(flags);
++ return;
++ }
++ msc->io_state &= ~(MSC_BLOCKIO_PENDING | MSC_BLOCKIO_FINISHED);
++
++ local_irq_restore(flags);
++ }
++
++ /* verify that the I/O completed
++ */
++ if (1 != uptodate) {
++ TRACE_MSG0(MSC,"BLOCK READ FAILED");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ /* debug output trace - dump rlba and computed crc
++ */
++ for (i = 0; i < bh->b_size / msc->block_size; i++) {
++ crc = crc32_compute(bh->b_data + (i * msc->block_size), msc->block_size, CRC32_INIT);
++ TRACE_RLBA(bh->b_rsector + i, crc);
++ }
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++ /* allocate a tx_urb and copy into it
++ */
++ THROW_IF(!(function = msc->function), error);
++ THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, bh->b_size, msc_urb_sent)), error);
++ TRACE_MSG1(MSC,"BLOCK READ FINISHED urb: %p", (int)tx_urb);
++
++ tx_urb->function_privdata = msc;
++ tx_urb->actual_length = tx_urb->buffer_length = bh->b_size;
++ memcpy(tx_urb->buffer, bh->b_data, bh->b_size);
++
++ msc->read_pending=0;
++
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++
++ msc->io_state |= MSC_SEND_PENDING;
++ msc->TransferLength_in_bytes -= bh->b_size;
++ msc->TransferLength_in_blocks -= TransferLength_in_blocks;
++ msc->lba += TransferLength_in_blocks;
++
++ if (!msc->TransferLength_in_blocks) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED - IO FINISHED");
++ // set flag so that CSW can be sent
++ msc->io_state |= MSC_DATA_IN_READ_FINISHED;
++ }
++ local_irq_restore(flags);
++ }
++
++ /* dispatch urb - msc_urb_sent() will be called when urb is finished
++ */
++ if ((rc = usbd_start_in_urb (tx_urb))) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED FAILED");
++ usbd_free_urb (tx_urb);
++ THROW(error);
++ }
++
++ /* if more data is required then call msc_start_reading_block_data() to
++ * issue another block i/o to get more data.
++ */
++ if (!(msc->io_state & MSC_DATA_IN_READ_FINISHED)) {
++ TRACE_MSG0(MSC,"BLOCK READ SEND RESTARTING");
++ msc_start_reading_block_data(msc->function, msc);
++ }
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED ERROR");
++ // stall?
++ }
++}
++
++/*! msc_in_read_10_urb_sent - called by msc_urb_sent when state is MSC_DATA_IN_READ
++ *
++ * This will process a read_10 urb that has been sent. Specifically if any previous
++ * read_10 block I/O has finished we recall the msc_block_read_finished() function
++ * to transmit another read_10 urb.
++ *
++ * If there is no other pending read_10 to do we create and send a CSW.
++ *
++ * If there is more I/O to do or there is already an outstanding I/O we simply
++ * return after freeing the URB.
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc)
++{
++ unsigned long flags;
++
++ TRACE_MSG0(MSC,"URB SENT DATA IN");
++
++ /*
++ * Potential race condition here, we may need to restart blockio.
++ */
++ local_irq_save(flags);
++
++ msc->io_state &= ~MSC_SEND_PENDING;
++ msc->data_transferred_in_bytes += tx_urb->actual_length;
++
++ TRACE_MSG1(MSC,"URB SENT DATA IN data transferred: %d", msc->data_transferred_in_bytes);
++
++ if (!tx_urb->actual_length)
++ msc->TransferLength_in_blocks = 0;
++
++ /* XXX We should be checking urb status
++ */
++
++ usbd_free_urb (tx_urb);
++
++ /*
++ * Check to see if we need to send CSW.
++ */
++ if (MSC_DATA_IN_READ_FINISHED & msc->io_state) {
++ TRACE_MSG0(MSC,"URB SENT DATA IN - FINISHED SENDING CSW");
++ local_irq_restore(flags);
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ }
++ /*
++ * Check to see if there is a block read needs to be finished.
++ */
++ if (MSC_BLOCKIO_FINISHED & msc->io_state) {
++ TRACE_MSG0(MSC,"URB SENT DATA IN - RESTART");
++ local_irq_restore(flags);
++ // XXX uptodate?
++ msc_block_read_finished(&msc->read_bh, msc->uptodate);
++ return 0;
++ }
++ local_irq_restore(flags);
++ return 0;
++}
++
++
++/* WRITE 10 - receive data from host and write to block device ********************************* */
++
++int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc);
++void msc_data_written(struct buffer_head *bh, int flag);
++void msc_data_test(struct buffer_head *bh, int flag);
++
++/*! msc_scsi_write_10 - process a write command
++ *
++ * Call either msc_start_receiving_data() or msc_start_sending_csw() as appropriate.
++ * Normally msc_start_receiving_data() is called and it will use msc_start_recv_urb()
++ * to setup a receive urb of the appropriate size.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_write_10(struct msc_private *msc, char *name, int op)
++{
++ SCSI_WRITE_10_COMMAND *command = (SCSI_WRITE_10_COMMAND *)&msc->command.CBWCB;
++
++ /* save the CBW and setup for receiving data to be written to the block device
++ */
++ msc->lba = be32_to_cpu(command->LogicalBlockAddress);
++ msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
++ msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
++
++ msc->command_state = MSC_DATA_OUT_WRITE;
++ msc->io_state = MSC_INACTIVE;
++
++ TRACE_MSG1(MSC,"RECV WRITE lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"RECV WRITE blocks: %d", msc->TransferLength_in_blocks);
++
++ return (msc->TransferLength_in_blocks) ?
++ msc_start_receiving_data(msc->function, msc) :
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/*! msc_start_receiving_data - called to initiate an urb to receive WRITE(10) data
++ *
++ * Initiate a receive urb to receive upto PAGE_SIZE WRITE(10) data. The
++ * msc_recv_urb() function will call msc_recv_out_blocks() to actually
++ * write the data.
++ *
++ * This is called from msc_scsi_write_10() to initiate the WRITE(10) and
++ * called from msc_data_written() to start the next page sized receive
++ * urb.
++ */
++int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc)
++{
++ /*
++ * Calculating the length is most of the work we do :-)
++ */
++ int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
++
++ TRACE_MSG1(MSC,"START RECEIVING DATA lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", msc->TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"START RECEIVING DATA bytes: %d", TransferLength_in_blocks * msc->block_size);
++
++ THROW_IF(msc->command_state != MSC_DATA_OUT_WRITE, error);
++ THROW_IF(!msc->TransferLength_in_blocks, error);
++
++ msc->io_state |= MSC_RECV_PENDING;
++
++ return msc_start_recv_urb(function, msc, TransferLength_in_blocks * msc->block_size);
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"START RECEIVING DATA ERROR");
++ return -EINVAL;
++ }
++}
++
++
++/*! msc_recv_out_blocks - process received WRITE(10) data by writing to block device
++ *
++ * We get here indirectly from msc_recv_urb() when state is MSC_DATA_OUT_WRITE.
++ *
++ * Dealloc the urb and call Initiate the generic request to write the
++ * received data. The b_end_io function msc_data_written() will send the
++ * CSW.
++ *
++ */
++void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc)
++{
++ int TransferLength_in_bytes = rcv_urb->actual_length;
++ int TransferLength_in_blocks = TransferLength_in_bytes / msc->block_size;
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ u32 crc;
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++ int i;
++
++ TRACE_MSG1(MSC,"RECV OUT bytes: %d", TransferLength_in_bytes);
++ TRACE_MSG1(MSC,"RECV OUT iostate: %x", msc->io_state);
++ TRACE_MSG1(MSC,"RECV OUT data transferred: %d", msc->data_transferred_in_bytes);
++
++ /*
++ * Race condition here, we may get to here before the previous block
++ * write completed. If so just exit and the msc_data_written()
++ * function will recall us.
++ */
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++ if (msc->io_state & MSC_BLOCKIO_PENDING) {
++ TRACE_MSG0(MSC,"RECV OUT BLOCKIO PENDING");
++ msc->io_state |= MSC_RECV_FINISHED;
++ msc->rcv_urb_finished = rcv_urb;
++ local_irq_restore(flags);
++ return;
++ }
++ msc->io_state &= ~(MSC_RECV_PENDING |MSC_RECV_FINISHED);
++ local_irq_restore(flags);
++ }
++
++ msc->data_transferred_in_bytes += rcv_urb->actual_length;
++
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ for (i = 0; i < TransferLength_in_blocks; i++) {
++ crc = crc32_compute(rcv_urb->buffer + (i * msc->block_size), msc->block_size, CRC32_INIT);
++ TRACE_SLBA(msc->lba + i, crc);
++ }
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++
++ msc->write_pending=1;
++
++ memcpy(msc->write_bh.b_data, rcv_urb->buffer, rcv_urb->actual_length);
++
++ usbd_free_urb(rcv_urb);
++
++ /* ensure media state is ok
++ */
++ if (msc->block_dev_state != DEVICE_INSERTED) {
++ TRACE_MSG0(MSC,"START READ MEDIA NOT PRESENT");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ // XXX an ioctl has requested that pending io be aborted
++ if (msc->io_state & MSC_ABORT_IO) {
++ unsigned long flags;
++ local_irq_save(flags);
++ msc->io_state &= ~MSC_ABORT_IO;
++ TRACE_MSG0(MSC,"BLOCK READ ABORTED");
++ local_irq_restore(flags);
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ /* sanity check lba against capacity
++ */
++ if (msc->lba >= msc->capacity) {
++ TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ /* additional sanity check for lba - ensure non-zero
++ */
++ if (!msc->TransferLength_in_blocks) {
++ TRACE_MSG0(MSC,"START READ LBA TransferLength_in_blocks zero:");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ /* XXX additional sanity check required here - verify that the transfer
++ * size agrees with what we where expecting, specifically I think
++ * we need to verify that we have received a multiple of the block
++ * size and either a full bulk transfer (so more will come) or
++ * the actual exact amount that the host said it would send.
++ * An error should generate a CSW with a USB_MSC_PHASE_ERROR
++ */
++
++
++ TRACE_MSG1(MSC,"RECV OUT lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"RECV OUT blocks left: %d", msc->TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"RECV OUT blocks current: %d", TransferLength_in_blocks);
++
++ /* Initiate writing the data - msc_data_written() will be called
++ * when finished.
++ */
++ msc->write_bh.b_end_io = msc_data_written;
++
++ /* set address in buffer head
++ */
++ msc->write_bh.b_size = TransferLength_in_bytes;
++ msc->write_bh.b_rsector = msc->lba;
++
++ /* decrement counters and increment address
++ */
++ msc->TransferLength_in_bytes -= TransferLength_in_bytes;
++ msc->TransferLength_in_blocks -= TransferLength_in_blocks;
++ msc->lba += TransferLength_in_blocks;
++ msc->write_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
++ msc->io_state |= MSC_BLOCKIO_PENDING;
++
++
++ /* Check current status of TransferLength - if non-zero then we need
++ * to queue another urb to receive more data.
++ */
++ if (!msc->TransferLength_in_blocks)
++ msc->command_state = MSC_DATA_OUT_WRITE_FINISHED;
++ else
++ msc_start_receiving_data(msc->function, msc);
++
++ /* initiate the block i/o request
++ */
++ generic_make_request(WRITE, &msc->write_bh);
++ generic_unplug_device(blk_get_queue(msc->write_bh.b_rdev));
++}
++
++
++/*! msc_data_written - called by generic request
++ *
++ * Called when current block i/o read is finished, restart block i/o or send the CSW.
++ *
++ */
++void msc_data_written(struct buffer_head *bh, int uptodate)
++{
++ struct msc_private *msc = bh->b_private;
++ unsigned long flags;
++ u8 io_state;
++
++ TRACE_MSG4(MSC,"DATA WRITTEN uptodate: %x b_state: %x state: %x io: %x",
++ uptodate, bh->b_state, msc->command_state, msc->io_state);
++
++ TRACE_MSG1(MSC,"DATA WRITTEN lba: %x", msc->lba);
++
++ local_irq_save(flags);
++ io_state = msc->io_state &= ~MSC_BLOCKIO_PENDING;
++ msc->write_pending=0;
++
++ local_irq_restore(flags);
++
++ // XXX an ioctl has waited for io to complete, need to wake it up
++ #if 0
++ local_irq_save(flags);
++ if (msc->io_state & MSC_IOCTL_WAITING) {
++ wake_up_interruptible(&msc->ioctl_wq);
++ msc->io_state &= ~MSC_IOCTL_WAITING;
++ }
++ local_irq_restore(flags);
++ #endif
++
++ wake_up_interruptible(&msc->ioctl_wq);
++
++ /*
++ * verify that the I/O completed
++ */
++ if (1 != uptodate) {
++ TRACE_MSG0(MSC,"BLOCK READ FAILED");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ // XXX CHECKME
++ if (msc->rcv_urb_finished) {
++ usbd_free_urb(msc->rcv_urb_finished);
++ msc->rcv_urb_finished = NULL;
++ }
++ return;
++ }
++
++ /*
++ * If there was a rcv_urb that was not processed then we need
++ * to process it now. This is done by simply restarting msc_recv_out()
++ */
++ if ((io_state & MSC_RECV_FINISHED) && msc->rcv_urb_finished) {
++ struct usbd_urb *rcv_urb = msc->rcv_urb_finished;
++ msc->rcv_urb_finished = NULL;
++ TRACE_MSG0(MSC,"DATA WRITTEN RECV FINISHED");
++ msc_recv_out_blocks(rcv_urb, msc);
++ }
++ /*
++ * DATA_IN mode and no more data to write
++ */
++ if (MSC_DATA_OUT_WRITE_FINISHED == msc->command_state) {
++ // finished, send CSW
++ TRACE_MSG0(MSC,"DATA WRITTEN send CSW");
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ }
++}
++
++extern struct usbd_function_operations msc_function_ops;
++extern struct usbd_function_driver msc_function_driver;
++
++
++/* USB Module init/exit ************************************************************************ */
++
++int msc_io_init_l24(void);
++void msc_io_exit_l24(void);
++
++/*! msc_modinit - module init
++ *
++ */
++static int msc_modinit (void)
++{
++ int rc;
++ struct msc_private *msc = &msc_private;
++
++ printk(KERN_INFO "Copyright (c) 2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
++ printk (KERN_INFO "%s vendor_id: %04x product_id: %04x major: %d minor: %d\n", __FUNCTION__,
++ vendor_id, product_id, major, minor);
++
++
++ MSC = otg_trace_obtain_tag();
++
++ if (vendor_id)
++ msc_function_driver.idVendor = cpu_to_le16(vendor_id);
++ if (product_id)
++ msc_function_driver.idProduct = cpu_to_le16(product_id);
++
++ init_waitqueue_head(&msc->msc_wq);
++ init_waitqueue_head(&msc->ioctl_wq);
++
++ msc->block_dev_state = DEVICE_EJECTED;
++
++
++ msc->command_state = MSC_READY;
++ msc->io_state = MSC_INACTIVE;
++
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ make_crc_table();
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++
++ TRACE_MSG3(MSC,"PAGE_SHIFT: %x PAGE_SIZE: %x %d", PAGE_SHIFT, PAGE_SIZE, PAGE_SIZE);
++
++ THROW_IF(msc_io_init_l24(), error);
++
++ /* register as usb function driver
++ */
++ THROW_UNLESS ((msc->function = usbd_register_function (&msc_function_driver, "msc", NULL)), error);
++ msc->usb_driver_registered++;
++
++ CATCH(error) {
++ if (msc->usb_driver_registered) {
++ usbd_deregister_function (msc->function);
++ msc->usb_driver_registered = 0;
++ }
++ otg_trace_invalidate_tag(MSC);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*! msc_modexit - module cleanup
++ */
++static void msc_modexit (void)
++{
++ struct msc_private *msc = &msc_private;
++
++ /* destroy control io interface
++ */
++ msc_io_exit_l24();
++
++ /* flush io and free page buffers
++ */
++ msc_close_blockdev(msc);
++
++ if (msc->usb_driver_registered)
++ usbd_deregister_function (msc->function);
++
++#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
++ free_crc_table();
++#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
++ otg_trace_invalidate_tag(MSC);
++}
++
++
++module_init (msc_modinit);
++module_exit (msc_modexit);
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc-original.c linux/drivers/otg/functions/msc/msc-original.c
+--- linux/drivers/no-otg/functions/msc/msc-original.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-original.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,2209 @@
++/*
++ * otg/msc_fd/msc.c
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
++ *
++ * To use simply load with something like:
++ *
++ * insmod msc_fd.o vendor_id=0xffff product_id=0xffff
++ *
++ * Notes:
++ *
++ * 1. Currently block I/O is done a page at a time. I have not determined if
++ * it is possible to dispatch a multiple page generic request. It should at
++ * least be possible to queue page requests.
++ *
++ * 2. Currently for READ operations we have a maximum of one outstanding
++ * read block I/O and send urb. These are allowed to overlap so that we can
++ * continue to read data while sending data to the host.
++ *
++ * 3. Currently for WRITE operations we have a maximum of one outstanding
++ * recv urb and one outstanding write block I/O. These are allowed to
++ * overlap so that we can continue to receive data from the host while
++ * waiting for writing to complete.
++ *
++ * 4. It would be possible to allow multiple writes to be pending, to the
++ * limit of the page cache, if desired.
++ *
++ * 5. It should be possible to allow multiple outstanding reads to be
++ * pending, to the limit of the page cache, but this potentially could
++ * require dealing with out of order completions of the reads. Essentially a
++ * list of completed buffer heads would be required to hold any completed
++ * buffer heads that cannot be sent prior to another, earlier request being
++ * completed.
++ *
++ * 6. Currently we only support the Bulk Only model. Microsoft states that
++ * further support for the mass storage driver will only be done for devices
++ * that conform to the Bulk Only model.
++ *
++ * 7. Multiple LUN's are not supported, but in theory they could be.
++ *
++ * 8. It should be possible to use the removalble disk model to allow for a
++ * hotplug script to umount locally and signal that the block device is now
++ * available. An insertion event would notify the host that it can now use
++ * the device. Similarily applications could notify us to send a removal
++ * event to the host so that the device can be mounted locally.
++ *
++ * 9. Error handling should be done with STALL but using ZLP seems to also
++ * work. ZLP is usually easier to implement (except possibly on the SA1100.)
++ * We may need to make STALL an option if we find devices (perhaps SA1100)
++ * that cannot reliaby send a ZLP on BULK-IN endpoint.
++ *
++ *
++ * 10. WinXP will match the following:
++ *
++ * USB\Class_08&SubClass_02&Prot_50
++ * USB\Class_08&SubClass_05&Prot_50
++ * USB\Class_08&SubClass_06&Prot_50
++ *
++ * SubClass 02 is MMC or SFF8020I
++ * SubClass 05 is SFF or SFF8070I
++ * SubClass 06 is SCSI
++ *
++ * From the Windows USB Storage FAQ:
++ *
++ * RBC not supported
++ *
++ * SubClass = 6 (SCSI)
++ * CDBs SHOULD NOT be padded to 12 bytes
++ * ModeSense/ModeSelect SHOULD NOT be translated from 1ah/15h to 5ah/55h
++ * should be used for FLASH
++ *
++ * SubClass !=6
++ * CDBs SHOULD be padded to 12 bytes
++ * ModeSense/ModeSelect SHOULD be translated from 1ah/15h to 5ah/55h
++ *
++ * We are using the former, SubClass = 6, and implement the required SCSI operations.
++ *
++ *
++ * TODO
++ *
++ * 1. error handling for block io, e.g. what if using with removable block
++ * device (like CF card) and it is removed.
++ *
++ * 2. Currently we memcpy() data from between the urb buffer and buffer
++ * head page. It should be possible to simply use the page buffer for the
++ * urb.
++ *
++ * 3. Should we offer using fileio as an option? This would allow direct access
++ * to a block device image stored in a normal file or direct access to (for example)
++ * ram disks. It would require implementing a separate file I/O kernel thread to
++ * do the actual I/O.
++ *
++ *
++ * TODO FIXME Bus Interface Notes
++ *
++ * 1. The bus interface driver must correctly implement NAK'ing if not rcv_urb is
++ * present (see au1x00.c or wmmx.c for examples.)
++ *
++ * 2. The bus interface driver must implement USBD_URB_SENDZLP flag (see au1x00.c
++ * for example.)
++ *
++ */
++
++#if 1
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-mesg.h>
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include <linux/blkdev.h>
++
++
++#include "msc-scsi.h"
++#include "msc.h"
++#include "crc.h"
++
++static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
++{
++ TRACE_MSG2(MSC, "--> SENSE: %06x INFO: %08x", sense, info);
++}
++static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "<-- rlba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "--> slba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
++{
++ TRACE_MSG2(MSC, "--> tlba [%8x %08x]", lba, crc);
++}
++static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
++{
++ TRACE_MSG2(MSC, "--> TAG: %8x FRAME: %03x", tag, frame);
++}
++static __inline__ void TRACE_CBW(char *msg, int val)
++{
++ TRACE_MSG2(MSC, " --> %s %02x", msg, val);
++}
++static __inline__ void TRACE_RECV(unsigned char *cp)
++{
++ TRACE_MSG8(MSC, "<-- recv [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++}
++static __inline__ void TRACE_SENT(unsigned char *cp)
++{
++ TRACE_MSG8(MSC, "--> sent [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++}
++
++
++#else
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_LICENSE("PROPRIETARY");
++MODULE_DESCRIPTION ("Belcarra Mass Storage Class Bulk Only Function");
++
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <asm/atomic.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include <linux/blkdev.h>
++
++#include "usbp-chap9.h"
++#include <usbp-mem.h>
++#include <otg-compat.h>
++#include <usbp-func.h>
++
++USBD_MODULE_INFO ("msc_fd 2.0-beta");
++
++#include "msc-scsi.h"
++#include "msc.h"
++
++#include "trace.h"
++#include "crc.h"
++#endif
++
++//#include "rbc.h"
++
++
++/* Module Parameters ************************************************************************* */
++
++static u32 vendor_id;
++static u32 product_id;
++
++static u32 major;
++static u32 minor;
++
++MODULE_PARM (vendor_id, "i");
++MODULE_PARM (product_id, "i");
++MODULE_PARM (major, "i");
++MODULE_PARM (minor, "i");
++
++MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
++MODULE_PARM_DESC (product_id, "Device Product ID");
++MODULE_PARM_DESC (major, "Device Major");
++MODULE_PARM_DESC (minor, "Device Minor");
++
++/*
++ * MSC Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++#define BULK_OUT 0x00
++#define BULK_IN 0x01
++#define ENDPOINTS 0x02
++
++/*
++ * Mass Storage Class - Bulk Only
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++static u8 msc_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++static u8 msc_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++static struct usbd_endpoint_descriptor *msc_default[] = {
++ (struct usbd_endpoint_descriptor *) msc_data_1,
++ (struct usbd_endpoint_descriptor *) msc_data_2, };
++u8 msc_indexes[] = { BULK_OUT, BULK_IN, };
++
++
++/* Endpoint, Interface, Configuration and Device descriptions and descriptors
++ */
++static u8 msc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
++ 0x09, USB_DT_INTERFACE,
++ 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor), // bNumEndpoints
++ MASS_STORAGE_CLASS,
++ MASS_STORAGE_SUBCLASS_SCSI,
++ MASS_STORAGE_PROTO_BULK_ONLY,
++ 0x00,
++};
++
++static struct usbd_alternate_description msc_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_MSC_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&msc_data_alternate_descriptor,
++ endpoints:sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: msc_default,
++ endpoint_indexes: msc_indexes,
++ },
++};
++
++
++struct usbd_interface_description msc_interfaces[] = {
++ { alternates:sizeof (msc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:msc_data_alternate_descriptions,},
++};
++
++u8 msc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++struct usbd_configuration_description msc_description[] = {
++ { iConfiguration: CONFIG_OTG_MSC_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)msc_configuration_descriptor,
++ },
++};
++
++
++static struct usbd_device_descriptor msc_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: 0x00,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++static struct usbd_device_qualifier_descriptor msc_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: 0x00,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++
++
++
++static struct usbd_endpoint_request msc_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
++ { 0, },
++};
++
++struct usbd_otg_descriptor msc_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++struct usbd_device_description msc_device_description = {
++ device_descriptor: &msc_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &msc_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &msc_otg_descriptor,
++ iManufacturer: CONFIG_OTG_MSC_MANUFACTURER,
++ iProduct: CONFIG_OTG_MSC_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++#define DEVICE_EJECTED 0x0001 // MEDIA_EJECTED
++#define DEVICE_INSERTED 0x0002 // MEDIA_INSERT
++
++#define DEVICE_OPEN 0x0004 // WR_PROTECT_OFF
++#define DEVICE_WRITE_PROTECTED 0x0008 // WR_PROTECT_ON
++
++#define DEVICE_CHANGE_ON 0x0010 // MEDIA_CHANGE_ON
++
++#define DEVICE_PREVENT_REMOVAL 0x0020
++
++
++#define DEF_NUMBER_OF_HEADS 0x10
++#define DEF_SECTORS_PER_TRACK 0x20
++
++
++
++/* MSC ******************************************************************************************** */
++
++static struct msc_private msc_private;
++int msc_interrupts;
++
++int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
++static int msc_recv_urb (struct usbd_urb *urb, int rc);
++
++
++/* Sense Key *********************************************************************************** */
++
++void set_sense_data(struct msc_private *msc, u32 sensedata, u32 info)
++{
++ TRACE_SENSE(sensedata, info);
++ msc->sensedata = sensedata;
++ msc->info = info;
++}
++
++
++static int msc_reset(void)
++{
++ struct msc_private *msc = &msc_private;
++ msc->device_state = MSC_DEVICE_DN;
++ msc->command_state = MSC_READY;
++ msc->io_state = MSC_INACTIVE;
++ msc->block_dev_state = 0;
++ msc->sensedata = 0;
++ msc->info = 0;
++ return 0;
++}
++
++
++/* Generic start recv urb and send csw ********************************************************* */
++
++/* msc_start_recv - queue a receive urb
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size)
++{
++ struct usbd_urb *rcv_urb = NULL;
++ int wMaxPacketSize;
++
++ TRACE_MSG1(MSC, "START RECV URB size: %d", size);
++
++ // ensure that we are a multiple of the endpoint packetsize
++ wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
++ if ((size % wMaxPacketSize)) {
++ size += wMaxPacketSize;
++ size = (size / wMaxPacketSize) * wMaxPacketSize;
++ }
++
++ // allocate urb and queue it
++ THROW_IF(!(rcv_urb = usbd_alloc_urb (function, BULK_OUT, size, msc_recv_urb)), error);
++ TRACE_MSG1(MSC, "START RECV urb: %p", (int)rcv_urb);
++
++ rcv_urb->function_privdata = msc;
++ msc->rcv_urb_finished = NULL;
++ THROW_IF(usbd_start_out_urb(rcv_urb), error);
++ return 0;
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"START RECV URB ERROR");
++ if (rcv_urb)
++ usbd_free_urb(rcv_urb);
++ return -EINVAL;
++ }
++}
++
++/* msc_start_sending - start sending a new data or csw urb
++ *
++ * Generate a CSW (Command Status Wrapper) to send to the the host.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status)
++{
++ COMMAND_STATUS_WRAPPER *csw;
++ int length = sizeof(COMMAND_STATUS_WRAPPER);
++ struct usbd_urb *tx_urb;
++
++ TRACE_MSG1(MSC,"START SENDING CSW %08x", status);
++
++ msc->command_state = MSC_STATUS;
++
++ THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
++ TRACE_MSG1(MSC,"START sending csw urb: %p", (int)tx_urb);
++ tx_urb->actual_length = length;
++ tx_urb->function_privdata = msc;
++
++ // fill in CSW and queue the urb
++ csw = (COMMAND_STATUS_WRAPPER *) tx_urb->buffer;
++ csw->dCSWSignature = CSW_SIGNATURE;
++ csw->dCSWTag = msc->command.dCBWTag;
++ csw->dCSWDataResidue = msc->command.dCBWDataTransferLength - msc->data_transferred_in_bytes;
++ csw->bCSWStatus = status;
++
++ TRACE_MSG1(MSC,"START SENDING CSW data residue: %d", csw->dCSWDataResidue);
++
++ THROW_IF (usbd_start_in_urb (tx_urb), error);
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"START SENDING CSW FAILED");
++ if (tx_urb) usbd_free_urb (tx_urb);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/* msc_start_sending_csw_failed - starting sending a CSW showing failure
++ *
++ * Sets sensedata and generates a CSW with status set to USB_MSC_FAILED.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status)
++{
++ set_sense_data(msc, sensedata, info);
++ return msc_start_sending_csw(msc->function, msc, status);
++}
++
++
++/* ********************************************************************************************* */
++
++/* msc_alloc_urb - allocate an urb for returning a query
++ *
++ * Returns NULL if there is an error in the USB layer.
++ */
++struct usbd_urb * msc_alloc_urb(struct msc_private *msc, int length)
++{
++ struct usbd_function_instance *function;
++ struct usbd_urb *urb;
++
++ THROW_IF(!(function = msc->function), error);
++ THROW_IF(!(urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
++ return urb;
++
++ CATCH(error) {
++ msc->command_state = MSC_READY;
++ return NULL;
++ }
++}
++
++
++/* msc_dispatch_query_urb - dispatch an urb containing query data
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status)
++{
++ int rc;
++
++ TRACE_MSG1(MSC,"DISPATCH URB len: %d", length);
++
++ // save information in msc and urb
++ //
++ urb->function_privdata = msc;
++ urb->actual_length = msc->TransferLength_in_bytes = length;
++
++ // dispatch urb
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++ if ((rc = usbd_start_in_urb (urb))) {
++
++ TRACE_MSG0(MSC,"DISPATCH URB FAILED");
++ usbd_free_urb (urb);
++
++ // stall?
++ msc->command_state = MSC_READY;
++ local_irq_restore(flags);
++ return -EINVAL;
++ }
++ msc->command_state = MSC_QUERY;
++ msc->status = status;
++ local_irq_restore(flags);
++ }
++ return 0;
++}
++
++
++/* msc_dispatch_query_urb_zlp - send a ZLP
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status)
++{
++ struct usbd_urb *urb;
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1)));
++ set_sense_data(msc, sensedata, info);
++ urb->flags |= USBD_URB_SENDZLP;
++ return msc_dispatch_query_urb(urb, msc, 0, status);
++}
++
++
++
++/* Block Device ******************************************************************************** */
++
++/* msc_open_blockdev - open the block device specified in msc->major, msc->minor
++ *
++ * Sets appropriate fields to show current status of block device.
++ *
++ * XXX TODO - this needs to be tested against RO and absent devices.
++ *
++ */
++void msc_open_blockdev(struct msc_private *msc)
++{
++ int rc;
++ msc->block_dev_state = DEVICE_EJECTED;
++
++ TRACE_MSG2(MSC, "OPEN BLOCKDEV: Major: %x Minor: %x", major, minor);
++ //printk(KERN_INFO"%s: major: %d minor: %d\n", __FUNCTION__, major, minor);
++
++ /*
++ * Check device information and verify access to the block device.
++ */
++ THROW_IF (!major, ejected);
++
++ msc->dev = MKDEV(major, minor);
++
++ THROW_IF (!(msc->bdev = bdget(kdev_t_to_nr(msc->dev))), ejected);
++
++ if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
++
++ TRACE_MSG0(MSC,"OPEN BLOCKDEV: cannot open RW");
++ //printk(KERN_INFO"%s: cannot open RW\n", __FUNCTION__);
++ THROW_IF ((rc = blkdev_get(msc->bdev, FMODE_READ, 0, BDEV_RAW)), ejected);
++ msc->block_dev_state |= DEVICE_WRITE_PROTECTED;
++ }
++
++ msc->block_dev_state &= ~DEVICE_EJECTED;
++ msc->block_dev_state |= DEVICE_INSERTED;
++
++ TRACE_MSG1(MSC,"OPEN BLOCKDEV: opened block_dev_state: %x", msc->block_dev_state);
++
++ /*
++ * Note that capacity must return the LBA of the last addressable block
++ * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
++ *
++ * The blk_size array contains the number of addressable blocks or N,
++ * capacity is therefore N-1.
++ */
++
++ msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
++ msc->block_size = get_hardsect_size(msc->dev);
++ msc->max_blocks = PAGE_SIZE / msc->block_size;
++
++ TRACE_MSG1(MSC,"blk_size: %x", blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1);
++ TRACE_MSG1(MSC,"blk_size: %d", blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1);
++
++ TRACE_MSG1(MSC,"capacity: %x", msc->capacity);
++ TRACE_MSG1(MSC,"capacity: %d", msc->capacity);
++
++ TRACE_MSG1(MSC,"block_size: %x", msc->block_size);
++ TRACE_MSG1(MSC,"block_size: %d", msc->block_size);
++
++ TRACE_MSG1(MSC,"max_blocks: %d", msc->max_blocks);
++
++ printk(KERN_INFO"%s: finis\n", __FUNCTION__);
++
++ CATCH(ejected) {
++ TRACE_MSG1(MSC,"OPEN BLOCKDEV: EJECTED block_dev_state: %x", msc->block_dev_state);
++ printk(KERN_INFO"%s: cannot open R)\n", __FUNCTION__);
++ printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor);
++ }
++}
++
++/* msc_check_blockdev - check current status of the block device
++ *
++ * Check if the block device is operational, generate a failed CSW if not.
++ *
++ * Returns non-zero if the block device is not available for I/O operations
++ * and a failed CSW has already been sent.
++ */
++int msc_check_blockdev(struct msc_private *msc, int zlp)
++{
++ if (msc->block_dev_state & DEVICE_EJECTED) {
++ TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_EJECTED");
++
++ (zlp ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
++ (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++
++ return -EINVAL;
++ }
++ if (msc->block_dev_state & DEVICE_CHANGE_ON) {
++ TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_CHANGE_ON");
++ (zlp ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
++ (msc, SCSI_SENSEKEY_NOT_READY_TO_CHANGE, msc->lba, USB_MSC_FAILED);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++
++/* READ 10 COMMAND - read and send data to the host ******************************************** */
++
++int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc);
++void msc_block_read_finished(struct buffer_head *bh, int flag);
++
++
++/* msc_scsi_read_10 - process a read(10) command
++ *
++ * We have received a READ(10) CBW, if transfer length is non-zero
++ * initiate a generic block i/o otherwise send a CSW.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_10(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_10_COMMAND *command = (SCSI_READ_10_COMMAND *)&msc->command.CBWCB;
++
++ RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
++
++ /*
++ * save the CBW information and setup for transmitting data read from the block device
++ */
++ msc->lba = be32_to_cpu(command->LogicalBlockAddress);
++ msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
++ msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
++ msc->command_state = MSC_DATA_IN_READ;
++ msc->io_state = MSC_INACTIVE;
++
++ /*
++ * Start reading blocks to send or simply send the CSW if the host
++ * didn't actually ask for a non-zero length.
++ */
++ return (msc->TransferLength_in_blocks) ? msc_start_reading_block_data(msc->function, msc) :
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_start_reading_block_data - start reading data
++ *
++ * Generate a generic block io request to read some data to transmit.
++ *
++ * This function is initially called by msc_scsi_read_10() but can also be called
++ * by msc_urb_sent() if the amount of data requested was too large.
++ *
++ * The function msc_block_read_finished() will be called to actually send the data
++ * to the host when the I/O request is complete.
++ *
++ */
++int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc)
++{
++ int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
++
++ TRACE_MSG1(MSC,"START READING BLOCK DATA lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"START READING BLOCK DATA blocks: %d", msc->TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"START READING BLOCK DATA blocks: %d", TransferLength_in_blocks);
++
++ if (msc->block_dev_state != DEVICE_INSERTED) {
++ TRACE_MSG0(MSC,"START READ MEDIUM NOT PRESENT");
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++ }
++
++ if (msc->lba >= msc->capacity) {
++ TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ }
++
++ // setup buffer head
++ msc->read_bh.b_size = TransferLength_in_blocks * msc->block_size;
++ msc->read_bh.b_end_io = msc_block_read_finished;
++ msc->read_bh.b_rsector = msc->lba;
++ msc->read_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
++ msc->io_state |= MSC_BLOCKIO_PENDING;
++ msc->read_bh.b_data = page_address(msc->read_bh.b_page);
++ memset(msc->read_bh.b_data, 0x0, msc->read_bh.b_size);
++
++ generic_make_request(READ, &msc->read_bh);
++ generic_unplug_device(blk_get_queue(msc->read_bh.b_rdev));
++
++ return 0;
++}
++
++
++/* msc_block_read_finished - called by generic request
++ *
++ * Called when block i/o read is complete, send the data to the host if possible.
++ *
++ * The function msc_urb_sent() will be called when the data is sent to
++ * either send additional data or the CSW as appropriate.
++ *
++ */
++void msc_block_read_finished(struct buffer_head *bh, int uptodate)
++{
++ struct msc_private *msc = bh->b_private;
++ int TransferLength_in_blocks = bh->b_size / msc->block_size;
++ struct usbd_function_instance *function;
++ struct usbd_urb *tx_urb;
++ int rc;
++ u32 crc;
++ int i;
++
++ msc_interrupts++;
++ TRACE_MSG1(MSC,"BLOCK READ FINISHED size: %x", bh->b_size);
++
++ /*
++ * Race condition here, if we have not finished sending the
++ * previous tx_urb then we want to simply exit and let
++ * msc_in_read_10_urb_sent() call us again.
++ *
++ * Ensure that we do not reset BLOCKIO flags if SEND PENDING and
++ * that we do reset BLOCKIO if not SEND PENDING
++ */
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++ if (msc->io_state & MSC_SEND_PENDING) {
++ TRACE_MSG0(MSC,"BLOCK READ SEND PENDING");
++ msc->io_state |= MSC_BLOCKIO_FINISHED;
++ msc->uptodate = uptodate;
++ local_irq_restore(flags);
++ return;
++ }
++ msc->io_state &= ~(MSC_BLOCKIO_PENDING | MSC_BLOCKIO_FINISHED);
++ local_irq_restore(flags);
++ }
++
++ // verify that the I/O completed
++ //
++ if (1 != uptodate) {
++ TRACE_MSG0(MSC,"BLOCK READ FAILED");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ // debug output trace
++ //
++ for (i = 0; i < bh->b_size / msc->block_size; i++) {
++ crc = crc32_compute(bh->b_data + (i * msc->block_size), msc->block_size, CRC32_INIT);
++ TRACE_RLBA(bh->b_rsector + i, crc);
++ }
++
++ // allocate a tx_urb and copy into it
++ //
++ THROW_IF(!(function = msc->function), error);
++ THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, bh->b_size, msc_urb_sent)), error);
++ TRACE_MSG1(MSC,"BLOCK READ FINISHED urb: %p", (int)tx_urb);
++
++ tx_urb->function_privdata = msc;
++ tx_urb->actual_length = tx_urb->buffer_length = bh->b_size;
++ memcpy(tx_urb->buffer, bh->b_data, bh->b_size);
++
++ msc->read_bh.b_data = NULL;
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++
++ msc->io_state |= MSC_SEND_PENDING;
++ msc->TransferLength_in_bytes -= bh->b_size;
++ msc->TransferLength_in_blocks -= TransferLength_in_blocks;
++ msc->lba += TransferLength_in_blocks;
++
++ if (!msc->TransferLength_in_blocks) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED - IO FINISHED");
++ // set flag so that CSW can be sent
++ msc->io_state |= MSC_DATA_IN_READ_FINISHED;
++ }
++ local_irq_restore(flags);
++ }
++
++ // dispatch urb
++ if ((rc = usbd_start_in_urb (tx_urb))) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED FAILED");
++ usbd_free_urb (tx_urb);
++ THROW(error);
++ }
++ if (!(msc->io_state & MSC_DATA_IN_READ_FINISHED)) {
++ TRACE_MSG0(MSC,"BLOCK READ SEND RESTARTING");
++ msc_start_reading_block_data(msc->function, msc);
++ return;
++ }
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"BLOCK READ FINISHED ERROR");
++ // stall?
++ }
++}
++
++/* msc_in_read_10_urb_sent - called by msc_urb_sent when state is MSC_DATA_IN_READ
++ *
++ * This will process a read_10 urb that has been sent. Specifically if any previous
++ * read_10 block I/O has finished we recall the msc_block_read_finished() function
++ * to transmit another read_10 urb.
++ *
++ * If there is no other pending read_10 to do we create and send a CSW.
++ *
++ * If there is more I/O to do or there is already an outstanding I/O we simply
++ * return after freeing the URB.
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc)
++{
++ unsigned long flags;
++
++ TRACE_MSG0(MSC,"URB SENT DATA IN");
++
++ /*
++ * Potential race condition here, we may need to restart blockio.
++ */
++
++ local_irq_save(flags);
++
++ msc->io_state &= ~MSC_SEND_PENDING;
++ msc->data_transferred_in_bytes += tx_urb->actual_length;
++
++ TRACE_MSG1(MSC,"URB SENT DATA IN data transferred: %d", msc->data_transferred_in_bytes);
++
++ if (!tx_urb->actual_length)
++ msc->TransferLength_in_blocks = 0;
++
++ usbd_free_urb (tx_urb);
++
++ /*
++ * Check to see if we need to send CSW.
++ */
++ if (MSC_DATA_IN_READ_FINISHED & msc->io_state) {
++ TRACE_MSG0(MSC,"URB SENT DATA IN - FINISHED SENDING CSW");
++ local_irq_restore(flags);
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ }
++ /*
++ * Check to see if there is a block read needs to be finished.
++ */
++ if (MSC_BLOCKIO_FINISHED & msc->io_state) {
++ TRACE_MSG0(MSC,"URB SENT DATA IN - RESTART");
++ local_irq_restore(flags);
++ // XXX uptodate?
++ msc_block_read_finished(&msc->read_bh, msc->uptodate);
++ return 0;
++ }
++ local_irq_restore(flags);
++ return 0;
++}
++
++
++/* WRITE 10 - receive data from host and write to block device ********************************* */
++
++int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc);
++void msc_data_written(struct buffer_head *bh, int flag);
++void msc_data_test(struct buffer_head *bh, int flag);
++
++/* msc_scsi_write_10 - process a write command
++ *
++ * Call either msc_start_receiving_data() or msc_start_sending_csw() as appropriate.
++ * Normally msc_start_receiving_data() is called and it will use msc_start_recv_urb()
++ * to setup a receive urb of the appropriate size.
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_write_10(struct msc_private *msc, char *name, int op)
++{
++ SCSI_WRITE_10_COMMAND *command = (SCSI_WRITE_10_COMMAND *)&msc->command.CBWCB;
++
++ RETURN_ZERO_IF (msc_check_blockdev(msc, 0));
++
++ // save the CBW and setup for receiving data to be written to the block device
++ //
++ msc->lba = be32_to_cpu(command->LogicalBlockAddress);
++ msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
++ msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
++
++ msc->command_state = MSC_DATA_OUT_WRITE;
++ msc->io_state = MSC_INACTIVE;
++
++ TRACE_MSG1(MSC,"RECV WRITE lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"RECV WRITE blocks: %d", msc->TransferLength_in_blocks);
++
++ return (msc->TransferLength_in_blocks) ?
++ msc_start_receiving_data(msc->function, msc) :
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_start_receiving_data - called to initiate an urb to receive WRITE(10) data
++ *
++ * Initiate a receive urb to receive upto PAGE_SIZE WRITE(10) data. The
++ * msc_recv_urb() function will call msc_recv_out_blocks() to actually
++ * write the data.
++ *
++ * This is called from msc_scsi_write_10() to initiate the WRITE(10) and
++ * called from msc_data_written() to start the next page sized receive
++ * urb.
++ *
++ */
++int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc)
++{
++ /*
++ * Calculating the length is most of the work we do :-)
++ */
++ int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
++
++ TRACE_MSG1(MSC,"START RECEIVING DATA lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", msc->TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"START RECEIVING DATA bytes: %d", TransferLength_in_blocks * msc->block_size);
++
++ THROW_IF(msc->command_state != MSC_DATA_OUT_WRITE, error);
++ THROW_IF(!msc->TransferLength_in_blocks, error);
++
++ msc->io_state |= MSC_RECV_PENDING;
++
++ return msc_start_recv_urb(function, msc, TransferLength_in_blocks * msc->block_size);
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"START RECEIVING DATA ERROR");
++ return -EINVAL;
++ }
++}
++
++
++/* msc_recv_out_blocks - process received WRITE(10) data by writing to block device
++ *
++ * We get here indirectly from msc_recv_urb() when state is MSC_DATA_OUT_WRITE.
++ *
++ * Dealloc the urb and call Initiate the generic request to write the
++ * received data. The b_end_io function msc_data_written() will send the
++ * CSW.
++ *
++ */
++void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc)
++{
++ int TransferLength_in_bytes = rcv_urb->actual_length;
++ int TransferLength_in_blocks = TransferLength_in_bytes / msc->block_size;
++ u32 crc;
++ int i;
++
++ TRACE_MSG1(MSC,"RECV OUT bytes: %d", TransferLength_in_bytes);
++ TRACE_MSG1(MSC,"RECV OUT iostate: %x", msc->io_state);
++ TRACE_MSG1(MSC,"RECV OUT data transferred: %d", msc->data_transferred_in_bytes);
++
++ /*
++ * Race condition here, we may get to here before the previous block
++ * write completed. If so just exit and the msc_data_written()
++ * function will recall us.
++ */
++ {
++ unsigned long flags;
++ local_irq_save(flags);
++ if (msc->io_state & MSC_BLOCKIO_PENDING) {
++ TRACE_MSG0(MSC,"RECV OUT BLOCKIO PENDING");
++ msc->io_state |= MSC_RECV_FINISHED;
++ msc->rcv_urb_finished = rcv_urb;
++ local_irq_restore(flags);
++ return;
++ }
++ msc->io_state &= ~(MSC_RECV_PENDING |MSC_RECV_FINISHED);
++ local_irq_restore(flags);
++ }
++
++ msc->data_transferred_in_bytes += rcv_urb->actual_length;
++
++ for (i = 0; i < TransferLength_in_blocks; i++) {
++ crc = crc32_compute(rcv_urb->buffer + (i * msc->block_size), msc->block_size, CRC32_INIT);
++ TRACE_SLBA(msc->lba + i, crc);
++ }
++
++ msc->write_bh.b_data = page_address(msc->write_bh.b_page);
++ memcpy(msc->write_bh.b_data, rcv_urb->buffer, rcv_urb->actual_length);
++
++ usbd_free_urb(rcv_urb);
++
++ if (msc->block_dev_state != DEVICE_INSERTED) {
++ TRACE_MSG0(MSC,"START READ MEDIUM NOT PRESENT");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ if (msc->lba >= msc->capacity) {
++ TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ if (!msc->TransferLength_in_blocks) {
++ TRACE_MSG0(MSC,"START READ LBA TransferLength_in_blocks zero:");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
++ return;
++ }
++
++ // Initiate writing the data
++
++ TRACE_MSG1(MSC,"RECV OUT lba: %x", msc->lba);
++ TRACE_MSG1(MSC,"RECV OUT blocks left: %d", msc->TransferLength_in_blocks);
++ TRACE_MSG1(MSC,"RECV OUT blocks current: %d", TransferLength_in_blocks);
++
++
++ // set address in buffer head
++ msc->write_bh.b_size = TransferLength_in_bytes;
++ msc->write_bh.b_rsector = msc->lba;
++
++ // decrement counters and increment address
++ msc->TransferLength_in_bytes -= TransferLength_in_bytes;
++ msc->TransferLength_in_blocks -= TransferLength_in_blocks;
++ msc->lba += TransferLength_in_blocks;
++ msc->write_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
++ msc->write_bh.b_end_io = msc_data_written;
++ msc->io_state |= MSC_BLOCKIO_PENDING;
++
++
++ // start new urb here
++ if (!msc->TransferLength_in_blocks)
++ msc->command_state = MSC_DATA_OUT_WRITE_FINISHED;
++ else
++ msc_start_receiving_data(msc->function, msc);
++
++ generic_make_request(WRITE, &msc->write_bh);
++ generic_unplug_device(blk_get_queue(msc->write_bh.b_rdev));
++}
++
++
++/* msc_data_written - called by generic request
++ *
++ * Called when current block i/o read is finished, restart block i/o or send the CSW.
++ *
++ */
++void msc_data_written(struct buffer_head *bh, int uptodate)
++{
++ struct msc_private *msc = bh->b_private;
++ unsigned long flags;
++ u8 io_state;
++
++ msc_interrupts++;
++
++ TRACE_MSG4(MSC,"DATA WRITTEN uptodate: %x b_state: %x state: %x io: %x",
++ uptodate, bh->b_state, msc->command_state, msc->io_state);
++
++ TRACE_MSG1(MSC,"DATA WRITTEN lba: %x", msc->lba);
++
++ local_irq_save(flags);
++ io_state = msc->io_state &= ~MSC_BLOCKIO_PENDING;
++ msc->write_bh.b_data = NULL;
++ local_irq_restore(flags);
++
++ /*
++ * verify that the I/O completed
++ */
++ if (1 != uptodate) {
++ TRACE_MSG0(MSC,"BLOCK READ FAILED");
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
++ // XXX CHECKME
++ if (msc->rcv_urb_finished) {
++ usbd_free_urb(msc->rcv_urb_finished);
++ msc->rcv_urb_finished = NULL;
++ }
++ return;
++ }
++ /*
++ * If there was a rcv_urb that was not processed then we need
++ * to process it now. This is done by simply restarting msc_recv_out()
++ */
++ if ((io_state & MSC_RECV_FINISHED) && msc->rcv_urb_finished) {
++ struct usbd_urb *rcv_urb = msc->rcv_urb_finished;
++ msc->rcv_urb_finished = NULL;
++ TRACE_MSG0(MSC,"DATA WRITTEN RECV FINISHED");
++ msc_recv_out_blocks(rcv_urb, msc);
++ }
++ /*
++ * DATA_IN mode and no more data to write
++ */
++ if (MSC_DATA_OUT_WRITE_FINISHED == msc->command_state) {
++ // finished, send CSW
++ TRACE_MSG0(MSC,"DATA WRITTEN send CSW");
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ }
++}
++
++
++/* SCSI Commands ******************************************************************************* */
++
++/* msc_scsi_inquiry - process an inquiry
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_inquiry(struct msc_private *msc, char *name, int op)
++{
++ SCSI_INQUIRY_COMMAND *command = (SCSI_INQUIRY_COMMAND *)&msc->command.CBWCB;
++ SCSI_INQUIRY_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_INQUIRY_DATA);
++
++ /*
++ * C.f. SPC2 7.3 INQUIRY command
++ * C.f. Table 46 - Standard INQUIRY data format
++ *
++ * C.f. Table 47 - Peripheral Qualifier
++ *
++ * 000b The specified peripheral device type is currently connected to this
++ * logical unit.....
++ * 001b The device server is capable of of supporting the peripheral device
++ * type on this logical unit. However, the physical device is not currently
++ * connected to this logical unit.....
++ * 010b Reserved
++ * 011b The device server is not capable of supporting a physical device on
++ * this logical unit....
++ *
++ */
++
++ TRACE_MSG4(MSC,"INQUIRY EnableVPD: %02x LogicalUnitNumber: %02x PageCode: %02x AllocLen: %02x",
++ command->EnableVPD, command->LogicalUnitNumber, command->PageCode, command->AllocationLength);
++
++ // XXX THROW_IF(msc->command_state != MSC_READY, error);
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_INQUIRY_DATA *)urb->buffer;
++ data->PeripheralQaulifier = msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON) ? 0x1 : 0;
++ data->PeripheralDeviceType = 0x00;
++ data->RMB = 0x1;
++ data->ResponseDataFormat = 0x1;
++ data->AdditionalLength = 0x1f;
++
++ strncpy(data->VendorInformation, CONFIG_OTG_MSC_MANUFACTURER, strlen(CONFIG_OTG_MSC_MANUFACTURER));
++ strncpy(data->ProductIdentification, CONFIG_OTG_MSC_PRODUCT_NAME, strlen(CONFIG_OTG_MSC_PRODUCT_NAME));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++
++/* old_msc_scsi_read_format_capacity - process a query
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int old_msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op)
++{
++ // send ZLP then CSW
++ return msc_dispatch_query_urb_zlp(msc, 0, 0, USB_MSC_PASSED);
++}
++
++/* msc_scsi_read_format_capacity - process a query
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_FORMAT_CAPACITY_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_READ_FORMAT_CAPACITY_DATA);
++ u32 block_num = msc->capacity;
++ u32 block_len;
++
++
++
++ /*
++ * If we don't have a valid block device then simply
++ * send a ZLP.
++ *
++ * XXX VERIFY this is correct thing to do for this situation.
++ */
++ //if (msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON))
++ // return msc_dispatch_query_urb_zlp(msc);
++ RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_READ_FORMAT_CAPACITY_DATA *) urb->buffer;
++
++ data->CapacityListHeader.CapacityListLength = sizeof(data->CurrentMaximumCapacityDescriptor);
++
++ data->CurrentMaximumCapacityDescriptor.NumberofBlocks = block_num;
++ data->CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
++ memcpy(data->CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len, sizeof(block_len));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/* msc_read_capacity - process a read_capacity command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_read_capacity(struct msc_private *msc, char *name, int op)
++{
++ SCSI_READ_CAPACITY_COMMAND *command = (SCSI_READ_CAPACITY_COMMAND *)&msc->command.CBWCB;
++ SCSI_READ_CAPACITY_DATA *data;
++ struct usbd_urb *urb;
++ int length = 8;
++ u32 lba;
++
++ /*
++ * C.f. RBC 5.3
++ */
++
++ /*
++ * If we don't have a valid block device then simply
++ * send a ZLP.
++ *
++ * XXX VERIFY this is correct thing to do for this situation.
++ */
++ //if (msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON))
++ // return msc_dispatch_query_urb_zlp(msc);
++
++ RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
++
++ //memcpy(&lba, &command->LogicalBlockAddress, 4);
++ //lba = be32_to_cpu(lba);
++
++ lba = be32_to_cpu(command->LogicalBlockAddress);
++
++ TRACE_MSG1(MSC,"READ CAPACITY LBA: %d", lba);
++
++ if ((command->PMI > 1) || (!command->PMI && lba)) {
++ TRACE_MSG1(MSC,"READ CAPACITY PMI: %d", command->PMI);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, lba, USB_MSC_FAILED);
++ }
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_READ_CAPACITY_DATA *) urb->buffer;
++
++ data->LastLogicalBlockAddress = cpu_to_be32(msc->capacity);
++ data->BlockLengthInBytes = cpu_to_be32(msc->block_size);
++
++ TRACE_MSG1(MSC,"RECV READ CAPACITY lba: %x", be32_to_cpu(data->LastLogicalBlockAddress));
++ TRACE_MSG1(MSC,"RECV READ CAPACITY block_size: %x", be32_to_cpu(data->BlockLengthInBytes));
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_request_sense - process a request_sense command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_request_sense(struct msc_private *msc, char *name, int op)
++{
++ SCSI_REQUEST_SENSE_COMMAND* command = (SCSI_REQUEST_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_REQUEST_SENSE_DATA *data;
++
++ /*
++ * C.f. SPC2 7.20 REQUEST SENSE command
++ */
++
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_REQUEST_SENSE_DATA);
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ data = (SCSI_REQUEST_SENSE_DATA *) urb->buffer;
++ memset(command, 0x0, length);
++ data->ErrorCode = SCSI_ERROR_CURRENT;
++ data->SenseKey = msc->sensedata >> 16;
++ data->AdditionalSenseCode = msc->sensedata >> 8;
++ data->AdditionalSenseCodeQualifier = msc->sensedata;
++ data->Valid = 1;
++
++ set_sense_data(msc, SCSI_SENSEKEY_NO_SENSE, 0);
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/* msc_scsi_mode_sense - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int old_msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
++{
++ SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_MODE_SENSE_DATA *data;
++ int length = sizeof(SCSI_MODE_SENSE_DATA);
++
++ struct usbd_urb *urb;
++ u8 *cp;
++
++
++ TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x",
++ command->DBD,
++ command->PageControl,
++ command->PageCode,
++ 0);
++
++ length = 8;
++
++ // alloc urb
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++
++ cp = (u8 *) urb->buffer;
++ memset(cp, 0x0, length);
++
++ cp[0] = 0;
++ cp[1] = 0;
++ cp[2] = 0; // 0x80 is writeprotect
++ cp[3] = 0x08;
++ cp[4] = 0;
++ cp[5] = 0;
++ cp[6] = 0;
++ cp[7] = 0;
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++/* msc_scsi_mode_sense - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
++{
++
++ /*
++ * C.f. SPC2 7.8.1 MODE SENSE(6) command
++ */
++
++ static READ_WRITE_ERROR_RECOVERY_PAGE page_01 = {
++ PageCode:0x01,
++ PageLength:0x0A,
++ ReadRetryCount:0x03,
++ WriteRetryCount:0x80,
++ };
++ static FLEXIBLE_DISK_PAGE page_05 = {
++ PageCode:0x05,
++ PageLength:0x1E,
++ TransferRate:__constant_cpu_to_be16(0xFA00),
++ NumberofHeads:0xA0,
++ SectorsperTrack:0x00,
++ DataBytesperSector:__constant_cpu_to_be16(0x0002),
++ NumberofCylinders:__constant_cpu_to_be16(0x0000),
++ MotorOnDelay:0x05,
++ MotorOffDelay:0x1E,
++ MediumRotationRate:__constant_cpu_to_be16(0x6801),
++ };
++ static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
++ PageCode:0x1B,
++ PageLength:0x0A,
++ TLUN:0x01,
++ };
++ static TIMER_AND_PROTECT_PAGE page_1c = {
++ PageCode:0x1c,
++ PageLength:0x06,
++ InactivityTimeMultiplier:0x0A,
++ };
++
++ SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
++ SCSI_MODE_SENSE_DATA *data;
++ struct usbd_urb *urb;
++ int length = sizeof(SCSI_MODE_SENSE_DATA);
++
++ TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x",
++ command->DBD,
++ command->PageControl,
++ command->PageCode,
++ 0);
++
++
++ if (msc->block_dev_state & DEVICE_EJECTED) {
++ u16 sector = htons((unsigned short)msc->block_size);
++ u16 cylinder = 0;
++ page_05.NumberofHeads = 0;
++ page_05.SectorsperTrack = 0;
++ memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++ }
++ else {
++ u16 sector = htons((unsigned short)msc->block_size);
++ u32 size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
++ u16 cylinder = htons(msc->capacity / size);
++ page_05.NumberofHeads = DEF_NUMBER_OF_HEADS;
++ page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK;
++ memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++
++ }
++
++
++ if (SCSI_MODEPAGE_CONTROL_CURRENT != command->PageControl) {
++ TRACE_MSG2(MSC,"MODE SENSE - requeested other than CONTROL_CURRENT: %d %d",
++ command->PageControl, command->PageCode);
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
++ }
++
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
++ data = (SCSI_MODE_SENSE_DATA *) urb->buffer;
++
++ data->ModeParameterHeader.WriteProtect = msc->block_dev_state & DEVICE_WRITE_PROTECTED ? 1 : 0;
++
++ switch (command->PageCode) {
++ case SCSI_MODEPAGE_ERROR_RECOVERY:
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_01, sizeof(page_01));
++ break;
++ case SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE:
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_05, sizeof(page_05));
++ break;
++ case SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS:
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_1b, sizeof(page_1b));
++ break;
++ case SCSI_MODEPAGE_INFORMATION_EXCEPTIONS:
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages, &page_1c, sizeof(page_1c));
++ break;
++ case SCSI_MODEPAGE_ALL_SUPPORTED:
++ length = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
++ data->ModeParameterHeader.ModeDataLength = length - 1;
++ memcpy(&data->ModePages.ModeAllPages.ReadWriteErrorRecoveryPage, &page_01, sizeof(page_01));
++ memcpy(&data->ModePages.ModeAllPages.FlexibleDiskPage, &page_05, sizeof(page_05));
++ memcpy(&data->ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage, &page_1b, sizeof(page_1b));
++ memcpy(&data->ModePages.ModeAllPages.TimerAndProtectPage, &page_1c, sizeof(page_1c));
++ break;
++ case SCSI_MODEPAGE_CACHING:
++ // see file_storage.c for an example if we want to support this
++ break;
++ }
++
++ TRACE_MSG2(MSC,"LENGTH: %d %d", msc->command.dCBWDataTransferLength, length);
++
++ /*
++ * XXX verify that length is <= 256 bytes, return CHECK_CONDITION if it is
++ */
++ length = MIN(msc->command.dCBWDataTransferLength, length);
++
++ return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_test_unit_ready - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_test_unit_ready(struct msc_private *msc, char *name, int op)
++{
++ /*
++ * C.f. SPC2 7.25 TEST UNIT READY command
++ *
++ * Return GOOD, illegal request for bad LUN or NOT READY
++ *
++ */
++ RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_prevent_allow - process a request_sense command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_prevent_allow(struct msc_private *msc, char *name, int op)
++{
++ SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*)&msc->command.CBWCB;
++
++ /*
++ * C.f. SPC2 7.12 Table 78 PREVENT ALLOW MEDIUM REMOVAL Prevent Field
++ *
++ * 00b Medium removal shall be allowed from both the data transport
++ * element and the attached medium changer (if any).
++ * 01b Medium removal shall be prohibited from the data transport
++ * element but allowed from the attached medium changer (if any).
++ * 10b Medium removal shall be allowed for the data transport element
++ * but prohibited for the attached medium changer.
++ * 11b Medium remval shall be prohibited from both the data transport
++ * element and the attached medium changer
++ *
++ * Prevention shall terminate after 00b or 10b, after a SYNC CACHE or hard reset.
++ */
++
++ TRACE_MSG1(MSC,"PREVENT: %d", command->Prevent);
++
++ RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
++
++
++ // XXX TODO
++ // this is from storageproto.c, shouldn't we implement something?
++ if (command->Prevent)
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD, msc->lba, USB_MSC_FAILED);
++
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_start_stop - process a request_sense command
++ *
++ * C.f. RBC 5.4 and 5.4.2
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_start_stop(struct msc_private *msc, char *name, int op)
++{
++ SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)&msc->command.CBWCB;
++
++ TRACE_MSG4(MSC,"START STOP: Immed: %d Power: %x LoEj: %d Start: %d",
++ command->IMMED, command->PowerConditions, command->LoEj, command->Start);
++
++ /*
++ * C.f. 5.4
++ *
++ * IMMED - if set return status immediately after command validation, otherwise
++ * return status as soon operation is completed.
++ *
++ * C.f. 5.4.1 Table 8 POWER CONDITIONS
++ *
++ * 0 - M - no change in power condition
++ * 1 - M - place device in active condition
++ * 2 - M - place device in idle condition
++ * 3 - M - place device in Standby condition
++ * 4 - - reserved
++ * 5 - M - place device in Sleep condition
++ * 6 - - reserved
++ * 7 - 0 - Device Control
++ *
++ * C.f. 5.4.2 Table 9 START STOP control bit definitions
++ *
++ * Power Load/Eject Start
++ * 1-7 x x LoEj and Start Ignored
++ * 0 0 0 Stop the medium
++ * 0 0 1 Make the medium ready
++ * 0 1 0 Unload the medium
++ * 0 1 1 Load the medium
++ *
++ */
++
++
++ RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
++
++ // XXX TODO
++ // this is from storageproto.c, shouldn't we implement something?
++
++ if (command->Start && command->LoEj)
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD, msc->lba, USB_MSC_FAILED);
++
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_verify - process a verify command
++ *
++ * Used by:
++ * win2k
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_verify(struct msc_private *msc, char *name, int op)
++{
++ SCSI_VERIFY_COMMAND *command = (SCSI_VERIFY_COMMAND *)&msc->command.CBWCB;
++ /*
++ * C.f. RBC 5.7 VERIFY command
++ */
++ // XXX This actually should use the read_10 function and when
++ // finished reading simply send the following
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_scsi_mode_select - process a select command
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_scsi_mode_select(struct msc_private *msc, char *name, int op)
++{
++ //SCSI_MODE_SELECT_COMMAND *command = (SCSI_MODE_SELECT_COMMAND *)&msc->command.CBWCB;
++
++ /*
++ * C.f. SPC2 7.6 MODE SELECT(6) command
++ */
++
++ // if less than correct amount of data return USB_MSC_PHASE_ERROR - see MV
++ //
++ return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++}
++
++
++/* msc_cmd_unknown - process an unknown command
++ *
++ *
++ * Returns non-zero if there is an error in the USB layer.
++ */
++int msc_cmd_unknown(struct msc_private *msc, char *name, int op)
++{
++ /*
++ struct usbd_urb *urb;
++ RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1))); // XXX +1 ?
++ urb->flags |= USBD_URB_SENDZLP;
++ return msc_dispatch_query_urb(urb, msc, 0);
++ */
++
++ printk(KERN_ERR"%s: NOT IMPLEMENTED %s opcode: %02x\n", __FUNCTION__, name, op);
++
++ // should we send ZLP for unknow commands?
++ // return msc_dispatch_query_urb_zlp(msc);
++
++ // or failed
++ return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++}
++
++
++struct rbc_dispatch {
++ u8 op;
++ char *name;
++ int (*rbc_command) (struct msc_private *, char *, int op);
++};
++
++/* Command cross reference
++ *
++ * This is the list of commands observed from each host OS. It is necessarily
++ * incomplete in that we not have reached some condition necessary to have
++ * other commands used.
++ * Win2k WinXP
++ * SCSI_TEST_UNIT_READY yes yes
++ * SCSI_READ_10 yes yes
++ * SCSI_WRITE_10 yes yes
++ * SCSI_READ_CAPACITY yes yes
++ * SCSI_VERIFY yes
++ * SCSI_INQUIRY yes yes
++ * SCSI_MODE_SENSE yes
++ * SCSI_READ_FORMAT_CAPACITY yes yes
++ * SCSI_REQUEST_SENSE
++ * SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL
++ * SCSI_START_STOP
++ * SCSI_MODE_SELECT
++ * SCSI_FORMAT_UNIT
++ *
++ */
++
++struct rbc_dispatch rbc_dispatch_table[] = {
++ { SCSI_TEST_UNIT_READY, "SCSI_TEST_UNIT_READY", msc_scsi_test_unit_ready }, //
++ { SCSI_READ_10, "SCSI_READ_10", msc_scsi_read_10 }, //
++ { SCSI_WRITE_10, "SCSI_WRITE_10", msc_scsi_write_10 }, //
++ { SCSI_READ_CAPACITY, "SCSI_READ_CAPACITY", msc_scsi_read_capacity }, //
++ { SCSI_VERIFY, "SCSI_VERIFY", msc_scsi_verify }, //
++ { SCSI_INQUIRY, "SCSI_INQUIRY", msc_scsi_inquiry }, //
++ { SCSI_MODE_SENSE, "SCSI_MODE_SENSE", msc_scsi_mode_sense }, //
++ { SCSI_READ_FORMAT_CAPACITY, "SCSI_READ_FORMAT_CAPACITY", msc_scsi_read_format_capacity }, //
++ { SCSI_REQUEST_SENSE, "SCSI_REQUEST_SENSE", msc_scsi_request_sense }, //
++ { SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL", msc_scsi_prevent_allow }, //
++ { SCSI_START_STOP, "SCSI_START_STOP", msc_scsi_start_stop }, //
++ { SCSI_MODE_SELECT, "SCSI_MODE_SELECT", msc_scsi_mode_select },
++ { SCSI_FORMAT_UNIT, "SCSI_FORMAT_UNIT", msc_cmd_unknown },
++
++ { SCSI_READ_6, "SCSI_READ_6", msc_cmd_unknown },
++ { SCSI_WRITE_6, "SCSI_WRITE_6", msc_cmd_unknown },
++ { SCSI_RESERVE, "SCSI_RESERVE", msc_cmd_unknown },
++ { SCSI_RELEASE, "SCSI_RELEASE", msc_cmd_unknown },
++ { SCSI_SEND_DIAGNOSTIC, "SCSI_SEND_DIAGNOSTIC", msc_cmd_unknown },
++ { SCSI_SYNCHRONIZE_CACHE, "SCSI_SYNCHRONIZE_CACHE", msc_cmd_unknown },
++ { SCSI_MODE_SENSE_10, "SCSI_MODE_SENSE_10", msc_cmd_unknown },
++ { SCSI_REZERO_UNIT, "SCSI_REZERO_UNIT", msc_cmd_unknown },
++ { SCSI_SEEK_10, "SCSI_SEEK_10", msc_cmd_unknown },
++ { SCSI_WRITE_AND_VERIFY, "SCSI_WRITE_AND_VERIFY", msc_cmd_unknown },
++ { SCSI_WRITE_12, "SCSI_WRITE_12", msc_cmd_unknown },
++ { SCSI_READ_12, "SCSI_READ_12", msc_cmd_unknown },
++
++ { 0xff, "SCSI_UNKNOWN", msc_cmd_unknown },
++};
++
++
++/* msc_recv_command - process a new CBW
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++int msc_recv_command(struct usbd_urb *urb, struct msc_private *msc)
++{
++ COMMAND_BLOCK_WRAPPER *command = (COMMAND_BLOCK_WRAPPER *)urb->buffer;
++ u8 op = command->CBWCB[0];
++ struct rbc_dispatch *dispatch;
++
++ /*
++ * c.f. section 6.2 - Valid and Meaningful CBW
++ * c.f. section 6.2.1 - Valid CBW
++ *
++ * The CBW was received after the device had sent a CSW or after a
++ * reset XXX check that we only set MSC_READY after reset or sending
++ * CSW.
++ *
++ * The CBW is 31 (1Fh) bytes in length and the bCBWSignature is
++ * equal to 43425355h.
++ */
++ THROW_IF(31 != urb->actual_length, error);
++ THROW_IF(CBW_SIGNATURE != le32_to_cpu(command->dCBWSignature), error);
++
++ /*
++ * c.f. section 6.2.2 - Meaningful CBW
++ *
++ * no reserved bits are set
++ * the bCBWLUN contains a valid LUN supported by the device
++ * both bCBWCBlength and the content of the CBWCB are in accordance with bInterfaceSubClass
++ */
++
++ // XXX checklun etc
++
++ /*
++ * Success
++ */
++ memcpy(&msc->command, command, sizeof(COMMAND_BLOCK_WRAPPER));
++ msc->data_transferred_in_bytes = msc->TransferLength_in_blocks = msc->TransferLength_in_bytes = 0;
++
++ TRACE_TAG(command->dCBWTag, urb->framenum);
++ usbd_free_urb(urb);
++
++ /*
++ * Search using the opcode to find the dispatch function to use and
++ * call it.
++ */
++ for (dispatch = rbc_dispatch_table; dispatch->op != 0xff; dispatch++) {
++ if ((dispatch->op == op)) {
++ TRACE_CBW(dispatch->name, dispatch->op);
++ TRACE_RECV(&(command->CBWCB[1]));
++ if (dispatch->rbc_command(msc, dispatch->name, op))
++ TRACE_MSG0(MSC,"COMMAND ERROR");
++ return 0;
++ }
++ }
++ /* FALL THROUGH if no match is found */
++
++ THROW_IF(msc_cmd_unknown(msc, "CMD_UNKNOWN", op), error);
++ return 0;
++
++ CATCH(error) {
++ TRACE_MSG0(MSC,"RECV CBW ERROR");
++ }
++
++ /*
++ * default behaviour is to stall or send ZLP on BULK-IN endpoint
++ */
++ TRACE_CBW("UNKNOWN COMMAND", op);
++
++ /*
++ * We cannot return error as we have deallocated urb and there is no
++ * other sensible course of action that the usbdcore layer can take
++ * for us.
++ */
++ return 0;
++}
++
++
++/* Sent Function - process a sent urb ********************************************************** */
++
++/* msc_urb_sent - called to indicate URB transmit finished
++ * @urb: pointer to struct usbd_urb
++ * @rc: result
++ *
++ * This is called when an urb is sent. Depending on current state
++ * it may:
++ *
++ * - continue sending data
++ * - send a CSW
++ * - start a recv for a CBW
++ *
++ * This is called from BOTTOM HALF context.
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++int msc_urb_sent (struct usbd_urb *tx_urb, int rc)
++{
++ struct usbd_function_instance *function;
++ struct msc_private *msc = &msc_private;
++
++ msc_interrupts++;
++
++ TRACE_MSG1(MSC,"URB SENT tx_urb: %p", (int)tx_urb);
++ TRACE_MSG1(MSC,"URB SENT function: %p", (int)tx_urb->function_instance);
++
++ RETURN_EINVAL_IF(!(function = tx_urb->function_instance));
++
++ TRACE_MSG1(MSC,"URB SENT status: %p", usbd_get_device_status(function));
++ RETURN_EINVAL_IF(usbd_get_device_status(function) == USBD_CLOSING);
++
++ TRACE_MSG1(MSC,"URB SENT state: %p", usbd_get_device_state(function));
++ RETURN_EINVAL_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
++
++ switch (msc->command_state) {
++ case MSC_DATA_IN_READ:
++ case MSC_DATA_IN_READ_FINISHED:
++ TRACE_MSG0(MSC,"URB SENT READ");
++ return msc_in_read_10_urb_sent(tx_urb, msc);
++ case MSC_QUERY:
++ // finished, send CSW
++ TRACE_MSG0(MSC,"URB SENT QUERY");
++ msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
++ break;
++ case MSC_STATUS:
++ default:
++ // sent a CSW need to receive the next CBW
++ TRACE_MSG0(MSC,"URB SENT STATUS");
++ msc->command_state = MSC_READY;
++ msc_start_recv_urb(msc->function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
++ break;
++ }
++ usbd_free_urb (tx_urb);
++ return 0;
++}
++
++
++/* Receive Function - receiving an urb ********************************************************* */
++
++/* msc_recv_urb - process a received urb
++ *
++ * Return non-zero if urb was not disposed of.
++ */
++static int msc_recv_urb (struct usbd_urb *rcv_urb, int rc)
++{
++ struct msc_private *msc = &msc_private;
++
++ msc_interrupts++;
++
++ RETURN_EINVAL_IF(!msc->connected);
++
++ TRACE_MSG2(MSC, "RECV URB length: %d state: %d", rcv_urb->actual_length, msc->command_state);
++
++ switch(msc->command_state) {
++
++ // ready to start a new transaction
++ case MSC_READY:
++ return msc_recv_command(rcv_urb, msc);
++
++ // we think we are receiving data
++ case MSC_DATA_OUT_WRITE:
++ case MSC_DATA_OUT_WRITE_FINISHED:
++ msc_recv_out_blocks(rcv_urb, msc);
++ return 0;
++
++ // we think we are sending data
++ case MSC_DATA_IN_READ:
++ case MSC_DATA_IN_READ_FINISHED:
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++ break;
++
++ // we think we are sending status
++ case MSC_STATUS:
++ msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
++ break;
++
++ // we don't think
++ case MSC_UNKNOWN:
++ default:
++ TRACE_MSG0(MSC,"RECV URB ERROR");
++ }
++ // let caller dispose of urb
++ return -EINVAL;
++}
++
++/* USB Device Functions ************************************************************************ */
++
++/* msc_event_handler - process a device event
++ *
++ * This function is called when an USBD event occurs.
++ *
++ * This is called from INTERRUPT context.
++ */
++void msc_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct msc_private *msc = &msc_private;
++
++ msc_interrupts++;
++
++ TRACE_MSG1(MSC,"EVENT IRQ %d", event);
++
++ switch (event) {
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(MSC,"EVENT CONFIGURED");
++ msc->connected = 1;
++ msc->command_state = MSC_READY;
++ msc_start_recv_urb(function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
++ break;
++
++ case DEVICE_BUS_INACTIVE:
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG0(MSC,"EVENT RESET");
++ BREAK_IF(!msc->connected);
++ msc->connected = 0;
++ if (msc->rcv_urb_finished) {
++ usbd_free_urb (msc->rcv_urb_finished);
++ msc->rcv_urb_finished = NULL;
++ }
++ break;
++
++ default:
++ TRACE_MSG0(MSC,"EVENT IGNORED");
++ break;
++ }
++}
++
++
++/* msc_device_request - called to indicate urb has been received
++ *
++ * This function is called when a SETUP packet has been received that
++ * should be handled by the function driver. It will not be called to
++ * process the standard chapter nine defined requests.
++ *
++ * Return non-zero for failure.
++ */
++int msc_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct msc_private *msc = &msc_private;
++ struct usbd_urb *urb;
++
++ TRACE_MSG0(MSC,"RECV SETUP");
++ msc_interrupts++;
++
++ // verify that this is a usb class request per cdc-acm specification or a vendor request.
++ RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
++
++ // determine the request direction and process accordingly
++ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
++
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case MSC_BULKONLY_RESET:
++ // XXX TODO FIXME
++ return 0;
++ }
++
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
++ switch (request->bRequest) {
++ case MSC_BULKONLY_GETMAXLUN:
++ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, 1, NULL)));
++ urb->buffer[0] = 0;
++ urb->actual_length = 1;
++ RETURN_ZERO_IF(!usbd_start_in_urb(urb));
++ usbd_free_urb(urb);
++ return -EINVAL;
++ }
++ default:
++ break;
++ }
++ return -EINVAL;
++}
++
++/* msc_function_enable - this is called by the USBD core layer
++ *
++ * This is called to initialize the function when a bus interface driver
++ * is loaded.
++ */
++static int msc_function_enable (struct usbd_function_instance *function)
++{
++ struct msc_private *msc = &msc_private;
++
++ MOD_INC_USE_COUNT;
++
++ // XXX TODO need to verify that serial number is minimum of 12
++
++ msc_interrupts++;
++
++ msc->function = function;
++ msc->command_state = MSC_READY;
++
++ //msc_open_blockdev(msc);
++ return 0;
++}
++
++/* msc_function_disable - this is called by the USBD core layer
++ *
++ * This is called to close the function when a bus interface driver
++ * is unloaded.
++ */
++static void msc_function_disable (struct usbd_function_instance *function)
++{
++ struct msc_private *msc = &msc_private;
++
++ msc_interrupts++;
++
++ TRACE_MSG0(MSC,"FUNCTION EXIT");
++
++ msc->function = NULL;
++
++ MOD_DEC_USE_COUNT;
++}
++
++static struct usbd_function_operations function_ops = {
++ event_handler: msc_event_handler,
++ device_request: msc_device_request,
++ function_enable: msc_function_enable,
++ function_disable: msc_function_disable,
++};
++
++static struct usbd_function_driver function_driver = {
++ name: "msc-bulkonly",
++ fops:&function_ops,
++ device_description:&msc_device_description,
++ bNumConfigurations:sizeof (msc_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:msc_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
++ bNumInterfaces:sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:msc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: msc_endpoint_requests,
++};
++
++
++/* USB Module init/exit ************************************************************************ */
++
++/*
++ * msc_modinit - module init
++ *
++ */
++static int msc_modinit (void)
++{
++ int rc;
++ struct msc_private *msc = &msc_private;
++
++ printk(KERN_INFO "Copyright (c) 2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
++ printk (KERN_INFO "%s vendor_id: %04x product_id: %04x major: %d minor: %d\n", __FUNCTION__,
++ vendor_id, product_id, major, minor);
++
++ if (vendor_id)
++ function_driver.idVendor = cpu_to_le16(vendor_id);
++ if (product_id)
++ function_driver.idProduct = cpu_to_le16(product_id);
++
++ init_waitqueue_head(&msc->msc_wq);
++#if 0
++ /*
++ * Check device information and verify access to the block device.
++ */
++ RETURN_EINVAL_IF(!major && !minor);
++ msc->dev = MKDEV(major, minor);
++ if(!(msc->bdev = bdget(kdev_t_to_nr(msc->dev)))) {
++ printk(KERN_INFO"%s: Cannot find device %d %d\n", __FUNCTION__, major, minor);
++ return -EINVAL;
++ }
++ if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
++ printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor);
++ return -EINVAL;
++ }
++
++ /*
++ * Note that capacity must return the LBA of the last addressable block
++ * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
++ *
++ * The blk_size array contains the number of addressable blocks or N,
++ * capacity is therefore N-1.
++ */
++
++ msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
++ msc->block_size = get_hardsect_size(msc->dev);
++ msc->max_blocks = PAGE_SIZE / msc->block_size;
++#endif
++
++ msc->block_dev_state = DEVICE_EJECTED;
++
++ msc_open_blockdev(msc);
++
++ /*
++ * setup generic buffer_head
++ */
++
++ msc->read_bh.b_rdev = msc->dev;
++ msc->read_bh.b_private = msc;
++ msc->read_bh.b_page = alloc_page(GFP_NOIO);
++
++ msc->write_bh.b_rdev = msc->dev;
++ msc->write_bh.b_private = msc;
++ msc->write_bh.b_page = alloc_page(GFP_NOIO);
++
++ msc->command_state = MSC_READY;
++ msc->io_state = MSC_INACTIVE;
++
++ msc_trace_init("msctrace", &msc_private);
++ make_crc_table();
++
++ TRACE_MSG1(MSC,"PAGE_SHIFT: %x", PAGE_SHIFT);
++ TRACE_MSG1(MSC,"PAGE_SIZE: %x", PAGE_SIZE);
++ TRACE_MSG1(MSC,"PAGE_SIZE: %d", PAGE_SIZE);
++
++ // register as usb function driver
++ THROW_IF (usbd_register_function (&function_driver, NULL), error);
++ msc->usb_driver_registered++;
++
++ CATCH(error) {
++ if (msc->usb_driver_registered) {
++ usbd_deregister_function (&function_driver);
++ msc->usb_driver_registered = 0;
++ }
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/* msc_modexit - module cleanup
++ */
++static void msc_modexit (void)
++{
++ struct msc_private *msc = &msc_private;
++
++ if (msc->bdev) {
++ blkdev_put(msc->bdev, BDEV_RAW);
++ }
++ // XXX this should be a wait for read_bh/write_bh to go to NULL
++ while (msc->read_bh.b_data) {
++ printk(KERN_INFO"%s: sleeping on read bh\n", __FUNCTION__);
++ sleep_on_timeout(&msc->msc_wq, 20);
++ }
++
++ while (msc->write_bh.b_data) {
++ printk(KERN_INFO"%s: sleeping on read bh\n", __FUNCTION__);
++ sleep_on_timeout(&msc->msc_wq, 20);
++ }
++
++ printk(KERN_INFO"%s: freeing read bh\n", __FUNCTION__);
++ __free_page((void *)&msc->read_bh.b_page);
++ msc->read_bh.b_page = NULL;
++
++ printk(KERN_INFO"%s: freeing write bh\n", __FUNCTION__);
++ __free_page((void *)&msc->write_bh.b_page);
++ msc->write_bh.b_page = NULL;
++
++ if (msc->usb_driver_registered) {
++ usbd_deregister_function (&function_driver);
++ }
++
++ msc_trace_exit("msctrace");
++ free_crc_table();
++}
++
++
++module_init (msc_modinit);
++module_exit (msc_modexit);
+diff -uNr linux/drivers/no-otg/functions/msc/msc-scsi.h linux/drivers/otg/functions/msc/msc-scsi.h
+--- linux/drivers/no-otg/functions/msc/msc-scsi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc-scsi.h 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,795 @@
++/*
++ * otg/msc_fd/msc_scsi.h - mass storage protocol library header
++ *
++ * Copyright(c) 2004, Belcarra
++ *
++ * Adapated from work:
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++/*
++ *
++ * Documents
++ * Universal Serial Bus Mass Storage Class - Specification Overview
++ * Universal Serial Bus Mass Storage Class - Bulk-Only Transport
++ * T10/1240-D - Information technology - Reduced Block Commands
++ *
++ * Notes
++ *
++ * 1. Reduced Block Command set C.f. Table 2 RBC
++ *
++ * Command Support
++ * Name OpCode Fixed Removable Reference
++ * Format Unit 04h O O RBC
++ * Inquiry 12h M M SPC-2
++ * Mode Select (6) 15h M M SPC-2
++ * Mode Sense (6) 1Ah M M SPC-2
++ * Perisstent Reserve In 5Eh O O SPC-2
++ * Persistent Reserve Out 5Fh O O SPC-2
++ * Prevent/Allow Medium Removal 1Eh N/A M SPC-2
++ * Read (10) 28h M M RBC
++ * Read Capacity 25h M M RBC
++ * Reelase (6) 17h O O SPC-2
++ * Request Sense 03h O O SPC-2
++ * Reserve (6) 16h O O SPC-2
++ * Start Stop Unit 1Bh M M RBC
++ * Synchronize Cache 35h O O RBC
++ * Test Unit Ready 00h M M SPC-2
++ * Verify (10) 2Fh M M RBC
++ * Write (10) 2Ah M M RBC
++ * Write Buffer 3Bh M O SPC-2
++ *
++ * 2. Other commands seen?
++ * Sh MV FS
++ * SCSI_REZERO_UNIT 0x01 no
++ * SCSI_READ_6 0x08 yes
++ * SCSI_WRITE_6 0x0a yes
++ * SCSI_SEND_DIAGNOSTIC 0x1d no yes
++ * SCSI_READ_FORMAT_CAPACITY 0x23 yes yes
++ * SCSI_WRITE_AND_VERIFY 0x2e no
++ * SCSI_SEEK_10 0x2b no
++ * SCSI_MODE_SELECT_10 0x55 no yes yes
++ * SCSI_READ_12 0xa8 no yes
++ * SCSI_WRITE_12 0xaa no yes
++ *
++ *
++ * 3. Status - C.f. Chapter 5 - RBC
++ *
++ * Check Condition 02h
++ *
++ *
++ * 4. Sense Keys - C.f. Chapter 5 - RBC
++ *
++ * Not Ready 02h
++ * Media Error 03h
++ * Illegal Request 05h
++ * Unit Attention 06h
++ *
++ * 5. ASC/ASCQ - C.f. Chapter 5 - RBC
++ *
++ * Logical Unit Not Ready 04h
++ * Logical Unit Not Ready, Format in Progress 04h,04h
++ * Invalid Command Operation Code 20h
++ * Invalide Field in CDB 24h
++ * Format Command Failed 31h,01h
++ * Status Notification / Power Management Class Event 38h,02h
++ * Status Notification / Media Class Event 38h,04h
++ * Status Notification / Device Busy Class Event 38h,06h
++ * Low Power Condition Active 5Eh,00
++ * Power Condition Change to Active 5Eh,41h
++ * Power Condition Change to Idle 5Eh,42h
++ * Power Condition Change to Standby 5Eh,43h
++ * Power Condition Change to Sleep 5Eh,45h
++ * Power Condition Change to Device Control 5Eh,47h
++ *
++ * 6. ASCQ - C.f. Chapter 5 - RBC
++ *
++ *
++ *
++ * 7. Sense Keys C.f. Chapter 5 - RBC
++ *
++ * Command Status Sense Key ASC/ASCQ
++ *
++ * 5.1 Format Unit
++ * Format progress Check Condition Not Ready, Logical Unit Note Ready, Format in Progress
++ * Sueccsful completion Check Condition Unit Attention, Status Notification / Media Class Event
++ * Failure Check Condition Media error, Format Command Failed
++ *
++ * 5.2 Read (10)
++ *
++ * 5.3 Read Capacity
++ * No Media Check Condition Not Ready, Logical Unit Not Ready
++ *
++ * 5.4 Start Stop Unit
++ * Power Consumption Check Condition Illegal Request,Low Power Condition Active
++ *
++ * 5.5 Synchronize Cache Check Condition Illegal Request,Invalid Command Operation Code
++ *
++ * 5.6 Write (10
++ *
++ * 5.7 Verify
++ *
++ * 5.8 Mode
++ *
++ * 6.1 Inquiry
++ *
++ * 6.2 Mode Select (6)
++ * Cannot Save Check Condition Illegal Request,Invalid Field in CDB
++ *
++ * 6.3 Mode Sense (6)
++ *
++ * 6.4 Prevent Allow Medium Removal
++ *
++ * 6.5 Request Sense
++ *
++ * 6.6 Test Unit Ready
++ *
++ * 6.7 Write Buffer
++ *
++ * 7.1 Unit Attention
++ * Power Contition change Check Condition Unit Attention, Power Condition Change Notification
++ *
++ * 7.4.1 Event Status Sense
++ *
++ * Power Management Event Check Condition Unit Attention, Event Status Notification / Power Managment
++ * Media Class Event Check Condition Unit Attention, Event Status Notification / Media Class
++ * Device Busy Event Check Condition Unit Attention, Event Status Notification / Device Busy Class
++ *
++ * 7.4.6 Removable Medium Device Initial Response
++ * Ready Check Condition Unit Attention, Event Status Notification / Media Class Event
++ * Power Check Condition Unit Attention, Event Status Notification / Power Management Class Event
++ */
++
++#ifndef _MSCSCSIPROTO_H_
++#define _MSCSCSIPROTO_H_
++
++
++/*
++ * Class Specific Requests - C.f. MSC BO Chapter 3
++ */
++
++#define MSC_BULKONLY_RESET 0xff
++#define MSC_BULKONLY_GETMAXLUN 0xfe
++
++
++/*
++ * Class Code
++ */
++
++#define MASS_STORAGE_CLASS 0x08
++
++/*
++ * MSC - Specification Overview
++ *
++ * SubClass Codes - C.f MSC Table 2.1
++ */
++
++#define MASS_STORAGE_SUBCLASS_RBC 0x01
++#define MASS_STORAGE_SUBCLASS_SFF8020I 0x02
++#define MASS_STORAGE_SUBCLASS_QIC157 0x03
++#define MASS_STORAGE_SUBCLASS_UFI 0x04
++#define MASS_STORAGE_SUBCLASS_SFF8070I 0x05
++#define MASS_STORAGE_SUBCLASS_SCSI 0x06
++
++/*
++ * Protocol - C.f MSC Table 3.1
++ */
++
++#define MASS_STORAGE_PROTO_CBI_WITH_COMP 0x00
++#define MASS_STORAGE_PROTO_CBI_NO_COMP 0x01
++#define MASS_STORAGE_PROTO_BULK_ONLY 0x50
++
++/*
++ * SCSI Command
++*/
++
++#define SCSI_TEST_UNIT_READY 0x00
++#define SCSI_REQUEST_SENSE 0x03
++#define SCSI_FORMAT_UNIT 0x04
++#define SCSI_INQUIRY 0x12
++#define SCSI_MODE_SELECT 0x15 // aka MODE_SELECT_6
++#define SCSI_MODE_SENSE 0x1a // aka MODE_SENSE_6
++#define SCSI_START_STOP 0x1b
++#define SCSI_PREVENT_ALLOW_MEDIA_REMOVAL 0x1e
++#define SCSI_READ_FORMAT_CAPACITY 0x23
++#define SCSI_READ_CAPACITY 0x25
++#define SCSI_READ_10 0x28
++#define SCSI_WRITE_10 0x2a
++#define SCSI_VERIFY 0x2f
++
++#define SCSI_READ_6 0x08
++#define SCSI_WRITE_6 0x0a
++#define SCSI_RESERVE 0x16
++#define SCSI_RELEASE 0x17
++#define SCSI_SEND_DIAGNOSTIC 0x1d
++#define SCSI_SYNCHRONIZE_CACHE 0x35
++#define SCSI_MODE_SENSE_10 0x5a
++
++#define SCSI_REZERO_UNIT 0x01
++#define SCSI_REASSIGN_BLOCKS 0x07
++#define SCSI_COPY 0x18
++#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
++#define SCSI_WRITE_AND_VERIFY 0x2e
++#define SCSI_PREFETCH 0x34
++#define SCSI_READ_DEFECT_DATA 0x37
++#define SCSI_COMPARE 0x39
++#define SCSI_COPY_AND_VERIFY 0x3a
++#define SCSI_WRITE_BUFFER 0x3b
++#define SCSI_READ_BUFFER 0x3c
++#define SCSI_READ_LONG 0x3e
++#define SCSI_WRITE_LONG 0x3f
++#define SCSI_CHANGE_DEFINITION 0x40
++#define SCSI_WRITE_SAME 0x41
++#define SCSI_LOG_SELECT 0x4c
++#define SCSI_LOG_SENSE 0x4d
++#define SCSI_XD_WRITE 0x50
++#define SCSI_XP_WRITE 0x51
++#define SCSI_XD_READ 0x52
++#define SCSI_MODE_SELECT_10 0x55
++#define SCSI_RESERVE_10 0x56
++#define SCSI_RELEASE_10 0x57
++#define SCSI_MODE_SELECT_10 0x55
++#define SCSI_XD_WRITE_EXTENDED 0x80
++#define SCSI_REBUILD 0x81
++#define SCSI_REGENERATE 0x82
++
++#define SCSI_SEEK_10 0x2b
++#define SCSI_WRITE_AND_VERIFY 0x2e
++#define SCSI_WRITE_12 0xaa
++#define SCSI_READ_12 0xa8
++
++/*
++ * Private
++ */
++#define SCSI_PRIVATE_PCS 0xff
++
++/*
++ * SCSI Command Parameter
++ */
++
++#define CBW_SIGNATURE 0x43425355 /* USBC */
++#define CSW_SIGNATURE 0x53425355 /* USBS */
++
++#define PRODUCT_REVISION_LEVEL "1.00"
++
++/*
++ * Command Block Status Values - C.f MSC BO Table 5.3
++ */
++
++#define USB_MSC_PASSED 0x00 // good
++#define USB_MSC_FAILED 0x01 // bad
++#define USB_MSC_PHASE_ERROR 0x02 // we want to be reset
++
++
++
++
++/*
++ * SCSI Sense
++ * SenseKey
++ * AdditionalSenseCode
++ * SenseCodeQualifier
++ */
++
++#define SCSI_ERROR_CURRENT 0x70
++#define SCSI_ERROR_DEFERRED 0x07
++
++/*
++ * SCSI Sense Keys
++ */
++
++#define SK_NO_SENSE 0x00
++#define SK_RECOVERED_ERROR 0x01
++#define SK_NOT_READY 0x02
++#define SK_MEDIA_ERROR 0x03
++#define SK_HARDWARE_ERROR 0x04
++#define SK_ILLEGAL_REQUEST 0x05
++#define SK_UNIT_ATTENTION 0x06
++#define SK_DATA_PROTECT 0x07
++#define SK_BLANK_CHECK 0x08
++#define SK_COPY_ABORTED 0x0a
++#define SK_ABORTED_COMMAND 0x0b
++#define SK_VOLUME_OVERFLOW 0x0d
++#define SK_MISCOMPARE 0x0e
++
++/*
++ * 5. ASC/ASCQ - C.f. Chapter 5 - RBC
++ */
++
++#define SK(SenseKey,ASC,ASCQ) ((SenseKey<<16) | (ASC << 8) | (ASCQ))
++
++#define SCSI_SENSEKEY_NO_SENSE SK(SK_NO_SENSE, 0x00,0x00) // 0x000000
++
++#define SCSI_FAILURE_PREDICTION_THRESHOLD_EXCEEDED SK(SK_RECOVERED_ERROR, 0x5d,0x00) // 0x015d00
++
++#define SCSI_SENSEKEY_LOGICAL_UNIT_NOT_READY SK(SK_NOT_READY, 0x04,0x00) // 0x020400
++#define SCSI_SENSEKEY_FORMAT_IN_PROGRESS SK(SK_NOT_READY, 0x04,0x04) // 0x020404
++#define SCSI_SENSEKEY_MEDIA_NOT_PRESENT SK(SK_NOT_READY, 0x3a,0x00) // 0x023a00
++
++#define SCSI_SENSEKEY_WRITE_ERROR SK(SK_MEDIA_ERROR, 0x0c,0x02) // 0x030c02
++#define SCSI_SENSEKEY_UNRECOVERED_READ_ERROR SK(SK_MEDIA_ERROR, 0x11,0x00) // 0x031100
++#define SCSI_FORMAT_COMMAND_FAILED SK(SK_MEDIA_ERROR, 0x31,0x01) // 0x033101
++
++#define SCSI_SENSEKEY_COMMUNICATION_FAILURE SK(SK_HARDWARE_ERROR, 0x08,0x00) // 0x040800
++
++#define SCSI_SENSEKEY_INVALID_COMMAND SK(SK_ILLEGAL_REQUEST, 0x20,0x00) // 0x052000
++#define SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE SK(SK_ILLEGAL_REQUEST, 0x21,0x00) // 0x052100
++#define SCSI_SENSEKEY_INVALID_FIELD_IN_CDB SK(SK_ILLEGAL_REQUEST, 0x24,0x00) // 0x052400
++#define SCSI_SENSEKEY_LOGICAL_UNIT_NOT_SUPPORTED SK(SK_ILLEGAL_REQUEST, 0x25,0x00) // 0x052500
++#define SCSI_SENSEKEY_SAVING_PARAMETERS_NOT_SUPPORTED SK(SK_ILLEGAL_REQUEST, 0x39,0x00) // 0x053900
++#define SCSI_MEDIA_REMOVAL_PREVENTED SK(SK_ILLEGAL_REQUEST, 0x53,0x02) // 0x055302
++
++#define SCSI_SENSEKEY_NOT_READY_TO_READY_CHANGE SK(SK_UNIT_ATTENTION, 0x28,0x00) // 0x062800
++#define SCSI_SENSEKEY_RESET_OCCURRED SK(SK_UNIT_ATTENTION, 0x29,0x00) // 0x062900
++
++#define SCSI_SENSEKEY_STATUS_NOTIFICATION_POWER_CLASS SK(SK_UNIT_ATTENTION, 0x38,0x02) // 0x063802
++#define SCSI_SENSEKEY_STATUS_NOTIFICATION_MEDIA_CLASS SK(SK_UNIT_ATTENTION, 0x38,0x04) // 0x063804
++#define SCSI_SENSEKEY_STATUS_NOTIFICATION_DEVICE_BUSY SK(SK_UNIT_ATTENTION, 0x38,0x06) // 0x063806
++
++#define SCSI_SENSEKEY_LOW_POWER_CONDITION_ACTIVE SK(SK_UNIT_ATTENTION, 0x5e,0x00) // 0x065e00
++#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_ACTIVE SK(SK_UNIT_ATTENTION, 0x5e,0x41) // 0x065e41
++#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_IDLE SK(SK_UNIT_ATTENTION, 0x5e,0x42) // 0x065e42
++#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_STANDBY SK(SK_UNIT_ATTENTION, 0x5e,0x43) // 0x065e43
++#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_SLEEP SK(SK_UNIT_ATTENTION, 0x5e,0x45) // 0x065e45
++#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_DEVICE SK(SK_UNIT_ATTENTION, 0x5e,0x47) // 0x065e47
++
++
++#define SCSI_SENSEKEY_WRITE_PROTECTED SK(SK_DATA_PROTECT, 0x27,0x00) // 0x072700
++
++
++/*
++ * Mode Page Code and Page Control
++ */
++#define SCSI_MODEPAGE_CONTROL_CURRENT 0x0
++#define SCSI_MODEPAGE_CONTROL_CHANGEABLE 0x1
++#define SCSI_MODEPAGE_CONTROL_DEFAULT 0x2
++#define SCSI_MODEPAGE_CONTROL_SAVED 0x3
++
++#define SCSI_MODEPAGE_UNIT_ATTENTION 0x00
++#define SCSI_MODEPAGE_ERROR_RECOVERY 0x01
++#define SCSI_MODEPAGE_DISCONNNECT_RECONNECT 0x02
++#define SCSI_MODEPAGE_FORMAT 0x03
++#define SCSI_MODEPAGE_RIGID_DRIVE_GEOMETRY 0x04
++#define SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE 0x05 // check
++#define SCSI_MODEPAGE_VERIFY_ERROR_RECOVERY 0x07
++#define SCSI_MODEPAGE_CACHING 0x08
++#define SCSI_MODEPAGE_CONTROL_MODE 0x0a
++#define SCSI_MODEPAGE_NOTCH_AND_PARTITION 0x0c
++#define SCSI_MODEPAGE_POWER_CONDITION 0x0d
++#define SCSI_MODEPAGE_XOR 0x10
++#define SCSI_MODEPAGE_CONTROL_MODE_ALIAS 0x1a
++#define SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS 0x1b// check
++#define SCSI_MODEPAGE_INFORMATION_EXCEPTIONS 0x1c
++#define SCSI_MODEPAGE_ALL_SUPPORTED 0x3f
++
++
++
++/*
++ * Command Block Wrapper / Command Status Wrapper
++ */
++
++/*
++ * Command Block Wrapper
++ */
++typedef struct{
++ unsigned long dCBWSignature;
++ unsigned long dCBWTag;
++ unsigned long dCBWDataTransferLength;
++ u8 bmCBWFlags;
++ u8 bCBWLUN:4,
++ Reserved:4;
++ u8 bCBWCBLength:5,
++ Reserved2:3;
++ u8 CBWCB[16];
++} __attribute__((packed)) COMMAND_BLOCK_WRAPPER;
++
++/*
++ * Command Status Wrapper
++ */
++typedef struct{
++ unsigned long dCSWSignature;
++ unsigned long dCSWTag;
++ unsigned long dCSWDataResidue;
++ u8 bCSWStatus;
++} __attribute__((packed)) COMMAND_STATUS_WRAPPER;
++
++/*
++ * SCSI Command
++ */
++
++/*
++ * INQUIRY
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 EnableVPD:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ u8 PageCode;
++ u8 Reserved2;
++ u8 AllocationLength;
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++} __attribute__((packed)) SCSI_INQUIRY_COMMAND;
++
++typedef struct{
++ u8 PeripheralDeviceType:5,
++ PeripheralQaulifier:3;
++ u8 Reserved2:7,
++ RMB:1;
++ u8 ANSIVersion:3,
++ ECMAVersion:3,
++ ISOVersion:2;
++ u8 ResponseDataFormat:4,
++ Reserved3:4;
++ u8 AdditionalLength;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 VendorInformation[8];
++ u8 ProductIdentification[16];
++ u8 ProductRevisionLevel[4];
++} __attribute__((packed)) SCSI_INQUIRY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 Reserved1:5,
++ LogicalUnitNumber:3;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u16 AllocationLength;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_COMMAND;
++
++typedef struct{
++ struct{
++ u8 Reserved1;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 CapacityListLength;
++ } __attribute__((packed)) CapacityListHeader;
++
++ struct{
++ u32 NumberofBlocks;
++ u8 DescriptorCode:2,
++ Reserved1:6;
++ u8 BlockLength[3];
++ } __attribute__((packed)) CurrentMaximumCapacityDescriptor;
++
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 RelAdr:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ u32 LogicalBlockAddress;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 PMI:1,
++ Reserved4:7;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++} __attribute__((packed)) SCSI_READ_CAPACITY_COMMAND;
++
++typedef struct{
++ u32 LastLogicalBlockAddress;
++ u32 BlockLengthInBytes;
++} __attribute__((packed)) SCSI_READ_CAPACITY_DATA;
++
++/*
++ * REQUEST SENSE
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 Reserved1:5,
++ LogicalUnitNumber:3;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 AllocationLength;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++ u8 Reserved10;
++} __attribute__((packed)) SCSI_REQUEST_SENSE_COMMAND;
++
++typedef struct{
++ u8 ErrorCode:7,
++ Valid:1;
++ u8 Reserved1;
++ u8 SenseKey:4,
++ Reserved2:4;
++ u32 Information;
++ u8 AdditionalSenseLength;
++ u8 Reserved3[4];
++ u8 AdditionalSenseCode;
++ u8 AdditionalSenseCodeQualifier;
++ u8 Reserved4;
++ u8 Reserved5[3];
++} __attribute__((packed)) SCSI_REQUEST_SENSE_DATA;
++
++/*
++ * READ(10)
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 RelAdr:1,
++ Reserved1:2,
++ FUA:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ u32 LogicalBlockAddress;
++ u8 Reserved2;
++ u16 TransferLength;
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++} __attribute__((packed)) SCSI_READ_10_COMMAND;
++
++/*
++ * MODE SENSE
++ */
++typedef struct{
++ u8 OperationCode;
++ u8 Reserved1:3,
++ DBD:1,
++ Reserved2:1,
++ LogicalUnitNumber:3;
++ u8 PageCode:6,
++ PageControl:2; // PC
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u16 ParameterListLength;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++} __attribute__((packed)) SCSI_MODE_SENSE_COMMAND;
++
++typedef struct{
++ u8 ModeDataLength;
++ u8 MediumTypeCode;
++ u8 Reserved1:4,
++ DPOFUA:1,
++ Reserved2:2,
++ WriteProtect:1;
++ u8 Reserved3;
++} __attribute__((packed)) MODE_PARAMETER_HEADER;
++
++typedef struct{
++ u8 PageCode:6,
++ Reserved1:1,
++ PS:1;
++ u8 PageLength;
++ u8 DCR:1,
++ Reserved2:1,
++ PER:1,
++ Reserved3:1,
++ RC:1,
++ Reserved4:1,
++ Reserved5:1,
++ AWRE:1;
++ u8 ReadRetryCount;
++ u8 Reserved6[4];
++ u8 WriteRetryCount;
++ u8 Reserved7[3];
++} __attribute__((packed)) READ_WRITE_ERROR_RECOVERY_PAGE;
++
++typedef struct{
++ u8 PageCode:6,
++ Reserved1:1,
++ PS:1;
++ u8 PageLength;
++ u16 TransferRate;
++ u8 NumberofHeads;
++ u8 SectorsperTrack;
++ u16 DataBytesperSector;
++ u16 NumberofCylinders;
++ u8 Reserved2[9];
++ u8 MotorOnDelay;
++ u8 MotorOffDelay;
++ u8 Reserved3[7];
++ u16 MediumRotationRate;
++ u8 Reserved4;
++ u8 Reserved5;
++} __attribute__((packed)) FLEXIBLE_DISK_PAGE;
++
++typedef struct{
++ u8 PageCode:6,
++ Reserved1:1,
++ PS:1;
++ u8 PageLength;
++ u8 Reserved2:6,
++ SRFP:1,
++ SFLP:1;
++ u8 TLUN:3,
++ Reserved3:3,
++ SML:1,
++ NCD:1;
++ u8 Reserved4[8];
++} __attribute__((packed)) REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE;
++
++typedef struct{
++ u8 PageCode:6,
++ Reserved1:1,
++ PS:1;
++ u8 PageLength;
++ u8 Reserved2;
++ u8 InactivityTimeMultiplier:4,
++ Reserved3:4;
++ u8 SWPP:1,
++ DISP:1,
++ Reserved4:6;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++} __attribute__((packed)) TIMER_AND_PROTECT_PAGE;
++
++typedef struct{
++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage;
++ FLEXIBLE_DISK_PAGE FlexibleDiskPage;
++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage;
++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage;
++} __attribute__((packed)) MODE_ALL_PAGES;
++
++typedef struct{
++ MODE_PARAMETER_HEADER ModeParameterHeader;
++ union{
++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage;
++ FLEXIBLE_DISK_PAGE FlexibleDiskPage;
++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage;
++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage;
++ MODE_ALL_PAGES ModeAllPages;
++ } __attribute__((packed)) ModePages;
++} __attribute__((packed)) SCSI_MODE_SENSE_DATA;
++
++/*
++ * TEST UNIT READY
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 Reserved1:5,
++ LogicalUnitNumber:3;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++ u8 Reserved10;
++ u8 Reserved11;
++} __attribute__((packed)) SCSI_TEST_UNIT_READY_COMMAND;
++
++/*
++ * PREVENT-ALLOW MEDIA REMOVAL
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 Reserved1:5,
++ LogicalUnitNumber:3;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 Prevent:2,
++ Reserved4:6;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++ u8 Reserved10;
++ u8 Reserved11;
++} __attribute__((packed)) SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND;
++
++/*
++ * START-STOP UNIT
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 IMMED:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ u8 Reserved2;
++ u8 Reserved3;
++ u8 Start:1,
++ LoEj:1,
++ Reserved4:2,
++ PowerConditions:4;
++ u8 Reserved5;
++ u8 Reserved6;
++ u8 Reserved7;
++ u8 Reserved8;
++ u8 Reserved9;
++ u8 Reserved10;
++ u8 Reserved11;
++} __attribute__((packed)) SCSI_START_STOP_COMMAND;
++
++/*
++ * WRITE(10)
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 RelAdr:1,
++ Reserved1:2,
++ FUA:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ u32 LogicalBlockAddress;
++ u8 Reserved2;
++ u16 TransferLength;
++ u8 Reserved3;
++ u8 Reserved4;
++ u8 Reserved5;
++} __attribute__((packed)) SCSI_WRITE_10_COMMAND;
++
++/*
++ * VERIFY
++ */
++
++typedef struct{
++ u8 OperationCode;
++ u8 RelAdr:1,
++ ByteChk:1,
++ Reserved1:1,
++ Reserved2:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ u32 LogicalBlockAddress;
++ u8 Reserved3;
++ u16 VerificationLength;
++ u8 Reserved4;
++ u8 Reserved5;
++ u8 Reserved6;
++} __attribute__((packed)) SCSI_VERIFY_COMMAND;
++
++#endif /* _MSCSCSIPROTO_H_ */
++
+diff -uNr linux/drivers/no-otg/functions/msc/msc.h linux/drivers/otg/functions/msc/msc.h
+--- linux/drivers/no-otg/functions/msc/msc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/msc.h 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,141 @@
++/*
++ * otg/function/msc/msc.h - Mass Storage Class
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup MSCFunction Mass Storage
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/msc/msc.h
++ * @brief Mass Storage Driver private defines
++ *
++ *
++ * @ingroup MSCFunction
++ */
++
++#ifndef MSC_H
++#define MSC_H 1
++
++extern otg_tag_t msc_fd_trace_tag;
++#define MSC msc_fd_trace_tag
++
++/*
++ * Command/Data/Status Flow
++ * C.f. 5 - Figure 1
++ */
++
++typedef enum msc_state {
++ MSC_READY,
++ MSC_DATA_OUT_WRITE,
++ MSC_DATA_OUT_WRITE_FINISHED,
++ MSC_DATA_IN_READ,
++ MSC_DATA_IN_READ_FINISHED,
++ MSC_STATUS,
++ MSC_QUERY,
++ MSC_PHASE_ERROR,
++ MSC_UNKNOWN
++} msc_state_t;
++
++
++/*
++ * Device Transfer state
++ * C.F. Table 6.1
++ */
++
++typedef enum msc_device_state {
++ MSC_DEVICE_DN, // The device intends to transfer no data
++ MSC_DEVICE_DI, // The device intends to send data to the host
++ MSC_DEVICE_DO, // The device intents to received data from the host
++} msc_device_state_t;
++
++#define MSC_INACTIVE 0x0000
++#define MSC_BLOCKIO_PENDING 0x0001
++#define MSC_BLOCKIO_FINISHED 0x0002
++#define MSC_RECV_PENDING 0x0010
++#define MSC_RECV_FINISHED 0x0020
++#define MSC_SEND_PENDING 0x0040
++#define MSC_SEND_FINISHED 0x0080
++#define MSC_IOCTL_WAITING 0x0100 // there is an ioctl call waiting for I/O completion
++#define MSC_ABORT_IO 0x0200 // please abort current i/o
++
++#if 0
++struct SPC_inquiry_cdb {
++ u8 OperationCode; /* 12H */
++ u8 EnableVPD:1;
++ u8 CmdSupportData:1;
++ u8 Reserved0:6;
++ u8 PageCode;
++ u8 Reserved1;
++ u8 AllocationLen;
++ u8 Control;
++} __attribute__((packed));
++#endif
++
++struct msc_private {
++ struct usbd_function_instance *function;
++
++ int usb_driver_registered; // non-zero if usb function registered
++ unsigned char connected; // non-zero if connected to host (configured)
++
++ struct usbd_urb *rcv_urb_finished;
++
++ struct buffer_head read_bh;
++ struct buffer_head write_bh;
++
++ u16 read_pending;
++ u16 write_pending;
++
++ msc_device_state_t device_state;
++ msc_state_t command_state; // current command state
++ u16 io_state; // current IO state
++
++ COMMAND_BLOCK_WRAPPER command;
++
++ u32 lba; // next lba to read/write from
++ u32 transfer_blocks;
++ u32 TransferLength_in_blocks; // amount of transfer remaining
++ u32 TransferLength_in_bytes; // amount of transfer remaining
++ u32 data_transferred_in_bytes; // amount of data actually transferred
++
++ int major;
++ int minor;
++ kdev_t dev;
++ struct block_device *bdev;
++ u32 block_size;
++ u32 capacity;
++ u32 max_blocks;
++
++ int uptodate;
++
++ wait_queue_head_t msc_wq;
++ wait_queue_head_t ioctl_wq;
++
++ u32 status;
++ u32 block_dev_state;
++ u32 sensedata;
++ u32 info;
++};
++
++
++/*
++ * MSC Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ */
++
++#define BULK_OUT 0x00
++#define BULK_IN 0x01
++#define ENDPOINTS 0x02
++
++extern struct usbd_function_operations function_ops;
++extern struct usbd_function_driver function_driver;
++
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/msc/scripts/test1 linux/drivers/otg/functions/msc/scripts/test1
+--- linux/drivers/no-otg/functions/msc/scripts/test1 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/scripts/test1 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,37 @@
++#!/bin/sh
++#
++# Basic Start/Stop test
++#
++#
++# 1. Wait for connection
++# 2. loop making block device available for 10 second intervals
++# 3. exit if disconnected
++#
++
++MAJOR=7
++MINOR=0
++
++TIMEOUT=5
++
++set -x
++
++# wait for connection
++msc_check connect
++
++while sleep 1
++do
++
++ # make block device available
++ msc_check start $MAJOR $MINOR
++
++ sleep $TIMEOUT
++
++ # make block device un-available
++ msc_check stop
++
++ sleep $TIMEOUT
++
++ msc_check connected || break
++
++done
++
+diff -uNr linux/drivers/no-otg/functions/msc/scripts/test2 linux/drivers/otg/functions/msc/scripts/test2
+--- linux/drivers/no-otg/functions/msc/scripts/test2 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/scripts/test2 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,35 @@
++#!/bin/sh
++#
++# Basic Start/Stop test on connect/disconnect.
++#
++# Loop
++# 1. wait for connection
++# 2. making block device available for 10 seconds
++# 3. wait for disconnect
++# 4. continue
++#
++
++MAJOR=7
++MINOR=0
++
++TIMEOUT=5
++
++set -x
++
++while sleep 1
++do
++ # wait for connection
++ msc_check connect
++
++ # make block device available
++ msc_check start $MAJOR $MINOR
++
++ sleep $TIMEOUT
++
++ # make block device un-available
++ msc_check stop
++
++ msc_check disconnect
++
++done
++
+diff -uNr linux/drivers/no-otg/functions/msc/scripts/test3 linux/drivers/otg/functions/msc/scripts/test3
+--- linux/drivers/no-otg/functions/msc/scripts/test3 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/scripts/test3 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,46 @@
++#!/bin/sh
++#
++# Force connect/disconnect with start/stop.
++#
++# 1. loop making block device available for 10 second intervals
++# 2. exit if disconnected
++# 3. start
++# 4. stop
++# 5. force disconnect
++#
++
++MAJOR=7
++MINOR=0
++
++TIMEOUT=5
++
++set -x
++
++while sleep 1
++do
++
++ # bus request
++ otgd bus_req
++
++ # wait for connection
++ msc_check connect
++
++ # make block device available
++ msc_check start $MAJOR $MINOR
++
++ sleep $TIMEOUT
++
++ # make block device un-available
++ msc_check stop
++
++ sleep $TIMEOUT
++
++ # bus request/
++ otgd bus_req/
++
++ msc_check disconnect
++
++ sleep $TIMEOUT
++
++done
++
+diff -uNr linux/drivers/no-otg/functions/msc/scripts/test4 linux/drivers/otg/functions/msc/scripts/test4
+--- linux/drivers/no-otg/functions/msc/scripts/test4 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/scripts/test4 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,47 @@
++#!/bin/sh
++
++# Force connect/disconnect without start/stop.
++#
++#
++# 1. loop making block device available for 10 second intervals
++# 2. exit if disconnected
++# 3. force disconnect
++# 4. force connect
++#
++
++MAJOR=7
++MINOR=0
++
++TIMEOUT=5
++
++set -x
++
++# make block device available
++msc_check start $MAJOR $MINOR
++
++
++while sleep 1
++do
++
++ # bus request
++ otgd bus_req
++
++ # wait for connection
++ msc_check connect
++
++ sleep $TIMEOUT
++
++ sleep $TIMEOUT
++
++ # bus request/
++ otgd bus_req/
++
++ msc_check disconnect
++
++ sleep $TIMEOUT
++
++done
++
++# make block device un-available
++msc_check stop
++
+diff -uNr linux/drivers/no-otg/functions/msc/scripts/test5 linux/drivers/otg/functions/msc/scripts/test5
+--- linux/drivers/no-otg/functions/msc/scripts/test5 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/scripts/test5 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,47 @@
++#!/bin/sh
++#
++# Force connect/disconnect with start/stop.
++#
++# 1. loop making block device available for 10 second intervals
++# 2. exit if disconnected
++# 3. start
++# 4. force disconnect
++# 5. stop
++# 6. force connect
++#
++
++MAJOR=7
++MINOR=0
++
++TIMEOUT=5
++
++set -x
++
++while sleep 1
++do
++
++ # bus request
++ otgd bus_req
++
++ # wait for connection
++ msc_check connect
++
++ # make block device available
++ msc_check start $MAJOR $MINOR
++
++ sleep $TIMEOUT
++
++ # bus request/
++ otgd bus_req/
++
++ # make block device un-available
++ msc_check stop
++
++ sleep $TIMEOUT
++
++ msc_check disconnect
++
++ sleep $TIMEOUT
++
++done
++
+diff -uNr linux/drivers/no-otg/functions/msc/trace.c linux/drivers/otg/functions/msc/trace.c
+--- linux/drivers/no-otg/functions/msc/trace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/trace.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,340 @@
++/*
++ * otg/msc_fd/trace.c
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * Adapted from earlier work:
++ * Copyright (c) 2002, 2003 Belcarra
++ * Copyright (c) 2002 Lineo
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <linux/proc_fs.h>
++#include <linux/vmalloc.h>
++
++#include <asm/atomic.h>
++#include <asm/io.h>
++
++#include <linux/proc_fs.h>
++
++#include <linux/netdevice.h>
++#include <linux/pci.h>
++#include <linux/cache.h>
++
++
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++
++#include <usbp-chap9.h>
++#include <usbp-mem.h>
++#include <usbp-func.h>
++#include "msc-scsi.h"
++#include "msc.h"
++#include "trace.h"
++
++
++static struct msc_private *msc_private;
++int msc_trace_first;
++int msc_trace_next;
++msc_trace_t *msc_traces;
++
++extern int msc_interrupts;
++
++
++#if defined(CONFIG_OTG_MSC_REGISTER_TRACE) && defined(CONFIG_PROC_FS)
++
++msc_trace_t *MSC_TRACE_NEXT(msc_trace_types_t msc_trace_type)
++{
++ msc_trace_t *p;
++
++ p = msc_traces + msc_trace_next;
++
++ if (msc_private) {
++ p->ticks = usbd_ticks(msc_private->function);
++ p->sofs = usbd_framenum(msc_private->function);
++ }
++ p->interrupts = msc_interrupts;
++ p->msc_trace_type = msc_trace_type;
++
++ msc_trace_next++;
++ msc_trace_next = (msc_trace_next == TRACE_MAX) ? 0 : msc_trace_next;
++
++ if (msc_trace_next == msc_trace_first) {
++ msc_trace_first++;
++ msc_trace_first = (msc_trace_first == TRACE_MAX) ? 0 : msc_trace_first;
++ }
++
++ return p;
++}
++
++/* Proc Filesystem *************************************************************************** */
++
++/* *
++ * msc_trace_proc_read - implement proc file system read.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Standard proc file system read function.
++ */
++static ssize_t msc_trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int oindex;
++ int previous;
++
++ MOD_INC_USE_COUNT;
++ // get a page, max 4095 bytes of data...
++ if (!(page = get_free_page (GFP_KERNEL))) {
++ MOD_DEC_USE_COUNT;
++ return -ENOMEM;
++ }
++
++ len = 0;
++ oindex = index = (*pos)++;
++
++ if (index == 0)
++ len += sprintf ((char *) page + len, " Index Ints Ticks\n");
++
++
++ index += msc_trace_first;
++ if (index >= TRACE_MAX)
++ index -= TRACE_MAX;
++
++ previous = (index) ? (index - 1) : (TRACE_MAX - 1);
++
++
++ if (
++ ((msc_trace_first < msc_trace_next) && (index >= msc_trace_first) && (index < msc_trace_next)) ||
++ ((msc_trace_first > msc_trace_next) && ((index < msc_trace_next) || (index >= msc_trace_first)))
++ )
++ {
++
++ u64 ticks = 0;
++
++ msc_trace_t *p = msc_traces + index;
++ unsigned char *cp;
++ unsigned int *ip;
++ int skip = 0;
++
++ if (oindex > 0) {
++ msc_trace_t *o = msc_traces + previous;
++
++ if (o->ticks)
++ ticks = (p->ticks > o->ticks) ? (p->ticks - o->ticks) : (o->ticks - p->ticks) ;
++
++ if (o->interrupts != p->interrupts)
++ skip++;
++
++ }
++
++ //printk(KERN_INFO"index: %d interrupts: %d\n", index, p->interrupts);
++ len += sprintf ((char *) page + len, "%s%6d %8d ", skip?"\n":"", index, p->interrupts);
++
++ if (ticks > 1024*1024)
++ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
++ else
++ len += sprintf ((char *) page + len, "%8d ", ticks);
++
++ len += sprintf ((char *) page + len, "%6d ", (int)p->sofs);
++
++ switch (p->msc_trace_type) {
++ case msc_trace_msg:
++ len += sprintf ((char *) page + len, " -- ");
++ len += sprintf ((char *) page + len, p->trace.msg.msg);
++ break;
++
++ case msc_trace_w:
++ len += sprintf ((char *) page + len, " --> ");
++ len += sprintf ((char *) page + len, "[%8x] W %s", p->trace.msg32.val, p->trace.msg32.msg);
++ break;
++
++ case msc_trace_r:
++ len += sprintf ((char *) page + len, "<-- ");
++ len += sprintf ((char *) page + len, "[%8x] R %s", p->trace.msg32.val, p->trace.msg32.msg);
++ break;
++
++ case msc_trace_msg32:
++ len += sprintf ((char *) page + len, " -- ");
++ len += sprintf ((char *) page + len, p->trace.msg32.msg, p->trace.msg32.val);
++ break;
++
++ case msc_trace_msg16:
++ len += sprintf ((char *) page + len, " -- ");
++ len += sprintf ((char *) page + len, p->trace.msg16.msg, p->trace.msg16.val0, p->trace.msg16.val1);
++ break;
++
++ case msc_trace_msg8:
++ len += sprintf ((char *) page + len, " -- ");
++ len += sprintf ((char *) page + len, p->trace.msg8.msg,
++ p->trace.msg8.val0, p->trace.msg8.val1, p->trace.msg8.val2, p->trace.msg8.val3);
++ break;
++
++ case msc_trace_setup:
++ cp = (unsigned char *)&p->trace.setup;
++ len += sprintf ((char *) page + len,
++ " -- request [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++ break;
++
++ case msc_trace_recv:
++ case msc_trace_sent:
++ cp = (unsigned char *)&p->trace.sent;
++ len += sprintf ((char *) page + len,
++ "%s %s [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ ( p->msc_trace_type == msc_trace_recv)?"<-- ":" -->",
++ ( p->msc_trace_type == msc_trace_recv)?"recv":"sent",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++ break;
++ case msc_trace_rlba:
++ ip = (unsigned int *)&p->trace.ints;
++ len += sprintf ((char *) page + len,
++ "%s %s [%8x %08x]",
++ "<-- ", "rlba", ip[0], ip[1]);
++ break;
++ case msc_trace_slba:
++ case msc_trace_tlba:
++ ip = (unsigned int *)&p->trace.ints;
++ len += sprintf ((char *) page + len,
++ "%s %s [%8x %08x]", " -->",
++ ( p->msc_trace_type == msc_trace_tlba)?"tlba":"slba",
++ ip[0], ip[1]);
++ break;
++
++ case msc_trace_tag:
++ ip = (unsigned int *)&p->trace.ints;
++ len += sprintf ((char *) page + len,
++ "%s TAG: %8x FRAME: %03x", " -->",
++ ip[0], ip[1]);
++ break;
++
++ case msc_trace_sense:
++ ip = (unsigned int *)&p->trace.ints;
++ len += sprintf ((char *) page + len,
++ "%s SENSE: %06x INFO: %08x", " -->",
++ ip[0], ip[1]);
++ break;
++
++ case msc_trace_cbw:
++ len += sprintf ((char *) page + len, " --> ");
++ len += sprintf ((char *) page + len, "%s %02x", p->trace.msg32.msg, p->trace.msg32.val);
++ break;
++ }
++ len += sprintf ((char *) page + len, "\n");
++ }
++
++ if ((len > count) || (len == 0))
++ len = -EINVAL;
++ else if (len > 0 && copy_to_user (buf, (char *) page, len))
++ len = -EFAULT;
++
++ free_page (page);
++ MOD_DEC_USE_COUNT;
++ return len;
++}
++
++/* *
++ * msc_trace_proc_write - implement proc file system write.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Proc file system write function, used to signal monitor actions complete.
++ * (Hotplug script (or whatever) writes to the file to signal the completion
++ * of the script.) An ugly hack.
++ */
++static ssize_t msc_trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
++{
++ return count;
++}
++
++static struct file_operations msc_trace_proc_operations_functions = {
++ read:msc_trace_proc_read,
++ write:msc_trace_proc_write,
++};
++
++
++/**
++ * msc_trace_init
++ *
++ * Return non-zero if not successful.
++ */
++int msc_trace_init (char *name, struct msc_private *msc)
++{
++ printk(KERN_INFO"%s:\n", __FUNCTION__);
++ if (!(msc_traces = vmalloc(sizeof(msc_trace_t) * TRACE_MAX))) {
++ printk(KERN_ERR"%s: malloc failed %p %d\n", __FUNCTION__, msc_traces, sizeof(msc_trace_t) * TRACE_MAX);
++ return -EINVAL;
++ }
++ memset(msc_traces, 0, sizeof(msc_trace_t) * TRACE_MAX);
++
++ {
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry (name, 0, 0)) == NULL) {
++ printk(KERN_INFO"BITRACE PROC FS failed\n");
++ }
++ else {
++ p->proc_fops = &msc_trace_proc_operations_functions;
++ }
++ }
++ printk(KERN_INFO"%s: OK\n", __FUNCTION__);
++ msc_private = msc;
++ return 0;
++}
++
++/**
++ * udc_release_io - release UDC io region
++ */
++void msc_trace_exit (char *name)
++{
++ msc_private = NULL;
++ {
++ unsigned long flags;
++ local_irq_save (flags);
++ remove_proc_entry (name, NULL);
++ if (msc_traces) {
++ msc_trace_t *p = msc_traces;
++ msc_traces = NULL;
++ vfree(p);
++ }
++ local_irq_restore (flags);
++ }
++}
++
++
++#else
++int msc_trace_init (void)
++{
++ return 0;
++}
++
++void msc_trace_exit (char *)
++{
++ return;
++}
++#endif
++
+diff -uNr linux/drivers/no-otg/functions/msc/trace.h linux/drivers/otg/functions/msc/trace.h
+--- linux/drivers/no-otg/functions/msc/trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/msc/trace.h 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,303 @@
++/*
++ * otg/msc_fd/trace.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * Adapted from earlier work:
++ * Copyright (c) 2002, 2003 Belcarra
++ * Copyright (c) 2002 Lineo
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ *
++ */
++
++
++typedef enum msc_trace_int_types {
++ msc_trace_int_udc, msc_trace_int_ep0, msc_trace_int_in, msc_trace_int_out, msc_trace_int_int
++} msc_trace_int_types_t;
++
++typedef struct msc_trace_int {
++ u32 last;
++ u32 total;
++ u32 samples;
++} msc_trace_int_t;
++
++
++typedef enum msc_trace_types {
++ msc_trace_setup, msc_trace_msg, msc_trace_msg32, msc_trace_msg16,
++ msc_trace_msg8, msc_trace_recv, msc_trace_sent, msc_trace_w, msc_trace_r,
++ msc_trace_rlba, msc_trace_slba, msc_trace_tlba, msc_trace_tag,
++ msc_trace_sense, msc_trace_cbw
++} msc_trace_types_t;
++
++
++typedef struct msc_trace_regs32 {
++ u32 reg;
++ char * msg;
++} msc_trace_regs32_t;
++
++
++typedef struct msc_trace_msg {
++ char *msg;
++} msc_trace_msg_t;
++
++typedef struct msc_trace_msg32 {
++ u32 val;
++ char *msg;
++} msc_trace_msg32_t;
++
++typedef struct msc_trace_msg16 {
++ u16 val0;
++ u16 val1;
++ char *msg;
++} msc_trace_msg16_t;
++
++typedef struct msc_trace_msg8 {
++ u8 val0;
++ u8 val1;
++ u8 val2;
++ u8 val3;
++ char *msg;
++} msc_trace_msg8_t;
++
++
++typedef struct trace {
++ msc_trace_types_t msc_trace_type;
++ char *function;
++ u32 interrupts;
++ u64 ticks;
++ u64 sofs;
++
++ union {
++ msc_trace_msg_t msg;
++ msc_trace_msg8_t msg8;
++ msc_trace_msg16_t msg16;
++ msc_trace_msg32_t msg32;
++
++ struct usbd_device_request setup;
++ unsigned char recv[8];
++ unsigned char sent[8];
++
++ unsigned int ints[2];
++
++ } trace;
++
++} msc_trace_t;
++
++
++#define TRACE_MAX 30000
++
++extern int msc_trace_first;
++extern int msc_trace_next;
++
++extern msc_trace_int_t *msc_trace_ints;
++extern msc_trace_t *msc_traces;
++
++#ifdef CONFIG_OTG_MSC_REGISTER_TRACE
++
++msc_trace_t *MSC_TRACE_NEXT(msc_trace_types_t msc_trace_type);
++
++static __inline__ void TRACE_SETUP(struct usbd_device_request *setup)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_setup);
++ p->msc_trace_type = msc_trace_setup;
++ memcpy(&p->trace.setup, setup, sizeof(struct usbd_device_request));
++ }
++}
++
++static __inline__ void TRACE_MSG(char *msg)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg);
++ p->trace.msg.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_W(char *msg, u32 val)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_w);
++ p->trace.msg32.val = val;
++ p->trace.msg32.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_R(char *msg, u32 val)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_r);
++ p->trace.msg32.val = val;
++ p->trace.msg32.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_MSG32(char *msg, u32 val)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg32);
++ p->trace.msg32.val = val;
++ p->trace.msg32.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg16);
++ p->trace.msg16.val0 = val0;
++ p->trace.msg16.val1 = val1;
++ p->trace.msg16.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_MSG8(char *msg, u8 val0, u8 val1, u8 val2, u8 val3)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg8);
++ p->trace.msg8.val0 = val0;
++ p->trace.msg8.val1 = val1;
++ p->trace.msg8.val2 = val2;
++ p->trace.msg8.val3 = val3;
++ p->trace.msg8.msg = msg;
++ }
++}
++
++static __inline__ void TRACE_RECV(unsigned char *cp)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_recv);
++ memcpy(&p->trace.recv, cp, 8);
++ }
++}
++
++static __inline__ void TRACE_RECVN(unsigned char *cp, int bytes)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_recv);
++ memset(&p->trace.recv, 0, 8);
++ memcpy(&p->trace.recv, cp, bytes);
++ }
++}
++
++static __inline__ void TRACE_SENT(unsigned char *cp)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_sent);
++ memcpy(&p->trace.sent, cp, 8);
++ }
++}
++
++
++static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_rlba);
++ p->trace.ints[0] = lba;
++ p->trace.ints[1] = crc;
++ }
++}
++
++static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_slba);
++ p->trace.ints[0] = lba;
++ p->trace.ints[1] = crc;
++ }
++}
++
++static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_tlba);
++ p->trace.ints[0] = lba;
++ p->trace.ints[1] = crc;
++ }
++}
++
++static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_tag);
++ p->trace.ints[0] = tag;
++ p->trace.ints[1] = frame;
++ }
++}
++
++static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_sense);
++ p->trace.ints[0] = sense;
++ p->trace.ints[1] = info;
++ }
++}
++
++static __inline__ void TRACE_CBW(char *msg, int val)
++{
++ if (msc_traces) {
++ msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_cbw);
++ p->trace.msg32.val = val;
++ p->trace.msg32.msg = msg;
++ }
++}
++
++#else
++
++static __inline__ void TRACE_SETUP(struct usbd_device_request *setup)
++{
++}
++
++static __inline__ void TRACE_IRQS(u32 cr, u32 sr)
++{
++}
++
++static __inline__ void TRACE_RECV(unsigned char *cp)
++{
++}
++
++static __inline__ void TRACE_SENT(unsigned char *cp)
++{
++}
++
++static __inline__ void TRACE_W(char *msg, u32 val)
++{
++}
++
++static __inline__ void TRACE_R(char *msg, u32 val)
++{
++}
++
++static __inline__ void TRACE_MSG(char *msg)
++{
++}
++
++static __inline__ void TRACE_MSG32(char *msg, u32 val)
++{
++}
++
++static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
++{
++}
++
++static __inline__ void TRACE_TLBA(char *msg, u16 val0, u16 val1)
++{
++}
++
++static __inline__ void TRACE_TAG(char *msg, u16 val0, u16 val1)
++{
++}
++
++static __inline__ void TRACE_SENSE(char *msg, u8 val0, u8 val1, u8 val2, u8 vale)
++{
++}
++
++#endif
++
++int msc_trace_init (char *str, struct msc_private *);
++void msc_trace_exit (char *str);
++
+diff -uNr linux/drivers/no-otg/functions/network/Config.in linux/drivers/otg/functions/network/Config.in
+--- linux/drivers/no-otg/functions/network/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,70 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2004 Belcarra
++#
++
++mainmenu_option next_comment
++comment "USB Peripheral Function Driver - Network"
++
++dep_tristate ' Network Function Driver' CONFIG_OTG_NETWORK $CONFIG_OTG
++
++if [ "$CONFIG_OTG_NETWORK" != "n" ]; then
++
++ hex 'VendorID (hex value)' CONFIG_OTG_NETWORK_VENDORID "15ec"
++ hex 'ProductID (hex value)' CONFIG_OTG_NETWORK_PRODUCTID "e003"
++ hex 'bcdDevice (binary-coded decimal)' CONFIG_OTG_NETWORK_BCDDEVICE "0100"
++
++ string 'iManufacturer (string)' CONFIG_OTG_NETWORK_MANUFACTURER "Belcarra"
++ string 'iProduct (string)' CONFIG_OTG_NETWORK_PRODUCT_NAME "Belcarra BLAN Device"
++
++ choice "Mode" "\
++ MDLM-BLAN-Networking-for-personal-devices CONFIG_OTG_NETWORK_BLAN \
++ MDLM-SAFE-Networking-for-Bridge-Routers CONFIG_OTG_NETWORK_SAFE \
++ CDC-Networking-for-Bridge-Routers CONFIG_OTG_NETWORK_CDC \
++ Failsafe-BASIC-Networking-testing-only CONFIG_OTG_NETWORK_BASIC \
++ Failsafe-BASIC2-Networking-testing-only CONFIG_OTG_NETWORK_BASIC2 \
++ Experimental-Ethernet-Mode-Networking-testing-only CONFIG_OTG_NETWORK_EEM \
++ " MDLM-BLAN-Networking-for-personal-devices
++
++ if [ "$CONFIG_OTG_NETWORK_BLAN" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-blan
++ fi
++
++ if [ "$CONFIG_OTG_NETWORK_SAFE" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-safe
++ fi
++
++ if [ "$CONFIG_OTG_NETWORK_CDC" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-cdc
++ fi
++
++ if [ "$CONFIG_OTG_NETWORK_BASIC" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-basic
++ fi
++
++ if [ "$CONFIG_OTG_NETWORK_BASIC2" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-basic2
++ fi
++
++ if [ "$CONFIG_OTG_NETWORK_EEM" = "y" ]; then
++ source drivers/otg/functions/network/Config.in-eem
++ fi
++
++ comment ''
++ comment 'Testing Options'
++ bool 'Start Single Urb Test' CONFIG_OTG_NETWORK_START_SINGLE
++ bool 'EP0 Test' CONFIG_OTG_NETWORK_EP0TEST
++ dep_bool "Hotplug-config" CONFIG_OTG_NETWORK_HOTPLUG $CONFIG_HOTPLUG
++
++else
++ define_bool CONFIG_OTG_NETWORK_BLAN n
++ define_bool CONFIG_OTG_NETWORK_SAFE n
++ define_bool CONFIG_OTG_NETWORK_CDC n
++ define_bool CONFIG_OTG_NETWORK_BASIC n
++ define_bool CONFIG_OTG_NETWORK_BASIC2 n
++ define_bool CONFIG_OTG_NETWORK_EEM n
++fi
++
++endmenu
++
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-basic linux/drivers/otg/functions/network/Config.in-basic
+--- linux/drivers/no-otg/functions/network/Config.in-basic 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-basic 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,17 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++comment "BASIC Networking Configuration"
++
++ #bool " Failsafe BASIC Networking mode" CONFIG_OTG_NETWORK_BASIC
++ if [ "$CONFIG_OTG_NETWORK_BASIC" = "y" ]; then
++ comment 'BASIC Configuration'
++ string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_BASIC_DESC "BASIC Net Cfg"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_BASIC_INTF "Data Intf"
++ fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-basic2 linux/drivers/otg/functions/network/Config.in-basic2
+--- linux/drivers/no-otg/functions/network/Config.in-basic2 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-basic2 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,13 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++ comment "BASIC2 Networking Configuration"
++ string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_BASIC2_DESC "BASIC Net Cfg"
++ string 'Comm Interface iInterface (string)' CONFIG_OTG_NETWORK_BASIC2_COMM_INTF "Comm Intf"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_BASIC2_DATA_INTF "Data Intf"
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-blan linux/drivers/otg/functions/network/Config.in-blan
+--- linux/drivers/no-otg/functions/network/Config.in-blan 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-blan 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,38 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++ comment "MBLM-BLAN Networking Configuration"
++
++ string 'iConfiguration (string)' CONFIG_OTG_NETWORK_BLAN_DESC "BLAN Net Cfg"
++ string 'iInterface (string)' CONFIG_OTG_NETWORK_BLAN_INTF "Comm/Data Intf"
++
++
++ comment 'Special Framing Options'
++ bool "CRC" CONFIG_OTG_NETWORK_BLAN_CRC
++ if [ "$CONFIG_OTG_NETWORK_BLAN_CRC" = "y" ]; then
++
++ bool "Pad Before CRC (to wMaxPacketSize-1)" CONFIG_OTG_NETWORK_BLAN_PADBEFORE
++ bool "Pad After CRC" CONFIG_OTG_NETWORK_BLAN_PADAFTER
++ if [ "$CONFIG_OTG_NETWORK_BLAN" = "y" -a "$CONFIG_OTG_NETWORK_BLAN_PADAFTER" = "y" ]; then
++ int 'Pad multiple' CONFIG_OTG_NETWORK_BLAN_PADBYTES "8"
++ fi
++ bool "Fermat Randomizer" CONFIG_OTG_NETWORK_BLAN_FERMAT
++ fi
++
++ comment 'USBLAN Options'
++ bool "Do not Set Time" CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME
++ bool "Request Hostname" CONFIG_OTG_NETWORK_BLAN_HOSTNAME
++ bool "Infrastructure Device" CONFIG_OTG_NETWORK_BLAN_NONBRIDGED
++ bool "Data Notification OK" CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
++ int 'Pad multiple' CONFIG_OTG_NETWORK_BLAN_PADBYTES "8"
++ int 'Polling Interval ' CONFIG_OTG_NETWORK_BLAN_INTERVAL "4"
++ bool "Set iProduct from IPADDR" CONFIG_OTG_NETWORK_BLAN_IPADDR
++ bool "Auto-config" CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++ comment ''
++
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-cdc linux/drivers/otg/functions/network/Config.in-cdc
+--- linux/drivers/no-otg/functions/network/Config.in-cdc 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-cdc 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,16 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++ comment "CDC Networking Configuration"
++
++ string 'iConfiguration (string)' CONFIG_OTG_NETWORK_CDC_DESC "SAFE Net Cfg"
++ string 'Comm Interface iInterface (string)' CONFIG_OTG_NETWORK_CDC_COMM_INTF "Comm Intf"
++ string 'Data (diabled) iInterface (string)' CONFIG_OTG_NETWORK_CDC_NODATA_INTF "Data (Disabled) Intf"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_CDC_DATA_INTF "Data Intf"
++
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-eem linux/drivers/otg/functions/network/Config.in-eem
+--- linux/drivers/no-otg/functions/network/Config.in-eem 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-eem 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,17 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++comment "EEM Networking Configuration"
++
++ #bool " Experimental Ethernet Mode" CONFIG_OTG_NETWORK_EEM
++ if [ "$CONFIG_OTG_NETWORK_EEM" = "y" ]; then
++ comment 'EEM Configuration'
++ string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_EEM_DESC "EEM Net Cfg"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_EEM_INTF "Data Intf"
++ fi
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Config.in-safe linux/drivers/otg/functions/network/Config.in-safe
+--- linux/drivers/no-otg/functions/network/Config.in-safe 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Config.in-safe 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,21 @@
++#
++# Network Function
++#
++# Copyright (C) 2002-2003 Belcarra
++#
++
++mainmenu_option next_comment
++ comment "MDLM-SAFE Networking Configuration"
++
++ string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_SAFE_DESC "SAFE Net Cfg"
++ string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_SAFE_INTF "Data Intf"
++ bool " Do not Set Time" CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME
++ bool " CRC" CONFIG_OTG_NETWORK_SAFE_CRC
++ if [ "$CONFIG_OTG_NETWORK_SAFE_CRC" = "y" ]; then
++ bool "Pad Before CRC (to wMaxPacketSize-1)" CONFIG_OTG_NETWORK_SAFE_PADBEFORE
++ fi
++ bool "Infrastructure Device" CONFIG_OTG_NETWORK_SAFE_NONBRIDGED
++ comment ''
++
++
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Kconfig linux/drivers/otg/functions/network/Kconfig
+--- linux/drivers/no-otg/functions/network/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Kconfig 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,131 @@
++menu "OTG Network Function"
++ depends on OTG
++
++config OTG_NETWORK
++ tristate " Network Function Driver"
++ depends on OTG
++
++menu "OTG Network Function options"
++ depends on OTG_NETWORK
++
++config OTG_NETWORK_VENDORID
++ hex "VendorID (hex value)"
++ depends on OTG && OTG_NETWORK
++ default "0x15ec"
++
++config OTG_NETWORK_PRODUCTID
++ hex "ProductID (hex value)"
++ depends on OTG && OTG_NETWORK
++ default "0xe003"
++
++config OTG_NETWORK_BCDDEVICE
++ hex "bcdDevice (binary-coded decimal)"
++ depends on OTG && OTG_NETWORK
++ default "0x0100"
++
++config OTG_NETWORK_MANUFACTURER
++ string "iManufacturer (string)"
++ depends on OTG && OTG_NETWORK
++ default "Belcarra"
++
++config OTG_NETWORK_PRODUCT_NAME
++ string "iProduct (string)"
++ depends on OTG && OTG_NETWORK
++ default "Belcarra BLAN Device"
++
++config OTG_NETWORK_BLAN_DESC
++ string " iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "BLAN Net Cfg"
++
++config OTG_NETWORK_MANUFACTURER
++ string "iManufacturer (string)"
++ depends on OTG && OTG_NETWORK
++ default "Belcarra"
++
++config OTG_NETWORK_PRODUCT_NAME
++ string "iProduct (string)"
++ depends on OTG && OTG_NETWORK
++ default "Belcarra BLAN Device"
++
++config OTG_NETWORK_BLAN_DESC
++ string " iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "BLAN Net Cfg"
++
++config OTG_NETWORK_BLAN_INTF
++ string " iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Comm/Data Intf"
++
++config OTG_NETWORK_BLAN_PADBYTES
++ int " Pad multiple"
++ default "8"
++
++config OTG_NETWORK_SAFE_DESC
++ string " Data Interface iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "SAFE Net Cfg"
++
++config OTG_NETWORK_SAFE_INTF
++ string " Data Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Data Intf"
++
++config OTG_NETWORK_CDC_DESC
++ string " iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "SAFE Net Cfg"
++
++config OTG_NETWORK_CDC_COMM_INTF
++ string " Comm Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Comm Intf"
++
++config OTG_NETWORK_CDC_NODATA_INTF
++ string " Data (diabled) iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Data (Disabled) Intf"
++
++config OTG_NETWORK_CDC_DATA_INTF
++ string " Data Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Data Intf"
++
++config OTG_NETWORK_BASIC_DESC
++ string " Data Interface iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "BASIC Net Cfg"
++
++config OTG_NETWORK_BASIC_INTF
++ string " Data Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Data Intf"
++
++config OTG_NETWORK_BASIC2_DESC
++ string " Data Interface iConfiguration (string)"
++ depends on OTG && OTG_NETWORK
++ default "BASIC Net Cfg"
++
++config OTG_NETWORK_BASIC2_COMM_INTF
++ string " Comm Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Comm Intf"
++
++config OTG_NETWORK_BASIC2_DATA_INTF
++ string " Data Interface iInterface (string)"
++ depends on OTG && OTG_NETWORK
++ default "Data Intf"
++
++config OTG_NETWORK_START_SINGLE
++ bool " Start Single Urb Test"
++ depends on OTG && OTG_NETWORK
++ default n
++
++config OTG_NETWORK_EP0TEST
++ bool " EP0 Test"
++ depends on OTG && OTG_NETWORK
++ default n
++
++endmenu
++endmenu
+diff -uNr linux/drivers/no-otg/functions/network/Makefile linux/drivers/otg/functions/network/Makefile
+--- linux/drivers/no-otg/functions/network/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Makefile 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,70 @@
++#
++# Network Function Driver
++#
++# Copyright (C) 2002-2003 Belcarra
++
++
++O_TARGET := network_target.o
++list-multi := network_fd.o
++
++network_fd-objs := net-l24-os.o net-fd.o basic.o basic2.o blan.o cdc.o safe.o fermat.o
++
++# Objects that export symbols.
++export-objs := net-l24-os.o net-fd.o
++
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_NETWORK) += network_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++
++OTG_DIR=$(TOPDIR)/drivers/otg
++NETWORK_DIR=$(OTG_DIR)/functions/network
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -Wno-unused -Wstrict-prototypes -Wno-format
++EXTRA_CFLAGS += -I$(NETWORK_DIR) -I$(OTG_DIR)
++EXTRA_CFLAGS_nostdinc += -Wstrict-prototypes -Wno-unused -Wno-format
++EXTRA_CFLAGS_nostdinc += -I$(NETWORK_DIR) -I$(OTG_DIR)
++
++# Link rules for multi-part drivers.
++
++network_fd.o: $(network_fd-objs)
++ $(LD) -r -o $@ $(network_fd-objs)
++
++# dependencies:
++
++net-fd.o: net-fd.h net-os.h network.h
++net-l24-os.o: net-fd.h net-os.h network.h
++
++
+diff -uNr linux/drivers/no-otg/functions/network/Makefile-l26 linux/drivers/otg/functions/network/Makefile-l26
+--- linux/drivers/no-otg/functions/network/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/Makefile-l26 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,22 @@
++#
++# Network Function Driver
++#
++# Copyright (C) 2002-2004 Belcarra Technologies Corp
++
++
++OTG=$(TOPDIR)/drivers/otg
++NETWORKD=$(OTG)/functions/network
++OTGCORE_DIR=$(OTG)/otgcore
++USBDCORE_DIR=$(OTG)/usbdcore
++EXTRA_CFLAGS += -I$(NETWORKD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
++EXTRA_CFLAGS_nostdinc += -I$(NETWORKD) -I$(OTG) -Wno-unused -Wno-format -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
++
++network_fd-objs := network.o basic.o basic2.o blan.o cdc.o safe.o fermat.o
++obj-$(CONFIG_OTG_NETWORK) += network_fd.o
++
++
++# Link rules for multi-part drivers.
++
++network_fd.o: $(network_fd-objs)
++ $(LD) -r -o $@ $(network_fd-objs)
++
+diff -uNr linux/drivers/no-otg/functions/network/TODO.txt linux/drivers/otg/functions/network/TODO.txt
+--- linux/drivers/no-otg/functions/network/TODO.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/TODO.txt 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,32 @@
++NETWORK TODO List Stuart Lynne
++Belcarra Tue Aug 24 21:36:09 PDT 2004
++
++
++1. NETWORK documentation
++
++
++2. BLAN
++ - data notification
++ - timeout to resend data notification after XX mS
++
++3. CDC
++ - filters
++
++
++4. RNDIS
++ - should we add back in?
++
++
++5. NOTIFICATIONS
++
++ NETWORK_CONNECTION
++ CONNECTION_SPEED_CHANGE
++
++
++
++I suspect that we should make the data notification a runtime option,
++the host driver would "enable" this after a certain number of devices
++are plugged in (say 5 or more, some configurable number.) This would
++be done by sending a vendor device request to the peripheral to tell
++the network driver that it needs to use this mechanism.
++
+diff -uNr linux/drivers/no-otg/functions/network/basic.c linux/drivers/otg/functions/network/basic.c
+--- linux/drivers/no-otg/functions/network/basic.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/basic.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,247 @@
++/*
++ * otg/functions/network/basic.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/basic.c
++ * @brief This file implements the required descriptors to implement
++ * a basic network device with a single interface.
++ *
++ * The BASIC network driver implements a very simple descriptor set.
++ * A single interface with two BULK data endpoints and a optional
++ * INTERRUPT endpoint.
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++#ifdef CONFIG_OTG_NETWORK_BASIC
++/* USB BASIC Configuration ******************************************************************** */
++
++/* BASIC Communication Interface Class descriptors
++ */
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic_data_1 = {
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_OUT,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0,
++};
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0x0,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT,0, 0x00, 0x0a, };
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: 0,
++ bInterval: 0xa,
++};
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *basic_default[] = { &basic_data_1,
++ &basic_data_2,
++ &basic_comm_1, };
++u8 basic_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor basic_data_alternate_descriptor = {
++ bLength:sizeof(struct usbd_interface_descriptor),
++ bDescriptorType:USB_DT_INTERFACE,
++ bInterfaceNumber: 0x00,
++ bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (basic_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
++ bInterfaceClass:LINEO_CLASS,
++ bInterfaceSubClass:LINEO_SUBCLASS_BASIC_NET,
++ bInterfaceProtocol:LINEO_BASIC_NET_CRC,
++ iInterface:0x00,
++};
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description basic_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_NETWORK_BASIC_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&basic_data_alternate_descriptor,
++ endpoints:sizeof (basic_default) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: basic_default,
++ endpoint_indexes: basic_indexes,
++ },
++};
++
++
++/* BASIC Data Interface Alternate descriptions and descriptors
++ */
++
++/* BASIC Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++struct usbd_interface_description basic_interfaces[] = {
++ { alternates:sizeof (basic_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:basic_data_alternate_descriptions,},
++};
++
++/* BASIC Configuration descriptions and descriptors
++ */
++/*! Configuration Descriptor
++ */
++u8 basic_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (basic_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++/*! Configuration Description List
++ */
++struct usbd_configuration_description basic_description[] = {
++ { iConfiguration: CONFIG_OTG_NETWORK_BASIC_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)basic_configuration_descriptor,
++ },
++
++};
++
++/* BASIC Device Description
++ */
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor basic_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor basic_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request basic_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor basic_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description basic_device_description = {
++ device_descriptor: &basic_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &basic_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &basic_otg_descriptor,
++ iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
++ iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++/*! basic_init
++ * @param function The function instance
++ */
++void basic_init (struct usbd_function_instance *function)
++{
++ basic_data_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
++}
++
++/*! function driver description
++ */
++struct usbd_function_driver basic_function_driver = {
++ name: "network-BASIC",
++ fops: &net_fd_function_ops,
++ device_description: &basic_device_description,
++ bNumConfigurations: sizeof (basic_description) / sizeof (struct usbd_configuration_description),
++ configuration_description: basic_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ bNumInterfaces:sizeof (basic_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:basic_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: basic_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_BASIC */
++
+diff -uNr linux/drivers/no-otg/functions/network/basic2.c linux/drivers/otg/functions/network/basic2.c
+--- linux/drivers/no-otg/functions/network/basic2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/basic2.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,320 @@
++/*
++ * otg/functions/network/basic2.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/basic2.c
++ * @brief This file implements the required descriptors to implement
++ * a basic network device with two interfaces.
++ *
++ * The BASIC2 network driver implements a very simple descriptor set.
++ * A data interface with two BULK data endpoints and comm interface with
++ * an INTERRUPT endpoint.
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-compat.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++/* USB BASIC Configuration ******************************************************************** */
++
++/*
++ * This provides a slight amplification of the basic configuration, it moves the
++ * interrupt endpoint (if available) to a separate interface, so that it is similiar
++ * to the cdc configuration
++ */
++
++/* BASIC Communication Interface Class descriptors
++ */
++//static u8 basic2_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK, 0, 0x00, 0x00, };
++//static u8 basic2_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++//static u8 basic2_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT,0, 0x00, 0x0a, };
++
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic2_data_1 = {
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_OUT,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0,
++};
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic2_data_2 = {
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0x0,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor basic2_comm_1 = {
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: 0,
++ bInterval: 0xa,
++};
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *basic2_default[] = {
++ &basic2_data_1,
++ &basic2_data_2,
++ &basic2_comm_1, };
++u8 basic2_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++
++static struct usbd_endpoint_descriptor *basic2_comm_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) &basic2_comm_1, };
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *basic2_data_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) &basic2_data_1,
++ (struct usbd_endpoint_descriptor *) &basic2_data_2, };
++
++u8 basic2_comm_indexes[] = { INT_IN, };
++u8 basic2_data_indexes[] = { BULK_OUT, BULK_IN, };
++
++
++/* BASIC2 Data Interface Alternate endpoints
++ */
++
++
++#ifndef COMMUNICATIONS_NETWORK_SUBCLASS
++#define COMMUNICATIONS_NETWORK_SUBCLASS 0
++#endif
++
++#ifndef VENDOR_PROTOCOL
++#define VENDOR_PROTOCOL 0xFF
++#endif
++/*! Comm Interface Descriptor
++ */
++static struct usbd_interface_descriptor basic2_comm_alternate_descriptor = {
++ bLength:sizeof(struct usbd_interface_descriptor),
++ bDescriptorType:USB_DT_INTERFACE,
++ bInterfaceNumber: 0x00,
++ bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (basic2_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
++ bInterfaceClass:COMMUNICATIONS_INTERFACE_CLASS,
++ bInterfaceSubClass:COMMUNICATIONS_NETWORK_SUBCLASS,
++ bInterfaceProtocol:VENDOR_PROTOCOL,
++ iInterface:0x00,
++};
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor basic2_data_alternate_descriptor = {
++ bLength:sizeof(struct usbd_interface_descriptor),
++ bDescriptorType:USB_DT_INTERFACE,
++ bInterfaceNumber: 0x01,
++ bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (basic2_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
++ bInterfaceClass:DATA_INTERFACE_CLASS,
++ bInterfaceSubClass:COMMUNICATIONS_NO_SUBCLASS,
++ bInterfaceProtocol:COMMUNICATIONS_NO_PROTOCOL,
++ iInterface:0x00,
++};
++
++/*! Comm Alternate Interface Description List
++ */
++static struct usbd_alternate_description basic2_comm_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_NETWORK_BASIC2_COMM_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&basic2_comm_alternate_descriptor,
++ endpoints:sizeof (basic2_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list:basic2_comm_endpoints,
++ endpoint_indexes:basic2_comm_indexes,
++ },
++};
++
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description basic2_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_NETWORK_BASIC2_DATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&basic2_data_alternate_descriptor,
++ endpoints:sizeof (basic2_data_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: basic2_data_endpoints,
++ endpoint_indexes: basic2_data_indexes,
++ },
++};
++
++
++/* BASIC Data Interface Alternate descriptions and descriptors
++ */
++
++/* BASIC Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++static struct usbd_interface_description basic2_interfaces[] = {
++ { alternates:sizeof (basic2_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:basic2_comm_alternate_descriptions,},
++
++ { alternates:sizeof (basic2_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:basic2_data_alternate_descriptions,},
++};
++
++
++/* BASIC Configuration descriptions and descriptors
++ */
++/*! Configuration Descriptor
++ */
++u8 basic2_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (basic2_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++/*! Configuration Description List
++ */
++struct usbd_configuration_description basic2_description[] = {
++ { iConfiguration: CONFIG_OTG_NETWORK_BASIC2_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)basic2_configuration_descriptor,
++ },
++
++};
++
++/* BASIC Device Description
++ */
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor basic2_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor basic2_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request basic2_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor basic2_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++/*! Device Description
++ */
++struct usbd_device_description basic2_device_description = {
++ device_descriptor: &basic2_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &basic2_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &basic2_otg_descriptor,
++ iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
++ iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++/*! basic2_init
++ * @param function The function instance
++ */
++void basic2_init (struct usbd_function_instance *function)
++{
++ TRACE_MSG0(NTT,"entered");
++
++ basic2_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
++
++ TRACE_MSG2(NTT,"alternate: %p endpoints: %d",
++ basic2_data_alternate_descriptions,
++ basic2_data_alternate_descriptions->endpoints
++ );
++
++ TRACE_MSG0(NTT,"exited");
++}
++
++
++/*! function driver description
++ */
++struct usbd_function_driver basic2_function_driver = {
++ name: "network-BASIC2",
++ fops: &net_fd_function_ops,
++ device_description: &basic2_device_description,
++ bNumConfigurations: sizeof (basic2_description) / sizeof (struct usbd_configuration_description),
++ configuration_description: basic2_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ bNumInterfaces:sizeof (basic2_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:basic2_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: basic2_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_BASIC2 */
++
+diff -uNr linux/drivers/no-otg/functions/network/blan.c linux/drivers/otg/functions/network/blan.c
+--- linux/drivers/no-otg/functions/network/blan.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/blan.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,403 @@
++/*
++ * otg/functions/network/blan.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/blan.c
++ * @brief This file implements the required descriptors to implement
++ * a BLAN network device with a single interface.
++ *
++ * The BLAN network driver implements the BLAN protocol descriptors.
++ *
++ * The BLAN protocol is designed to support smart devices that want
++ * to create a virtual network between them host and other similiar
++ * devices.
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++#ifdef CONFIG_OTG_NETWORK_BLAN
++/* USB BLAN Configuration ******************************************************************** */
++
++/*
++ * BLAN Ethernet Configuration
++ */
++
++/* Communication Interface Class descriptors
++ */
++
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor blan_data_1 = {
++ .bLength = sizeof(struct usbd_endpoint_descriptor),
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = BULK,
++ .wMaxPacketSize = 0,
++ .bInterval = 0,
++};
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor blan_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++{
++ .bLength = sizeof(struct usbd_endpoint_descriptor),
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = BULK,
++ .wMaxPacketSize = 0,
++ .bInterval = 0x0,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor blan_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT,0, 0x00, 0x0a, };
++{
++ .bLength = sizeof(struct usbd_endpoint_descriptor),
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = INTERRUPT,
++ .wMaxPacketSize = 0,
++#if defined (CONFIG_OTG_NETWORK_BLAN_INTERVAL)
++ .bInterval = CONFIG_OTG_NETWORK_BLAN_INTERVAL,
++#else
++ .bInterval = 0x08,
++#endif /* defined (CONFIG_OTG_NETWORK_BLAN_INTERVAL) */
++};
++
++//static u8 blan_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static struct usbd_class_header_function_descriptor blan_class_1 = {
++ .bFunctionLength = 0x05, /* Length */
++ .bDescriptorType = CS_INTERFACE,
++ .bDescriptorSubtype = USB_ST_HEADER,
++ .bcdCDC = __constant_cpu_to_le16(0x0110) /*Version */
++};
++//static u8 blan_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
++// 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, /* bGUID */
++static struct usbd_class_mdlm_descriptor blan_class_2 = {
++ .bFunctionLength = 0x15,
++ .bDescriptorType = CS_INTERFACE,
++ .bDescriptorSubtype = USB_ST_MDLM,
++ .bcdVersion = __constant_cpu_to_le16(0x0100),
++ .bGUID = {
++ 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, /* bGUID */
++ 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, /* bGUID */ },
++};
++
++
++
++//static u8 blan_class_3[] = { 0x07, CS_INTERFACE, USB_ST_MDLMD, 0x01, 0x00, 0x00, 0x00, };
++static struct usbd_class_blan_descriptor blan_class_3 = {
++ .bFunctionLength = 0x07,
++ .bDescriptorType = CS_INTERFACE,
++ .bDescriptorSubtype = USB_ST_MDLMD,
++ .bGuidDescriptorType = 0x01,
++ .bmNetworkCapabilities = 0x00,
++ .bmDataCapabilities = 0x00,
++ .bPad = 0x00,
++};
++
++//static u8 blan_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF,
++// 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
++// 0x00, 0x00, 0x00 , };
++static struct usbd_class_ethernet_networking_descriptor blan_class_4 = {
++ .bFunctionLength = 0x0d,
++ .bDescriptorType = CS_INTERFACE,
++ .bDescriptorSubtype = USB_ST_ENF,
++ .iMACAddress = 0x00,
++ .bmEthernetStatistics = 0x00,
++ .wMaxSegmentSize = 0x05ea, /* 1514 maximum frame size */
++ .wNumberMCFilters = 0x00,
++ .bNumberPowerFilters = 0x00 ,
++};
++
++//static u8 blan_class_5[] = { 0x07, CS_INTERFACE, USB_ST_NCT, 0x00, 0x00, 0x00, 0x00, };
++static struct usbd_class_network_channel_descriptor blan_class_5 = {
++ .bFunctionLength = 0x07,
++ .bDescriptorType = CS_INTERFACE,
++ .bDescriptorSubtype = USB_ST_NCT,
++ .bEntityId = 0,
++ .iName = 0,
++ .bChannelIndex = 0,
++ .bPhysicalInterface = 0,
++};
++
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *blan_alt_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) &blan_data_1,
++ (struct usbd_endpoint_descriptor *) &blan_data_2,
++ (struct usbd_endpoint_descriptor *) &blan_comm_1, };
++
++u8 blan_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++
++static struct usbd_generic_class_descriptor *blan_comm_class_descriptors[] = {
++ (struct usbd_generic_class_descriptor *) &blan_class_1,
++ (struct usbd_generic_class_descriptor *) &blan_class_2,
++ (struct usbd_generic_class_descriptor *) &blan_class_3,
++ (struct usbd_generic_class_descriptor *) &blan_class_4,
++ (struct usbd_generic_class_descriptor *) &blan_class_5, };
++
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor blan_alternate_descriptor = {
++ .bLength = 0x09,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x00, // bInterfaceNumber, bAlternateSetting
++ .bNumEndpoints = sizeof (blan_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
++ .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS,
++ .bInterfaceSubClass = COMMUNICATIONS_MDLM_SUBCLASS,
++ .bInterfaceProtocol = COMMUNICATIONS_NO_PROTOCOL,
++ .iInterface = 0x00,
++};
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description blan_alternate_descriptions[] = {
++ {
++ .iInterface = CONFIG_OTG_NETWORK_BLAN_INTF,
++ .interface_descriptor = (struct usbd_interface_descriptor *)&blan_alternate_descriptor,
++ .classes = sizeof (blan_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ .class_list = blan_comm_class_descriptors,
++ .endpoints = sizeof (blan_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ .endpoint_list = blan_alt_endpoints,
++ .endpoint_indexes = blan_alt_indexes,
++ },
++};
++/* Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++static struct usbd_interface_description blan_interfaces[] = {
++ {
++ .alternates = sizeof (blan_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ .alternate_list = blan_alternate_descriptions,
++ },
++};
++
++
++/* Configuration descriptions and descriptors
++ */
++
++/*! Configuration Descriptor
++ */
++static struct usbd_configuration_descriptor blan_configuration_descriptor = {
++ .bLength = 0x09,
++ .bDescriptorType = USB_DT_CONFIGURATION,
++ .wTotalLength = 0x00, // wLength
++ .bNumInterfaces = sizeof (blan_interfaces) / sizeof (struct usbd_interface_description),
++ .bConfigurationValue = 0x01,
++ .iConfiguration = 0x00, // bConfigurationValue, iConfiguration
++ .bmAttributes = 0,
++ .bMaxPower = 0,
++};
++
++/*! Configuration Description List
++ */
++struct usbd_configuration_description blan_description[] = {
++ {
++ .iConfiguration = CONFIG_OTG_NETWORK_BLAN_DESC,
++ .configuration_descriptor = &blan_configuration_descriptor,
++ },
++};
++
++/* Device Description
++ */
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor blan_device_descriptor = {
++ .bLength = sizeof(struct usbd_device_descriptor),
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
++ .bDeviceClass = COMMUNICATIONS_DEVICE_CLASS,
++ .bDeviceSubClass = 0x02,
++ .bDeviceProtocol = 0x00,
++ .bMaxPacketSize0 = 0x00,
++ .idVendor = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ .idProduct = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor blan_device_qualifier_descriptor = {
++ .bLength = sizeof(struct usbd_device_qualifier_descriptor),
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++ .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
++ .bDeviceClass = COMMUNICATIONS_DEVICE_CLASS,
++ .bDeviceSubClass = 0x02,
++ .bDeviceProtocol = 0x00,
++ .bMaxPacketSize0 = 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request blan_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor blan_otg_descriptor = {
++ .bLength = sizeof(struct usbd_otg_descriptor),
++ .bDescriptorType = USB_DT_OTG,
++ .bmAttributes = 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description blan_device_description = {
++ .device_descriptor = &blan_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ .device_qualifier_descriptor = &blan_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ .otg_descriptor = &blan_otg_descriptor,
++ .iManufacturer = CONFIG_OTG_NETWORK_MANUFACTURER,
++ .iProduct = CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ .iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++/*! blan_init
++ * @param function The function instance
++ */
++void blan_init (struct usbd_function_instance *function)
++{
++ struct usbd_class_ethernet_networking_descriptor *ethernet;
++ struct usbd_class_network_channel_descriptor *channel;
++
++ int len = 0;
++ char buf[255];
++
++ buf[0] = 0;
++
++ blan_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
++
++ // Update the iMACAddress field in the ethernet descriptor
++ {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
++ char address_str[14];
++ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
++ local_dev_addr[0], local_dev_addr[1], local_dev_addr[2],
++ local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
++#else
++ char address_str[20];
++ sprintf(address_str, "%02x%02x%02x%02x%02x%02x",
++ local_dev_addr[0], local_dev_addr[1], local_dev_addr[2],
++ local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
++#endif
++ TRACE_MSG0(NTT,"alloc mac string");
++ if ((ethernet = &blan_class_4))
++ ethernet->iMACAddress = usbd_alloc_string(address_str);
++ TRACE_MSG0(NTT,"alloc mac string done");
++ }
++ TRACE_MSG0(NTT,"alloc channel string");
++ if ((channel = &blan_class_5))
++ channel->iName = usbd_alloc_string(system_utsname.nodename);
++ TRACE_MSG0(NTT,"alloc channel string done");
++
++#ifdef CONFIG_OTG_NETWORK_BLAN_PADBYTES
++ blan_class_3.bPad = CONFIG_OTG_NETWORK_BLAN_PADBYTES;
++ len += sprintf(buf + len, "PADBYTES: %02x ", blan_class_3.bPad);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_PADBEFORE
++ blan_class_3.bmDataCapabilities |= BMDATA_PADBEFORE;
++ len += sprintf(buf + len, "PADBEFORE: %02x ", blan_class_3.bmDataCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_PADAFTER
++ blan_class_3.bmDataCapabilities |= BMDATA_PADAFTER;
++ len += sprintf(buf + len, "PADAFTER: %02x ", blan_class_3.bmDataCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_CRC
++ blan_class_3.bmDataCapabilities |= BMDATA_CRC;
++ len += sprintf(buf + len, "CRC: %02x ", blan_class_3.bmDataCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
++ blan_class_3.bmDataCapabilities |= BMDATA_FERMAT;
++ len += sprintf(buf + len, "FERMAT: %02x ", blan_class_3.bmDataCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME
++ blan_class_3.bmDataCapabilities |= BMDATA_HOSTNAME;
++ len += sprintf(buf + len, "HOSTNAME: %02x ", blan_class_3.bmDataCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_NONBRIDGED
++ blan_class_3.bmNetworkCapabilities |= BMNETWORK_NONBRIDGED;
++ len += sprintf(buf + len, "NONBRIDGE: %02x ", blan_class_3.bmNetworkCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
++ blan_class_3.bmNetworkCapabilities |= BMNETWORK_DATA_NOTIFY_OK;
++ len += sprintf(buf + len, "DATA NOTIFY: %02x ", blan_class_3.bmNetworkCapabilities);
++#endif
++ if (strlen(buf))
++ TRACE_MSG1(NTT,"%s", buf);
++}
++
++/*! function driver description
++ */
++struct usbd_function_driver blan_function_driver = {
++ .name = "network-BLAN",
++ .fops = &net_fd_function_ops,
++ .device_description = &blan_device_description,
++ .bNumConfigurations = sizeof (blan_description) / sizeof (struct usbd_configuration_description),
++ .configuration_description = blan_description,
++ .idVendor = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ .idProduct = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ .bNumInterfaces = sizeof (blan_interfaces) / sizeof (struct usbd_interface_description),
++ .interface_list = blan_interfaces,
++ .endpointsRequested = ENDPOINTS,
++ .requestedEndpoints = blan_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_BLAN */
++
+diff -uNr linux/drivers/no-otg/functions/network/cdc.c linux/drivers/otg/functions/network/cdc.c
+--- linux/drivers/no-otg/functions/network/cdc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/cdc.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,376 @@
++/*
++ * otg/functions/network/cdc.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * The CDC network driver implements the standard CDC Ethernet descriptors.
++ *
++ * The CDC protocol is suitable for infrastructure devices that
++ * are implementing a bridged or routed connection betwen an
++ * external network and the USB Host.
++ *
++ */
++/*!
++ * @file otg/functions/network/cdc.c
++ * @brief This file implements the required descriptors to implement
++ * a CDC network device with two interfaces.
++ *
++ * @ingroup NetworkFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++
++#ifdef CONFIG_OTG_NETWORK_CDC
++/* USB CDC Configuration ********************************************************************* */
++
++/* CDC Communication Interface Class descriptors
++ */
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor cdc_data_1 = {
++ bLength: 0x07,
++ bDescriptorType: USB_DT_ENDPOINT,
++ bEndpointAddress: USB_DIR_OUT,
++ bmAttributes: BULK,
++ wMaxPacketSize: __constant_cpu_to_le16(0x00),
++ bInterval: 0x00,
++};
++
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor cdc_data_2 = {
++ bLength: 0x07,
++ bDescriptorType: USB_DT_ENDPOINT,
++ bEndpointAddress: USB_DIR_IN,
++ bmAttributes: BULK,
++ wMaxPacketSize: __constant_cpu_to_le16(0x00),
++ bInterval: 0x00,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor cdc_comm_1 = {
++ bLength: 0x07,
++ bDescriptorType: USB_DT_ENDPOINT,
++ bEndpointAddress: USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: __constant_cpu_to_le16(0x00),
++ bInterval: 0x0a,
++};
++
++
++
++
++//static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++
++static struct usbd_class_header_function_descriptor cdc_class_1 = {
++ bFunctionLength: 0x05,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_HEADER,
++ bcdCDC: __constant_cpu_to_le16(0x0110),
++};
++
++
++//static u8 cdc_class_2[] = {
++// 0x0d, CS_INTERFACE, USB_ST_ENF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
++// 0x00, 0x00, 0x00 , };
++static struct usbd_class_ethernet_networking_descriptor cdc_class_2 = {
++ bFunctionLength: 0x0D,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_HEADER,
++ iMACAddress: 0x00,
++ bmEthernetStatistics: 0x00,
++ wMaxSegmentSize: __constant_cpu_to_le16(0x05ea),
++ wNumberMCFilters: 0,
++ bNumberPowerFilters: 0,
++};
++
++//static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface, bSlaveInterface */};
++
++static struct usbd_class_union_function_descriptor cdc_class_3 =
++{
++ bFunctionLength: 0x05,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_UF,
++ bMasterInterface: 0x00,
++ bSlaveInterface0: {1},
++
++};
++
++static usbd_class_descriptor_t *cdc_comm_class_descriptors[] = {
++ (struct usbd_generic_class_descriptor *) &cdc_class_1,
++ (struct usbd_generic_class_descriptor *) &cdc_class_2,
++ (struct usbd_generic_class_descriptor *) &cdc_class_3,
++};
++
++/*! Endpoint descriptor list
++ */
++static usbd_endpoint_descriptor_t *cdc_data_endpoints[] = {
++ (struct usbd_endpoint_descriptor *) &cdc_data_1,
++ (struct usbd_endpoint_descriptor *) &cdc_data_2,
++};
++static usbd_endpoint_descriptor_t *cdc_comm_endpoints[] = {
++ (usbd_endpoint_descriptor_t *) &cdc_comm_1, };
++
++u8 cdc_comm_indexes[] = { INT_IN, };
++u8 cdc_data_indexes[] = { BULK_OUT, BULK_IN, };
++
++
++/*! Comm Interface Descriptor
++ */
++static struct usbd_interface_descriptor cdc_comm_alternate_descriptor = {
++ bLength: sizeof(struct usbd_interface_descriptor),
++ bDescriptorType: USB_DT_INTERFACE,
++ bInterfaceNumber: 0x00,
++ bAlternateSetting: 0x00,
++ bNumEndpoints: sizeof(cdc_comm_endpoints)/sizeof(usbd_endpoint_descriptor_t *),
++ bInterfaceClass: COMMUNICATIONS_INTERFACE_CLASS,
++ bInterfaceSubClass: COMMUNICATIONS_ENCM_SUBCLASS,
++ bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
++ iInterface: 0x00
++};
++
++/*! No Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor cdc_nodata_alternate_descriptor = {
++ bLength: sizeof(struct usbd_interface_descriptor),
++ bDescriptorType: USB_DT_INTERFACE,
++ bInterfaceNumber: 0x01,
++ bAlternateSetting: 0x00,
++ bNumEndpoints: 0,
++ bInterfaceClass: DATA_INTERFACE_CLASS,
++ bInterfaceSubClass: COMMUNICATIONS_NO_SUBCLASS,
++ bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
++ iInterface: 0x00
++};
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor cdc_data_alternate_descriptor = {
++ bLength: sizeof(struct usbd_interface_descriptor),
++ bDescriptorType: USB_DT_INTERFACE,
++ bInterfaceNumber: 0x01,
++ bAlternateSetting: 0x01,
++ bNumEndpoints: sizeof(cdc_comm_endpoints)/sizeof(usbd_endpoint_descriptor_t *),
++ bInterfaceClass: DATA_INTERFACE_CLASS,
++ bInterfaceSubClass: COMMUNICATIONS_NO_SUBCLASS,
++ bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
++ iInterface: 0x00
++};
++
++/*! Comm Alternate Interface Description List
++ */
++static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
++ {
++ iInterface: CONFIG_OTG_NETWORK_CDC_COMM_INTF,
++ interface_descriptor: &cdc_comm_alternate_descriptor,
++ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: cdc_comm_class_descriptors,
++
++ endpoints:sizeof (cdc_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: cdc_comm_endpoints,
++ endpoint_indexes: cdc_comm_indexes,
++ },
++};
++
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
++ {
++ iInterface: CONFIG_OTG_NETWORK_CDC_NODATA_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&cdc_nodata_alternate_descriptor,
++ },
++ {
++ iInterface: CONFIG_OTG_NETWORK_CDC_DATA_INTF,
++ interface_descriptor: &cdc_data_alternate_descriptor,
++ endpoints:sizeof (cdc_data_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: cdc_data_endpoints,
++ endpoint_indexes: cdc_data_indexes,
++ },
++};
++
++/* Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++static struct usbd_interface_description cdc_interfaces[] = {
++ {
++ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_comm_alternate_descriptions,
++ },
++ {
++ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:cdc_data_alternate_descriptions,
++ },
++};
++
++
++/* Configuration descriptions and descriptors
++ */
++
++/*! Configuration Descriptor
++ */
++static struct usbd_configuration_descriptor cdc_configuration_descriptor = {
++ bLength: sizeof(struct usbd_configuration_descriptor),
++ bDescriptorType: USB_DT_CONFIGURATION,
++ wTotalLength:0,
++ bNumInterfaces:sizeof(cdc_interfaces)/sizeof(struct usbd_interface_description *),
++ bConfigurationValue: 0x01,
++ iConfiguration: 0x00,
++ bmAttributes:0,
++ bMaxPower:0,
++};
++
++/*! Configuration Description List
++ */
++static struct usbd_configuration_description cdc_description[] = {
++ { iConfiguration: CONFIG_OTG_NETWORK_CDC_DESC,
++ configuration_descriptor: &cdc_configuration_descriptor,
++ },
++};
++
++
++
++/* Device Description
++ */
++
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor cdc_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor cdc_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request cdc_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 1, 1, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 1, 1, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor cdc_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description cdc_device_description = {
++ device_descriptor: &cdc_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &cdc_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &cdc_otg_descriptor,
++ iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
++ iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++
++/*! cdc_init
++ * @param function The function instance
++ */
++void cdc_init (struct usbd_function_instance *function)
++{
++ struct usbd_class_ethernet_networking_descriptor *ethernet;
++
++ cdc_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
++
++ // Update the iMACAddress field in the ethernet descriptor
++ {
++ char address_str[14];
++ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
++ remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2],
++ remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
++
++ if ((ethernet = &cdc_class_2)) {
++ if (ethernet->iMACAddress) {
++ usbd_free_string_descriptor(ethernet->iMACAddress);
++ }
++ ethernet->iMACAddress = usbd_alloc_string(address_str);
++ }
++ }
++}
++
++
++/*! function driver description
++ */
++struct usbd_function_driver cdc_function_driver = {
++ name: "network-CDC",
++ fops: &net_fd_function_ops,
++ device_description: &cdc_device_description,
++ bNumConfigurations: sizeof (cdc_description) / sizeof (struct usbd_configuration_description),
++ configuration_description: cdc_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:cdc_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: cdc_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_CDC */
++
+diff -uNr linux/drivers/no-otg/functions/network/eem.c linux/drivers/otg/functions/network/eem.c
+--- linux/drivers/no-otg/functions/network/eem.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/eem.c 2006-09-01 21:41:28.000000000 +0200
+@@ -0,0 +1,247 @@
++/*
++ * otg/functions/network/eem.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/eem.c
++ * @brief This file implements the required descriptors to implement
++ * a eem network device with a single interface.
++ *
++ * The BASIC network driver implements a very simple descriptor set.
++ * A single interface with two BULK data endpoints and a optional
++ * INTERRUPT endpoint.
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++#ifdef CONFIG_OTG_NETWORK_BASIC
++/* USB BASIC Configuration ******************************************************************** */
++
++/* BASIC Communication Interface Class descriptors
++ */
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor eem_data_1 = {
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_OUT,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0,
++};
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor eem_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN, BULK, 0, 0x00, 0x00, };
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: BULK,
++ wMaxPacketSize: 0,
++ bInterval: 0x0,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor eem_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN, INTERRUPT,0, 0x00, 0x0a, };
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: 0,
++ bInterval: 0xa,
++};
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *eem_default[] = { &eem_data_1,
++ &eem_data_2,
++ &eem_comm_1, };
++u8 eem_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor eem_data_alternate_descriptor = {
++ bLength:sizeof(struct usbd_interface_descriptor),
++ bDescriptorType:USB_DT_INTERFACE,
++ bInterfaceNumber: 0x00,
++ bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
++ sizeof (eem_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
++ bInterfaceClass:LINEO_CLASS,
++ bInterfaceSubClass:LINEO_SUBCLASS_BASIC_NET,
++ bInterfaceProtocol:LINEO_BASIC_NET_CRC,
++ iInterface:0x00,
++};
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description eem_data_alternate_descriptions[] = {
++ { iInterface: CONFIG_OTG_NETWORK_BASIC_INTF,
++ interface_descriptor: (struct usbd_interface_descriptor *)&eem_data_alternate_descriptor,
++ endpoints:sizeof (eem_default) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: eem_default,
++ endpoint_indexes: eem_indexes,
++ },
++};
++
++
++/* BASIC Data Interface Alternate descriptions and descriptors
++ */
++
++/* BASIC Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++struct usbd_interface_description eem_interfaces[] = {
++ { alternates:sizeof (eem_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:eem_data_alternate_descriptions,},
++};
++
++/* BASIC Configuration descriptions and descriptors
++ */
++/*! Configuration Descriptor
++ */
++u8 eem_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
++ 0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
++ sizeof (eem_interfaces) / sizeof (struct usbd_interface_description),
++ 0x01, 0x00, // bConfigurationValue, iConfiguration
++ 0, 0,
++};
++
++/*! Configuration Description List
++ */
++struct usbd_configuration_description eem_description[] = {
++ { iConfiguration: CONFIG_OTG_NETWORK_BASIC_DESC,
++ configuration_descriptor: (struct usbd_configuration_descriptor *)eem_configuration_descriptor,
++ },
++
++};
++
++/* BASIC Device Description
++ */
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor eem_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor eem_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request eem_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor eem_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description eem_device_description = {
++ device_descriptor: &eem_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &eem_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &eem_otg_descriptor,
++ iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
++ iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++
++/*! eem_init
++ * @param function The function instance
++ */
++void eem_init (struct usbd_function_instance *function)
++{
++ eem_data_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
++}
++
++/*! function driver description
++ */
++struct usbd_function_driver eem_function_driver = {
++ name: "network-BASIC",
++ fops: &net_fd_function_ops,
++ device_description: &eem_device_description,
++ bNumConfigurations: sizeof (eem_description) / sizeof (struct usbd_configuration_description),
++ configuration_description: eem_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ bNumInterfaces:sizeof (eem_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:eem_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: eem_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_BASIC */
++
+diff -uNr linux/drivers/no-otg/functions/network/fermat.c linux/drivers/otg/functions/network/fermat.c
+--- linux/drivers/no-otg/functions/network/fermat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/fermat.c 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,140 @@
++/*
++ * otg/functions/network/fermat.c - Network Function Driver
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/fermat.c
++ * @brief This implements a special data munging function that
++ * randomizes data. This is a very specific fix for a device
++ * that had trouble with runs of zeros.
++ *
++ * @ingroup NetworkFunction
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++
++#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
++
++#include "fermat.h"
++
++#ifndef FERMAT_DEFINED
++typedef unsigned char BYTE;
++typedef struct fermat {
++ int length;
++ BYTE power[256];
++} FERMAT;
++#endif
++
++
++static int fermat_setup(FERMAT *p, int seed){
++ int i = 0;
++ unsigned long x,y;
++ y = 1;
++ do{
++ x = y;
++ p->power[i] = ( x == 256 ? 0 : x);
++ y = ( seed * x ) % 257;
++ i += 1;
++ }while( y != 1);
++ p->length = i;
++ return i;
++}
++
++static void fermat_xform(FERMAT *p, BYTE *data, int length){
++ BYTE *pw = p->power;
++ int i, j;
++ BYTE * q ;
++ for(i = 0, j=0, q = data; i < length; i++, j++, q++){
++ if(j>=p->length){
++ j = 0;
++ }
++ *q ^= pw[j];
++ }
++}
++
++static FERMAT default_fermat;
++static const int primitive_root = 5;
++void fermat_init(){
++ (void) fermat_setup(&default_fermat, primitive_root);
++}
++
++// Here are the public official versions.
++// Change the primitive_root above to another primitive root
++// if you need better scatter. Possible values are 3 and 7
++
++
++void fermat_encode(BYTE *data, int length){
++ fermat_xform(&default_fermat, data, length);
++}
++
++void fermat_decode(BYTE *data, int length){
++ fermat_xform(&default_fermat, data, length);
++}
++
++
++// Note: the seed must be a "primitive root" of 257. This means that
++// the return value of the setup routine must be 256 (otherwise the
++// seed is not a primitive root. The routine will still work fine
++// but will be less pseudo-random.
++
++#undef TEST
++#if TEST
++#include <stdio.h>
++#include <memory.h>
++
++// Use FERMAT in two ways: to encode, and to generate test data.
++
++main(){
++ //Note 3, 5, and 7 are primitive roots of 257
++ // 11 is not a primitive root
++ FERMAT three, five, seven;
++
++ FERMAT three2;
++ printf("Cycle lengths: 3,5,7 %d %d %d \n",
++ fermat_setup(&three, 3),
++ fermat_setup(&five, 5),
++ fermat_setup(&seven, 7));
++ three2=three; // Copy data from three
++ fermat_xform(&three,three2.power,three2.length);
++ fermat_xform(&five,three2.power,three2.length);
++ fermat_xform(&seven,three2.power,three2.length);
++ fermat_xform(&seven,three2.power,three2.length);
++ fermat_xform(&five,three2.power,three2.length);
++ fermat_xform(&three,three2.power,three2.length);
++
++ //At this stage, three2 and three should be identical
++ if(memcpy(&three,&three2,sizeof(FERMAT))){
++ printf("Decoded intact\n");
++ }
++
++ fermat_init();
++ fermat_encode(three2.power,256);
++
++}
++#endif
++
++#endif /* CONFIG_OTG_NETWORK_BLAN_FERMAT */
++
+diff -uNr linux/drivers/no-otg/functions/network/fermat.h linux/drivers/otg/functions/network/fermat.h
+--- linux/drivers/no-otg/functions/network/fermat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/fermat.h 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,46 @@
++/*
++ * otg/functions/network/fermat.h - Network Function Driver
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ */
++/*!
++ * @file otg/functions/network/fermat.h
++ * @brief Fermat related data structures.
++ *
++ *
++ * @ingroup NetworkFunction
++ */
++
++#ifndef FERMAT_DEFINED
++#define FERMAT_DEFINED 1
++typedef unsigned char BYTE;
++typedef struct fermat {
++ int length;
++ BYTE power[256];
++} FERMAT;
++
++void fermat_init(void);
++void fermat_encode(BYTE *data, int length);
++void fermat_decode(BYTE *data, int length);
++#endif
++
++
+diff -uNr linux/drivers/no-otg/functions/network/net-fd.c linux/drivers/otg/functions/network/net-fd.c
+--- linux/drivers/no-otg/functions/network/net-fd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/net-fd.c 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,1463 @@
++/*
++ * otg/functions/network/net-fd.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/net-fd.c
++ * @brief The lower edge (USB Device Function) implementation of
++ * the Network Function Driver. This performs the core protocol
++ * handling and data encpasulation.
++ *
++ * This implements the lower edge (USB Device) layer of the Network Function
++ * Driver. Specifically the data encapsulation, envent and protocol handlers.
++ *
++ *
++ *
++ * This network function driver intended to interoperate with
++ * Belcarra's USBLAN Class drivers.
++ *
++ * These are available for Windows, Linux and Mac OSX. For more
++ * information and to download a copy for testing:
++ *
++ * http://www.belcarra.com/usblan/
++ *
++ * When configured for CDC it can also work with any CDC Class driver.
++ *
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++//#include <linux/config.h>
++//#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <net/arp.h>
++#include <linux/rtnetlink.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/random.h>
++#include <linux/utsname.h>
++
++#include <linux/ip.h>
++#include <linux/if_ether.h>
++#include <linux/in.h>
++#include <linux/inetdevice.h>
++
++#include <linux/kmod.h>
++
++#include <asm/uaccess.h>
++#include <asm/system.h>
++
++#include <otg/usbp-chap9.h>
++//#include <otg/usbd-mem.h>
++#include <otg/usbp-func.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#include "network.h"
++#include "net-fd.h"
++#include "net-os.h"
++#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
++#include "fermat.h"
++#endif
++
++otg_tag_t network_fd_trace_tag;
++#define NTT network_fd_trace_tag
++
++#if defined(CONFIG_OTG_NETWORK_CDC)
++void cdc_init(struct usbd_function_instance *);
++extern struct usbd_function_driver cdc_function_driver;
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_EEM
++void eem_init(struct usbd_function_instance *);
++extern struct usbd_function_driver eem_function_driver;
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC
++void basic_init(struct usbd_function_instance *);
++extern struct usbd_function_driver basic_function_driver;
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++void basic2_init(struct usbd_function_instance *);
++extern struct usbd_function_driver basic2_function_driver;
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_SAFE
++void safe_init(struct usbd_function_instance *);
++extern struct usbd_function_driver safe_function_driver;
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BLAN
++void blan_init(struct usbd_function_instance *);
++extern struct usbd_function_driver blan_function_driver;
++#endif
++
++static char ip_addr_str[20];
++u32 ip_addr;
++u32 router_ip;
++u32 network_mask;
++u32 dns_server_ip;
++
++//_________________________________________________________________________________________________
++
++/*
++ * If the following are defined we implement the crc32_copy routine using
++ * Duff's device. This will unroll the copy loop by either 4 or 8. Do not
++ * use these without profiling to test if it actually helps on any specific
++ * device.
++ */
++#undef CONFIG_OTG_NETWORK_CRC_DUFF4
++#undef CONFIG_OTG_NETWORK_CRC_DUFF8
++
++static u32 *network_crc32_table;
++
++#define CRC32_INIT 0xffffffff // Initial FCS value
++#define CRC32_GOOD 0xdebb20e3 // Good final FCS value
++
++#define CRC32_POLY 0xedb88320 // Polynomial for table generation
++
++#define COMPUTE_FCS(val, c) (((val) >> 8) ^ network_crc32_table[((val) ^ (c)) & 0xff])
++
++//_________________________________________________________________________________________________
++// crc32_copy
++
++/*! make_crc_table
++ * Generate the crc32 table
++ *
++ * @return non-zero if malloc fails
++ */
++STATIC int make_crc_table(void)
++{
++ u32 n;
++ RETURN_ZERO_IF(network_crc32_table);
++ RETURN_ENOMEM_IF(!(network_crc32_table = (u32 *)ckmalloc(256*4, GFP_KERNEL)));
++ for (n = 0; n < 256; n++) {
++ int k;
++ u32 c = n;
++ for (k = 0; k < 8; k++) {
++ c = (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1);
++ }
++ network_crc32_table[n] = c;
++ }
++ return 0;
++}
++
++#if !defined(CONFIG_OTG_NETWORK_CRC_DUFF4) && !defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
++/*! crc32_copy
++ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
++ *
++ * @param dst Pointer to the destination memory area.
++ * @param src Pointer to the source memory area.
++ * @param len Number of bytes to copy.
++ * @param val Starting value for the CRC FCS.
++ *
++ * @return Final value of the CRC FCS.
++ *
++ * @sa crc32_pad
++ */
++static u32 __inline__ crc32_copy (u8 *dst, u8 *src, int len, u32 val)
++{
++ for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = *src++));
++ return val;
++}
++
++#else /* DUFFn */
++
++/*! crc32_copy
++ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
++ *
++ * @param dst Pointer to the destination memory area.
++ * @param src Pointer to the source memory area.
++ * @param len Number of bytes to copy.
++ * @param val Starting value for the CRC FCS.
++ *
++ * @return Final value of the CRC FCS.
++ *
++ * @sa crc32_pad
++ */
++static u32 crc32_copy (u8 *dst, u8 *src, int len, u32 val)
++{
++#if defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
++ int n = (len + 7) / 8;
++ switch (len % 8)
++#elif defined(CONFIG_OTG_NETWORK_CRC_DUFF4)
++ int n = (len + 3) / 4;
++ switch (len % 4)
++#endif
++ {
++ case 0: do {
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++#if defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
++ case 7:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ case 6:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ case 5:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ case 4:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++#endif
++ case 3:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ case 2:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ case 1:
++ val = COMPUTE_FCS (val, *dst++ = *src++);
++ } while (--n > 0);
++ }
++ return val;
++}
++#endif /* DUFFn */
++
++
++//_________________________________________________________________________________________________
++// crc32_pad
++
++/*! crc32_pad - pad and calculate crc32
++ *
++ * @return CRC FCS
++ */
++static u32 __inline__ crc32_pad (u8 *dst, int len, u32 val)
++{
++ for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = '\0'));
++ return val;
++}
++
++//_________________________________________________________________________________________________
++// net_fd_send_int
++//
++
++/*! net_fd_urb_sent_int - callback for completed INT URB
++ *
++ * Handles notification that an urb has been sent (successfully or otherwise).
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_urb_sent_int (struct usbd_urb *urb, int urb_rc)
++{
++ unsigned long flags;
++ int rc = -EINVAL;
++ struct usb_network_private *npd = urb->function_privdata;
++
++ TRACE_MSG3(NTT,"urb: %p npd: %p urb_rc: %d", urb, npd, urb_rc);
++
++ local_irq_save(flags);
++ npd->int_urb = NULL;
++ usbd_free_urb (urb);
++ local_irq_restore(flags);
++ return 0;
++}
++
++/*! net_fd_send_int_blan - send an interrupt notification response
++ *
++ * Generates a response urb on the notification (INTERRUPT) endpoint.
++ *
++ * This is called from either a scheduled task or from the process context
++ * that calls network_open() or network_close().
++ * This must be called with interrupts locked out as net_fd_event_handler can
++ * change the NETWORK_ATTACHED status
++ *
++ */
++STATIC void net_fd_send_int_blan(struct usb_network_private *npd, int connected, int data)
++{
++ struct usbd_urb *urb;
++ struct cdc_notification_descriptor *cdc;
++ int rc;
++ struct usbd_function_instance *function = (npd?npd->function:NULL);
++
++ TRACE_MSG2(NTT,"npd=%p function=%p",npd,function);
++
++ do {
++ BREAK_IF(!function);
++
++
++ BREAK_IF(npd->network_type != network_blan);
++ BREAK_IF(!npd->have_interrupt);
++
++ BREAK_IF(!(npd->flags & NETWORK_ATTACHED));
++
++ TRACE_MSG3(NTT,"connected: %d network: %d %d", connected,
++ npd->network_type, network_blan);
++
++ BREAK_IF(usbd_get_device_status(function) != USBD_OK);
++
++ //if (npd->int_urb) {
++ // printk(KERN_INFO"%s: int_urb: %p\n", __FUNCTION__, npd->int_urb);
++ // usbd_cancel_urb_irq(npd->int_urb);
++ // npd->int_urb = NULL;
++ //}
++
++ BREAK_IF(!(urb = usbd_alloc_urb (function, INT_IN,
++ sizeof(struct cdc_notification_descriptor), net_fd_urb_sent_int)));
++
++ urb->actual_length = sizeof(struct cdc_notification_descriptor);
++ memset(urb->buffer, 0, sizeof(struct cdc_notification_descriptor));
++ urb->function_privdata = npd;
++
++ cdc = (struct cdc_notification_descriptor *)urb->buffer;
++
++ cdc->bmRequestType = 0xa1;
++
++ if (data) {
++ cdc->bNotification = 0xf0;
++ cdc->wValue = 1;
++ }
++ else {
++ cdc->bNotification = 0x00;
++ cdc->wValue = connected ? 0x01 : 0x00;
++ }
++ cdc->wIndex = 0x00; // XXX interface - check that this is correct
++
++
++ npd->int_urb = urb;
++ TRACE_MSG1(NTT,"int_urb: %p", urb);
++ BREAK_IF (!(rc = usbd_start_in_urb (urb)));
++
++ TRACE_MSG1(NTT,"usbd_start_in_urb failed err: %x", rc);
++ printk(KERN_ERR"%s: usbd_start_in_urb failed err: %x\n", __FUNCTION__, rc);
++ urb->function_privdata = NULL;
++ npd->int_urb = NULL;
++ usbd_free_urb (urb);
++
++ } while(0);
++}
++
++//_________________________________________________________________________________________________
++// net_fd_start_xmit
++
++/*! net_fd_urb_sent_bulk - callback for completed BULK xmit URB
++ *
++ * Handles notification that an urb has been sent (successfully or otherwise).
++ *
++ * @param urb Pointer to the urb that has been sent.
++ * @param urb_rc Result code from the send operation.
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_urb_sent_bulk (struct usbd_urb *urb, int urb_rc)
++{
++ unsigned long flags;
++ void *buff_ctx;
++ int rc = -EINVAL;
++
++ TRACE_MSG2(NTT,"urb: %p urb_rc: %d", urb, urb_rc);
++
++ local_irq_save(flags);
++ do {
++
++ BREAK_IF(!urb);
++ buff_ctx = urb->function_privdata;
++ TRACE_MSG2(NTT,"urb: %p buff_ctx: %p", urb, buff_ctx);
++ urb->function_privdata = NULL;
++
++ BREAK_IF(net_os_xmit_done(urb->function_instance,buff_ctx,urb_rc));
++
++ usbd_free_urb (urb);
++ rc = 0;
++
++ } while (0);
++ local_irq_restore(flags);
++ return rc;
++}
++
++/*! net_fd_start_xmit - start sending a buffer
++ *
++ * Called with net_os_mutex_enter()d.
++ *
++ * @return: 0 if all OK
++ * -EINVAL, -EUNATCH, -ENOMEM
++ * rc from usbd_start_in_urb() if that fails (is != 0, may be one of err values above)
++ * Note: -ECOMM is interpreted by calling routine as signal to leave IF stopped.
++ */
++STATIC int net_fd_start_xmit (struct usb_network_private *npd, u8 *buff, int len, void *buff_ctx)
++{
++ struct usbd_function_instance *function = (npd?npd->function:NULL);
++ struct usbd_urb *urb = NULL;
++ int rc;
++ int in_pkt_sz;
++ u8 *cp;
++ u32 crc;
++ TRACE_MSG2(NTT,"npd=%p function=%p",npd,function);
++
++#if 0
++ printk(KERN_INFO"%s: %s len: %d encap: %d\n", __FUNCTION__, net_device->name, len, npd->encapsulation);
++ printk(KERN_INFO"start_xmit: len: %x data: %p\n", len, buff);
++ {
++ u8 *cp = buff;
++ int i;
++ for (i = 0; i < len; i++) {
++ if ((i%32) == 0) {
++ printk("\ntx[%2x] ", i);
++ }
++ printk("%02x ", *cp++);
++ }
++ printk("\n");
++ }
++#endif
++
++ if (!(npd->flags & NETWORK_ATTACHED)) {
++ return -EUNATCH;
++ }
++ if (usbd_get_device_status(function) != USBD_OK) {
++ return -EINVAL;
++ }
++
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ // verify interface is enabled - non-zero altsetting means data is enabled
++ if (!usbd_interface_AltSetting(function, DATA_INTF)) {
++ return -EINVAL;
++ }
++#endif
++ in_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_IN, usbd_high_speed(function));
++
++ if (npd->encapsulation != simple_crc) {
++ TRACE_MSG0(NTT,"unknown encapsulation");
++ printk(KERN_ERR"%s: unknown encapsulation\n", __FUNCTION__);
++ // Since we are now only really using one, just fix it.
++ npd->encapsulation = simple_crc;
++ }
++ //TRACE_MSG0(NTT,"SIMPLE_CRC");
++ // allocate urb 5 bytes larger than required
++ if (!(urb = usbd_alloc_urb (function, BULK_IN, len + 5 + 4 + in_pkt_sz, net_fd_urb_sent_bulk ))) {
++ u8 epa = usbd_endpoint_bEndpointAddress(function, BULK_IN, usbd_high_speed(function));
++ TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa);
++ printk(KERN_ERR"%s: urb alloc failed len: %d endpoint: %02x\n", __FUNCTION__, len, epa);
++ return -ENOMEM;
++ }
++
++ switch (npd->network_type) {
++ case network_eem:
++ cp = urb->buffer + 2;
++ urb->actual_length = len + 2;
++ break;
++ default:
++ cp = urb->buffer;
++ urb->actual_length = len;
++ break;
++ }
++ // copy and crc len bytes
++ crc = crc32_copy(cp, buff, len, CRC32_INIT);
++
++ switch (npd->network_type) {
++ case network_eem:
++ break;
++ default:
++ if ((urb->actual_length % in_pkt_sz) == (in_pkt_sz - 4)) {
++
++ #undef CONFIG_OTG_NETWORK_PADBYTE
++ #ifdef CONFIG_OTG_NETWORK_PADBYTE
++ // add a pad byte if required to ensure a short packet, usbdnet driver
++ // will correctly handle pad byte before or after CRC, but the MCCI driver
++ // wants it before the CRC.
++ crc = crc32_pad(urb->buffer + urb->actual_length, 1, crc);
++ urb->actual_length++;
++ #else /* CONFIG_OTG_NETWORK_PADBYTE */
++ urb->flags |= USBD_URB_SENDZLP;
++ TRACE_MSG2(NTT,"setting ZLP: urb: %p flags: %x", urb, urb->flags);
++ #endif /* CONFIG_OTG_NETWORK_PADBYTE */
++ }
++ break;
++ }
++ // munge and append crc
++ crc = ~crc;
++ urb->buffer[urb->actual_length++] = crc & 0xff;
++ urb->buffer[urb->actual_length++] = (crc >> 8) & 0xff;
++ urb->buffer[urb->actual_length++] = (crc >> 16) & 0xff;
++ urb->buffer[urb->actual_length++] = (crc >> 24) & 0xff;
++ // End of CRC processing
++ //
++ switch (npd->network_type) {
++ case network_eem:
++ break;
++ default:
++ break;
++ }
++
++ TRACE_MSG3(NTT,"urb=%p buff_ctx=%p priv=%p",urb,buff_ctx,urb->function_privdata);
++ urb->function_privdata = (void *) buff_ctx;
++#if 0
++ printk(KERN_INFO"start_xmit: len: %d : %d data: %p\n", skb->len, urb->actual_length, urb->buffer);
++ {
++ u8 *cp = urb->buffer;
++ int i;
++ for (i = 0; i < urb->actual_length; i++) {
++ if ((i%32) == 0) {
++ printk("\ntx[%2x] ", i);
++ }
++ printk("%02x ", *cp++);
++ }
++ printk("\n");
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_BLAN_FERMAT)
++ if (npd->fermat) {
++ fermat_encode(urb->buffer, urb->actual_length);
++ }
++#endif
++ TRACE_MSG1(NTT,"sending urb: %p", urb);
++ if ((rc = usbd_start_in_urb (urb))) {
++
++ TRACE_MSG1(NTT,"FAILED: %d", rc);
++ printk(KERN_ERR"%s: FAILED: %d\n", __FUNCTION__, rc);
++ urb->function_privdata = NULL;
++ usbd_free_urb (urb);
++
++ return(rc);
++ }
++ #if 0
++ {
++ static int xmit_count = 0;
++ if (xmit_count++ == 100) {
++ TRACE_MSG1(NTT, "halt test: %02x", BULK_IN);
++ usbd_halt_endpoint(function, BULK_IN);
++ }
++ }
++ #endif
++
++ TRACE_MSG0(NTT,"OK");
++ return 0;
++}
++
++
++//_________________________________________________________________________________________________
++
++/*! net_fd_recv_urb - callback to process a received URB
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_recv_urb(struct usbd_urb *urb, int rc)
++{
++ struct usbd_function_instance *function = urb->function_instance;
++ struct usb_network_private *npd = urb->function_privdata;
++ void *buff_ctx = NULL;
++ u8 *buff;
++ int crc_bad = 0;
++ int trim = 0;
++ int len;
++ int out_pkt_sz;
++ u32 crc;
++
++#if 0
++ printk(KERN_INFO"%s: urb: %p len: %d maxtransfer: %d encap: %d\n", __FUNCTION__,
++ urb, urb->actual_length, npd->maxtransfer, npd->encapsulation);
++
++ {
++ u8 *cp = urb->buffer;
++ int i;
++ for (i = 0; i < urb->actual_length; i++) {
++ if ((i%32) == 0) {
++ printk("\n[%2x] ", i);
++ }
++ printk("%02x ", *cp++);
++ }
++ printk("\n");
++ }
++#endif
++ if (!urb || !urb->function_instance || !npd || !npd->function ||
++ urb->function_instance != npd->function) {
++ TRACE_MSG4(NTT,"urb=%p npd=%p u->f=%p n->f=%p",
++ urb,(urb?npd:NULL),(urb?urb->function_instance:NULL),
++ ((urb&&npd)?npd->function:NULL));
++ }
++
++ THROW_IF(urb->status != RECV_OK, error);
++
++ out_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
++ // There is only one working encapsulation.
++ if (npd->encapsulation != simple_crc) {
++ npd->encapsulation = simple_crc;
++ }
++
++ len = urb->actual_length;
++ trim = 0;
++ buff_ctx = net_os_alloc_buff(npd, &buff, len);
++ THROW_IF((NULL == buff_ctx), error);
++
++#if defined(CONFIG_OTG_NETWORK_BLAN_PADAFTER)
++ {
++ /* This version simply checks for a correct CRC along the
++ * entire packet. Some UDC's have trouble with some packet
++ * sizes, this allows us to add pad bytes after the CRC.
++ */
++
++ u8 *src = urb->buffer;
++ int copied;
++
++ // XXX this should work, but the MIPS optimizer seems to get it wrong....
++ //copied = (len < out_pkt_sz) ? 0 : ((len / out_pkt_sz) - 1) * out_pkt_sz;
++
++ if (len < out_pkt_sz*2)
++ copied = 0;
++ else {
++ int pkts = ((len - out_pkt_sz) / out_pkt_sz);
++ copied = (pkts - 1) * out_pkt_sz;
++ }
++
++ len -= copied;
++ crc = CRC32_INIT;
++ for (; copied-- > 0 ; crc = COMPUTE_FCS (crc, *buff++ = *src++));
++
++ for (; (len-- > 0) && (CRC32_GOOD != crc); crc = COMPUTE_FCS (crc, *buff++ = *src++));
++
++ trim = len + 4;
++
++ if (CRC32_GOOD != crc) {
++ TRACE_MSG1(NTT,"AAA frame: %03x", urb->framenum);
++ THROW_IF(npd->crc, crc_error);
++ }
++ else
++ npd->crc = 1;
++ }
++#else
++ /*
++ * The CRC can be sent in two ways when the size of the transfer
++ * ends up being a multiple of the packetsize:
++ *
++ * |
++ * <data> <CRC><CRC><CRC><CRC>|<???> case 1
++ * <data> <NUL><CRC><CRC><CRC>|<CRC> case 2
++ * <data> <NUL><CRC><CRC><CRC><CRC>| case 3
++ * <data> <NUL><CRC><CRC><CRC>|<CRC> | case 4
++ * |
++ *
++ * This complicates CRC checking, there are four scenarios:
++ *
++ * 1. length is 1 more than multiple of packetsize with a trailing byte
++ * 2. length is 1 more than multiple of packetsize
++ * 3. length is multiple of packetsize
++ * 4. none of the above
++ *
++ * Finally, even though we always compute CRC, we do not actually throw
++ * things away until and unless we have previously seen a good CRC.
++ * This allows backwards compatibility with hosts that do not support
++ * adding a CRC to the frame.
++ *
++ */
++
++ // test if 1 more than packetsize multiple
++ if (1 == (len % out_pkt_sz)) {
++
++ // copy and CRC up to the packetsize boundary
++ crc = crc32_copy(buff, urb->buffer, len - 1, CRC32_INIT);
++ buff += len - 1;
++
++ // if the CRC is good then this is case 1
++ if (CRC32_GOOD != crc) {
++
++ crc = crc32_copy(buff, urb->buffer + len - 1, 1, crc);
++ buff += 1;
++
++ if (CRC32_GOOD != crc) {
++ //crc_errors[len%64]++;
++ TRACE_MSG2(NTT,"A CRC error %08x %03x", crc, urb->framenum);
++ THROW_IF(npd->crc, crc_error);
++ }
++ else
++ npd->crc = 1;
++ }
++ else
++ npd->crc = 1;
++ }
++ else {
++ crc = crc32_copy(buff, urb->buffer, len, CRC32_INIT);
++ buff += len;
++
++ if (CRC32_GOOD != crc) {
++ //crc_errors[len%64]++;
++ TRACE_MSG2(NTT,"B CRC error %08x %03x", crc, urb->framenum);
++ THROW_IF(npd->crc, crc_error);
++ }
++ else
++ npd->crc = 1;
++ }
++ // trim IFF we are paying attention to crc
++ if (npd->crc)
++ trim = 4;
++#endif
++ // catch a simple error, just increment missed error and general error
++ CATCH(error) {
++ TRACE_MSG4(NTT,"CATCH(error) urb: %p status: %d len: %d function: %p",
++ urb, urb->status, urb->actual_length, function);
++ // catch a CRC error
++ CATCH(crc_error) {
++ crc_bad = 1;
++#if 0
++ printk(KERN_INFO"%s: urb: %p status: %d len: %d maxtransfer: %d encap: %d\n", __FUNCTION__,
++ urb, urb->status, urb->actual_length, npd->maxtransfer,
++ npd->encapsulation);
++
++ {
++ u8 *cp = urb->buffer;
++ int i;
++ for (i = 0; i < urb->actual_length; i++) {
++ if ((i%32) == 0) {
++ printk("\n[%2x] ", i);
++ }
++ printk("%02x ", *cp++);
++ }
++ printk("\n");
++ }
++#endif
++ }
++ }
++ net_os_recv_buff(npd,buff_ctx,crc_bad,trim);
++ TRACE_MSG1(NTT,"restart: %p", urb);
++ return (usbd_start_out_urb (urb));
++}
++/*! net_fd_recv_urb_eem - callback to process a received URB
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_recv_urb_eem(struct usbd_urb *urb, int rc)
++{
++ return 0;
++}
++
++//_________________________________________________________________________________________________
++// net_fd_device_request
++//
++/*! net_fd_urb_received_ep0 - callback for sent URB
++ *
++ * Handles notification that an urb has been sent (successfully or otherwise).
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_urb_received_ep0 (struct usbd_urb *urb, int urb_rc)
++{
++ TRACE_MSG2(NTT,"urb: %p status: %d", urb, urb->status);
++
++ printk(KERN_INFO"%s:\n", __FUNCTION__);
++ RETURN_EINVAL_IF (RECV_OK != urb->status);
++
++ // TRACE_MSG1(NTT,"%s", urb->buffer); // QQSV is this really a NUL-terminated string???
++
++ printk(KERN_INFO"%s: ok\n", __FUNCTION__);
++ return -EINVAL; // caller will de-allocate
++}
++
++/*! net_fd_device_request - process a received SETUP URB
++ *
++ * Processes a received setup packet and CONTROL WRITE data.
++ * Results for a CONTROL READ are placed in urb->buffer.
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
++ struct usbd_urb *urb;
++ int index;
++
++ // Verify that this is a USB Class request per CDC specification or a vendor request.
++ RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
++
++ // Determine the request direction and process accordingly
++ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
++
++ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR:
++
++ switch (request->bRequest) {
++ case MCCI_ENABLE_CRC:
++ if (make_crc_table())
++ return -EINVAL;
++ npd->encapsulation = simple_crc;
++ return 0;
++
++ case BELCARRA_PING:
++ TRACE_MSG1(NTT,"H2D VENDOR IP: %08x", ip_addr);
++ if ((npd->network_type == network_blan))
++ net_os_send_notification_later(npd);
++ break;
++
++#if !defined(CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME) || !defined(CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME)
++ case BELCARRA_SETTIME:
++ {
++#if defined(LINUX24)
++ struct timeval tv;
++#else
++ struct timespec tv;
++#endif
++ memset(&tv, 0, sizeof(tv));
++
++ // wIndex and wLength contain RFC868 time - seconds since midnight 1 jan 1900
++
++ tv.tv_sec = ntohl( request->wValue << 16 | request->wIndex);
++ // tv.tv_usec = 0;
++
++ // convert to Unix time - seconds since midnight 1 jan 1970
++
++ tv.tv_sec -= RFC868_OFFSET_TO_EPOCH;
++
++ TRACE_MSG1(NTT,"H2D VENDOR TIME: %08x", tv.tv_sec);
++
++ // set the time
++ do_settimeofday(&tv);
++ } break;
++#endif
++ case BELCARRA_SETIP:
++ ip_addr = ntohl( request->wValue << 16 | request->wIndex);
++ // XXX need to get in correct order here
++ npd->local_dev_addr[2] = (ip_addr >> 24) & 0xff;
++ npd->local_dev_addr[3] = (ip_addr >> 16) & 0xff;
++ npd->local_dev_addr[4] = (ip_addr >> 8) & 0xff;
++ npd->local_dev_addr[5] = (ip_addr >> 0) & 0xff;
++#ifdef CONFIG_OTG_NETWORK_BLAN_IPADDR
++ snprintf(ip_addr_str, sizeof(ip_addr_str), "%d.%d.%d.%d",
++ (ip_addr >> 24) & 0xff, (ip_addr >> 16) & 0xff,
++ (ip_addr >> 8) & 0xff, (ip_addr) & 0xff);
++ index = usbd_realloc_string(
++ npd->function_driver->device_description->device_descriptor->iProduct, ip_addr_str);
++#endif /* CONFIG_OTG_NETWORK_IPADDR */
++ break;
++
++ case BELCARRA_SETMSK:
++ network_mask = ntohl( request->wValue << 16 | request->wIndex);
++ break;
++
++ case BELCARRA_SETROUTER:
++ router_ip = ntohl( request->wValue << 16 | request->wIndex);
++ break;
++
++ case BELCARRA_SETDNS:
++ dns_server_ip = ntohl( request->wValue << 16 | request->wIndex);
++ break;
++#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
++ case BELCARRA_SETFERMAT:
++ npd->fermat = 1;
++ break;
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME
++ case BELCARRA_HOSTNAME:
++ TRACE_MSG0(NTT,"HOSTNAME");
++ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, le16_to_cpu(request->wLength),
++ net_fd_urb_received_ep0) ));
++ RETURN_ZERO_IF(!usbd_start_out_urb(urb)); // return if no error
++ usbd_free_urb(urb); // de-alloc if error
++ return -EINVAL;
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
++ case BELCARRA_DATA_NOTIFY:
++ TRACE_MSG0(NTT,"DATA NOTIFY");
++ npd->data_notify = 1;
++ return -EINVAL;
++#endif
++ }
++ return 0;
++#if 0
++ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
++ urb->actual_length = 0;
++ switch (request->bRequest) {
++ case BELCARRA_GETMAC:
++ {
++ // copy and free the original buffer
++ memcpy(urb->buffer, npd->local_dev_addr, ETH_ALEN);
++ urb->actual_length = ETH_ALEN;
++ return 0;
++ }
++ }
++#endif
++ return 0;
++ default:
++ break;
++ }
++ return -EINVAL;
++}
++//_________________________________________________________________________________________________
++
++#ifdef CONFIG_OTG_NETWORK_START_SINGLE
++#define NETWORK_START_URBS 1
++#else
++#define NETWORK_START_URBS 2
++#endif
++
++typedef enum mesg {
++ mesg_unknown,
++ mesg_configured,
++ mesg_reset,
++} mesg_t;
++mesg_t net_last_mesg;
++
++char * net_messages[3] = {
++ "",
++ "Network Configured",
++ "Network Reset",
++};
++
++/*! net_check_mesg
++ */
++void net_check_mesg(mesg_t curr_mesg)
++{
++ RETURN_UNLESS(net_last_mesg != curr_mesg);
++ net_last_mesg = curr_mesg;
++ otg_message(net_messages[curr_mesg]);
++}
++
++
++
++/*! net_fd_start_recv - start recv urb(s)
++ */
++STATIC void net_fd_start_recv(struct usbd_function_instance *function)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
++ int i;
++ for (i = 0; i < NETWORK_START_URBS; i++) {
++ struct usbd_urb *urb;
++ BREAK_IF(!(urb = usbd_alloc_urb(function, BULK_OUT,
++ usbd_endpoint_transferSize(function, BULK_OUT, usbd_high_speed(function)),
++ net_fd_recv_urb)));
++ TRACE_MSG5(NTT,"i: %d urb=%p priv=%p npd=%p function=%p",
++ i, urb, urb->function_privdata, npd, function);
++
++ urb->function_privdata = npd;
++ if (usbd_start_out_urb(urb)) {
++ urb->function_privdata = NULL;
++ usbd_free_urb(urb);
++ }
++ }
++}
++
++/*! net_fd_start_recv_eem - start recv urb(s)
++ */
++STATIC void net_fd_start_recv_eem(struct usbd_function_instance *function)
++{
++}
++
++/*! net_fd_event_handler - Processes a USB event.
++ */
++STATIC void net_fd_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
++
++ switch (event) {
++
++ case DEVICE_RESET:
++ case DEVICE_DESTROY:
++ case DEVICE_BUS_INACTIVE:
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG1(NTT,"RESET/DESTROY/BUS_INACTIVE/DE_CONFIGURED %08x",ip_addr);
++ net_check_mesg(mesg_reset);
++ {
++ // Return if argument is null.
++
++ // XXX flush
++
++ npd->flags &= ~NETWORK_ATTACHED;
++ npd->int_urb = NULL;
++
++ // Disable our net-device.
++ // Apparently it doesn't matter if we should do this more than once.
++
++ net_os_carrier_off(npd);
++
++ // If we aren't already tearing things down, do it now.
++ if (!(npd->flags & NETWORK_DESTROYING)) {
++ npd->flags |= NETWORK_DESTROYING;
++ //npd->device = NULL;
++ }
++ }
++ npd->crc = 0;
++ break;
++
++ case DEVICE_CONFIGURED:
++ case DEVICE_BUS_ACTIVITY:
++ TRACE_MSG1(NTT,"CONFIGURED/BUS_ACTIVITY %08x",ip_addr);
++ net_check_mesg(mesg_configured);
++ npd->flags |= NETWORK_ATTACHED;
++ if ((npd->network_type == network_blan) && (npd->flags & NETWORK_OPEN))
++ net_os_send_notification_later(npd);
++ net_os_carrier_on(npd);
++ (npd->network_type == network_eem) ? net_fd_start_recv_eem : net_fd_start_recv(function);
++ break;
++
++ case DEVICE_SET_INTERFACE:
++ // XXX if CDC then we can check device->alternates[1] and see if we should
++ // enable/disable data flow.
++ // XXX verify ep0.c SET_CONFIGURATION and SET_INTERFACE implmentation are
++ // complete before using this
++ break;
++
++ default:
++ return;
++ }
++ // Let the OS layer know, if it's interested.
++ net_os_config(npd);
++ net_os_hotplug(npd);
++}
++
++
++/*! net_fd_endpoint_cleared -
++ */
++STATIC void net_fd_endpoint_cleared (struct usbd_function_instance *function, int bEndpointAddress, int wIndex)
++{
++ TRACE_MSG2(NTT, "bEndpointAddress: %02x wIndex: %02x", bEndpointAddress, wIndex);
++}
++
++
++//_________________________________________________________________________________________________
++
++/*! net_fd_function_enable - enable the function driver
++ *
++ * Called for usbd_function_enable() from usbd_register_device()
++ */
++
++STATIC int net_fd_function_enable (struct usbd_function_instance *function)
++{
++ struct usb_network_private *npd;
++#if 0
++ /* This is the first time we've seen the function instance
++ (it's allocated by the usbdcore), so we need to let the OS
++ layer see it and initialize the privdata pointer. */
++ net_os_enable(function);
++ npd = (struct usb_network_private *) (function->privdata);
++ TRACE_MSG0(NTT,"semaphore DOWN");
++ net_os_mutex_enter(npd);
++#else
++ npd = (struct usb_network_private *) (function->privdata);
++ TRACE_MSG0(NTT,"semaphore DOWN");
++ net_os_mutex_enter(npd);
++ net_os_enable(function);
++#endif
++ _MOD_INC_USE_COUNT; // QQQ Should this be _before_ the mutex_enter()?
++ TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
++
++ // set the network device address from the local device address
++ // Now done in net_os_enable() above.
++ // memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
++
++ npd->have_interrupt = usbd_endpoint_bEndpointAddress(function, INT_IN, usbd_high_speed(function)) ? 1 : 0;
++
++ npd->flags |= NETWORK_ENABLED;
++
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ cdc_init(function);
++#endif /* CONFIG_OTG_NETWORK_CDC */
++
++#ifdef CONFIG_OTG_NETWORK_EEM
++ eem_init(function);
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC
++ basic_init(function);
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++ basic2_init(function);
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_SAFE
++ safe_init(function);
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN
++ blan_init(function);
++#endif
++ net_os_mutex_exit(npd);
++ TRACE_MSG0(NTT,"semaphore UP");
++ return 0;
++}
++
++/*! net_fd_function_disable - disable the function driver
++ *
++ */
++STATIC void net_fd_function_disable (struct usbd_function_instance *function)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
++ TRACE_MSG0(NTT,"semaphore DOWN");
++ net_os_mutex_enter(npd);
++ npd->flags &= ~NETWORK_ENABLED;
++ _MOD_DEC_USE_COUNT; // QQQ Should this be _after_ the up()?
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++ net_os_mutex_exit(npd);
++ TRACE_MSG0(NTT,"semaphore UP");
++}
++
++/*! net_fd_function_ops - operations table for network function driver
++ */
++struct usbd_function_operations net_fd_function_ops = {
++ device_request: net_fd_device_request,
++ event_handler: net_fd_event_handler,
++ function_enable: net_fd_function_enable,
++ function_disable: net_fd_function_disable,
++ endpoint_cleared: net_fd_endpoint_cleared,
++};
++
++//______________________________________module_init and module_exit________________________________
++
++/*! hexdigit -
++ *
++ * Converts characters in [0-9A-F] to 0..15, characters in [a-f] to 42..47, and all others to 0.
++ */
++static u8 hexdigit (char c)
++{
++ return isxdigit (c) ? (isdigit (c) ? (c - '0') : (c - 'A' + 10)) : 0;
++}
++
++/*! set_address -
++ */
++static void set_address(char *mac_address_str, u8 *dev_addr)
++{
++ int i;
++ if (mac_address_str && strlen(mac_address_str)) {
++ for (i = 0; i < ETH_ALEN; i++) {
++ dev_addr[i] =
++ hexdigit (mac_address_str[i * 2]) << 4 |
++ hexdigit (mac_address_str[i * 2 + 1]);
++ }
++ }
++ else {
++ get_random_bytes(dev_addr, ETH_ALEN);
++ dev_addr[0] = (dev_addr[0] & 0xfe) | 0x02;
++ }
++}
++
++/*! macstrtest -
++ */
++static int macstrtest(char *mac_address_str)
++{
++ int l = 0;
++
++ if (mac_address_str) {
++ l = strlen(mac_address_str);
++ }
++ return ((l != 0) && (l != 12));
++}
++
++/*! select_network_type
++ *
++ */
++STATIC network_type_t select_network_type(struct usb_network_params *p)
++{
++ /*
++ * Figure out what network mode to operate in.
++ */
++ network_type_t network_type = network_unknown;
++ /*
++ * Step 1. Look to see if network_type is specified by something like module params.
++ */
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ p->cdc_capable = 1;
++ if (p->cdc) {
++ TRACE_MSG0(NTT,"cdc");
++ network_type = network_cdc;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_EEM
++ p->eem_capable = 1;
++ if (p->eem) {
++ THROW_IF (network_type != network_unknown, select_error);
++ TRACE_MSG0(NTT,"eem");
++ network_type = network_eem;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_BASIC
++ p->basic_capable = 1;
++ if (p->basic) {
++ THROW_IF (network_type != network_unknown, select_error);
++ TRACE_MSG0(NTT,"basic");
++ network_type = network_basic;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++ p->basic2_capable = 1;
++ if (p->basic2) {
++ THROW_IF (network_type != network_unknown, select_error);
++ TRACE_MSG0(NTT,"basic2");
++ network_type = network_basic2;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_SAFE
++ p->safe_capable = 1;
++ if (p->safe) {
++ THROW_IF (network_type != network_unknown, select_error);
++ TRACE_MSG0(NTT,"safe");
++ network_type = network_safe;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN
++ p->blan_capable = 1;
++ if (p->blan) {
++ THROW_IF (network_type != network_unknown, select_error);
++ TRACE_MSG0(NTT,"blan");
++ network_type = network_blan;
++ }
++#endif
++
++ /*
++ * Step 2. If nothing was specified by parameter, default to
++ * to the first available (i.e. compiled) of:
++ * CDC, BASIC, BASIC2, SAFE, BLAN.
++ */
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => cdc");
++ network_type = network_cdc;
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_EEM)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => eem");
++ network_type = network_eem;
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_BASIC)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => basic");
++ network_type = network_basic;
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_BASIC2)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => basic2");
++ network_type = network_basic2;
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_SAFE)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => safe");
++ network_type = network_safe;
++ }
++#endif
++#if defined(CONFIG_OTG_NETWORK_BLAN)
++ if (network_type == network_unknown) {
++ TRACE_MSG0(NTT,"unknown => blan");
++ network_type = network_blan;
++ }
++#endif
++ CATCH(select_error) {
++ network_type == network_unknown;
++ }
++ return(network_type);
++}
++
++/*! select_descriptors
++ *
++ */
++STATIC struct usbd_function_driver * select_descriptors(network_type_t network_type)
++{
++ // select the function driver descriptors based on network_type
++
++ switch (network_type) {
++
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ case network_cdc:
++ TRACE_MSG0(NTT,"fd=cdc");
++ return(&cdc_function_driver);
++#endif
++#if defined(CONFIG_OTG_NETWORK_EEM)
++ case network_eem:
++ TRACE_MSG0(NTT,"fd=eem");
++ return(&eem_function_driver);
++#endif
++#if defined(CONFIG_OTG_NETWORK_BASIC)
++ case network_basic:
++ TRACE_MSG0(NTT,"fd=basic");
++ return(&basic_function_driver);
++#endif
++#if defined(CONFIG_OTG_NETWORK_BASIC2)
++ case network_basic2:
++ TRACE_MSG0(NTT,"fd=basic2");
++ return(&basic2_function_driver);
++#endif
++#if defined(CONFIG_OTG_NETWORK_SAFE)
++ case network_safe:
++ TRACE_MSG1(NTT,"fd=safe bNumConfigurations: %d",
++ safe_function_driver.bNumConfigurations);
++ return(&safe_function_driver);
++#endif
++#if defined(CONFIG_OTG_NETWORK_BLAN)
++ case network_blan:
++ TRACE_MSG1(NTT,"fd=blan bNumConfigurations: %d",
++ blan_function_driver.bNumConfigurations);
++ return(&blan_function_driver);
++#endif
++ default:
++ break;
++ }
++ return(NULL);
++}
++
++/*! net_fd_init - function driver usb part intialization
++ *
++ * @return non-zero for failure.
++ */
++STATIC int net_fd_init(struct usb_network_private *npd, char *info_str)
++{
++ struct usb_network_params *p = npd->params;
++
++ printk(KERN_INFO "Copyright (c) 2002-2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
++ NTT = otg_trace_obtain_tag();
++
++ /*
++ * Figure out what network mode to operate in.
++ */
++ if (network_unknown == (npd->network_type = select_network_type(p)) ||
++ NULL == (npd->function_driver = select_descriptors(npd->network_type))) {
++ printk(KERN_INFO"configuration selection error");
++ otg_trace_invalidate_tag(NTT);
++ return -EINVAL;
++ }
++
++#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
++ TRACE_MSG2(NTT,"checking idVendor: %04x idProduct: %04x", p->vendor_id, p->product_id);
++
++ if (p->vendor_id)
++ npd->function_driver->idVendor = cpu_to_le16(p->vendor_id);
++
++ if (p->product_id)
++ npd->function_driver->idProduct = cpu_to_le16(p->product_id);
++#endif
++ printk(KERN_INFO "%s: %s vendor_id: %04x product_id: %04x\n",
++ __FUNCTION__, info_str,
++ le16_to_cpu(npd->function_driver->idVendor),
++ le16_to_cpu(npd->function_driver->idProduct));
++ TRACE_MSG3(NTT,"%s vendor_id: %04x product_id: %04x", info_str,
++ le16_to_cpu(npd->function_driver->idVendor),
++ le16_to_cpu(npd->function_driver->idProduct));
++
++#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
++ TRACE_MSG0(NTT,"fermat");
++ fermat_init();
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_EP0TEST
++ /*
++ * ep0test - test that bus interface can do ZLP on endpoint zero
++ *
++ * This will artificially force iProduct string descriptor to be
++ * exactly the same as the endpoint zero packetsize. When the host
++ * requests this string it will request it not knowing the strength
++ * and will use a max length of 0xff. The bus interface driver must
++ * send a ZLP to terminate the transaction.
++ *
++ * The iProduct descriptor is used because both the Linux and
++ * Windows usb implmentations fetch this in a default enumeration.
++ *
++ */
++ //UNLESS (ep0test)
++ // ep0test = usbd_endpoint_zero_wMaxPacketsize(function);
++
++ if (ep0test) {
++ switch (ep0test) {
++ case 8: npd->function_driver->device_description->iProduct = "012"; break;
++ case 16: npd->function_driver->device_description->iProduct = "0123456"; break;
++ case 32: npd->function_driver->device_description->iProduct = "0123456789abcde"; break;
++ case 64: npd->function_driver->device_description->iProduct = "0123456789abcdef0123456789abcde"; break;
++ default: printk(KERN_ERR"%s: ep0test: bad value: %d, must be one of 8, 16, 32 or 64\n",
++ __FUNCTION__, ep0test); return -EINVAL;
++ break;
++ }
++ TRACE_MSG1(NTT,"ep0test: iProduct set to: %s",
++ npd->function_driver->device_description->iProduct);
++ printk(KERN_INFO"%s: ep0test: iProduct set to: %s\n", __FUNCTION__,
++ npd->function_driver->device_description->iProduct);
++ }
++ else {
++ TRACE_MSG0(NTT,"ep0test: not set");
++ printk(KERN_INFO"%s: ep0test: not set\n", __FUNCTION__);
++ }
++#endif /* CONFIG_OTG_NETWORK_EP0TEST */
++
++
++#ifdef CONFIG_OTG_NETWORK_LOCAL_MACADDR
++ if (NULL == p->local_mac_address_str) {
++ /* There is a configured override, and it has NOT been
++ overridden in turn by a module load time parameter, so use it. */
++ p->local_mac_address_str = CONFIG_OTG_NETWORK_LOCAL_MACADDR;
++ }
++#endif
++#ifdef CONFIG_OTG_NETWORK_REMOTE_MACADDR
++ if (NULL == p->remote_mac_address_str) {
++ /* There is a configured override, and it has NOT been
++ overridden in turn by a module load time parameter, so use it. */
++ p->remote_mac_address_str = CONFIG_OTG_NETWORK_REMOTE_MACADDR;
++ }
++#endif
++ if ((macstrtest(p->local_mac_address_str) || macstrtest(p->remote_mac_address_str))) {
++ TRACE_MSG2(NTT,"bad size %s %s", p->local_mac_address_str, p->remote_mac_address_str);
++ otg_trace_invalidate_tag(NTT);
++ return -EINVAL;
++ }
++
++ set_address(p->local_mac_address_str, npd->local_dev_addr);
++ set_address(p->remote_mac_address_str, npd->remote_dev_addr);
++ npd->encapsulation = simple_crc;
++
++ if (make_crc_table() ||
++ NULL == (npd->function = usbd_register_function(npd->function_driver, "net-fd", NULL))) {
++ if (network_crc32_table) {
++ lkfree(network_crc32_table);
++ network_crc32_table = NULL;
++ }
++ otg_trace_invalidate_tag(NTT);
++ return -EINVAL;
++ }
++ npd->function->privdata = (void *) npd;
++
++ return 0;
++
++}
++
++//_____________________________________________________________________________
++
++/*! net_fd_term - driver exit
++ *
++ * Cleans up the module. Deregisters the function driver and destroys the network object.
++ */
++STATIC void net_fd_term(struct usb_network_private *npd)
++{
++ if (NULL != npd->function) {
++ usbd_deregister_function(npd->function);
++ npd->function = NULL;
++ }
++ if (network_crc32_table) {
++ lkfree(network_crc32_table);
++ network_crc32_table = NULL;
++ }
++ otg_trace_invalidate_tag(NTT);
++}
++
++//_________________________________________________________________________________________________
++
++
++/*! net_fd_usb_ops operations
++ */
++struct net_usb_services net_fd_usb_ops = {
++ .initialize_usb_part = net_fd_init,
++ .terminate_usb_part = net_fd_term,
++ .send_int_notification = net_fd_send_int_blan,
++ .start_xmit = net_fd_start_xmit,
++};
+diff -uNr linux/drivers/no-otg/functions/network/net-fd.h linux/drivers/otg/functions/network/net-fd.h
+--- linux/drivers/no-otg/functions/network/net-fd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/net-fd.h 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * otg/functions/network/net-fd.h - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/net-fd.h
++ * @brief These are the functions exported by the USB specific parts
++ * (i.e. net-fd.c and net-cl.c) for use in the OS specific
++ * layers (e.g. net-l24-os.c).
++ *
++ *
++ * @ingroup NetworkFunction
++ */
++#ifndef NET_FD_H
++#define NET_FD_H 1
++
++struct net_usb_services {
++ int (*initialize_usb_part)(struct usb_network_private *npd, char *info_str);
++ void (*terminate_usb_part)(struct usb_network_private *npd);
++ void (*send_int_notification)(struct usb_network_private *npd, int connected, int data);
++ int (*start_xmit)(struct usb_network_private *npd, __u8 *buff, int len, void *buff_ctx);
++};
++
++extern struct net_usb_services net_fd_usb_ops;
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/network/net-l24-os.c linux/drivers/otg/functions/network/net-l24-os.c
+--- linux/drivers/no-otg/functions/network/net-l24-os.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/net-l24-os.c 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,1395 @@
++/*
++ * otg/functions/network/net-l24-os.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra Technologies
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++/*!
++ * @file otg/functions/network/net-l24-os.c
++ * @brief The Linux 2.4 OS specific upper edge (network interface)
++ * implementation for the Network Function Driver.
++ *
++ * This file implements a standard Linux network driver interface and
++ * the standard Linux 2.4 module init and exit functions.
++ *
++ * If compiled into the kernel, this driver can be used with NFSROOT to
++ * provide the ROOT filesystem. Please note that the kernel NFSROOT support
++ * (circa 2.4.20) can have problems if there are multiple interfaces. So
++ * it is best to ensure that there are no other network interfaces compiled
++ * in.
++ *
++ *
++ * @ingroup NetworkFunction
++ */
++
++
++/* OS-specific #includes */
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/random.h>
++#include <linux/utsname.h>
++#include <linux/kmod.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++
++/* Networking #includes from OS */
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <net/arp.h>
++#include <linux/rtnetlink.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/ip.h>
++#include <linux/if_ether.h>
++#include <linux/in.h>
++#include <linux/inetdevice.h>
++
++
++
++/* Belcarra public interfaces */
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++#include <otg/usbp-chap9.h>
++//#include <otg/usbd-mem.h>
++#include <otg/usbp-func.h>
++
++/* Belcarra private interfaces SUBJECT TO CHANGE WITHOUT NOTICE */
++#include "network.h"
++#include "net-os.h"
++#include "net-fd.h"
++
++MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com, balden@belcarra.com");
++
++EMBED_LICENSE();
++
++MOD_DESCRIPTION ("USB Network Function");
++
++
++
++EMBED_USBD_INFO ("network_fd 2.0-beta");
++
++
++#define NTT network_fd_trace_tag
++
++wait_queue_head_t usb_netif_wq;
++#ifdef CONFIG_OTG_NET_NFS_SUPPORT
++int usb_is_configured;
++#endif
++
++/* Module Parameters ************************************************************************* */
++
++STATIC struct usb_network_params params;
++
++#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
++// override vendor ID
++static int vendor_id;
++MOD_PARM (vendor_id, "i");
++MOD_PARM_DESC (vendor_id, "vendor id");
++
++// override product ID
++static int product_id;
++MOD_PARM (product_id, "i");
++MOD_PARM_DESC (product_id, "product id");
++#endif
++
++// override local mac address
++static char *local_mac_address_str;
++MOD_PARM (local_mac_address_str, "s");
++MOD_PARM_DESC (local_mac_address_str, "Local MAC");
++
++// override remote mac address
++static char *remote_mac_address_str;
++MOD_PARM (remote_mac_address_str, "s");
++MOD_PARM_DESC (remote_mac_address_str, "Remote MAC");
++
++#ifdef CONFIG_OTG_NETWORK_EP0TEST
++static int ep0test;
++MOD_PARM (ep0test, "i");
++MOD_PARM_DESC (ep0test, "Test EP0 String Handling - set to ep0 packetsize [8,16,32,64]");
++#endif
++
++static int zeroconf;
++MOD_PARM (zeroconf, "i");
++MOD_PARM_DESC (zeroconf, "Use usbz%d for network name");
++
++#if defined(CONFIG_OTG_NETWORK_CDC)
++static int cdc;
++MOD_PARM (cdc, "i");
++MOD_PARM_DESC (cdc, "Enable CDC mode");
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC
++static int basic;
++MOD_PARM (basic, "i");
++MOD_PARM_DESC (basic, "Enable BASIC mode");
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++static int basic2;
++MOD_PARM (basic2, "i");
++MOD_PARM_DESC (basic2, "Enable BASIC2 mode");
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_SAFE
++static int safe;
++MOD_PARM (safe, "i");
++MOD_PARM_DESC (safe, "Enable SAFE mode");
++#endif
++
++#ifdef CONFIG_OTG_NETWORK_BLAN
++static int blan;
++MOD_PARM (blan, "i");
++MOD_PARM_DESC (blan, "Enable BLAN mode");
++#endif
++
++/* End of Module Parameters ****************************************************************** */
++
++
++u8 local_dev_addr[ETH_ALEN];
++
++u8 remote_dev_addr[ETH_ALEN];
++static u8 zeros[ETH_ALEN];
++
++extern u32 ip_addr;
++extern u32 router_ip;
++extern u32 network_mask;
++extern u32 dns_server_ip;
++
++/* Prevent overlapping of bus administrative functions:
++ *
++ * network_function_enable
++ * network_function_disable
++ * network_hard_start_xmit
++ */
++DECLARE_MUTEX(usbd_network_sem);
++
++
++struct net_device Network_net_device;
++struct usb_network_private Usb_network_private;
++
++void notification_schedule_bh (void);
++int network_urb_sent_bulk (struct usbd_urb *urb, int urb_rc);
++int network_urb_sent_int (struct usbd_urb *urb, int urb_rc);
++
++
++//_________________________________________________________________________________________________
++
++/*
++ * Synchronization
++ *
++ *
++ * Notification bottom half
++ *
++ * This is a scheduled task that will send an interrupt notification. Because it
++ * is called from the task scheduler context it needs to verify that the device is
++ * still usable.
++ *
++ * static int network_send_int_blan(struct usbd_function_instance *, int )
++ * static void notification_bh (void *)
++ * void notification_schedule_bh (void)
++ *
++ *
++ * Netdevice functions
++ *
++ * These are called by the Linux network layer. They must be protected by irq locks
++ * if necessary to prevent interruption by IRQ level events.
++ *
++ * int network_init (struct net_device *net_device)
++ * void network_uninit (struct net_device *net_device)
++ * int network_open (struct net_device *net_device)
++ * int network_stop (struct net_device *net_device)
++ * struct net_device_stats *network_get_stats (struct net_device *net_device)
++ * int network_set_mac_addr (struct net_device *net_device, void *p)
++ * void network_tx_timeout (struct net_device *net_device)
++ * int network_set_config (struct net_device *net_device, struct ifmap *map)
++ * int network_stop (struct net_device *net_device)
++ * int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
++ * int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
++ *
++ *
++ * Data bottom half functions
++ *
++ * These are called from the bus bottom half handler.
++ *
++ * static int network_recv (struct usb_network_private *, struct net_device *, struct sk_buff *)
++ * int network_recv_urb (struct usbd_urb *)
++ * int network_urb_sent (struct usbd_urb *, int )
++ *
++ *
++ * Hotplug bottom half:
++ *
++ * This is a scheduled task that will send do a hotplug call. Because it is
++ * called from the task scheduler context it needs to verify that the
++ * device is still usable.
++ *
++ * static int hotplug_attach (u32 ip, u32 mask, u32 router, int attach)
++ * static void hotplug_bh (void *data)
++ * void net_os_hotplug (void)
++ *
++ *
++ * Irq level functions:
++ *
++ * These are called at interrupt time do process or respond to USB setup
++ * commands.
++ *
++ * int network_device_request (struct usbd_device_request *)
++ * void network_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++ *
++ *
++ * Enable and disable functions:
++ *
++ * void network_function_enable (struct usbd_function_instance *, struct usbd_function_instance *)
++ * void network_function_disable (struct usbd_function_instance *function)
++ *
++ *
++ * Driver initialization and exit:
++ *
++ * static int network_create (struct usb_network_private *)
++ * static void network_destroy (struct usb_network_private *)
++ *
++ * int network_modinit (void)
++ * void network_modexit (void)
++ */
++
++
++//_______________________________USB part Functions_________________________________________
++
++/*
++ * net_os_mutex_enter - enter mutex region
++ */
++void net_os_mutex_enter(struct usb_network_private *npd)
++{
++ down(&usbd_network_sem);
++}
++
++/*
++ * net_os_mutex_exit - exit mutex region
++ */
++void net_os_mutex_exit(struct usb_network_private *npd)
++{
++ up(&usbd_network_sem);
++}
++
++/* notification_bh - Bottom half handler to send a notification status
++ *
++ * Send a notification with open/close status
++ *
++ * It should not be possible for this to be called more than once at a time
++ * as it is only called via schedule_task() which protects against a second
++ * invocation.
++ */
++STATIC void notification_bh (void *data)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) data;
++ unsigned long flags;
++ local_irq_save(flags);
++ (*(npd->fd_ops->send_int_notification))(npd, npd->flags & NETWORK_OPEN, 0);
++ local_irq_restore(flags);
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++}
++
++/* notification_schedule_bh - schedule a call for notification_bh
++ */
++void net_os_send_notification_later(struct usb_network_private *npd)
++{
++#ifdef LINUX24
++ //LINUX 2.4 is the only supported OS to need the USE_COUNT
++ //_MOD_INC_USE_COUNT;
++ TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
++ if (!SCHEDULE_WORK(npd->notification_bh)) {
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++ }
++#else
++ SCHEDULE_WORK(npd->notification_bh);
++ //XXX No provision for failure of schedule ....
++#endif
++}
++
++/*! net_os_xmit_done - called from USB part when a transmit completes, good or bad.
++ * tx_rc is SEND_FINISHED_ERROR, SEND_CANCELLED or...
++ * buff_ctx is the pointer passed to fd_ops->start_xmit().
++ * @return non-zero only if network does not exist, ow 0.
++ */
++int net_os_xmit_done(struct usbd_function_instance *function, void *buff_ctx, int tx_rc)
++{
++ struct sk_buff *skb = (struct sk_buff *) buff_ctx;
++ struct usb_network_private *npd;
++ struct net_device *net_device;
++ int rc = 0;
++
++ npd = (function ? (struct usb_network_private *) (function->privdata) : NULL);
++ if (skb) {
++ if (NULL != npd && 0 == (rc = !(npd->flags & NETWORK_CREATED))) {
++ switch (tx_rc) {
++ case SEND_FINISHED_ERROR:
++ npd->stats.tx_errors++;
++ npd->stats.tx_dropped++;
++ break;
++ case SEND_CANCELLED:
++ npd->stats.tx_errors++;
++ npd->stats.tx_carrier_errors++;
++ break;
++ default:
++ break;
++ }
++
++ npd->avg_queue_entries += npd->queued_entries;
++ npd->queued_entries--;
++ npd->samples++;
++ npd->jiffies += jiffies - *(time_t *) (&skb->cb);
++ npd->queued_bytes -= skb->len;
++ if (NULL != (net_device = npd->net_dev) &&
++ netif_queue_stopped(net_device)) {
++ netif_wake_queue(net_device);
++ npd->restarts++;
++ }
++ }
++ dev_kfree_skb_any(skb);
++ }
++ return rc;
++}
++
++/*! net_os_alloc_buf
++ */
++void *net_os_alloc_buff(struct usb_network_private *npd, u8 **cp, int n)
++{
++ struct sk_buff *skb;
++ // allocate skb of appropriate length, reserve 2 to align ip
++ if (!(skb = dev_alloc_skb(n+2))) {
++ *cp = NULL;
++ return(NULL);
++ }
++ skb_reserve(skb, 2);
++ *cp = skb_put(skb, n);
++ return((void*) skb);
++}
++
++/*! network_recv - function to process an received data URB
++ *
++ * Passes received data to the network layer. Passes skb to network layer.
++ *
++ * @return non-zero for failure.
++ */
++STATIC __inline__ int network_recv (struct usb_network_private *npd,
++ struct net_device *net_device, struct sk_buff *skb)
++{
++ int rc;
++#if 0
++ printk(KERN_INFO"%s: len: %x head: %p data: %p tail: %p\n", __FUNCTION__,
++ skb->len, skb->head, skb->data, skb->tail);
++ {
++ u8 *cp = skb->data;
++ int i;
++ for (i = 0; i < skb->len; i++) {
++ if ((i%32) == 0) {
++ printk("\nrx[%2x] ", i);
++ }
++ printk("%02x ", *cp++);
++ }
++ printk("\n");
++ }
++#endif
++
++ // refuse if no device present
++ if (!netif_device_present (net_device)) {
++ TRACE_MSG0(NTT,"device not present");
++ printk(KERN_INFO"%s: device not present\n", __FUNCTION__);
++ return -EINVAL;
++ }
++
++ // refuse if no carrier
++ if (!netif_carrier_ok (net_device)) {
++ TRACE_MSG0(NTT,"no carrier");
++ printk(KERN_INFO"%s: no carrier\n", __FUNCTION__);
++ return -EINVAL;
++ }
++
++ // refuse if the net device is down
++ if (!(net_device->flags & IFF_UP)) {
++ TRACE_MSG1(NTT,"not up net_dev->flags: %x", net_device->flags);
++ //printk(KERN_INFO"%s: not up net_dev->flags: %x\n", __FUNCTION__, net_device->flags);
++ //npd->stats.rx_dropped++;
++ return -EINVAL;
++ }
++
++ skb->dev = net_device;
++ skb->pkt_type = PACKET_HOST;
++ skb->protocol = eth_type_trans (skb, net_device);
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++ //TRACE_MSG4(NTT,"len: %x head: %p data: %p tail: %p",
++ // skb->len, skb->head, skb->data, skb->tail);
++
++
++ // pass it up to kernel networking layer
++ if ((rc = netif_rx (skb))) {
++ TRACE_MSG1(NTT,"netif_rx rc: %d", rc);
++ }
++ // QQSV - should be else case for stats?
++ npd->stats.rx_bytes += skb->len;
++ npd->stats.rx_packets++;
++
++ return 0;
++}
++
++/*! net_os_recv_buff - forward a received URB, or clean up after a bad one.
++ * buff_ctx == NULL --> just accumulate stats (count 1 bad buff)
++ * crc_bad != 0 --> count a crc error and free buff_ctx/skb
++ * trim --> amount to trim from valid skb
++ */
++void net_os_recv_buff(struct usb_network_private *npd, void *buff_ctx, int crc_bad, int trim)
++{
++ struct sk_buff *skb = (struct sk_buff *) buff_ctx;
++
++ if (NULL == skb) {
++ /* Lower layer never got around to allocating an skb, but
++ needs to count a packet it can't forward. */
++ npd->stats.rx_frame_errors++;
++ npd->stats.rx_errors++;
++ } else {
++ // There is an skb, either forward it or free it.
++ if (crc_bad) {
++ npd->stats.rx_crc_errors++;
++ npd->stats.rx_errors++;
++ } else if ((npd->flags & NETWORK_ATTACHED) && NULL != npd->net_dev) {
++ // All good, forward it.
++ if (trim) {
++ skb_trim(skb, skb->len - trim);
++ }
++ // all done if network_recv() == 0, ow fall through to error handling
++ RETURN_IF(!network_recv(npd, npd->net_dev, skb));
++ // Network layer wouldn't take it.
++ // rx_dropped gets counted below, any other counter we need?
++ }
++ // Something wrong, free the skb
++ dev_kfree_skb_any (skb);
++ }
++ // The received buffer didn't get forwarded, so...
++ npd->stats.rx_dropped++;
++}
++
++/*! net_os_enable
++ *
++ */
++void net_os_enable(struct usbd_function_instance *function)
++{
++ //struct usb_network_private *npd = &Usb_network_private;
++ struct usb_network_private *npd = (struct usb_network_private *) function->privdata;
++#if 0
++ /* This is the first time we've gotten access to the function instance,
++ and it's an allocated structure. Fill in the links to our private data. */
++ function->privdata = (void *) npd;
++ npd->function = function;
++#endif
++ TRACE_MSG3(NTT,"npd=%p function=%p, f->p=%p",npd,function,function->privdata);
++
++ // set the network device address from the local device address
++ memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
++}
++
++/*! net_os_disable
++ *
++ */
++extern void net_os_disable(struct usbd_function_instance *function)
++{
++#if 0
++ struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
++ function->privdata = NULL;
++ npd->function = NULL;
++#endif
++}
++
++/*
++ *
++ */
++void net_os_carrier_on(struct usb_network_private *npd)
++{
++ netif_carrier_on(npd->net_dev);
++ netif_wake_queue(npd->net_dev);
++#ifdef CONFIG_OTG_NET_NFS_SUPPORT
++ if (!usb_is_configured) {
++ wake_up(&usb_netif_wq);
++ usb_is_configured = 1;
++ }
++#endif
++
++}
++
++/*
++ *
++ */
++void net_os_carrier_off(struct usb_network_private *npd)
++{
++ netif_stop_queue(npd->net_dev);
++ netif_carrier_off(npd->net_dev);
++}
++
++
++//_______________________________Network Layer Functions____________________________________
++
++/*
++ * In general because the functions are called from an independant layer it is necessary
++ * to verify that the device is still ok and to lock interrupts out to prevent in-advertant
++ * closures while in progress.
++ */
++
++/* network_init -
++ *
++ * Initializes the specified network device.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_init (struct net_device *net_device)
++{
++ TRACE_MSG0(NTT,"no-op");
++ return 0;
++}
++
++
++/* network_uninit -
++ *
++ * Uninitializes the specified network device.
++ */
++STATIC void network_uninit (struct net_device *net_device)
++{
++ TRACE_MSG0(NTT,"no-op");
++ return;
++}
++
++
++/* network_open -
++ *
++ * Opens the specified network device.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_open (struct net_device *net_device)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++ unsigned long flags;
++
++ _MOD_INC_USE_COUNT;
++ TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
++ npd->flags |= NETWORK_OPEN;
++ netif_wake_queue (net_device);
++
++ local_irq_save(flags);
++ (*(npd->fd_ops->send_int_notification))(npd, 1, 0);
++ local_irq_restore(flags);
++
++#ifdef CONFIG_OTG_NET_NFS_SUPPORT
++ if (!usb_is_configured) {
++ if (!in_interrupt()) {
++ TRACE_MSG0(NTT,"Please replug USB cable and then ifconfig host interface.\n");
++ printk(KERN_ERR"Please replug USB cable and then ifconfig host interface.\n");
++ interruptible_sleep_on(&usb_netif_wq);
++ }
++ else {
++ TRACE_MSG_0(NTT,"Warning! In interrupt\n");
++ printk(KERN_ERR"Warning! In interrupt\n");
++ }
++ }
++#endif
++ return 0;
++}
++
++
++/* network_stop -
++ *
++ * Stops the specified network device.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_stop (struct net_device *net_device)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++ unsigned long flags;
++
++ TRACE_MSG0(NTT,"-");
++
++ //netif_stop_queue (net_device);
++
++ npd->flags &= ~NETWORK_OPEN;
++
++ local_irq_save(flags);
++ (*(npd->fd_ops->send_int_notification))(npd, 0, 0);
++ local_irq_restore(flags);
++
++ _MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++ return 0;
++}
++
++
++/* network_get_stats -
++ *
++ * Gets statistics from the specified network device.
++ *
++ * Returns pointer to net_device_stats structure with the required information.
++ */
++STATIC struct net_device_stats *network_get_stats (struct net_device *net_device)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++ return &npd->stats;
++}
++
++
++/* network_set_mac_addr
++ *
++ * Sets the MAC address of the specified network device. Fails if the device is in use.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_set_mac_addr (struct net_device *net_device, void *p)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++ struct sockaddr *addr = p;
++ unsigned long flags;
++
++ TRACE_MSG0(NTT,"--");
++
++ RETURN_EBUSY_IF(netif_running (net_device));
++ local_irq_save(flags);
++ memcpy(net_device->dev_addr, addr->sa_data, net_device->addr_len);
++ memcpy(npd->local_dev_addr, npd->net_dev->dev_addr, ETH_ALEN);
++ local_irq_restore(flags);
++ return 0;
++}
++
++
++/* network_tx_timeout -
++ *
++ * Tells the specified network device that its current transmit attempt has timed out.
++ */
++STATIC void network_tx_timeout (struct net_device *net_device)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++#if 0
++ //printk(KERN_ERR"%s:\n", __FUNCTION__);
++ npd->stats.tx_errors++;
++ npd->stats.tx_dropped++;
++ usbd_cancel_urb_irq (npd->bus, NULL); // QQSV
++#endif
++#if 0
++ // XXX attempt to wakeup the host...
++ if ((npd->network_type == network_blan) && (npd->flags & NETWORK_OPEN)) {
++ notification_schedule_bh();
++ }
++#endif
++}
++
++
++/** network_set_config -
++ *
++ * Sets the specified network device's configuration. Fails if the device is in use.
++ *
++ * map An ifmap structure containing configuration values.
++ * Those values which are non-zero/non-null update the corresponding fields
++ * in net_device.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_set_config (struct net_device *net_device, struct ifmap *map)
++{
++ RETURN_EBUSY_IF(netif_running (net_device));
++ if (map->base_addr)
++ net_device->base_addr = map->base_addr;
++ if (map->mem_start)
++ net_device->mem_start = map->mem_start;
++ if (map->irq)
++ net_device->irq = map->irq;
++ return 0;
++}
++
++
++/* network_change_mtu -
++ *
++ * Sets the specified network device's MTU. Fails if the new value is larger and
++ * the device is in use.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_change_mtu (struct net_device *net_device, int mtu)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++
++ TRACE_MSG0(NTT,"-");
++
++ RETURN_EBUSY_IF(netif_running (net_device));
++ RETURN_EBUSY_IF(mtu > npd->mtu);
++
++ npd->mtu = mtu;
++ return 0;
++}
++
++//_________________________________________________________________________________________________
++// network_hard_start_xmit
++
++/*
++ * net_os_start_xmit - start sending an skb, with usbd_network_sem already held.
++ *
++ * Return non-zero (1) if busy. QQSV - this code always returns 0.
++ */
++STATIC __inline__ int net_os_start_xmit (struct sk_buff *skb, struct net_device *net_device)
++{
++ struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
++ int rc;
++
++ if (!netif_carrier_ok(net_device)) {
++ dev_kfree_skb_any (skb);
++ npd->stats.tx_dropped++;
++ //netif_stop_queue(net_device); // XXX
++ // XXX this is what we should do, blows up on some 2.4.20 kernels
++ // return(NET_XMIT_DROP);
++ return(0);
++ }
++
++ // stop queue, it will be restarted only when we are ready for another skb
++ netif_stop_queue(net_device);
++ npd->stopped++;
++
++ // Set the timestamp for tx timeout
++ net_device->trans_start = jiffies;
++
++ // XXX request IN, should start a timer to resend this.
++ if (npd->data_notify)
++ (*(npd->fd_ops->send_int_notification))(npd, 0, 1);
++
++ rc = (*(npd->fd_ops->start_xmit))(npd,skb->data,skb->len,(void*)skb);
++ switch (rc) {
++ case 0:
++ TRACE_MSG1(NTT,"OK: %d", rc);
++ // update some stats
++ npd->queued_entries++;
++ npd->queued_bytes += skb->len;
++ npd->stats.tx_packets++;
++ npd->stats.tx_bytes += skb->len;
++
++ // Should we restart network queue
++ if ((npd->queued_entries < npd->max_queue_entries) &&
++ (npd->queued_bytes < npd->max_queue_bytes))
++ netif_wake_queue (net_device);
++
++ break;
++
++ case -EINVAL:
++ case -EUNATCH:
++ TRACE_MSG1(NTT,"not attached, send failed: %d", rc);
++ printk(KERN_ERR"%s: not attached, send failed: %d\n", __FUNCTION__, rc);
++ npd->stats.tx_errors++;
++ npd->stats.tx_carrier_errors++;
++ netif_wake_queue(net_device);
++ break;
++
++ case -ENOMEM:
++ TRACE_MSG1(NTT,"no mem, send failed: %d", rc);
++ printk(KERN_ERR"%s: no mem, send failed: %d\n", __FUNCTION__, rc);
++ npd->stats.tx_errors++;
++ npd->stats.tx_fifo_errors++;
++ netif_wake_queue(net_device);
++ break;
++
++ case -ECOMM:
++ TRACE_MSG2(NTT,"comm failure, send failed: %d %p", rc, net_device);
++ printk(KERN_ERR"%s: comm failure, send failed: %d %p\n", __FUNCTION__, rc, net_device);
++ // Leave the IF queue stopped.
++ npd->stats.tx_dropped++;
++ break;
++
++ }
++ if (0 != rc) {
++ dev_kfree_skb_any (skb);
++ // XXX this is what we should do, blows up on some 2.4.20 kernels
++ // return(NET_XMIT_DROP);
++ return(0);
++ }
++
++ return 0;
++}
++
++/*
++ * network_hard_start_xmit - start sending an skb. Called by the OS network layer.
++ *
++ * Return non-zero (1) if busy. QQSV - this code always returns 0.
++ */
++STATIC int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
++{
++ int rc;
++ down(&usbd_network_sem);
++ rc = net_os_start_xmit(skb,net_device);
++ up(&usbd_network_sem);
++ return rc;
++}
++
++
++/* network_do_ioctl - perform an ioctl call
++ *
++ * Carries out IOCTL commands for the specified network device.
++ *
++ * rp Points to an ifreq structure containing the IOCTL parameter(s).
++ * cmd The IOCTL command.
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
++{
++ return -ENOIOCTLCMD;
++}
++
++//_________________________________________________________________________________________________
++
++struct net_device Network_net_device = {
++ get_stats: network_get_stats,
++ tx_timeout: network_tx_timeout,
++ do_ioctl: network_do_ioctl,
++ set_config: network_set_config,
++ set_mac_address: network_set_mac_addr,
++ hard_start_xmit: network_hard_start_xmit,
++ change_mtu: network_change_mtu,
++ init: network_init,
++ uninit: network_uninit,
++ open: network_open,
++ stop: network_stop,
++ priv: &Usb_network_private,
++};
++
++//_________________________________________________________________________________________________
++
++#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++/* sock_ioctl - perform an ioctl call to inet device
++ */
++int sock_ioctl(u32 cmd, struct ifreq *ifreq)
++{
++ int rc = 0;
++ mm_segment_t save_get_fs = get_fs();
++ TRACE_MSG1(NTT, "cmd: %x", cmd);
++ set_fs(get_ds());
++ rc = devinet_ioctl(cmd, ifreq);
++ set_fs(save_get_fs);
++ return rc;
++}
++
++/* sock_addr - setup a socket address for specified interface
++ */
++static int sock_addr(char * ifname, u32 cmd, u32 s_addr)
++{
++ struct ifreq ifreq;
++ struct sockaddr_in *sin = (void *) &(ifreq.ifr_ifru.ifru_addr);
++
++ TRACE_MSG2(NTT, "ifname: %s addr: %x", ifname, ntohl(s_addr));
++
++ memset(&ifreq, 0, sizeof(ifreq));
++ strcpy(ifreq.ifr_ifrn.ifrn_name, ifname);
++
++ sin->sin_family = AF_INET;
++ sin->sin_addr.s_addr = s_addr;
++
++ return sock_ioctl(cmd, &ifreq);
++}
++
++
++/* sock_flags - set flags for specified interface
++ */
++static int sock_flags(char * ifname, u16 oflags, u16 sflags, u16 rflags)
++{
++ int rc = 0;
++ struct ifreq ifreq;
++
++ TRACE_MSG4(NTT, "ifname: %s oflags: %x s_flags: %x r_flags: %x", ifname, oflags, sflags, rflags);
++
++ memset(&ifreq, 0, sizeof(ifreq));
++ strcpy(ifreq.ifr_ifrn.ifrn_name, ifname);
++
++ oflags |= sflags;
++ oflags &= ~rflags;
++ ifreq.ifr_flags = oflags;
++
++ TRACE_MSG1(NTT, "-> ifr_flags: %x ", ifreq.ifr_flags);
++
++ THROW_IF ((rc = sock_ioctl(SIOCSIFFLAGS, &ifreq)), error);
++
++ TRACE_MSG1(NTT, "<- ifr_flags: %x ", ifreq.ifr_flags);
++
++ CATCH(error) {
++ TRACE_MSG1(NTT, "ifconfig: cannot get/set interface flags (%d)", rc);
++ return rc;
++ }
++ return rc;
++}
++
++/* network_attach - configure interface
++ *
++ * This will use socket calls to configure the interface to the supplied
++ * ip address and make it active.
++ */
++STATIC int network_attach(struct usb_network_private *npd, u32 ip, u32 mask, u32 router, int attach)
++{
++ int err = 0;
++
++ if (attach) {
++ TRACE_MSG5(NTT, "ATTACH npd: %x ip: %08x mask: %08x router: %08x attach: %d", npd, ip, mask, router, attach);
++ u16 oflags = (npd && npd->net_dev) ? npd->net_dev->flags : 0;
++
++ if (npd->net_dev)
++ memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
++
++ /* setup ip address, netwask, and broadcast address */
++ if (ip) {
++ THROW_IF ((err = sock_addr("usbl0", SIOCSIFADDR, htonl(ip))), error);
++ if (mask) {
++ THROW_IF ((err = sock_addr("usbl0", SIOCSIFNETMASK, htonl(mask))), error);
++ THROW_IF ((err = sock_addr("usbl0", SIOCSIFBRDADDR, htonl(ip | ~mask))), error);
++ }
++ /* bring the interface up */
++ THROW_IF ((err = sock_flags("usbl0", oflags, IFF_UP, 0)), error);
++ }
++ }
++ else {
++ TRACE_MSG5(NTT, "DETACH npd: %x ip: %08x mask: %08x router: %08x attach: %d", npd, ip, mask, router, attach);
++ u16 oflags = (npd && npd->net_dev) ? npd->net_dev->flags : 0;
++ /* bring the interface down */
++ THROW_IF ((err = sock_flags("usbl0", oflags, 0, IFF_UP)), error);
++ }
++
++ CATCH(error) {
++ TRACE_MSG1(NTT, "ifconfig: cannot configure interface (%d)", err);
++ return err;
++ }
++ return 0;
++}
++
++/* network_config - configure network
++ *
++ * Check connected status and load/unload as appropriate.
++ *
++ */
++STATIC void config_bh (void *data)
++{
++ struct usb_network_private *npd = (struct usb_network_private *) data;
++ struct usbd_function_instance *function = npd->function;
++
++ TRACE_MSG5(NTT, "function: %x enabled: %x status: %x state: %x npd->config_status: %d",
++ function,
++ npd->flags & NETWORK_ENABLED,
++ usbd_get_device_status(function),
++ usbd_get_device_state(function),
++ npd->config_status);
++
++ if ((npd->flags & NETWORK_ENABLED ) && (function && (USBD_OK == usbd_get_device_status(function))
++ && (STATE_CONFIGURED == usbd_get_device_state(function))
++ && ip_addr
++ ))
++ {
++ TRACE_MSG2(NTT,"BUS state: %d status: %d", usbd_get_device_state(function), usbd_get_device_status(function));
++ if (config_attached != npd->config_status) {
++ TRACE_MSG0(NTT,"ATTACH");
++ npd->config_status = config_attached;
++ network_attach (npd, ip_addr, network_mask, router_ip, 1);
++ }
++ return;
++ }
++
++ if (config_detached != npd->config_status) {
++ TRACE_MSG0(NTT,"DETACH");
++ npd->config_status = config_detached;
++ network_attach (npd, ip_addr, network_mask, router_ip, 0);
++ }
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++}
++
++/*
++ * net_os_config - schedule a call to config bottom half
++ */
++void net_os_config(struct usb_network_private *npd)
++{
++ //_MOD_INC_USE_COUNT;
++ TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
++ if (!SCHEDULE_WORK(npd->config_bh)) {
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++ }
++}
++#else /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
++void net_os_config(struct usb_network_private *npd)
++{
++ TRACE_MSG0(NTT, "NOT CONFIGURED");
++ // Do nothing, config not configured.
++}
++#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
++//______________________________________ Hotplug Functions ________________________________________
++
++#ifdef CONFIG_OTG_NETWORK_HOTPLUG
++
++#define AGENT "network_fd"
++
++/* hotplug_attach - call hotplug
++ */
++STATIC int hotplug_attach(struct usb_network_private *npd, u32 ip, u32 mask, u32 router, int attach)
++{
++ static int count = 0;
++ char *argv[3];
++ char *envp[10];
++ char ifname[20+12 + IFNAMSIZ];
++ int i;
++ char count_str[20];
++
++ RETURN_EINVAL_IF(!hotplug_path[0]);
++
++ argv[0] = hotplug_path;
++ argv[1] = AGENT;
++ argv[2] = 0;
++
++ sprintf (ifname, "INTERFACE=%s", npd->net_dev->name);
++ sprintf (count_str, "COUNT=%d", count++);
++
++ i = 0;
++ envp[i++] = "HOME=/";
++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++ envp[i++] = ifname;
++
++
++ if (attach) {
++ unsigned char *cp;
++ char ip_str[20+32];
++ char mask_str[20+32];
++ char router_str[20+32];
++ u32 nh;
++
++ nh = htonl(ip);
++ cp = (unsigned char*) &nh;
++ sprintf (ip_str, "IP=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
++
++ nh = htonl(mask);
++ cp = (unsigned char*) &nh;
++ sprintf (mask_str, "MASK=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
++
++ nh = htonl(router);
++ cp = (unsigned char*) &nh;
++ sprintf (router_str, "ROUTER=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
++
++ //TRACE_MSG3(NTT, "attach %s %s %s", ifname, ip_str, count_str);
++
++ envp[i++] = "ACTION=attach";
++ envp[i++] = ip_str;
++ envp[i++] = mask_str;
++ envp[i++] = router_str;
++
++ TRACE_MSG3(NTT, "attach ip: %08x mask: %08x router: %08x", ip, mask, router);
++ }
++ else {
++ //TRACE_MSG2(NTT,"detach %s %s", ifname, count_str);
++ envp[i++] = "ACTION=detach";
++ TRACE_MSG3(NTT, "detach ip: %08x mask: %08x router: %08x", ip, mask, router);
++ }
++
++ envp[i++] = count_str;
++ envp[i++] = 0;
++
++ return call_usermodehelper (argv[0], argv, envp);
++}
++
++
++/* hotplug_bh - bottom half handler to call hotplug script to signal ATTACH or DETACH
++ *
++ * Check connected status and load/unload as appropriate.
++ *
++ * It should not be possible for this to be called more than once at a time
++ * as it is only called via schedule_task() which protects against a second
++ * invocation.
++ */
++STATIC void hotplug_bh (void *data)
++{
++ //struct usb_network_private *network_private = &Usb_network_private;
++ struct usb_network_private *npd = (struct usb_network_private *) data;
++ struct usbd_function_instance *function = NULL;
++
++ UNLESS (npd) {
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "NPD NULL DEC: %d", MOD_IN_USE);
++ return;
++ }
++
++ function = npd->function;
++
++ TRACE_MSG2(NTT, "function: %x npd->hotplug_status: %d", function, npd->hotplug_status);
++
++
++ if ((npd->flags & NETWORK_ENABLED ) && (function && (USBD_OK == usbd_get_device_status(function))
++ && (STATE_CONFIGURED == usbd_get_device_state(function))))
++ {
++ TRACE_MSG2(NTT,"BUS state: %d status: %d", usbd_get_device_state(function), usbd_get_device_status(function));
++ if (hotplug_attached != npd->hotplug_status) {
++ TRACE_MSG0(NTT,"ATTACH");
++ npd->hotplug_status = hotplug_attached;
++ hotplug_attach (npd, ip_addr, network_mask, router_ip, 1);
++ }
++ return;
++ }
++
++ if (hotplug_detached != npd->hotplug_status) {
++ TRACE_MSG0(NTT,"DETACH");
++ npd->hotplug_status = hotplug_detached;
++ hotplug_attach (npd, ip_addr, network_mask, router_ip, 0);
++ }
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++}
++
++/*
++ * net_os_hotplug - schedule a call to hotplug bottom half
++ */
++void net_os_hotplug(struct usb_network_private *npd)
++{
++ //_MOD_INC_USE_COUNT;
++ TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
++ if (!SCHEDULE_WORK(npd->hotplug_bh)) {
++ //_MOD_DEC_USE_COUNT;
++ TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
++ }
++}
++#else
++void net_os_hotplug(struct usb_network_private *npd)
++{
++ TRACE_MSG0(NTT, "NOT CONFIGURED");
++ // Do nothing, hotplug not configured.
++}
++#endif /* CONFIG_OTG_NETWORK_HOTPLUG */
++
++//_________________________________________________________________________________________________
++
++/* network_create - create and initialize network private structure
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_create(struct usb_network_private *npd)
++{
++ TRACE_MSG0(NTT,"entered");
++
++ // Set some fields to generic defaults and register the network device with the kernel networking code
++
++ memset(&npd->stats, 0, sizeof npd->stats);
++
++ ether_setup(npd->net_dev);
++ RETURN_EINVAL_IF (register_netdev(npd->net_dev));
++ npd->flags |= NETWORK_REGISTERED;
++
++ netif_stop_queue(npd->net_dev);
++ netif_carrier_off(npd->net_dev);
++ npd->net_dev->flags &= ~IFF_UP;
++
++ npd->flags |= NETWORK_CREATED;
++
++ npd->maxtransfer = MAXFRAMESIZE + 4 + 64;
++
++ TRACE_MSG0(NTT,"finis");
++ return 0;
++}
++
++/* network_destroy - destroy network private struture
++ *
++ * Destroys the network interface referenced by the global variable @c Network_net_device.
++ */
++STATIC void network_destroy(struct usb_network_private *npd)
++{
++ if (npd->flags & NETWORK_REGISTERED) {
++ netif_stop_queue(npd->net_dev);
++ netif_carrier_off(npd->net_dev);
++ unregister_netdev(npd->net_dev);
++ }
++ npd->flags = 0;
++}
++
++
++//______________________________________module_init and module_exit________________________________
++
++#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++
++/*! network_proc_read_ip - implement proc file system read.
++ * Standard proc file system read function.
++ */
++static ssize_t network_proc_read_ip (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ char *bp;
++ int index = (*pos)++;
++
++ RETURN_ZERO_IF(index);
++
++ // get a page, max 4095 bytes of data...
++ RETURN_ENOMEM_UNLESS ((page = GET_KERNEL_PAGE()));
++
++ bp = (char *) page;
++
++ len = sprintf(bp, "%d.%d.%d.%d\n",
++ (router_ip >> 24) & 0xff,
++ (router_ip >> 16) & 0xff,
++ (router_ip >> 8) & 0xff,
++ (router_ip) & 0xff
++ );
++
++ if (copy_to_user(buf, (char *) page, len))
++ len = -EFAULT;
++
++ free_page (page);
++ return len;
++}
++
++static struct file_operations otg_message_proc_switch_functions = {
++ read: network_proc_read_ip,
++};
++
++#endif
++
++
++/* network_modinit - driver intialization
++ *
++ * Returns non-zero for failure.
++ */
++STATIC int network_modinit (void)
++{
++ // Pickup and link together the various global structs.
++ struct usb_network_private *npd = &Usb_network_private;
++ #ifdef CONFIG_PROC_FS
++ struct proc_dir_entry *p;
++ #endif /* CONFIG_PROC_FS */
++ npd->fd_ops = &net_fd_usb_ops;
++ npd->params = &params;
++ npd->net_dev = &Network_net_device;
++ npd->net_dev->priv = (void *) npd;
++#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
++ params.vendor_id = vendor_id;
++ params.product_id = product_id;
++#endif
++ params.local_mac_address_str = local_mac_address_str;
++ params.remote_mac_address_str = remote_mac_address_str;
++#ifdef CONFIG_OTG_NETWORK_EP0TEST
++ params.ep0test = ep0test;
++#endif
++ params.zeroconf = zeroconf;
++#if defined(CONFIG_OTG_NETWORK_CDC)
++ params.cdc = cdc;
++#endif
++#ifdef CONFIG_OTG_NETWORK_BASIC
++ params.basic = basic;
++#endif
++#ifdef CONFIG_OTG_NETWORK_BASIC2
++ params.basic2 = basic2;
++#endif
++#ifdef CONFIG_OTG_NETWORK_SAFE
++ params.safe = safe;
++#endif
++#ifdef CONFIG_OTG_NETWORK_BLAN
++ params.blan = blan;
++#endif
++ // That should be it for reference to globals except for network_modexit().
++
++ init_waitqueue_head(&usb_netif_wq);
++ PREPARE_WORK_ITEM(npd->notification_bh, notification_bh,npd);
++#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++ PREPARE_WORK_ITEM(npd->config_bh, config_bh, npd);
++ #ifdef CONFIG_PROC_FS
++ if ((p = create_proc_entry ("network_ip", 0666, 0)))
++ p->proc_fops = &otg_message_proc_switch_functions;
++ #endif /* CONFIG_PROC_FS */
++#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
++#ifdef CONFIG_OTG_NETWORK_HOTPLUG
++ PREPARE_WORK_ITEM(npd->hotplug_bh, hotplug_bh, npd);
++#endif /* CONFIG_OTG_NETWORK_HOTPLUG */
++
++ if (0 != (*(npd->fd_ops->initialize_usb_part))(npd,"linux network_fd")) {
++ // If the usb part fails, there are no trace functions.
++ return -EINVAL;
++ }
++
++ memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
++ /* QQSV - this is very strange, since npd->network type can have
++ a number of different values. setting zeroconf is not going to
++ be quite as obvious as it might at first seem. */
++ strncpy(npd->net_dev->name, ((npd->network_type == zeroconf) ? "usbz0" :
++ (network_blan ? "usbl0" : "usbb0")), 6);
++
++ if (network_create(npd)) {
++ (*(npd->fd_ops->terminate_usb_part))(npd);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++//_____________________________________________________________________________
++
++/* network_modexit - driver exit
++ *
++ * Cleans up the module. Deregisters the function driver and destroys the network object.
++ */
++STATIC void network_modexit (void)
++{
++ struct usb_network_private *npd = &Usb_network_private;
++
++ #ifdef CONFIG_PROC_FS
++ remove_proc_entry("network_ip", NULL);
++ #endif /* CONFIG_PROC_FS */
++
++ while (PENDING_WORK_ITEM(npd->notification_bh)) {
++ // TRACE_MSG pointless here, module will be gon before we can look at it.
++ printk(KERN_ERR"%s: waiting for notificationhotplug bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++ while (PENDING_WORK_ITEM(npd->config_bh)) {
++ printk(KERN_ERR"%s: waiting for config bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
++
++#ifdef CONFIG_OTG_NETWORK_HOTPLUG
++ while (PENDING_WORK_ITEM(npd->hotplug_bh)) {
++ printk(KERN_ERR"%s: waiting for hotplug bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++#endif
++ /* Which order to tear down the two parts? No matter which goes first,
++ the other could still try to send data through the now-torn-down part,
++ so go with usb last, because it has the otg_trace cleanup. */
++ network_destroy(npd);
++ if (npd->fd_ops)
++ (*(npd->fd_ops->terminate_usb_part))(npd);
++}
++
++//_________________________________________________________________________________________________
++
++module_init (network_modinit);
++module_exit (network_modexit);
++
+diff -uNr linux/drivers/no-otg/functions/network/net-os.h linux/drivers/otg/functions/network/net-os.h
+--- linux/drivers/no-otg/functions/network/net-os.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/net-os.h 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,107 @@
++/*
++ * otg/functions/network/net-os.h
++ *
++ * Copyright (c) 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++
++/*!
++ * @file otg/functions/network/net-os.h
++ * @brief Structures and function definitions required for implementation
++ * of the OS specific upper edge (network interface) for the Network
++ * Function Driver.
++ *
++ * A USB network driver is composed of two pieces:
++ * 1) An OS specific piece that handles creating and operating
++ * a network device for the given OS.
++ * 2) A USB specific piece that interfaces either with the host
++ * usbcore layer, or with the device usbdcore layer.
++ *
++ * If the USB piece interfaces with the host usbcore layer you get
++ * a network class driver. If the USB piece interfaces with the usbdcore
++ * layer you get a network function driver.
++ *
++ * This file describes the functions exported by the various net-*-os.c
++ * files (implementing (1)) for use in net-fd.c (2).
++ *
++ *
++ * @ingroup NetworkFunction
++ */
++
++#ifndef NET_OS_H
++#define NET_OS_H 1
++
++/*
++ * net_os_mutex_enter - enter mutex region
++ */
++extern void net_os_mutex_enter(struct usb_network_private *npd);
++
++/*
++ * net_os_mutex_exit - exit mutex region
++ */
++extern void net_os_mutex_exit(struct usb_network_private *npd);
++
++/*
++ * net_os_send_notification_later - schedule a callback to the USB part to send
++ * an INT notification.
++ */
++extern void net_os_send_notification_later(struct usb_network_private *npd);
++
++/*
++ * net_os_xmit_done - called from USB part when a transmit completes, good or bad.
++ * tx_rc is SEND_FINISHED_ERROR, SEND_CANCELLED or...
++ * buff_ctx is the pointer passed to fd_ops->start_xmit().
++ * Return non-zero only if network does not exist, ow 0.
++ */
++extern int net_os_xmit_done(struct usbd_function_instance *function, void *buff_ctx, int tx_rc);
++
++/*
++ *
++ */
++extern void *net_os_alloc_buff(struct usb_network_private *npd, u8 **cp, int n);
++
++/*
++ * net_os_recv_buff - forward a received URB, or clean up after a bad one.
++ * buff_ctx == NULL --> just accumulate stats (count 1 bad buff)
++ * crc_bad != 0 --> count a crc error and free buff_ctx/skb
++ * trim --> amount to trim from valid buffer (i.e. shorten
++ * from amount requested in net_os_alloc_buff(..... n).
++ * This will be called from interrupt context.
++ */
++extern void net_os_recv_buff(struct usb_network_private *npd, void *buff_ctx, int crc_bad, int trim);
++
++/*
++ * net_os_config - schedule a network hotplug event if the OS supports hotplug.
++ */
++extern void net_os_config(struct usb_network_private *npd);
++
++/*
++ * net_os_hotplug - schedule a network hotplug event if the OS supports hotplug.
++ */
++extern void net_os_hotplug(struct usb_network_private *npd);
++
++/*
++ *
++ */
++extern void net_os_enable(struct usbd_function_instance *function);
++
++/*
++ *
++ */
++extern void net_os_disable(struct usbd_function_instance *function);
++
++/*
++ *
++ */
++extern void net_os_carrier_on(struct usb_network_private *npd);
++
++/*
++ *
++ */
++extern void net_os_carrier_off(struct usb_network_private *npd);
++
++#endif
+diff -uNr linux/drivers/no-otg/functions/network/network.h linux/drivers/otg/functions/network/network.h
+--- linux/drivers/no-otg/functions/network/network.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/network.h 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,348 @@
++/*
++ * otg/functions/network/network.h - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Tom Rushworth <tbr@belcarra.com>
++ * Chris Lynne <cl@belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*!
++ * @defgroup NetworkFunction Network
++ * @ingroup functiongroup
++ */
++/*!
++ * @file otg/functions/network/network.h
++ * @brief Network Function Driver private defines
++ *
++ * This defines the internal and private structures required
++ * by the Network Function Driver.
++ *
++ * @ingroup NetworkFunction
++ */
++
++/*! This is a test
++ */
++#ifndef NETWORK_FD_H
++#define NETWORK_FD_H 1
++
++#include <otg/otg-trace.h>
++
++extern otg_tag_t network_fd_trace_tag;
++
++// Some platforms need to get rid of "static" when using GDB or looking at ksyms
++//#define STATIC
++#define STATIC static
++
++typedef enum network_encapsulation {
++ simple_net, simple_crc,
++} network_encapsulation_t;
++
++typedef enum network_config_status {
++ config_unkown,
++ config_attached,
++ config_detached
++} network_config_status_t;
++
++typedef enum network_hotplug_status {
++ hotplug_unkown,
++ hotplug_attached,
++ hotplug_detached
++} network_hotplug_status_t;
++
++typedef enum network_type {
++ network_unknown,
++ network_blan,
++ network_safe,
++ network_cdc,
++ network_basic,
++ network_basic2,
++ network_eem,
++} network_type_t;
++
++struct usb_network_params {
++ // enabling switchs
++ u32 cdc;
++ u32 basic;
++ u32 basic2;
++ u32 safe;
++ u32 blan;
++ // capability flags
++ u32 cdc_capable;
++ u32 basic_capable;
++ u32 basic2_capable;
++ u32 safe_capable;
++ u32 blan_capable;
++ // overrides
++ u32 vendor_id;
++ u32 product_id;
++ char *local_mac_address_str;
++ char *remote_mac_address_str;
++ // other switches
++ u32 ep0test;
++ u32 zeroconf;
++};
++
++#define CONFIG_OTG_NETWORK_ALLOW_SETID 1
++
++#define NETWORK_CREATED 0x01
++#define NETWORK_REGISTERED 0x02
++#define NETWORK_DESTROYING 0x04
++#define NETWORK_ENABLED 0x08
++#define NETWORK_ATTACHED 0x10
++#define NETWORK_OPEN 0x20
++
++
++#define MCCI_ENABLE_CRC 0x03
++#define BELCARRA_GETMAC 0x04
++
++#define BELCARRA_SETTIME 0x04
++#define BELCARRA_SETIP 0x05
++#define BELCARRA_SETMSK 0x06
++#define BELCARRA_SETROUTER 0x07
++#define BELCARRA_SETDNS 0x08
++#define BELCARRA_PING 0x09
++#define BELCARRA_SETFERMAT 0x0a
++#define BELCARRA_HOSTNAME 0x0b
++
++
++// RFC868 - seconds from midnight on 1 Jan 1900 GMT to Midnight 1 Jan 1970 GMT
++#define RFC868_OFFSET_TO_EPOCH 0x83AA7E80
++
++struct usb_network_private {
++
++ struct net_device_stats stats; /* network device statistics */
++
++ int flags;
++ struct net_device *net_dev;
++ struct usbd_function_instance *function;
++ struct usbd_function_driver *function_driver;
++ struct usb_network_params *params;
++ struct net_usb_services *fd_ops;
++ unsigned int maxtransfer;
++ rwlock_t rwlock;
++
++ network_config_status_t config_status;
++ network_hotplug_status_t hotplug_status;
++ network_type_t network_type;
++
++ int state;
++
++ int mtu;
++ int crc;
++#if defined(CONFIG_OTG_NETWORK_BLAN_FERMAT)
++ int fermat;
++#endif
++
++ unsigned int stopped;
++ unsigned int restarts;
++
++ unsigned int max_queue_entries;
++ unsigned int max_queue_bytes;
++
++ unsigned int queued_entries;
++ unsigned int queued_bytes;
++
++ time_t avg_queue_entries;
++
++ time_t jiffies;
++ unsigned long samples;
++
++ int have_interrupt;
++
++ int data_notify;
++
++ struct usbd_urb *int_urb;
++
++ network_encapsulation_t encapsulation;
++
++ struct WORK_ITEM notification_bh;
++#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
++ struct WORK_ITEM config_bh;
++#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
++#ifdef CONFIG_HOTPLUG
++ struct WORK_ITEM hotplug_bh;
++#endif /* CONFIG_HOTPLUG */
++ __u8 local_dev_addr[ETH_ALEN];
++ __u8 remote_dev_addr[ETH_ALEN];
++};
++
++// XXX this needs to be co-ordinated with rndis.c maximum's
++#define MAXFRAMESIZE 2000
++
++#if !defined(CONFIG_OTG_MANUFACTURER)
++ #define CONFIG_OTG_MANUFACTURER "Belcarra"
++#endif
++
++
++#if !defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ #define CONFIG_OTG_SERIAL_NUMBER_STR ""
++#endif
++
++/*
++ * Lineo specific
++ */
++
++#define VENDOR_SPECIFIC_CLASS 0xff
++#define VENDOR_SPECIFIC_SUBCLASS 0xff
++#define VENDOR_SPECIFIC_PROTOCOL 0xff
++
++/*
++ * Lineo Classes
++ */
++#define LINEO_CLASS 0xff
++
++#define LINEO_SUBCLASS_BASIC_NET 0x01
++#define LINEO_SUBCLASS_BASIC_SERIAL 0x02
++
++/*
++ * Lineo Protocols
++ */
++#define LINEO_BASIC_NET_CRC 0x01
++#define LINEO_BASIC_NET_CRC_PADDED 0x02
++
++#define LINEO_BASIC_SERIAL_CRC 0x01
++#define LINEO_BASIC_SERIAL_CRC_PADDED 0x02
++
++
++/*
++ * endpoint and interface indexes
++ */
++#define BULK_OUT 0x00
++#define BULK_IN 0x01
++#define INT_IN 0x02
++#define ENDPOINTS 0x03
++
++#define COMM_INTF 0x00
++#define DATA_INTF 0x01
++
++
++/* bmDataCapabilities */
++#define BMDATA_CRC 0x01
++#define BMDATA_PADBEFORE 0x02
++#define BMDATA_PADAFTER 0x04
++#define BMDATA_FERMAT 0x08
++#define BMDATA_HOSTNAME 0x10
++
++/* bmNetworkCapabilities */
++#define BMNETWORK_SET_PACKET_OK 0x01
++#define BMNETWORK_NONBRIDGED 0x02
++#define BMNETWORK_DATA_NOTIFY_OK 0x04
++
++
++/*
++ * BLAN Data Plane
++ */
++//#define CONFIG_OTG_NETWORK_PADBYTES 8
++//#define CONFIG_OTG_NETWORK_PADAFTER 1
++//#undef CONFIG_OTG_NETWORK_PADBEFORE
++//#define CONFIG_OTG_NETWORK_CRC 1
++
++
++extern __u8 network_requested_endpoints[ENDPOINTS+1];
++extern __u16 network_requested_transferSizes[ENDPOINTS+1];
++extern struct usb_network_private Usb_network_private;
++extern __u8 local_dev_addr[ETH_ALEN];
++extern __u8 remote_dev_addr[ETH_ALEN];
++
++extern struct usbd_function_operations net_fd_function_ops;
++
++struct usbd_class_safe_networking_mdlm_descriptor {
++ __u8 bFunctionLength; // 0x06
++ __u8 bDescriptorType; // 0x24
++ __u8 bDescriptorSubtype; // 0x13
++ __u8 bGuidDescriptorType; // 0x00
++ __u8 bmNetworkCapabilities;
++ __u8 bmDataCapabilities;
++} __attribute__ ((packed));
++
++struct usbd_class_blan_networking_mdlm_descriptor {
++ __u8 bFunctionLength; // 0x07
++ __u8 bDescriptorType; // 0x24
++ __u8 bDescriptorSubtype; // 0x13
++ __u8 bGuidDescriptorType; // 0x01
++ __u8 bmNetworkCapabilities;
++ __u8 bmDataCapabilities;
++ __u8 bPad;
++} __attribute__ ((packed));
++
++
++
++
++#define NETWORK_CREATED 0x01
++#define NETWORK_REGISTERED 0x02
++#define NETWORK_DESTROYING 0x04
++#define NETWORK_ENABLED 0x08
++#define NETWORK_ATTACHED 0x10
++#define NETWORK_OPEN 0x20
++
++
++#define MCCI_ENABLE_CRC 0x03
++#define BELCARRA_GETMAC 0x04
++
++#define BELCARRA_SETTIME 0x04
++#define BELCARRA_SETIP 0x05
++#define BELCARRA_SETMSK 0x06
++#define BELCARRA_SETROUTER 0x07
++#define BELCARRA_SETDNS 0x08
++#define BELCARRA_PING 0x09
++#define BELCARRA_SETFERMAT 0x0a
++#define BELCARRA_HOSTNAME 0x0b
++#define BELCARRA_DATA_NOTIFY 0x0c
++
++#define RFC868_OFFSET_TO_EPOCH 0x83AA7E80 // RFC868 - seconds from midnight on 1 Jan 1900 GMT to Midnight 1 Jan 1970 GMT
++
++
++extern __u32 *network_crc32_table;
++
++#define CRC32_INIT 0xffffffff // Initial FCS value
++#define CRC32_GOOD 0xdebb20e3 // Good final FCS value
++
++#define CRC32_POLY 0xedb88320 // Polynomial for table generation
++
++#define COMPUTE_FCS(val, c) (((val) >> 8) ^ network_crc32_table[((val) ^ (c)) & 0xff])
++
++
++#if 0
++#if !defined(CONFIG_OTG_NETWORK_CRC_DUFF4) && !defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
++/**
++ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
++ *
++ * dst Pointer to the destination memory area.
++ * src Pointer to the source memory area.
++ * len Number of bytes to copy.
++ * val Starting value for the CRC FCS.
++ *
++ * Returns Final value of the CRC FCS.
++ *
++ * @sa crc32_pad
++ */
++static __u32 __inline__ crc32_copy (__u8 *dst, __u8 *src, int len, __u32 val)
++{
++ for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = *src++));
++ return val;
++}
++
++#endif /* DUFFn */
++#endif
++
++
++
++
++#endif /* NETWORK_FD_H */
+diff -uNr linux/drivers/no-otg/functions/network/safe.c linux/drivers/otg/functions/network/safe.c
+--- linux/drivers/no-otg/functions/network/safe.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/functions/network/safe.c 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,362 @@
++/*
++ * otg/functions/network/safe.c - Network Function Driver
++ *
++ * Copyright (c) 2002, 2003, 2004 Belcarra
++ *
++ * By:
++ * Thomas Rushworth <tbr @belcarra.com>
++ * Stuart Lynne <sl@belcarra.com>
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * The SAFE network driver implements the SAFE protocol descriptors.
++ *
++ * The SAFE protocol is suitable for infrastructure devices that
++ * are implementing a bridged or routed connection betwen an
++ * external network and the USB Host.
++ *
++ *
++ */
++/*!
++ * @file otg/functions/network/safe.c
++ * @brief This file implements the required descriptors to implement
++ * a SAFE network device with one interface.
++ *
++ * @ingroup NetworkFunction
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/netdevice.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++
++#include "network.h"
++
++#define NTT network_fd_trace_tag
++
++#ifdef CONFIG_OTG_NETWORK_SAFE
++/* USB SAFE Configuration ********************************************************** */
++
++/*
++ * SAFE Ethernet Configuration
++ */
++
++/* Communication Interface Class descriptors
++ */
++
++/*! BULK OUT data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor safe_data_1 = {
++ bLength: 0x07,
++ bDescriptorType: USB_DT_ENDPOINT,
++ bEndpointAddress: USB_DIR_OUT,
++ bmAttributes: BULK,
++ wMaxPacketSize: __constant_cpu_to_le16(0),
++ bInterval: 0,
++};
++/*! BULK IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor safe_data_2 =
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: BULK,
++ wMaxPacketSize: __constant_cpu_to_le16(0),
++ bInterval: 0x0,
++};
++
++/*! INTERRUPT IN data endpoint descriptor
++ */
++static struct usbd_endpoint_descriptor safe_comm_1 =
++{
++ bLength:sizeof(struct usbd_endpoint_descriptor),
++ bDescriptorType:USB_DT_ENDPOINT,
++ bEndpointAddress:USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: __constant_cpu_to_le16(0),
++ bInterval: 0xa,
++};
++
++#if 0
++static struct usbd_endpoint_descriptor *basic_default[] = { &basic_data_1,
++ &basic_data_2,
++ &basic_comm_1, };
++u8 basic_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++#endif
++
++#if 0
++static u8 safe_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
++static u8 safe_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
++
++ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, /* bGUID */
++ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, /* bGUID */ };
++
++static u8 safe_class_3[] = { 0x06, CS_INTERFACE, USB_ST_MDLMD, 0x00, 0x00, 0x00, /* bDetailData */ };
++
++static u8 safe_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
++ 0x00, 0x00, 0x00 , };
++#else
++static struct usbd_class_header_function_descriptor safe_class_1 = {
++ bFunctionLength:0x05,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_HEADER,
++ bcdCDC: __constant_cpu_to_le16(0x0110), //0x10, 0x01,
++};
++
++static struct usbd_class_mdlm_descriptor safe_class_2 = {
++ bFunctionLength: 0x15,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_MDLM,
++ bcdVersion: __constant_cpu_to_le16( 0x0100), //0x00, 0x01,
++ bGUID: {
++ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, /* bGUID */
++ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, /* bGUID */ },
++};
++
++static struct usbd_class_safe_descriptor safe_class_3 = {
++ bFunctionLength: 0x06,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_MDLMD,
++ bGuidDescriptorType: 0x00,
++ bmNetworkCapabilities: 0x00,
++ bmDataCapabilities: 0x00, /* bDetailData */
++};
++
++static struct usbd_class_ethernet_networking_descriptor safe_class_4 = {
++ bFunctionLength: 0x0d,
++ bDescriptorType: CS_INTERFACE,
++ bDescriptorSubtype: USB_ST_ENF,
++ iMACAddress: 0x0,
++ bmEthernetStatistics: __constant_cpu_to_le32(0x00),
++ wMaxSegmentSize: __constant_cpu_to_le16(0x5ea),
++ wNumberMCFilters: __constant_cpu_to_le16(0x00),
++ bNumberPowerFilters: 0,
++};
++
++#endif
++
++/*! Endpoint descriptor list
++ */
++static struct usbd_endpoint_descriptor *safe_alt_endpoints[] = {
++ &safe_data_1, &safe_data_2, &safe_comm_1, };
++
++static struct usbd_generic_class_descriptor *safe_comm_class_descriptors[] = {
++ (struct usbd_generic_class_descriptor *) &safe_class_1,
++ (struct usbd_generic_class_descriptor *) &safe_class_2,
++ (struct usbd_generic_class_descriptor *) &safe_class_3,
++ (struct usbd_generic_class_descriptor *) &safe_class_4, };
++
++u8 safe_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
++
++/*! Data Interface Descriptor
++ */
++static struct usbd_interface_descriptor safe_alternate_descriptor = {
++ bLength: 0x09,
++ bDescriptorType: USB_DT_INTERFACE,
++ bInterfaceNumber: 0x00,
++ bAlternateSetting: 0x00,
++ bNumEndpoints: sizeof(safe_alt_endpoints)/sizeof(struct usbd_endpoint_descriptor *),
++ bInterfaceClass: COMMUNICATIONS_INTERFACE_CLASS,
++ bInterfaceSubClass: COMMUNICATIONS_MDLM_SUBCLASS,
++ bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
++ iInterface: 0x00,
++};
++
++/*! Data Alternate Interface Description List
++ */
++static struct usbd_alternate_description safe_alternate_descriptions[] = {
++ {
++ iInterface: CONFIG_OTG_NETWORK_SAFE_INTF,
++ interface_descriptor: &safe_alternate_descriptor,
++ classes: sizeof (safe_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
++ class_list: safe_comm_class_descriptors,
++ endpoints:sizeof (safe_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: safe_alt_endpoints,
++ endpoint_indexes: safe_alt_indexes,
++ },
++};
++
++/* Interface descriptions and descriptors
++ */
++/*! Interface Description List
++ */
++static struct usbd_interface_description safe_interfaces[] = {
++ {
++ alternates:sizeof (safe_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:safe_alternate_descriptions, },
++};
++
++
++/* Configuration descriptions and descriptors
++ */
++
++/*! Configuration Descriptor
++ */
++static struct usbd_configuration_descriptor safe_configuration_descriptor = {
++ bLength: 0x09,
++ bDescriptorType: USB_DT_CONFIGURATION,
++ wTotalLength: __constant_cpu_to_le16(0x0000), //0x00, 0x00, // wLength
++ bNumInterfaces:sizeof (safe_interfaces) / sizeof (struct usbd_interface_description),
++ bConfigurationValue:0x01,
++ iConfiguration: 0x00, // bConfigurationValue, iConfiguration
++ bmAttributes: 0,
++ bMaxPower:0,
++};
++
++/*! Configuration Description List
++ */
++struct usbd_configuration_description safe_description[] = {
++ {
++ iConfiguration: CONFIG_OTG_NETWORK_SAFE_DESC,
++ configuration_descriptor: &safe_configuration_descriptor,
++ },
++};
++
++/* Device Description
++ */
++/*! Device Descriptor
++ */
++static struct usbd_device_descriptor safe_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++/*! High Speed Device Qualifier Descriptor
++ */
++static struct usbd_device_qualifier_descriptor safe_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
++ bDeviceSubClass: 0x02,
++ bDeviceProtocol: 0x00,
++ bMaxPacketSize0: 0x00,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++/*! Endpoint Request List
++ */
++static struct usbd_endpoint_request safe_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
++ { 0, },
++};
++
++/*! OTG Descriptor
++ */
++static struct usbd_otg_descriptor safe_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++/*! Device Description
++ */
++struct usbd_device_description safe_device_description = {
++ device_descriptor: &safe_device_descriptor,
++#ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &safe_device_qualifier_descriptor,
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &safe_otg_descriptor,
++ iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
++ iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
++#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
++ iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
++#endif
++};
++
++/*! safe_init
++ * @param function The function instance
++ */
++void safe_init (struct usbd_function_instance *function)
++{
++ struct usbd_class_ethernet_networking_descriptor *ethernet;
++ int len = 0;
++ char buf[255];
++
++ buf[0] = 0;
++
++ safe_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
++
++ // Update the iMACAddress field in the ethernet descriptor
++ {
++ char address_str[14];
++ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
++ remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2],
++ remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
++ if ((ethernet = &safe_class_4)) {
++ if (ethernet->iMACAddress) {
++ usbd_free_string_descriptor(ethernet->iMACAddress);
++ }
++ ethernet->iMACAddress = usbd_alloc_string(address_str);
++ }
++ }
++
++#ifdef CONFIG_OTG_NETWORK_SAFE_PADBEFORE
++ safe_class_3.bmNetworkCapabilities |= BMDATA_PADBEFORE;
++ len += sprintf(buf + len, "PADBEFORE: %02x ", safe_class_3.bmNetworkCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_SAFE_CRC
++ safe_class_3.bmNetworkCapabilities |= BMDATA_CRC;
++ len += sprintf(buf + len, "CRC: %02x ", safe_class_3.bmNetworkCapabilities);
++#endif
++#ifdef CONFIG_OTG_NETWORK_SAFE_NONBRIDGED
++ safe_class_3.bmNetworkCapabilities |= BMNETWORK_NONBRIDGED;
++ len += sprintf(buf + len, "NONBRIDGE: %02x ",safe_class_3.bmDataCapabilities);
++#endif
++ if (strlen(buf))
++ TRACE_MSG1(NTT,"%s", buf);
++
++}
++
++/*! function driver description
++ */
++struct usbd_function_driver safe_function_driver = {
++ name: "network-SAFE",
++ fops: &net_fd_function_ops,
++ device_description: &safe_device_description,
++ bNumConfigurations: sizeof (safe_description) / sizeof (struct usbd_configuration_description),
++ configuration_description: safe_description,
++ idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
++ idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
++ bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
++ bNumInterfaces:sizeof (safe_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:safe_interfaces,
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: safe_endpoint_requests,
++};
++#endif /* CONFIG_OTG_NETWORK_SAFE */
++
+diff -uNr linux/drivers/no-otg/ocd/Config.in linux/drivers/otg/ocd/Config.in
+--- linux/drivers/no-otg/ocd/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/Config.in 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,15 @@
++
++#
++# Copyright (c) 2004 Belcarra
++#
++#
++
++ mainmenu_option next_comment
++ comment 'OTG Host Controller Driver (HCD)'
++ dep_tristate ' USB Host Controller Driver' CONFIG_OTG_HCD $CONFIG_OTG_HOSTCORE
++ hex 'VendorID (hex value)' CONFIG_OTG_ROOTHUB_VENDORID "15ec"
++ hex 'ProductID (hex value)' CONFIG_OTG_ROOTHUB_PRODUCTID "f010"
++ hex 'ProductID (hex value)' CONFIG_OTG_ROOTHUB_BCDDEVICE "0100"
++
++
++ endmenu
+diff -uNr linux/drivers/no-otg/ocd/Makefile linux/drivers/otg/ocd/Makefile
+--- linux/drivers/no-otg/ocd/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/Makefile 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,44 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++TOPDIR ?= ../../../..
++
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++# The target object and module list name.
++
++O_TARGET := ocd_target.o
++
++subdir-$(CONFIG_OTG_AU1550) += au1x00
++subdir-$(CONFIG_OTG_AU1X00) += au1x00
++subdir-$(CONFIG_OTG_ISP1301_OMAP_H2) += isp1301
++subdir-$(CONFIG_OTG_ISP1301_MAINSTONE) += isp1301
++
++subdir-$(CONFIG_OTG_MAX3353E_DB1550) += max3353e
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Bus Interface Drivers
++ocd-obj-$(CONFIG_OTG_AU1550) += au1x00/au1x00_pcd_drv.o
++ocd-obj-$(CONFIG_OTG_AU1X00) += au1x00/au1x00_pcd_drv.o
++
++# Platform
++ocd-obj-$(CONFIG_OTG_ISP1301_OMAP_H2) += isp1301/isp1301_target.o
++ocd-obj-$(CONFIG_OTG_ISP1301_MAINSTONE) += isp1301/isp1301_target.o
++
++ocd-obj-$(CONFIG_OTG_MAX3353E_DB1550) += max3353e/max3353e_target.o
++
++obj-y += $(ocd-obj-y)
++
++include $(TOPDIR)/Rules.make
++EXTRA_CFLAGS += -Wno-format -Wall
+diff -uNr linux/drivers/no-otg/ocd/Makefile-l26 linux/drivers/otg/ocd/Makefile-l26
+--- linux/drivers/no-otg/ocd/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/Makefile-l26 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,29 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++EXTRA_CFLAGS += -Wno-format -Wall
++
++# Bus Interface Drivers
++#subdir-$(CONFIG_OTG_AU1X00) += au1x00
++#subdir-$(CONFIG_OTG_LH7A400) += lh7a400
++#subdir-$(CONFIG_OTG_MX1) += mx1
++#subdir-$(CONFIG_OTG_MX2) += mx2
++#subdir-$(CONFIG_OTG_NC2280) += nc2280
++#subdir-$(CONFIG_OTG_PXA) += pxa
++#subdir-$(CONFIG_OTG_SA1100) += sa1100
++#subdir-$(CONFIG_OTG_SMDK2500) += smdk2500
++#subdir-$(CONFIG_OTG_SUPERH) += superh
++#subdir-$(CONFIG_OTG_SX2) += sx2
++#subdir-$(CONFIG_OTG_WMMX) += wmmx
++
++obj-m += scma11-evb/
++obj-m += omap/
++obj-m += isp1301/
++
++obj-y += scma11-evb/
++obj-y += omap/
++obj-y += isp1301/
++
++
+diff -uNr linux/drivers/no-otg/ocd/README linux/drivers/otg/ocd/README
+--- linux/drivers/no-otg/ocd/README 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/README 2006-09-01 21:41:30.000000000 +0200
+@@ -0,0 +1,54 @@
++otg/pcd
++
++
++Linux Build support:
++
++ Makefile
++ Makefile-l24
++ Makefile-l26
++
++ README
++
++PCD support files:
++
++ otg-pcd/pcd.c
++ otg-pcd/pcd-init-l24.c
++ otg-pcd/pcd-ocd-init-l24.c
++ otg-pcd/tr-init-l24.c
++
++TCD support files:
++
++ otg-tcd/tcd.c
++ otg-tcd/tcd-init-l24.c
++
++HCD support files;
++
++ otg-hcd/hcd-init-l24.c
++ otg-hcd/hcd-l26.c
++ otg-hcd/hcd-rh.c
++ otg-hcd/hcd.c
++
++Architecture Specific Drivers:
++
++ lh7a400
++ mx1
++ nc2280
++ pxa
++ sa1100
++ smdk2500
++ superh
++ sx2
++
++Device Specific Drivers:
++
++ atlas
++ isp1301
++ max3353e
++
++Platform Specific Drivers
++
++ au1x00
++ bvd
++ mx2
++ omap
++
+diff -uNr linux/drivers/no-otg/ocd/au1x00/Makefile linux/drivers/otg/ocd/au1x00/Makefile
+--- linux/drivers/no-otg/ocd/au1x00/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/au1x00/Makefile 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,111 @@
++#
++# Makefile for the kernel USBD (device not host) drivers.
++#
++# Copyright (c) 2002 Belcarra
++
++# Subdirs.
++# This is a bit complex, because some subdirs are for
++# proprietary code, and are simply not present in a
++# general distribution.
++
++# The all-CAPS *_DIRS get nuked in the new versions
++# of Rules.make, so use only the subdir-* methods.
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++# The target object and module list name.
++
++O_TARGET := au1x00_pcd_drv.o
++
++# Objects that export symbols.
++
++export-objs :=
++
++# Multipart objects.
++
++#au1x00_otg-objs := au1x00.o usbd-bi.o trace.o
++db1550_tr-objs := tr-init-l24.o au1550.o pcd.o
++db1550_dr-objs := tr-init-l24.o au1550.o pcd.o
++#au1550_tr-objs := tr-init-l24.o au1550.o pcd.o
++au1x00_tr-objs := tr-init-l24.o au1x00.o pcd.o
++
++# Optional parts of multipart objects.
++
++# Object file lists.
++
++#obj-y := usbd-bi.o
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_AU1550_DB1500_TR) += db1550_tr.o
++obj-$(CONFIG_OTG_AU1550_DB1550_TR) += db1550_tr.o
++obj-$(CONFIG_OTG_AU1550_DB1500_DR) += db1550_dr.o
++
++#obj-$(CONFIG_OTG_AU1550) += au1550_tr.o
++obj-$(CONFIG_OTG_AU1X00) += au1x00_tr.o
++
++# Object files in subdirectories
++
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++include $(TOPDIR)/Rules.make
++
++OTG=$(TOPDIR)/drivers/otg
++OCD_DIR=$(OTG)/ocd
++INCLUDE_DIRS = -I$(OTG)
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++
++I2C=$(OTG)/ocd/otg-i2c
++PCD=$(OTG)/ocd/otg-pcd
++vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD) $(I2C)
++
++
++# Link rules for multi-part drivers.
++
++db1550_tr.o: $(db1550_tr-objs)
++ $(LD) -r -o $@ $(db1550_tr-objs)
++
++db1550_dr.o: $(db1550_tr-objs)
++ $(LD) -r -o $@ $(au1550_tr-objs)
++
++#au1550_tr.o: $(au1550_tr-objs)
++# $(LD) -r -o $@ $(au1550_tr-objs)
++
++au1x00_tr.o: $(au1x00_tr-objs)
++ $(LD) -r -o $@ $(au1x00_tr-objs)
++
++# dependencies:
++
++# local
++
++
+diff -uNr linux/drivers/no-otg/ocd/au1x00/NOTES.txt linux/drivers/otg/ocd/au1x00/NOTES.txt
+--- linux/drivers/no-otg/ocd/au1x00/NOTES.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/au1x00/NOTES.txt 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,62 @@
++
++Notes
++
++1. EP0 - packetsize of 8 does not work, this means that PIO cannot be used for IN (transmit).
++DMA must be used. Only 16, 32 and 64 are usable.
++
++Update: even though we couldn't program the endpoint size to 8, we just set it to 8 in the
++device descriptor and things work ok. This works and we don't need or use DMA for either
++direction for EP0.
++
++2. For each BULK transfer the first N packets must be sent with the full packetsize and the
++last must be sent as a short packet. The packetsize must be set before enabling the DMA.
++
++3. For IN endpoints an interrupt will be generated for EVERY IN packet including ones that
++will be NAK'd. To reduce overhead the interrupt should only be enabled when there is data
++being sent and we need to know when it has been sent.
++
++Update: for new silicon this is not true, the UDC will interrupt less often and will NAK
++until the interrupt is cleared.
++
++4. The AU1x00 auto-acks many setup commands and is very sensitive to latency of the irq
++handler processing the interrupt and clearing the ep0 fifo. Like the pxa we need to spool the
++requests and process later when we receive a request for data. There is a special test in
++the bulk data receive handler to check if there are spooled requests to process.
++
++Update: this has been mostly mitigated by reducing all upper layer processing in recv_setup,
++event_irq etc so that they complete in less than a milli-second. This simplifies things and
++we can now pass UUT tests.
++
++5. There is a time sensitive problem in au_in_epn(). Without a udelay(8) sending large
++packets will eventually stall interrupts.
++
++Update: this is not required for new silicon.
++
++6. When receiving data (Bulk OUT) the UDC will not start NAKing until and unless the receive
++FIFO is full. This means that there is no reliable way to determine the end of one packet and
++the beginning of the next if there is any undue latency in handling the interrupt for the
++first packet.
++
++The Belcarra Windows and Macintosh network class drivers have an option that can be used
++to pad all outgoing packets to a multiple of 8 bytes. This helps eliminate this problem.
++
++Update: this is not a problem with new silicon, it NAK's until the interrupt is cleared.
++
++8. The original AU1x00 UDC generated an interrupt for EVERY IN packet. If we do not have
++any data we need to disable the interrupt for the endpoint to eliminate the overhead
++for processing them. The interrupt must be re-enabled when DMA is finished and we
++actually want to know that the endpoint has finished.
++
++Leaving the interrupt enabled also interfers with the DMA process. It is not apparant
++why.
++
++Update: This has been fixed on the new silicon but it doesn't hurt to continue to do this.
++
++9. The DMA functions replace the equivalent routines in au1100_dma.h except that they pass
++the actual struct dma_chan pointer instead of the channel number. The bounds checking and
++table lookup to derive this information amounts to a substantial increase in code size and
++latency which can simply be avoided by using the structure address directly and/or doing the
++equivalent i/o directly.
++
++10. The Au1x00 does not support REMOTE WAKEUP
++
+diff -uNr linux/drivers/no-otg/ocd/au1x00/au1550.c linux/drivers/otg/ocd/au1x00/au1550.c
+--- linux/drivers/no-otg/ocd/au1x00/au1550.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/au1x00/au1550.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,1451 @@
++/*
++ * otg/ocd/au1x00/au1x00.c -- USB Device Controller driver.
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++/*!
++ * @file otg/ocd/au1x00/au1550.c
++ * @brief AU1X00 Header
++ *
++ * This file contains the private defines and structures for the AU1X00
++ * Drivers.
++ *
++ * @ingroup AU1X00
++ */
++
++
++#include <otg/pcd-include.h>
++#include "au1x00.h"
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/au1000_dma.h>
++
++#if defined(CONFIG_SOC_AU1550)
++#include <asm/au1xxx_dbdma.h>
++#else
++#error "Wrong AU1X00_MDA"
++#endif
++
++#include <asm/mipsregs.h>
++
++#ifdef CONFIG_MIPS_FREEHAND
++#include <linux/i2c.h>
++#include <linux/sensors.h> /* for reading serial number */
++#endif
++
++
++#undef CHECK_LATENCY
++#undef RECORD_LATENCY
++#undef MAX_INTR_LOOP_STATS //10
++#if defined(MAX_INTR_LOOP_STATS)
++static u32 interrupt_loop_stats[MAX_INTR_LOOP_STATS+1];
++#endif
++#ifdef RECORD_LATENCY
++#define CP0_COUNTS 50
++u32 cp0_counts[CP0_COUNTS];
++u32 cp0_record;
++#endif
++u32 cp0_count;
++unsigned int udc_saw_bus_activity;
++int au_halt_dma_expired;
++u32 au1x00_inten;
++
++u8 au1x00_config_bulk[25] = {
++ 0x04, (USB_ENDPOINT_CONTROL << 4) | (EP0_PACKETSIZE & 0x380) >> 7, // 1
++ (EP0_PACKETSIZE & 0x7F) << 1, 0x00, 0x00,
++ 0x24, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 6
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x02,
++ 0x34, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 11
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x03,
++ 0x44, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 16
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x04,
++ 0x54, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 21
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x05,
++};
++
++/* ********************************************************************************************* */
++/* Note - The endpoints names are confusing. To simplify mapping of the interrupt request lines
++ * we use a numbering of the physical endpoints of 0-5, which also matches the fifo numbering
++ * (see the config block).
++ *
++ * Physical FIFO Name Direction Logical
++ * 0 0 EP0 OUT 0
++ * 1 1 EP0 IN 0
++ * 2 2 EP1 IN 81
++ * 3 3 EP2 IN 82
++ * 4 4 EP3 OUT 3
++ * 5 5 EP4 OUT 4
++ *
++ * The ep_regs array maps a physical endpoint number to the registers required to access the udc
++ * for that endpoint. Note that ep0 is always accessed via 0. The epl2p array maps the logical
++ * addresses back to the physical number. The epp2l array maps the physical number to the
++ * logical endpoint address
++ */
++struct ep_regs ep_regs[6] = {
++
++ { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
++ wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX0, tx_str: "EP0 IN WR",},
++
++ { rds: 0, wrs: 0, indma: -1, outdma: -1, }, // ep0
++ { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX1, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
++ { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX2, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
++
++ { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX3, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
++ { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX4, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
++};
++u8 epl2p[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, }; // map logical to physical
++u8 epp2l[6] = { 0x00, 0x00, 0x81, 0x82, 0x03, 0x04, }; // map physical to logical
++
++static __inline__ void au_fifo_read(struct ep_regs *ep, unsigned char * cp, int bytes)
++{
++ u32 rd = ep->rd;
++ for (; bytes--; *cp++ = au_readl(rd));
++}
++
++static __inline__ void au_fifo_write(int ep, unsigned char * cp, int bytes)
++{
++ u32 wr = ep_regs[ep].wr;
++ for (; bytes--; au_writel(*cp++, wr));
++ ep_regs[ep].last = bytes;
++}
++
++void __inline__ au_inten(u32 inten, char *msg)
++{
++ TRACE_MSG2(PCD, "%s %08x", msg, inten);
++ au1x00_inten = inten;
++ au_writel(au1x00_inten, USBD_INTEN);
++}
++
++void __inline__ au_epn_interrupt_enable(int epn)
++{
++ au_inten(au1x00_inten | (1 << epn), "epn enable");
++}
++
++void __inline__ au_epn_interrupt_disable(int epn)
++{
++ au_inten(au1x00_inten & ~(1 << epn), "epn disable");
++ au_writel((1 << epn) , USBD_INTSTAT);
++}
++
++static void __inline__ send_zlp(unsigned char epn)
++{
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep_regs[epn].wrs);
++ au_writel(0 << 1, ep_regs[epn].cs);
++ au_writel(0, ep_regs[epn].wr);
++}
++/* ********************************************************************************************* */
++#define AU_DMA_HALT_POLL 0x1000
++
++#define DDMA_DESCCMD_ARB (1<<15)
++#define DDMA_DESCCMD_DW (16)
++#define DDMA_DESCCMD_DW_N(n) ((n&3)<<DDMA_DESCCMD_DW)
++ #define DDMA_DESCCMD_DW_BYTE DDMA_DESCCMD_DW_N(0)
++ #define DDMA_DESCCMD_DW_HWORD DDMA_DESCCMD_DW_N(1)
++ #define DDMA_DESCCMD_DW_WORD DDMA_DESCCMD_DW_N(2)
++#define DDMA_DESCCMD_SW (18)
++#define DDMA_DESCCMD_SW_N(n) ((n&3)<<DDMA_DESCCMD_SW)
++ #define DDMA_DESCCMD_SW_BYTE DDMA_DESCCMD_SW_N(0)
++ #define DDMA_DESCCMD_SW_HWORD DDMA_DESCCMD_SW_N(1)
++ #define DDMA_DESCCMD_SW_WORD DDMA_DESCCMD_SW_N(2)
++
++#define DDMA_DESCCMD_DID (20)
++#define DDMA_DESCCMD_DID_N(n) ((n&0x1F)<<DDMA_DESCCMD_DID)
++#define DDMA_DESCCMD_SID (25)
++#define DDMA_DESCCMD_SID_N(n) ((n&0x1F)<<DDMA_DESCCMD_SID)
++
++/*
++ * Bit definitions for source stride/block 1 dimensional
++ */
++#define DDMA_DESCSRC_STRIDE_SS (0)
++#define DDMA_DESCSRC_STRIDE_SS_N(n) ((n&0x3fff)<<DDMA_DESCSRC_STRIDE_SS)
++#define DDMA_DESCSRC_STRIDE_SB (14)
++#define DDMA_DESCSRC_STRIDE_SB_N(n) ((n&0x3Fff)<<DDMA_DESCSRC_STRIDE_SB)
++#define DDMA_DESCSRC_STRIDE_SAM (28)
++#define DDMA_DESCSRC_STRIDE_SAM_N(n) ((n&3)<<DDMA_DESCSRC_STRIDE_SAM)
++ #define DDMA_DESCSRC_STRIDE_SAM_INC DDMA_DESCSRC_STRIDE_SAM_N(0)
++ #define DDMA_DESCSRC_STRIDE_SAM_DEC DDMA_DESCSRC_STRIDE_SAM_N(1)
++ #define DDMA_DESCSRC_STRIDE_SAM_STATIC DDMA_DESCSRC_STRIDE_SAM_N(2)
++ #define DDMA_DESCSRC_STRIDE_SAM_BURST DDMA_DESCSRC_STRIDE_SAM_N(3)
++#define DDMA_DESCSRC_STRIDE_STS (30)
++#define DDMA_DESCSRC_STRIDE_STS_N(n) ((n&3)<<DDMA_DESCSRC_STRIDE_STS)
++ #define DDMA_DESCSRC_STRIDE_STS_1 DDMA_DESCSRC_STRIDE_STS_N(0)
++ #define DDMA_DESCSRC_STRIDE_STS_2 DDMA_DESCSRC_STRIDE_STS_N(1)
++ #define DDMA_DESCSRC_STRIDE_STS_4 DDMA_DESCSRC_STRIDE_STS_N(2)
++ #define DDMA_DESCSRC_STRIDE_STS_8 DDMA_DESCSRC_STRIDE_STS_N(3)
++
++
++/*
++ * Bit definitions for dest stride/block 1 dimensional
++ */
++#define DDMA_DESCDST_STRIDE_DS (0)
++#define DDMA_DESCDST_STRIDE_DS_N(n) ((n&0x3fff)<<DDMA_DESCDST_STRIDE_DS)
++#define DDMA_DESCDST_STRIDE_DB (14)
++#define DDMA_DESCDST_STRIDE_DB_N(n) ((n&0x3Fff)<<DDMA_DESCDST_STRIDE_DB)
++#define DDMA_DESCDST_STRIDE_DAM (28)
++#define DDMA_DESCDST_STRIDE_DAM_N(n) ((n&3)<<DDMA_DESCDST_STRIDE_DAM)
++ #define DDMA_DESCDST_STRIDE_DAM_INC DDMA_DESCDST_STRIDE_DAM_N(0)
++ #define DDMA_DESCDST_STRIDE_DAM_DEC DDMA_DESCDST_STRIDE_DAM_N(1) #define DDMA_DESCDST_STRIDE_DAM_STATIC DDMA_DESCDST_STRIDE_DAM_N(2)
++ #define DDMA_DESCDST_STRIDE_DAM_BURST DDMA_DESCDST_STRIDE_DAM_N(3)
++#define DDMA_DESCDST_STRIDE_DTS (30)
++#define DDMA_DESCDST_STRIDE_DTS_N(n) ((n&3)<<DDMA_DESCDST_STRIDE_DTS)
++ #define DDMA_DESCDST_STRIDE_DTS_1 DDMA_DESCDST_STRIDE_DTS_N(0)
++ #define DDMA_DESCDST_STRIDE_DTS_2 DDMA_DESCDST_STRIDE_DTS_N(1)
++ #define DDMA_DESCDST_STRIDE_DTS_4 DDMA_DESCDST_STRIDE_DTS_N(2)
++ #define DDMA_DESCDST_STRIDE_DTS_8 DDMA_DESCDST_STRIDE_DTS_N(3)
++
++#ifndef CONFIG_MIPS_MTX2
++typedef struct dbdma_device_table {
++ u32 dev_flags;
++ u32 dev_tsize;
++ u32 dev_devwidth;
++ u32 dev_physaddr; /* If FIFO */
++ u32 dev_intlevel;
++ u32 dev_intpolarity;
++} dbdev_tab_t;
++
++typedef struct dbdma_chan_config {
++ u32 chan_flags;
++ u32 chan_index;
++ dbdev_tab_t *chan_src;
++ dbdev_tab_t *chan_dest;
++ au1x_dma_chan_t *chan_ptr;
++ au1x_ddma_desc_t *chan_desc_base;
++ au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr;
++ void *chan_callparam;
++ void (*chan_callback)(int, void *, struct pt_regs *);
++} chan_tab_t;
++#endif
++static void __inline__ au_halt_dma(u32 chan)
++{
++ chan_tab_t *ctp = *((chan_tab_t **)chan);
++ volatile au1x_dma_chan_t *cp = ctp->chan_ptr;;
++ au1x_ddma_desc_t *dp;
++
++ au1xxx_dbdma_stop(chan);
++ au_halt_dma_expired++;
++
++ dp = ctp->cur_ptr; // ensure that descriptor is stopped
++ dp->dscr_cmd0 &= ~DSCR_CMD0_V;
++
++}
++
++static void __inline__ au_start_dma_in(int indma, u32 tx_id, __u8 *bp, int len)
++{
++ chan_tab_t *ctp = *((chan_tab_t **)indma);
++ au1x_ddma_desc_t *dp = ctp->cur_ptr;
++ volatile au1x_dma_chan_t *cp = ctp->chan_ptr;;
++
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x MEM2USB",
++ indma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++
++ dp->dscr_source0 = virt_to_phys(bp);
++ dp->dscr_source1 = DDMA_DESCSRC_STRIDE_STS_4 | DDMA_DESCSRC_STRIDE_SAM_INC;
++
++ dp->dscr_cmd1 = len;
++ dp->dscr_cmd0 =
++ DSCR_CMD0_SID(DSCR_CMD0_ALWAYS) |
++ DSCR_CMD0_DID(indma)
++ ;
++ TRACE_MSG1(PCD, "cmd0: %08x SID/DID", dp->dscr_cmd0);
++
++ dp->dscr_cmd0 |=
++ DDMA_DESCCMD_SW_BYTE |
++ DDMA_DESCCMD_DW_BYTE
++ ;
++ TRACE_MSG1(PCD, "cmd0: %08x SW/DW", dp->dscr_cmd0);
++
++ dp->dscr_cmd0 = DSCR_CMD0_V |
++ DSCR_CMD0_SID(DSCR_CMD0_ALWAYS) |
++ DSCR_CMD0_DID(tx_id) |
++ DDMA_DESCCMD_SW_BYTE |
++ DDMA_DESCCMD_DW_BYTE |
++ DSCR_CMD0_ARB |
++ DSCR_CMD0_DN |
++ DSCR_CMD0_CV
++ ;
++
++ dp->dscr_dest1 = DDMA_DESCDST_STRIDE_DTS_4 | DDMA_DESCSRC_STRIDE_SAM_STATIC;
++
++ ctp->cur_ptr = dp;
++ cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
++ cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */
++ au_sync();
++ cp->ddma_dbell = 0xffffffff; /* Make it go */
++ au_sync();
++
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x MEM2USB start",
++ indma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++}
++
++static void __inline__ au_start_dma_out(unsigned int outdma, u32 rx_id, __u8 *bp, int wMaxPacketSize)
++{
++ chan_tab_t *ctp = *((chan_tab_t **)outdma);
++ au1x_ddma_desc_t *dp = ctp->cur_ptr;
++ volatile au1x_dma_chan_t *cp = ctp->chan_ptr;;
++
++
++ dma_cache_inv((unsigned long) bp, wMaxPacketSize);
++
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM",
++ outdma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++
++ // if (!au1xxx_dbdma_put_dest(outdma, bp, wMaxPacketSize))
++
++ dp->dscr_dest0 = virt_to_phys(bp);
++ dp->dscr_dest1 = DDMA_DESCDST_STRIDE_DTS_4 | DDMA_DESCDST_STRIDE_DAM_INC;
++
++ dp->dscr_cmd1 = wMaxPacketSize;
++ dp->dscr_cmd0 = DSCR_CMD0_V |
++ DSCR_CMD0_SID(rx_id) |
++ DSCR_CMD0_DID(DSCR_CMD0_ALWAYS) |
++ DDMA_DESCCMD_SW_BYTE |
++ DDMA_DESCCMD_DW_BYTE |
++ DSCR_CMD0_ARB |
++ DSCR_CMD0_SN |
++ DSCR_CMD0_CV
++ ;
++
++ dp->dscr_source1 = DDMA_DESCSRC_STRIDE_STS_4 | DDMA_DESCSRC_STRIDE_SAM_STATIC;
++
++ ctp->cur_ptr = dp;
++ cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
++ cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */
++ au_sync();
++ cp->ddma_dbell = 0xffffffff; /* Make it go */
++ au_sync();
++
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM start",
++ outdma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++}
++
++/* ********************************************************************************************* */
++static struct usbd_urb *au_rcv_complete_ep0_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
++{
++ struct usbd_urb *rcv_urb = endpoint->rcv_urb;
++ if (rcv_urb && !urb_bad) {
++ int i;
++ u8 *cp = rcv_urb->buffer + rcv_urb->actual_length;
++ for (i = 0 ; i < len; i+= 8)
++ TRACE_MSG8(PCD, "ARCV %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++
++ }
++ return pcd_rcv_complete_irq(endpoint, len, urb_bad);
++}
++
++/* au_start_in_ep0 - start transmit
++ */
++static void au_start_in_ep0 (struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ int last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN EP0 SENT: %d SENDING: %d", endpoint->sent, last);
++ RETURN_IF ((urb->actual_length - endpoint->sent) <= 0);
++ au_writel(last << 1, ep->cs); // XXX
++ au_fifo_write(0, urb->buffer + endpoint->sent, last);
++ endpoint->last = last;
++}
++
++/* au_in_ep0 - called to service an endpoint zero IN interrupt, data sent
++ */
++static void au_in_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ u32 cs;
++ struct usbd_urb *tx_urb;
++ int last;
++ TRACE_MSG1(PCD, "EP0 IN: tx_urb: %p", (int)endpoint->tx_urb);
++ if ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) { // clear stall if present
++ TRACE_MSG1(PCD, "CLEAR STALL %d", 0);
++ cs &= ~USBDEV_CS_STALL;
++ au_writel(cs, ep->cs);
++ return;
++ }
++ if (!(tx_urb = pcd_tx_complete_irq(endpoint, 0))) { // wait for setup if no more data
++ endpoint->state = WAIT_FOR_SETUP;
++ return;
++ }
++ TRACE_MSG4(PCD, "EP0 IN actual: %d last: %d sent: %d flags: %x", endpoint->tx_urb->actual_length,
++ endpoint->last, endpoint->sent, endpoint->tx_urb->flags);
++ if (pcd_tx_sendzlp(endpoint)) { // check if tx_urb we have is finished
++ TRACE_MSG0(PCD, "EP0 IN BULK - sending ZLP");
++ tx_urb->flags &= ~USBD_URB_SENDZLP;
++ send_zlp(0);
++ pcd_tx_complete_irq(endpoint, 0);
++ return;
++ }
++ if (tx_urb->actual_length > endpoint->sent) {
++ if ((tx_urb->actual_length - endpoint->sent) < endpoint->wMaxPacketSize)
++ TRACE_MSG1(PCD, "EP0 IN starting short packet %d", tx_urb->actual_length - endpoint->sent);
++ else
++ TRACE_MSG1(PCD, "EP0 IN LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ au_start_in_ep0(endpoint, ep);
++ }
++}
++
++/* au_out_ep0 - called to service an endpoint zero OUT interrupt, data received
++ */
++static void au_out_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_device_request request;
++ int i;
++ u32 cs;
++ u32 bytes;
++ TRACE_MSG0(PCD, "EP0 OUT");
++ cs = au_readl(ep->cs); // check if host aborted transfer and flush the write fifo
++ bytes = au_readl(ep->rds) & USBDEV_FSTAT_FCNT_MASK;
++ if (endpoint->state == DATA_STATE_RECV) {
++ struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
++ TRACE_MSG1(PCD, "EP0 OUT: RECV: rcv_urb: %x", (int) rcv_urb);
++ if (rcv_urb) {
++ au_fifo_read(ep, rcv_urb->buffer + rcv_urb->actual_length, bytes);
++ if (au_rcv_complete_ep0_irq(endpoint, bytes, 0))
++ return;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ endpoint->state = WAIT_FOR_SETUP;
++ send_zlp(0);
++ return;
++ }
++ endpoint->state = WAIT_FOR_SETUP;
++ }
++ pcd_tx_cancelled_irq(endpoint);
++ pcd_rcv_cancelled_irq(endpoint);
++ au_fifo_read(ep, (u8 *)&request, bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
++ if (bytes != 8) {
++ TRACE_MSG1(PCD, "ERROR SETUP SET not eight bytes: %d", bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
++ return;
++ }
++ TRACE_MSG4(PCD, "SETUP bmRequestType: %02x bRequest %02x state: %d status: %d", request.bmRequestType,
++ request.bRequest, pcd_instance->bus->device_state, pcd_instance->bus->status);
++ switch (request.bRequest) { // we need to simply ignore any of these
++ case USB_REQ_SET_ADDRESS: // Fake a bus reset IFF not state default and then process normally
++ BREAK_IF (pcd_instance->bus->device_state == STATE_DEFAULT);
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
++ //usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
++ break;
++ case USB_REQ_GET_DESCRIPTOR: // Fake a bus reset IFF suspended and then process normally
++ BREAK_IF (STATE_SUSPENDED != pcd_instance->bus->device_state);
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
++ //usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
++ break;
++ }
++ if (pcd_recv_setup_irq(pcd_instance, &request)) {
++ TRACE_MSG1(PCD, "ep0 STALL %d", cs);
++ au_writel(USBDEV_CS_STALL, USBD_EP0CS);
++ return;
++ }
++ if (((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu (request.wLength)) {
++ TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
++ endpoint->state = DATA_STATE_RECV;
++ return;
++ }
++ if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
++ TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
++ if ((request.bmRequestType & ~USB_REQ_DIRECTION_MASK)) {
++ TRACE_MSG1(PCD, "ep0 Class or Vendor, send ZLP %d", cs);
++ send_zlp(0);
++ return;
++ }
++ }
++ TRACE_MSG1(PCD, "ep0 Class D2H request %04x", le16_to_cpu(request.wLength));
++}
++/* ********************************************************************************************* */
++/* au_start_in_bulk - start transmit
++ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by
++ * DMA or PIO. The packetsize must be set first.
++ */
++static void au_start_in_bulk (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ u8 *bp = urb->buffer + endpoint->sent;
++ int last;
++ int i;
++ u32 *lp;
++ TRACE_MSG1(PCD, "START IN BULK %d", epn);
++ RETURN_IF (!urb || (( (urb->actual_length - endpoint->sent) == 0) && !(urb->flags & USBD_URB_SENDZLP)));
++ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN BULK sent: %d last:%d", endpoint->sent, last);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
++ if (!last) {
++ if (endpoint->tx_urb->flags & USBD_URB_SENDZLP) {
++ TRACE_MSG0(PCD, "START IN BULK - zending ZLP");
++ send_zlp(epn);
++ endpoint->tx_urb->flags &= ~USBD_URB_SENDZLP;
++ }
++ return;
++ }
++ else if (8 >= last) {
++ au_writel(last << 1, ep->cs);
++ au_fifo_write(epn, bp, last);
++ return;
++ }
++
++ dma_cache_wback_inv((unsigned long) bp, last);
++ //au_writel(last << 1, ep->cs);
++ au_start_dma_in(ep->indma, ep->tx_id, bp, last);
++ au_writel(last << 1, ep->cs);
++}
++
++static void au_in_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb;
++ int rc = 0;
++ u32 cs = au_readl(ep->cs);
++ u32 wrs = au_readl(ep->wrs);
++ u32 residue = au1xxx_get_dma_residue(ep->indma);
++ TRACE_MSG3(PCD, "BULK IN EPN - cs: %x wrs: %x residue:%d", cs, wrs, residue);
++ if (wrs) { // check for underflow or overflow
++ rc = 1;
++ if (wrs & USBDEV_FSTAT_UF) {
++ TRACE_MSG2(PCD, "BULK IN EPN - UF epn %d wrs: %x", epn, wrs);
++ rc = 1; // set rc to indicate an error
++ }
++ if (wrs & USBDEV_FSTAT_OF)
++ TRACE_MSG2(PCD, "BULK IN EPN - OF epn %d wrs: %x", epn, wrs);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // flush the fifo
++ }
++ if (cs & USBDEV_CS_NAK) {
++ RETURN_IF (ep->last && ((wrs&0x1f) == ep->last));
++ rc = 1;
++ }
++ if (cs & USBDEV_CS_STALL) { // clear stall if present
++ TRACE_MSG1(PCD, "BULK IN EPN - CLEAR STALL %d", epn);
++ cs &= ~USBDEV_CS_STALL;
++ au_writel(cs, ep->cs);
++ return;
++ }
++ TRACE_MSG4(PCD, "BULK IN EPN epn: %d rc: %d last: %d sent: %d", epn, rc, endpoint->last, endpoint->sent);
++
++ if ((tx_urb = pcd_tx_complete_irq(endpoint, rc))) {
++ if ((tx_urb->actual_length > endpoint->sent) || (endpoint->tx_urb->flags & USBD_URB_SENDZLP)) {
++ au_start_in_bulk(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
++ TRACE_MSG1(PCD, "BULK IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ return;
++ }
++ }
++ au_epn_interrupt_disable(epn); // disable interrupts
++}
++
++/* au_start_in_iso - start transmit
++ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by DMA or
++ * PIO. The packetsize must be set first.
++ */
++static void au_start_in_iso (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ unsigned char *bp = urb->buffer + endpoint->sent;
++ int last;
++ TRACE_MSG2(PCD, "START IN ISO actual: %d sent: %d", urb->actual_length, endpoint->sent);
++ RETURN_IF ((urb->actual_length - endpoint->sent) == 0);
++ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN ISO last: %d packetSize: %d", last, endpoint->wMaxPacketSize);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
++ au_epn_interrupt_enable (epn);
++ dma_cache_wback_inv((unsigned long) bp, last);
++ au_writel(last << 1, ep->cs);
++ au_start_dma_in(ep->indma, ep->tx_id, bp, last);
++}
++
++static void au_in_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
++ u32 cs = au_readl(ep->cs);
++ u32 wrs = au_readl(ep->wrs);
++ TRACE_MSG2(PCD, "ISO IN EPN - cs: %x wrs: %x", cs, wrs);
++ TRACE_MSG4(PCD, "ISO IN EPN epn: %d last: %d sent: %d", epn, endpoint->last, endpoint->sent, 0);
++ ep->last = 0;
++ if ((tx_urb = endpoint->tx_urb) && (tx_urb->actual_length > endpoint->sent)) {
++ au_start_in_iso(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
++ /* XXX magic delay - without this large packets will eventually stall the transmit
++ * XXX and all traffic in both directions will stop.
++ */
++ TRACE_MSG1(PCD, "ISO IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ return;
++ }
++
++ TRACE_MSG0(PCD, "ISO IN EPN - nothing to send");
++ au_epn_interrupt_disable(epn); // disable interrupts
++}
++/* ********************************************************************************************* */
++
++static struct usbd_urb *au_rcv_complete_epn_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
++{
++ return pcd_rcv_complete_irq(endpoint, len, urb_bad);
++}
++
++
++static void au_start_out_bulk(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ TRACE_MSG2(PCD, "START OUT BULK %d actual: %d pcktSize: %d", epn, endpoint->wMaxPacketSize);
++ if (!endpoint->rcv_urb) {
++ TRACE_MSG0(PCD, "START OUT BULK DISABLE");
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++ if (endpoint->rcv_error) {
++ TRACE_MSG0(PCD, "START OUT BULK reseting rcv_error");
++ endpoint->rcv_error = 0;
++ }
++ au_start_dma_out(ep->outdma, ep->rx_id,
++ endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
++}
++
++static void au_out_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ int bytes = 0;
++ int residue = 0;
++ u32 *lp = NULL;
++
++ struct usbd_urb *urb;
++ struct usbd_urb *completed_urb = NULL;
++ u32 cs;
++ u32 rds;
++ u32 nrds;
++ int i;
++
++ cs = au_readl(ep->cs);
++ rds = au_readl(ep->rds);
++
++ // XXX it appears that this is zero if 64 bytes where received!!!
++
++ // get dest ring buffer
++ au1xxx_dbdma_get_dest(ep->outdma, (void **)&lp, &bytes);
++
++ au_halt_dma(ep->outdma);
++ residue = endpoint->wMaxPacketSize - au1xxx_get_dma_residue(ep->outdma);
++
++ TRACE_MSG5(PCD, "BULK OUT CS: %04x RD: %04x bytes: %d residue: %d DMA %s",
++ cs, rds, bytes, residue, lp ? "FINISHED" : "ACTIVE");
++
++ /* check for NAK
++ */
++ if (cs & USBDEV_CS_NAK) {
++ TRACE_MSG0(PCD, "NAK bytes: 0");
++ bytes = 0;
++ }
++
++ /* with dbdma residue will either be zero or non-zero and less than packetsize, if
++ * zero then a complete transfer of packetsize was performed.
++ */
++ else if (!residue && !rds) {
++ TRACE_MSG0(PCD, "BULK OUT CS: forcing bytes: 64");
++ bytes = endpoint->wMaxPacketSize;
++ }
++ else {
++ TRACE_MSG0(PCD, "BULK OUT CS: using residue bytes: 64");
++ bytes = residue;
++ }
++
++
++ if (!(urb = pcd_rcv_next_irq(endpoint))) {
++ TRACE_MSG0(PCD, "BULK OUT EPN - no rcv_urb");
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++
++ TRACE_MSG4(PCD, "BULK OUT CS: %04x RD: %04x actual: %d DMA bytes: %d", cs, rds, urb->actual_length, bytes);
++
++ if (bytes)
++ dma_cache_inv((u32) urb->buffer + urb->actual_length, bytes);
++
++ /* The original AU1X00 UDC design will continue to receive data as long as there is room
++ * in the FIFO. We cannot tell when we are at the end of a packet and/or have the start
++ * of a new one.
++ *
++ * There are only two scenarios that are guaranteed (almost) to be correct:
++ *
++ * 64 bytes of data from DMA, empty fifo, continue Bulk OUT < 60 bytes of data and
++ * < 4 bytes in fifo, end Bulk OUT.
++ *
++ * There may be a third scenario that is ok:
++ *
++ * 0 bytes dma, 0 bytes in fifo, NAK
++ *
++ * Everything else is an error. In all cases we assume that it is safer to drop data
++ * than to accept it in error. This allows CRC or size protected encapsulations to
++ * notice bulk transfers received with errors.
++ *
++ * In general none of the policies or strategies are able to cope with all errors
++ * without missing errors and dropping good data. The intent is to minimize the amount
++ * of potentially bad data getting to the function driver while minimizing the amount of
++ * good data that is dropped.
++ *
++ * The new silicon mitigates this problem for non control endpoints because it will NAK
++ * additional data until the interrupt service flag is reset.
++ *
++ * Start with generic error tests, OF, UF or NAK indicate an error we cannot recover
++ * from, start flushing until end of current bulk transfer (wait for a short packet)
++ *
++ * XXX The following needs to be tested and streamlined for au1550, much of the extra
++ * testing done for older silicon cab probably be eliminated. For example the extra read
++ * of nrds to check for overrun in the FIFO should not be required.
++ *
++ */
++ if (rds & (USBDEV_FSTAT_OF | USBDEV_FSTAT_UF)) {
++ TRACE_MSG2(PCD, "BULK OUT FLUSHING %d length: %d", bytes, urb->actual_length);
++ THROW(start_flushing);
++ }
++ rds = rds & USBDEV_FSTAT_FCNT_MASK;
++ nrds = au_readl(ep->rds);
++
++ /* full size packet received, check that we are not flushing and that the FIFO
++ * does not have any data. If there is data in the FIFO we may not be able to
++ * restart DMA in time, so start flushing
++ */
++ if (endpoint->wMaxPacketSize == bytes) {
++ TRACE_MSG2(PCD, "BULK OUT 64 BYTES %d length: %d", bytes, urb->actual_length);
++ if (endpoint->rcv_error) {
++ TRACE_MSG4(PCD, "FULL PACKET bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if ((nrds > 6) && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "FIFO not empty bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING nrds > 6 < 8",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if (!urb->actual_length)
++ TRACE_MSG4(PCD, "PACKET ok bytes: %d rds: %d nrds: %d cp0: %d ACCEPTING 64 bytes",
++ bytes, rds, nrds, cp0_count);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ au_rcv_complete_epn_irq(endpoint, endpoint->wMaxPacketSize, 0);
++ if (cs & USBDEV_CS_NAK)
++ if (nrds && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING CS_NAK",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ }
++ /* a nak'd packet may be ok to ignore IFF the FIFO is empty(?) or completely full.
++ */
++ else if ((cs & USBDEV_CS_NAK) && (!nrds || (nrds == 8)) ) {
++ TRACE_MSG2(PCD, "BULK OUT NAK BYTES %d length: %d", bytes, urb->actual_length);
++ if (endpoint->rcv_error) {
++ TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ }
++ /* short packet by DMA, additional data for this packet in FIFO, more than 3
++ * bytes is probably an error.
++ */
++ else {
++ TRACE_MSG2(PCD, "BULK OUT < 64 BYTES %d length: %d", bytes, urb->actual_length);
++ if ((cs & USBDEV_CS_NAK) && nrds && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "BULK OUT NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if (nrds > 4) {
++ TRACE_MSG4(PCD, "BULK OUT SHORT PACKET by DMA full FIFO bytes: %d rds: %d nrds: %d cp0: %d START FLUSH",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ TRACE_MSG4(PCD, "BULK OUT SHORT bytes: %d rds: %d nrds: %d cp0: %d reading fifo", bytes, rds, nrds, cp0_count);
++ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, nrds);
++ bytes += nrds;
++ TRACE_MSG1(PCD, "BULK OUT < 64 BYTES %d", bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ if (!endpoint->rcv_error) {
++ TRACE_MSG0(PCD, "BULK OUT COMPLETED URB");
++ au_rcv_complete_epn_irq(endpoint, bytes, 0);
++ }
++ else {
++ TRACE_MSG0(PCD, "BULK OUT - FLUSHING URB - reseting rcv_error");
++ endpoint->rcv_error = 0;
++ }
++ }
++ CATCH(start_flushing) {
++ TRACE_MSG0(PCD, "BULK OUT - START FLUSHING URB");
++ endpoint->rcv_error = 1;
++ endpoint->rcv_urb->actual_length = 0;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ bytes = 0;
++ }
++ TRACE_MSG0(PCD, "BULK OUT - RESTARTING");
++ au_start_out_bulk(epn, endpoint, ep);
++}
++
++static void au_start_out_iso(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ RETURN_IF(!endpoint->rcv_urb);
++ au_start_dma_out(ep->outdma, ep->rx_id,
++ endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
++}
++
++static void au_out_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ int bytes = 0;
++ struct usbd_urb *urb;
++ u32 cs;
++ u32 rds;
++ au_halt_dma(ep->outdma);
++ cs = au_readl(ep->cs);
++ rds = au_readl(ep->rds);
++ if (!endpoint) {
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ return;
++ }
++ if (!(urb = endpoint->rcv_urb)) {
++ TRACE_MSG2(PCD, "ISO OUT EPN - rcv_urb was NULL bytes: %d rds: %d", bytes, rds);
++ au_rcv_complete_epn_irq(endpoint, bytes, 1);
++ TRACE_MSG0(PCD, "ISO OUT setting rcv_error");
++ }
++ bytes = endpoint->wMaxPacketSize - au1xxx_get_dma_residue(ep->outdma);
++ rds = rds & USBDEV_FSTAT_FCNT_MASK;
++ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, rds);
++ bytes += rds;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ au_rcv_complete_epn_irq(endpoint, bytes, 0);
++ au_start_out_iso(epn, endpoint, ep);
++}
++/* ********************************************************************************************* */
++/* au_tx_dma_done - TX DMA interrupt handler
++ */
++static void au_tx_dma_done(int irq, void *dev_id, struct pt_regs *regs)
++{
++ int epn = (int) dev_id;
++ struct usbd_endpoint_instance *endpoint = pcd_instance->bus->endpoint_array + epn;
++ struct ep_regs *ep = &ep_regs[epn];
++ int residue;
++ ocd_ops.interrupts++;
++ RETURN_IF (!epn);
++ au_halt_dma(ep->indma);
++ ep->last = 0;
++}
++
++/* au_int_req - usb interrupt handler
++ */
++static void au_int_req (int irq, void *dev_id, struct pt_regs *regs)
++{
++ u32 intstat;
++ struct ep_regs *ep;
++#if defined(MAX_INTR_LOOP_STATS)
++ u32 loopcount = 0;
++#endif
++#ifdef RECORD_LATENCY
++ cp0_count = (read_c0_count(CP0_COUNT) - cp0_record) >> 9;
++ if (cp0_count < CP0_COUNTS)
++ cp0_counts[cp0_count]++;
++#endif
++#ifdef CHECK_LATENCY
++ u32 cp0_count = read_c0_count(CP0_COUNT);
++#endif
++ ocd_ops.interrupts++;
++ TRACE_MSG2(PCD, "INT - device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
++#if 0
++ if (ocd_ops.interrupts > 2000) {
++ TRACE_MSG0(PCD, "UDC_INT call udc_disable_interrupts");
++ au_inten(0, "DISABLING");
++ return;
++ }
++#endif
++ while (( intstat = au_readl(USBD_INTSTAT) & au1x00_inten)) { // read and reset interrupt status register
++
++ int epn;
++#if 1
++ for (epn = 2; epn < 6; epn++) {
++ CONTINUE_IF (!(intstat & (1 << epn)));
++#else
++ // NOT TESTED
++ u32 local_intstat = intstat;
++ TRACE_MSG2(PCD, "INTSTAT: %04x %04x", intstat, au_readl(USBD_INTEN));
++ while (local_intstat & 0x3f) {
++ int epn = 31 - au_clz(local_intstat);
++ local_intstat &= ~(1<<epn);
++#endif
++ if (udc_saw_bus_activity) {
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_ACTIVITY, 0);
++ au_inten(0x0033/*|USBDEV_INT_SOF*/, "int SOF");
++ }
++ ep = &ep_regs[epn];
++ switch(ep->eptype) {
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ //TRACE_MSG2(PCD, "BULK IN %d %02x", epn, ep->eptype);
++ au_in_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ //TRACE_MSG2(PCD, "ISO IN %d %02x", epn, ep->eptype);
++ au_in_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ //TRACE_MSG2(PCD, "BULK OUT %d %02x", epn, ep->eptype);
++ au_out_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ //TRACE_MSG2(PCD, "ISO OUT %d %04d", epn, au_readl(NUSBD_FRAMENUM));
++ au_out_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ }
++ }
++ au_writel(intstat, USBD_INTSTAT); // Only clear the interrupt(s) AFTER servicing OUT
++ /* even though we disable the bulk-in interrupt (endpoint 2) prior to enabling
++ * DMA we always see one additional interrupt that is a NAK on that endpoint.
++ */
++ CONTINUE_IF(!(intstat & au1x00_inten));
++ /* handle control endpoint and suspend interrupt
++ */
++ if (intstat & ( ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | USBDEV_INT_SOF))) {
++ if (intstat & (1 << 0))
++ au_out_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
++ if (intstat & (1 << 1))
++ au_in_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
++ if (intstat & USBDEV_INT_SOF)
++ if (USBD_SUSPENDED == pcd_instance->bus->status) {
++ TRACE_MSG0(PCD, "SUS - ACTIVITY");
++ udc_saw_bus_activity++;
++ }
++ }
++#if defined(MAX_INTR_LOOP_STATS)
++ loopcount += 1; // Gather stats on how many times this loop is performed.
++#endif
++ }
++#if defined(MAX_INTR_LOOP_STATS)
++ interrupt_loop_stats[MIN(loopcount, MAX_INTR_LOOP_STATS)]++;
++#endif
++#if defined(CHECK_LATENCY)
++ TRACE_MSG1(PCD, "USB IRQ - %d", read_c0_count(CP0_COUNT) - cp0_count);
++#endif
++#if defined(RECORD_LATENCY)
++ cp0_record = read_c0_count(CP0_COUNT);
++#endif
++}
++
++/* au_int_sus -suspend interrupt handler
++ */
++static void au_int_sus (int irq, void *dev_id, struct pt_regs *regs)
++{
++ ocd_ops.interrupts++;
++ TRACE_MSG2(PCD, "SUS - INACTIVE device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
++ switch(pcd_instance->bus->status) {
++ case USBD_OPENING:
++ case USBD_OK:
++ au_inten(0x0033, "suspend");
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_INACTIVE, 0);
++ break;
++ default:
++ break;
++ }
++}
++/* ********************************************************************************************* */
++/*
++ * au_connect - enable pullup resistor
++ * Turn on the USB connection by enabling the pullup resistor.
++ *
++ * au_disconnect - disable pullup resistor
++ * Turn off the USB connection by disabling the pullup resistor.
++ */
++
++#if defined(CONFIG_MIPS_FREEHAND_NATIVE)
++#warning "Old code for Freehand"
++void au_connect (struct pcd_instance *pcd)
++{
++ au1000gpio_set(GPIO01);
++}
++
++void au_disconnect (struct pcd_instance *pcd)
++{
++ au1000gpio_clear(GPIO01);
++}
++#elif defined(CONFIG_AMX_MORDOR)
++void au_connect (struct pcd_instance *pcd)
++{
++ au_writel(0x00000008, SYS_OUTPUTSET);
++}
++
++void au_disconnect (struct pcd_instance *pcd)
++{
++ au_writel(0x00000008, SYS_OUTPUTCLR);
++}
++#elif defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_MTX2)
++void au_connect (struct pcd_instance *pcd)
++{
++ au_writel(au_readl(GPIO2_DIR) | 0x100, GPIO2_DIR);
++ au_writel(0x01000100, GPIO2_OUTPUT);
++ au_sync();
++}
++void au_disconnect (struct pcd_instance *pcd)
++{
++ au_writel(au_readl(GPIO2_DIR) | 0x100, GPIO2_DIR);
++ au_writel(0x01000000, GPIO2_OUTPUT);
++ au_sync();
++}
++#else
++#warning "Please define au_connect / au_disconnect"
++void au_connect (struct pcd_instance *pcd)
++{
++}
++void au_disconnect (struct pcd_instance *pcd)
++{
++}
++#endif
++
++#undef read_c0_COUNT
++#ifndef read_c0_count
++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
++#endif
++/* ********************************************************************************************* */
++/* au_ticks - get current ticks
++* */
++u64 au_ticks (void)
++{
++ return read_c0_count();
++}
++
++/* au_elapsed - return micro-seconds between two tick values
++ */
++u64 au_elapsed(u64 *t1, u64 *t2)
++{
++ u64 ticks = (*t1 > *t2) ? (*t1 - *t2) : (*t2 - *t1);
++ ticks = (u32)((u32) ticks / (u32) CONFIG_OTG_AU1X00_SCLOCK);
++ return ticks;
++}
++
++/* au_framenum - get current framenum
++ */
++u16 au_framenum (void)
++{
++ return au_readl(NUSBD_FRAMENUM);
++}
++
++
++/* ********************************************************************************************* */
++/* au_start_endpoint_in - start transmit
++ */
++void au_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
++ case USB_ENDPOINT_CONTROL:
++ au_in_ep0(endpoint, ep);
++ break;
++ case USB_ENDPOINT_BULK:
++ case USB_ENDPOINT_INTERRUPT:
++ au_start_in_bulk(epn, endpoint, ep);
++ break;
++ case USB_ENDPOINT_ISOCHRONOUS:
++ au_start_in_iso(epn, endpoint, ep);
++ break;
++ }
++ au_epn_interrupt_enable(epn);
++}
++
++/* au_start_endpoint_out - start receive
++ */
++void au_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
++ case USB_ENDPOINT_CONTROL:
++ break;
++ case USB_ENDPOINT_BULK:
++ case USB_ENDPOINT_INTERRUPT:
++ au_start_out_bulk(epn, endpoint, ep);
++ au_epn_interrupt_enable(epn);
++ break;
++ case USB_ENDPOINT_ISOCHRONOUS:
++ au_start_out_iso(epn, endpoint, ep);
++ break;
++ }
++}
++
++/*
++ * au_pcd_endpoint_halted() - is endpoint halted
++ */
++static int
++au_pcd_endpoint_halted (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++int cs;
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
++ struct ep_regs *ep = &ep_regs[epn];
++
++ TRACE_MSG2(PCD, "epn: %02x dir: %x", epn, dir);
++ return ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) ? TRUE : FALSE;
++}
++
++/* au_pcd_halt_endpoint - halt endpoint
++ */
++int au_pcd_halt_endpoint(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint, int flag)
++{
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
++ struct ep_regs *ep = &ep_regs[epn];
++
++ TRACE_MSG3(PCD, "epn: %02x dir: %x flag: %d", epn, dir, flag);
++
++ au_writel(au_readl(ep->cs) & USBDEV_CS_STALL, ep->cs);
++ return 0;
++}
++
++
++
++void au_cancel_in_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
++{
++ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ au_in_bulk(epn, ep, urb->endpoint);
++}
++
++void au_cancel_out_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
++{
++ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ au_out_bulk(epn, ep, urb->endpoint);
++}
++
++/* au_serial_init - set a serial number if available
++ */
++int au_serial_init (struct pcd_instance *pcd)
++{
++#if defined(CONFIG_MIPS_FREEHAND)
++ int length;
++ long data[16]; /* yeah a hack, but we KNOW it's 16 */
++ struct i2c_client *client;
++ char chData[16];
++ int i;
++
++ if (!(client = getFreeHandEepromClient())) {
++ printk(KERN_INFO"eeprom not ready when au_serial_init called\n");
++ return -EINVAL;
++ }
++ eeprom_contents(client, SENSORS_PROC_REAL_READ, EEPROM_SYSCTL1, &length, (long *)data);
++
++ /* serial number is first 9 longs. But each long is just an ASCII char
++ * convert this to a string and then extract a 4 byte value from it
++ */
++ for (i = 0; i < 9; chData[i] = (char)data[i], i++); /* trunc, is ok */
++ chData[9] = 0; /* terminate string */
++ printk(KERN_INFO"%s: %s\n", __FUNCTION__, chData);
++ pcd_instance->bus->serial_number_str = lstrdup(chData);
++ return 0;
++#else
++ return -EINVAL;
++#endif
++}
++
++
++/* au_start - start session
++ */
++void au_start (struct pcd_instance *pcd)
++{
++ au_inten(0x0033/*|USBDEV_INT_SOF*/, "START"); // Only enable receive interrupts.
++}
++
++/* au_stop - stop session
++ */
++void au_stop (struct pcd_instance *pcd)
++{
++ //au_inten(0, "STOP");
++}
++
++int au_assign_endpoint( u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
++ u16 wMaxPacketSize, u16 transferSize)
++{
++ struct ep_regs *ep = &ep_regs[physicalEndpoint];
++ RETURN_EINVAL_IF(used[physicalEndpoint]);
++ endpoint_map->bEndpointAddress[0] = epp2l[physicalEndpoint];
++ endpoint_map->physicalEndpoint[0] = physicalEndpoint;
++ endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
++ endpoint_map->transferSize[0] = transferSize;
++ endpoint_map->bmAttributes[0] = bmAttributes;
++ used[physicalEndpoint]++;
++ ep->eptype = bmAttributes & 0x83;
++ return 0;
++}
++
++int au_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested,
++ struct usbd_endpoint_request *requestedEndpoints)
++{
++ struct usbd_device_description *device_description;
++ int i, j;
++ int used[UDC_MAX_ENDPOINTS];
++ memset(used, 0, sizeof(used));
++ for (j = 0, i = 0; i < endpointsRequested; i++, j++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ u8 bmAttributes = requestedEndpoints[i].bmAttributes;
++ u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
++ RETURN_EINVAL_UNLESS(j < UDC_MAX_ENDPOINTS);
++ switch(bmAttributes) {
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ break;
++ }
++ CONTINUE_IF(bmAttributes & USB_ENDPOINT_OPT);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++struct usbd_endpoint_map *au_endpoint_map_array;
++int au_endpointsRequested;
++
++int au_set_endpoints2(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array);
++int au_set_endpoints(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
++{
++ au_endpointsRequested = endpointsRequested;
++ au_endpoint_map_array = endpoint_map_array;
++ return au_set_endpoints2(pcd, au_endpointsRequested, au_endpoint_map_array);
++}
++
++int au_set_endpoints2(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
++{
++ int i, j;
++ u8 config[25];
++ u8 *cp;
++ memcpy(config, au1x00_config_bulk, sizeof(config));
++ for (i = 0; i < endpointsRequested; i++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ int epreq = endpoint_map->bmAttributes[0];
++ int eptype = epreq & USB_ENDPOINT_MASK;
++ int epdir = epreq & USB_ENDPOINT_DIR_MASK ? 0x8 : 0;
++ int epsize = endpoint_map->wMaxPacketSize[0];
++ int epaddr = epp2l[endpoint_map->physicalEndpoint[0]];
++ CONTINUE_IF(!endpoint_map->physicalEndpoint[0] || (endpoint_map->physicalEndpoint[0] > 5));
++ cp = config + ((endpoint_map->physicalEndpoint[0] - 1) * 5);
++ cp[0] = (epaddr & 0xf) << 4 | 0x4;
++ cp[1] = (eptype << 4) | epdir | (epsize & 0x380) >> 7;
++ cp[2] = (epsize & 0x7F) << 1;
++ }
++ TRACE_MSG0(PCD, "Disable interrupts");
++ au_inten(0, "SET ENDPOINTS"); // disable interrupts
++ au_writel(0x0002, USBD_ENABLE); // reset controller
++ udelay(100);
++ au_writel(0x0003, USBD_ENABLE); // enable controller
++ udelay(100);
++ for (cp = config, i = 0; i < 25; i++, au_writel(*cp++, USBD_CONFIG)); // feed the config into the UDC
++ return 0;
++}
++
++/* au_loc_conn - used to enable or disable peripheral connecting to bus
++ *
++ */
++void au_loc_conn(struct otg_instance *otg, u8 flag)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)otg->pcd;
++ TRACE_MSG0(PCD, "--");
++ TRACE_MSG1(PCD, "PCD: %x", (int)pcd);
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_SET - Enable DP PULLUP");
++ au_set_endpoints2(pcd, au_endpointsRequested, au_endpoint_map_array);
++ au_inten(0x0033/*|USBDEV_INT_SOF*/, "START"); // Only enable receive interrupts.
++ au_connect(pcd);
++ break;
++
++ case RESET:
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Disable DP PULLUP");
++ au_disconnect(pcd);
++ au_inten(0, "RESET ENDPOINTS"); // disable interrupts
++ au_writel(0x0000, USBD_ENABLE); // reset controller
++ break;
++ }
++}
++
++
++/* ********************************************************************************************* */
++
++
++static u32 request_dma(int ep, int src, int dest, char *str, void dma_done(int , void *, struct pt_regs *))
++{
++ u32 dma;
++
++ chan_tab_t *ctp;
++ volatile au1x_dma_chan_t *cp;
++ au1x_ddma_desc_t *dp;
++
++
++ if ((dma = au1xxx_dbdma_chan_alloc(src, dest, dma_done, (void *)ep)) < 0) {
++ printk(KERN_INFO"request_io[%d] dma: %x src: %d dest: %d %s FAILED\n", ep, dma, src, dest, str);
++ return -1;
++ }
++
++ if(au1xxx_dbdma_ring_alloc(dma, 1) == 0) {
++ printk(KERN_INFO"request_io[%d] Ring Buffer Allocation for dma: %x src: %d dest: %d %s FAILED\n",
++ ep, dma, src, dest, str);
++ return -1;
++ }
++
++ ctp = *((chan_tab_t **)dma);
++ cp = ctp->chan_ptr;;
++ dp = ctp->put_ptr;
++ dp->dscr_cmd0 &= ~DSCR_CMD0_V;
++
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %04x dst: %08x %08x DBDMA",
++ dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++
++#if 0
++ // XXX copy static components from au_start_out
++ // transmit - mem to usb
++ if (src == DBDMA_MEM_CHAN) {
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %04x dst: %08x %08x MEM2USB",
++ dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++ }
++#endif
++#if 0
++ // XXX copy static components from au_start_in
++ // receive - usb to mem
++ if (dest == DBDMA_MEM_CHAN) {
++ TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM",
++ dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++ }
++#endif
++ TRACE_MSG5(PCD, "request_io[%d] dma: %x src: %d dest: %d %s SUCCEDED", ep, dma, src, dest, str);
++ return dma;
++}
++
++/* au_mod_init
++ */
++int au_mod_init (void)
++{
++ int dev = request_irq (AU1000_USB_DEV_REQ_INT, au_int_req, SA_INTERRUPT, UDC_NAME "UDC Req", NULL);
++ int sus = request_irq (AU1000_USB_DEV_SUS_INT, au_int_sus, SA_INTERRUPT, UDC_NAME "UDC Sus", NULL);
++ u32 cp0_prid = read_c0_prid();
++ int i;
++
++
++ if (dev || sus) { // check if either request irq failed
++ if (!dev) free_irq (AU1000_USB_DEV_REQ_INT, NULL); // free irqs that might have
++ if (!sus) free_irq (AU1000_USB_DEV_SUS_INT, NULL); // been successfully allocated
++ return -EINVAL;
++ }
++ for (i = 0; i < 6; i++) {
++ ep_regs[i].indma = ep_regs[i].tx_id ?
++ request_dma(i, DBDMA_MEM_CHAN, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
++ ep_regs[i].outdma = ep_regs[i].rx_id ?
++ request_dma(i, ep_regs[i].rx_id, DBDMA_MEM_CHAN, ep_regs[i].rx_str, NULL) : -1;
++ }
++ switch (cp0_prid & CP0_PRID_SOC_MASK) {
++ case CP0_PRID_AU1000:
++ case CP0_PRID_AU1100:
++ case CP0_PRID_AU1500:
++ return -EINVAL;
++ case CP0_PRID_AU1550:
++ TRACE_MSG1(PCD, "AU1550 cp0_prid: %08x\n", cp0_prid);
++ printk(KERN_INFO"%s: AU1550 cp0_prid: %08x\n", __FUNCTION__, cp0_prid);
++ break;
++ default:
++ printk(KERN_INFO"%s: UNKNOWN CPU cp0_prid: %08x UNKNOWN UDC\n", __FUNCTION__, cp0_prid);
++ break;
++ }
++ return 0;
++}
++
++/* au_mod_exit
++ */
++void au_mod_exit (void)
++{
++ int j;
++ au_writel(0x0000, USBD_ENABLE);
++ for (j = 0; j < 6; j++) {
++ struct ep_regs *ep = &ep_regs[j];
++ if (ep->indma != -1) {
++ au1xxx_dbdma_chan_free(ep->indma);
++ ep->indma = -1;
++ }
++ if (ep->outdma != -1) {
++ au1xxx_dbdma_chan_free(ep->outdma);
++ ep->outdma = -1;
++ }
++ }
++ free_irq (AU1000_USB_DEV_REQ_INT, NULL);
++ free_irq (AU1000_USB_DEV_SUS_INT, NULL);
++#if defined(MAX_INTR_LOOP_STATS)
++ {
++ u32 lc;
++ for (lc = 0; lc <= MAX_INTR_LOOP_STATS; lc++)
++ if (interrupt_loop_stats[lc])
++ printk(KERN_ERR "%s: interrupt loopcount[%02u] %9u\n", __FUNCTION__, lc,interrupt_loop_stats[lc]);
++ printk(KERN_INFO"%s: halt_dma_expired: %d\n", __FUNCTION__, au_halt_dma_expired);
++ }
++#endif
++#ifdef RECORD_LATENCY
++ {
++ int i;
++ for (i = 0; i < CP0_COUNTS; i++)
++ if (cp0_counts[i])
++ printk(KERN_INFO"%s: cp0_counts[%d] %d\n", __FUNCTION__, i, cp0_counts[i]);
++ }
++#endif
++}
++
++/* ********************************************************************************************* */
++struct usbd_pcd_ops usbd_pcd_ops = {
++ max_endpoints: UDC_MAX_ENDPOINTS,
++ ep0_packetsize: EP0_PACKETSIZE,
++ name: UDC_NAME,
++ start: au_start,
++ stop: au_stop,
++ start_endpoint_in: au_start_endpoint_in,
++ start_endpoint_out: au_start_endpoint_out,
++ request_endpoints: au_request_endpoints,
++ set_endpoints: au_set_endpoints,
++ cancel_in_irq: au_cancel_in_irq,
++ cancel_out_irq: au_cancel_out_irq,
++ serial_init: au_serial_init,
++ halt_endpoint: au_pcd_halt_endpoint,
++ endpoint_halted: au_pcd_endpoint_halted,
++};
++
++struct pcd_ops pcd_ops = {
++ pcd_en_func: pcd_en_func,
++ mod_init: au_mod_init,
++ mod_exit: au_mod_exit,
++ framenum: au_framenum,
++};
++
++struct ocd_ops ocd_ops = {
++ #if defined(CONFIG_OTG_TR_AUTO)
++ capabilities: OCD_CAPABILITIES_TR | OCD_CAPABILITIES_AUTO,
++ #else
++ capabilities: OCD_CAPABILITIES_TR,
++ #endif
++ ticks: au_ticks,
++ elapsed: au_elapsed,
++};
++
++struct tcd_ops tcd_ops = {
++ dp_pullup_func: au_loc_conn,
++};
++
+diff -uNr linux/drivers/no-otg/ocd/au1x00/au1x00.c linux/drivers/otg/ocd/au1x00/au1x00.c
+--- linux/drivers/no-otg/ocd/au1x00/au1x00.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/au1x00/au1x00.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,1293 @@
++/*
++ * otg/ocd/au1x00/au1x00.c -- USB Device Controller driver.
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++/*!
++ * @file otg/ocd/au1x00/au1x00.c
++ * @brief AU1X00 Header
++ *
++ * This file contains the private defines and structures for the AU1X00
++ * Drivers.
++ *
++ * @ingroup AU1X00
++ */
++
++
++#include <otg/pcd-include.h>
++#include "au1x00.h"
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/au1000_dma.h>
++
++#if defined(CONFIG_SOC_AU1550)
++#define DBDMA
++#endif
++#ifdef DBDMA
++#warning "Using AU1XXX_DBMDA"
++#include <asm/au1xxx_dbdma.h>
++#else /* DBDMA */
++#warning "Using AU1X00_MDA"
++#endif /* DBDMA */
++
++#include <asm/mipsregs.h>
++
++
++#ifdef CONFIG_MIPS_FREEHAND
++#include <linux/i2c.h>
++#include <linux/sensors.h> /* for reading serial number */
++#endif
++
++
++#undef CHECK_LATENCY
++#undef RECORD_LATENCY
++#undef MAX_INTR_LOOP_STATS //10
++#if defined(MAX_INTR_LOOP_STATS)
++static u32 interrupt_loop_stats[MAX_INTR_LOOP_STATS+1];
++#endif
++#ifdef RECORD_LATENCY
++#define CP0_COUNTS 50
++u32 cp0_counts[CP0_COUNTS];
++u32 cp0_record;
++#endif
++u32 cp0_count;
++unsigned int udc_saw_bus_activity;
++int au_halt_dma_expired;
++u32 au1x00_new_silicon;
++u32 au1x00_inten;
++
++u8 au1x00_config_bulk[25] = {
++ 0x04, (USB_ENDPOINT_CONTROL << 4) | (EP0_PACKETSIZE & 0x380) >> 7, // 1
++ (EP0_PACKETSIZE & 0x7F) << 1, 0x00, 0x00,
++ 0x24, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 6
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x02,
++ 0x34, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 11
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x03,
++ 0x44, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 16
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x04,
++ 0x54, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 21
++ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x05,
++};
++
++/* ********************************************************************************************* */
++/* Note - The endpoints names are confusing. To simplify mapping of the interrupt request lines
++ * we use a numbering of the physical endpoints of 0-5, which also matches the fifo numbering
++ * (see the config block).
++ *
++ * Physical FIFO Name Direction Logical
++ * 0 0 EP0 OUT 0
++ * 1 1 EP0 IN 0
++ * 2 2 EP1 IN 81
++ * 3 3 EP2 IN 82
++ * 4 4 EP3 OUT 3
++ * 5 5 EP4 OUT 4
++ *
++ * The ep_regs array maps a physical endpoint number to the registers required to access the udc
++ * for that endpoint. Note that ep0 is always accessed via 0. The epl2p array maps the logical
++ * addresses back to the physical number. The epp2l array maps the physical number to the
++ * logical endpoint address
++ */
++#ifdef DBDMA
++struct ep_regs ep_regs[6] = {
++
++ { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
++ wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX0, tx_str: "EP0 IN WR",},
++
++ { rds: 0, wrs: 0, indma: -1, outdma: -1, },
++ { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX1, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
++ { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX2, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
++
++ { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX3, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
++ { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX4, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
++};
++#else /*DBMA */
++struct ep_regs ep_regs[6] = {
++ { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
++ wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DMA_ID_USBDEV_EP0_TX, tx_str: "EP0 IN WR",},
++ { rds: 0, wrs: 0, indma: -1, outdma: -1, },
++ { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: NDMA_ID_USBDEV_EP1_TX, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
++ { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: NDMA_ID_USBDEV_EP2_TX, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
++
++ { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: NDMA_ID_USBDEV_EP3_RX, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
++ { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: NDMA_ID_USBDEV_EP4_RX, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
++};
++#endif /*DBMA */
++u8 epl2p[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, }; // map logical to physical
++u8 epp2l[6] = { 0x00, 0x00, 0x81, 0x82, 0x03, 0x04, }; // map physical to logical
++
++static __inline__ void au_fifo_read(struct ep_regs *ep, unsigned char * cp, int bytes)
++{
++ u32 rd = ep->rd;
++ for (; bytes--; *cp++ = au_readl(rd));
++}
++
++static __inline__ void au_fifo_write(int ep, unsigned char * cp, int bytes)
++{
++ u32 wr = ep_regs[ep].wr;
++ for (; bytes--; au_writel(*cp++, wr));
++ ep_regs[ep].last = bytes;
++}
++
++void __inline__ au_inten(u32 inten)
++{
++ au1x00_inten = inten;
++ au_writel(au1x00_inten, USBD_INTEN);
++}
++
++void __inline__ au_epn_interrupt_enable(int epn)
++{
++ au_inten(au1x00_inten | (1 << epn));
++}
++
++void __inline__ au_epn_interrupt_disable(int epn)
++{
++ au_inten(au1x00_inten & ~(1 << epn));
++ au_writel((1 << epn) , USBD_INTSTAT);
++}
++
++static void __inline__ send_zlp(unsigned char epn)
++{
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep_regs[epn].wrs);
++ au_writel(0 << 1, ep_regs[epn].cs);
++ au_writel(0, ep_regs[epn].wr);
++}
++/* ********************************************************************************************* */
++#define AU_DMA_HALT_POLL 0x1000
++#ifdef DBDMA
++static void __inline__ au_halt_dma(int chan)
++{
++ au1xxx_dbdma_stop(chan);
++ au_halt_dma_expired++;
++}
++
++static int __inline__ au_get_dma_residue(int chan)
++{
++ return au1xxx_get_dma_residue(chan);
++}
++
++static void __inline__ au_start_dma_in(int indma, __u8 *bp, int len)
++{
++ //printk("\n----------------------STARTING DMA IN dma:%X buffer:%p len:%d---------------\n", indma, bp, len);
++ // au1xxx_dbdma_stop(indma);
++ au1xxx_dbdma_put_source(indma, bp, len);
++ au1xxx_dbdma_start(indma);
++}
++
++static void __inline__ au_start_dma_out(unsigned int outdma, __u8 *bp, int packetSize)
++{
++ //printk("\n----------------------STARTING DMA OUT dma:%X buffer:%p len:%d---------------\n", outdma, bp, packetSize);
++ au1xxx_dbdma_put_dest(outdma, bp, packetSize);
++ au1xxx_dbdma_start(outdma);
++}
++
++static u32 __inline__ au_get_dma_chan(u32 dma)
++{
++ return dma;
++}
++#else /* DBDMA */
++static void __inline__ au_halt_dma(struct dma_chan *chan)
++{
++ int i;
++ au_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
++ for (i = 0; i < AU_DMA_HALT_POLL; i++)
++ RETURN_IF (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT);
++ au_halt_dma_expired++;
++}
++
++static int __inline__ au_get_dma_residue(struct dma_chan *chan)
++{
++ int curBufCntReg = (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;
++ return au_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
++}
++
++static void __inline__ au_start_dma(struct dma_chan *chan, u8 *bp, int len)
++{
++ if (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) {
++ au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
++ au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER1_COUNT);
++ au_writel(0, chan->io + DMA_BUFFER0_COUNT);
++ au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER1_START);
++ au_writel(DMA_BE1, chan->io + DMA_MODE_SET);
++ }
++ else {
++ au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
++ au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER0_COUNT);
++ au_writel(0, chan->io + DMA_BUFFER1_COUNT);
++ au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER0_START);
++ au_writel(DMA_BE0, chan->io + DMA_MODE_SET);
++ }
++ au_writel(DMA_GO, chan->io + DMA_MODE_SET);
++}
++
++static void __inline__ au_start_dma_in(int indma, u8 *bp, int len)
++{
++ au_start_dma(get_dma_chan(indma), bp, len);
++}
++
++static void __inline__ au_start_dma_out(int outdma, u8 *bp, int wMaxPacketSize)
++{
++ dma_cache_inv((unsigned long) bp, wMaxPacketSize);
++ au_start_dma(get_dma_chan(outdma), bp, wMaxPacketSize);
++}
++
++static __inline__ struct dma_chan * au_get_dma_chan(u32 dma)
++{
++ return get_dma_chan(dma);
++}
++#endif /* DBDMA */
++static struct usbd_urb *au_rcv_complete_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
++{
++ return pcd_rcv_complete_irq(endpoint, len, urb_bad);
++}
++/* ********************************************************************************************* */
++/* au_start_in_ep0 - start transmit
++ */
++static void au_start_in_ep0 (struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ int last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN EP0 SENT: %d SENDING: %d", endpoint->sent, last);
++ RETURN_IF ((urb->actual_length - endpoint->sent) <= 0);
++ au_writel(last << 1, ep->cs); // XXX
++ au_fifo_write(0, urb->buffer + endpoint->sent, last);
++ endpoint->last = last;
++}
++
++/* au_in_ep0 - called to service an endpoint zero IN interrupt, data sent
++ */
++static void au_in_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ u32 cs;
++ struct usbd_urb *tx_urb;
++ int last;
++ TRACE_MSG1(PCD, "EP0 IN: tx_urb: %p", (int)endpoint->tx_urb);
++ if ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) { // clear stall if present
++ TRACE_MSG1(PCD, "CLEAR STALL %d", 0);
++ cs &= ~USBDEV_CS_STALL;
++ au_writel(cs, ep->cs);
++ return;
++ }
++ if (!(tx_urb = pcd_tx_complete_irq(endpoint, 0))) { // wait for setup if no more data
++ endpoint->state = WAIT_FOR_SETUP;
++ return;
++ }
++ TRACE_MSG4(PCD, "EP0 IN actual: %d last: %d sent: %d flags: %x", endpoint->tx_urb->actual_length,
++ endpoint->last, endpoint->sent, endpoint->tx_urb->flags);
++ if (pcd_tx_sendzlp(endpoint)) { // check if tx_urb we have is finished
++ TRACE_MSG0(PCD, "EP0 IN BULK - sending ZLP");
++ tx_urb->flags &= ~USBD_URB_SENDZLP;
++ send_zlp(0);
++ pcd_tx_complete_irq(endpoint, 0);
++ return;
++ }
++ if (tx_urb->actual_length > endpoint->sent) {
++ if ((tx_urb->actual_length - endpoint->sent) < endpoint->wMaxPacketSize)
++ TRACE_MSG1(PCD, "EP0 IN starting short packet %d", tx_urb->actual_length - endpoint->sent);
++ else
++ TRACE_MSG1(PCD, "EP0 IN LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ au_start_in_ep0(endpoint, ep);
++ }
++}
++
++/* au_out_ep0 - called to service an endpoint zero OUT interrupt, data received
++ */
++static void au_out_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_device_request request;
++ int i;
++ u32 cs;
++ u32 bytes;
++ TRACE_MSG0(PCD, "EP0 OUT");
++ cs = au_readl(ep->cs); // check if host aborted transfer and flush the write fifo
++ bytes = au_readl(ep->rds) & USBDEV_FSTAT_FCNT_MASK;
++ if (endpoint->state == DATA_STATE_RECV) {
++ struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
++ TRACE_MSG1(PCD, "EP0 OUT: RECV: rcv_urb: %x", (int) rcv_urb);
++ if (rcv_urb) {
++ au_fifo_read(ep, rcv_urb->buffer + rcv_urb->actual_length, bytes);
++ if (au_rcv_complete_irq(endpoint, bytes, 0))
++ return;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ endpoint->state = WAIT_FOR_SETUP;
++ send_zlp(0);
++ return;
++ }
++ endpoint->state = WAIT_FOR_SETUP;
++ }
++ pcd_tx_cancelled_irq(endpoint);
++ pcd_rcv_cancelled_irq(endpoint);
++ au_fifo_read(ep, (u8 *)&request, bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
++ if (bytes != 8) {
++ TRACE_MSG1(PCD, "ERROR SETUP SET not eight bytes: %d", bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
++ return;
++ }
++ TRACE_MSG4(PCD, "SETUP bmRequestType: %02x bRequest %02x state: %d status: %d", request.bmRequestType,
++ request.bRequest, pcd_instance->bus->device_state, pcd_instance->bus->status);
++ switch (request.bRequest) { // we need to simply ignore any of these
++ case USB_REQ_SET_ADDRESS: // Fake a bus reset IFF not state default and then process normally
++ BREAK_IF (pcd_instance->bus->device_state == STATE_DEFAULT);
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
++ break;
++ case USB_REQ_GET_DESCRIPTOR: // Fake a bus reset IFF suspended and then process normally
++ BREAK_IF (STATE_SUSPENDED != pcd_instance->bus->device_state);
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
++ break;
++ }
++ if (pcd_recv_setup_irq(pcd_instance, &request)) {
++ TRACE_MSG1(PCD, "ep0 STALL %d", cs);
++ au_writel(USBDEV_CS_STALL, USBD_EP0CS);
++ return;
++ }
++ if (((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu (request.wLength)) {
++ TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
++ endpoint->state = DATA_STATE_RECV;
++ return;
++ }
++ if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
++ TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
++ if ((request.bmRequestType & ~USB_REQ_DIRECTION_MASK)) {
++ TRACE_MSG1(PCD, "ep0 Class or Vendor, send ZLP %d", cs);
++ send_zlp(0);
++ return;
++ }
++ }
++ TRACE_MSG1(PCD, "ep0 Class D2H request %04x", le16_to_cpu(request.wLength));
++}
++/* ********************************************************************************************* */
++/* au_start_in_bulk - start transmit
++ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by
++ * DMA or PIO. The packetsize must be set first.
++ */
++static void au_start_in_bulk (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ unsigned char *bp = urb->buffer + endpoint->sent;
++ int last;
++ TRACE_MSG1(PCD, "START IN BULK %d", epn);
++ RETURN_IF (!urb || (( (urb->actual_length - endpoint->sent) == 0) && !(urb->flags & USBD_URB_SENDZLP)));
++ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN BULK sent: %d last:%d", endpoint->sent, last);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
++ if (!last) {
++ if (endpoint->tx_urb->flags & USBD_URB_SENDZLP) {
++ TRACE_MSG0(PCD, "START IN BULK - zending ZLP");
++ send_zlp(epn);
++ endpoint->tx_urb->flags &= ~USBD_URB_SENDZLP;
++ }
++ return;
++ }
++ else if (au1x00_new_silicon && (8 >= last)) {
++ au_writel(last << 1, ep->cs);
++ au_fifo_write(epn, bp, last);
++ return;
++ }
++ if (!au1x00_new_silicon)
++ au_epn_interrupt_disable(epn);
++ dma_cache_wback_inv((unsigned long) bp, last);
++ au_writel(last << 1, ep->cs);
++ au_start_dma_in(ep->indma, bp, last);
++}
++
++static void au_in_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb;
++ int rc = 0;
++ u32 cs = au_readl(ep->cs);
++ u32 wrs = au_readl(ep->wrs);
++ TRACE_MSG2(PCD, "BULK IN EPN - cs: %x wrs: %x", cs, wrs);
++ if (!au1x00_new_silicon)
++ if (epn && (ep->last > 8)) {
++ TRACE_MSG2(PCD, "BULK IN EPN - DMA ACTIVE epn %d last %d", epn, ep->last);
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++ if (wrs) { // check for underflow or overflow
++ rc = 1;
++ if (wrs & USBDEV_FSTAT_UF) {
++ TRACE_MSG2(PCD, "BULK IN EPN - UF epn %d wrs: %x", epn, wrs);
++ rc = 1; // set rc to indicate an error
++ }
++ if (wrs & USBDEV_FSTAT_OF)
++ TRACE_MSG2(PCD, "BULK IN EPN - OF epn %d wrs: %x", epn, wrs);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // flush the fifo
++ }
++ if (cs & USBDEV_CS_NAK) {
++ RETURN_IF (ep->last && ((wrs&0x1f) == ep->last));
++ rc = 1;
++ }
++ if (cs & USBDEV_CS_STALL) { // clear stall if present
++ TRACE_MSG1(PCD, "BULK IN EPN - CLEAR STALL %d", epn);
++ cs &= ~USBDEV_CS_STALL;
++ au_writel(cs, ep->cs);
++ return;
++ }
++ TRACE_MSG4(PCD, "BULK IN EPN epn: %d rc: %d last: %d sent: %d", epn, rc, endpoint->last, endpoint->sent);
++ if ((tx_urb = pcd_tx_complete_irq(endpoint, rc))) {
++ if ((tx_urb->actual_length > endpoint->sent) || (endpoint->tx_urb->flags & USBD_URB_SENDZLP)) {
++ au_start_in_bulk(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
++ /* XXX magic delay - without this large packets will eventually stall the transmit
++ * XXX and all traffic in both directions will stop.
++ */
++ if (!au1x00_new_silicon)
++ udelay(8);
++ TRACE_MSG1(PCD, "BULK IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ return;
++ }
++ }
++ au_epn_interrupt_disable(epn); // disable interrupts
++}
++
++/* au_start_in_iso - start transmit
++ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by DMA or
++ * PIO. The packetsize must be set first.
++ */
++static void au_start_in_iso (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ struct usbd_urb *urb = endpoint->tx_urb;
++ unsigned char *bp = urb->buffer + endpoint->sent;
++ int last;
++ TRACE_MSG2(PCD, "START IN ISO actual: %d sent: %d", urb->actual_length, endpoint->sent);
++ RETURN_IF ((urb->actual_length - endpoint->sent) == 0);
++ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ TRACE_MSG2(PCD, "START IN ISO last: %d packetSize: %d", last, endpoint->wMaxPacketSize);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
++ au1x00_new_silicon ? au_epn_interrupt_enable : au_epn_interrupt_disable (epn);
++ dma_cache_wback_inv((unsigned long) bp, last);
++ au_writel(last << 1, ep->cs);
++ au_start_dma_in(ep->indma, bp, last);
++}
++
++static void au_in_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
++ u32 cs = au_readl(ep->cs);
++ u32 wrs = au_readl(ep->wrs);
++ TRACE_MSG2(PCD, "ISO IN EPN - cs: %x wrs: %x", cs, wrs);
++ if (!au1x00_new_silicon)
++ if (epn && (ep->last > 8)) {
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++ TRACE_MSG4(PCD, "ISO IN EPN epn: %d last: %d sent: %d", epn, endpoint->last, endpoint->sent, 0);
++ ep->last = 0;
++ if ((tx_urb = endpoint->tx_urb) && (tx_urb->actual_length > endpoint->sent)) {
++ au_start_in_iso(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
++ /* XXX magic delay - without this large packets will eventually stall the transmit
++ * XXX and all traffic in both directions will stop.
++ */
++ if (!au1x00_new_silicon)
++ udelay(8);
++ TRACE_MSG1(PCD, "ISO IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
++ return;
++ }
++ else
++ TRACE_MSG0(PCD, "ISO IN EPN - nothing to send");
++ au_epn_interrupt_disable(epn); // disable interrupts
++}
++/* ********************************************************************************************* */
++
++static void au_start_out_bulk(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ TRACE_MSG2(PCD, "START OUT BULK %d %d", epn, endpoint->wMaxPacketSize);
++ if (!endpoint->rcv_urb) {
++ TRACE_MSG0(PCD, "START OUT BULK DISABLE");
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++ if (endpoint->rcv_error) {
++ TRACE_MSG0(PCD, "START OUT BULK reseting rcv_error");
++ endpoint->rcv_error = 0;
++ }
++ au_start_dma_out(ep->outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
++}
++
++static void au_out_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ int bytes = 0;
++ struct usbd_urb *urb;
++ struct usbd_urb *completed_urb = NULL;
++ u32 cs;
++ u32 rds;
++ u32 nrds;
++ au_halt_dma(au_get_dma_chan(ep->outdma));
++ cs = au_readl(ep->cs);
++ rds = au_readl(ep->rds);
++ TRACE_MSG2(PCD, "BULK OUT CS: %04x RD: %04x", cs, rds);
++ bytes = endpoint->wMaxPacketSize - au_get_dma_residue(au_get_dma_chan(ep->outdma));
++ if (!(urb = pcd_rcv_next_irq(endpoint))) {
++ TRACE_MSG0(PCD, "BULK OUT EPN - no rcv_urb");
++ au_epn_interrupt_disable(epn);
++ return;
++ }
++ /* The original AU1X00 UDC design will continue to receive data as long as there is room
++ * in the FIFO. We cannot tell when we are at the end of a packet and/or have the start
++ * of a new one.
++ *
++ * There are only two scenarios that are guaranteed (almost) to be correct:
++ *
++ * 64 bytes of data from DMA, empty fifo, continue Bulk OUT < 60 bytes of data and
++ * < 4 bytes in fifo, end Bulk OUT.
++ *
++ * There may be a third scenario that is ok:
++ *
++ * 0 bytes dma, 0 bytes in fifo, NAK
++ *
++ * Everything else is an error. In all cases we assume that it is safer to drop data
++ * than to accept it in error. This allows CRC or size protected encapsulations to
++ * notice bulk transfers received with errors.
++ *
++ * In general none of the policies or strategies are able to cope with all errors
++ * without missing errors and dropping good data. The intent is to minimize the amount
++ * of potentially bad data getting to the function driver while minimizing the amount of
++ * good data that is dropped.
++ *
++ * The new silicon mitigates this problem for non control endpoints because it will NAK
++ * additional data until the interrupt service flag is reset.
++ *
++ * Start with generic error tests, OF, UF or NAK indicate an error we cannot recover
++ * from, start flushing until end of current bulk transfer (wait for a short packet)
++ *
++ */
++ if (rds & (USBDEV_FSTAT_OF | USBDEV_FSTAT_UF)) {
++ TRACE_MSG2(PCD, "BULK OUT FLUSHING %d length: %d", bytes, urb->actual_length);
++ THROW(start_flushing);
++ }
++ rds = rds & USBDEV_FSTAT_FCNT_MASK;
++ nrds = au_readl(ep->rds);
++ if (64 == bytes) {
++ TRACE_MSG2(PCD, "BULK OUT 64 BYTES %d length: %d", bytes, urb->actual_length);
++ /* full size packet received, check that we are not flushing and that the FIFO
++ * does not have any data. If there is data in the FIFO we may not be able to
++ * restart DMA in time, so start flushing
++ */
++ if (endpoint->rcv_error) {
++ TRACE_MSG4(PCD, "FULL PACKET bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if ((nrds > 6) && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "FIFO not empty bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING nrds > 6 < 8",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if (!urb->actual_length)
++ TRACE_MSG4(PCD, "PACKET ok bytes: %d rds: %d nrds: %d cp0: %d ACCEPTING 64 bytes",
++ bytes, rds, nrds, cp0_count);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ au_rcv_complete_irq(endpoint, 64, 0);
++ if (cs & USBDEV_CS_NAK)
++ if (nrds && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING CS_NAK",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ }
++ else if ((cs & USBDEV_CS_NAK) && (!nrds || (nrds == 8)) ) {
++ TRACE_MSG2(PCD, "BULK OUT NAK BYTES %d length: %d", bytes, urb->actual_length);
++ /* a nak'd packet may be ok to ignore IFF the FIFO is empty(?) or completely full.
++ */
++ if (endpoint->rcv_error) {
++ TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ }
++ else {
++ TRACE_MSG2(PCD, "BULK OUT < 64 BYTES %d length: %d", bytes, urb->actual_length);
++ /* short packet by DMA, additional data for this packet in FIFO, more than 3
++ * bytes is probably an error.
++ */
++ if ((cs & USBDEV_CS_NAK) && nrds && (nrds < 8) ) {
++ TRACE_MSG4(PCD, "BULK OUT NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ if (nrds > 4) {
++ TRACE_MSG4(PCD, "BULK OUT SHORT PACKET by DMA full FIFO bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING",
++ bytes, rds, nrds, cp0_count);
++ THROW(start_flushing);
++ }
++ TRACE_MSG4(PCD, "BULK OUT SHORT bytes: %d rds: %d nrds: %d cp0: %d reading fifo", bytes, rds, nrds, cp0_count);
++ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, nrds);
++ bytes += nrds;
++ TRACE_MSG1(PCD, "BULK OUT < 64 BYTES %d", bytes);
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ if (!endpoint->rcv_error) {
++ TRACE_MSG0(PCD, "BULK OUT COMPLETED URB");
++ au_rcv_complete_irq(endpoint, bytes, 0);
++ }
++ else {
++ TRACE_MSG0(PCD, "BULK OUT - FLUSHING URB - reseting rcv_error");
++ endpoint->rcv_error = 0;
++ }
++ }
++ CATCH(start_flushing) {
++ TRACE_MSG0(PCD, "BULK OUT - START FLUSHING URB");
++ endpoint->rcv_error = 1;
++ endpoint->rcv_urb->actual_length = 0;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ bytes = 0;
++ }
++ TRACE_MSG0(PCD, "BULK OUT - RESTARTING");
++ au_start_out_bulk(epn, endpoint, ep);
++}
++
++static void au_start_out_iso(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
++{
++ int outdma = ep->outdma;
++ RETURN_IF(!endpoint->rcv_urb);
++ au_start_dma_out(outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
++}
++
++static void au_out_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
++{
++ int bytes = 0;
++ struct usbd_urb *urb;
++ u32 cs;
++ u32 rds;
++ au_halt_dma(au_get_dma_chan(ep->outdma));
++ cs = au_readl(ep->cs);
++ rds = au_readl(ep->rds);
++ if (!endpoint) {
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ return;
++ }
++ if (!(urb = endpoint->rcv_urb)) {
++ TRACE_MSG2(PCD, "ISO OUT EPN - rcv_urb was NULL bytes: %d rds: %d", bytes, rds);
++ au_rcv_complete_irq(endpoint, bytes, 1);
++ TRACE_MSG0(PCD, "ISO OUT setting rcv_error");
++ }
++ bytes = endpoint->wMaxPacketSize - au_get_dma_residue(au_get_dma_chan(ep->outdma));
++ rds = rds & USBDEV_FSTAT_FCNT_MASK;
++ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, rds);
++ bytes += rds;
++ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
++ au_rcv_complete_irq(endpoint, bytes, 0);
++ au_start_out_iso(epn, endpoint, ep);
++}
++/* ********************************************************************************************* */
++/* au_tx_dma_done - TX DMA interrupt handler
++ */
++static void au_tx_dma_done(int irq, void *dev_id, struct pt_regs *regs)
++{
++ int epn = (int) dev_id;
++ struct usbd_endpoint_instance *endpoint = pcd_instance->bus->endpoint_array + epn;
++ struct ep_regs *ep = &ep_regs[epn];
++ int residue;
++#if 0
++ int indma = irq - 6;
++ struct dma_chan *chan = get_dma_chan(indma);
++#endif
++#ifdef DBDMA
++#else /* DBDMA */
++ struct dma_chan *chan = get_dma_chan(ep->indma);
++ u32 mode = au_readl(chan->io + DMA_MODE_READ);
++ TRACE_MSG1(PCD, "TX DMA done: mode: %x", mode);
++ if (mode & DMA_D0)
++ au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
++ if (mode & DMA_D1)
++ au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
++#endif /* DBDMA */
++ ocd_ops.interrupts++;
++ RETURN_IF (!epn);
++ au_halt_dma(au_get_dma_chan(ep->indma));
++ residue = au_get_dma_residue(au_get_dma_chan(ep->indma));
++ TRACE_MSG2(PCD, "TX DMA IRQ - epn %d residue %d", epn, residue);
++ if (!au1x00_new_silicon) {
++ /* XXX magic delay - without this large packets will eventually stall the transmit
++ * XXX and all traffic in both directions will stop.
++ */
++ udelay(8);
++ pcd_tx_complete_irq (endpoint, residue?1:0);
++ au_epn_interrupt_enable(epl2p[endpoint->bEndpointAddress&0xf]);
++ }
++ ep->last = 0;
++}
++
++/* au_int_req - usb interrupt handler
++ */
++static void au_int_req (int irq, void *dev_id, struct pt_regs *regs)
++{
++ u32 intstat;
++ struct ep_regs *ep;
++#if defined(MAX_INTR_LOOP_STATS)
++ u32 loopcount = 0;
++#endif
++#ifdef RECORD_LATENCY
++ cp0_count = (read_c0_count(CP0_COUNT) - cp0_record) >> 9;
++ if (cp0_count < CP0_COUNTS)
++ cp0_counts[cp0_count]++;
++#endif
++#ifdef CHECK_LATENCY
++ u32 cp0_count = read_c0_count(CP0_COUNT);
++#endif
++ ocd_ops.interrupts++;
++#if 0
++ if (ocd_ops.interrupts > 2000) {
++ TRACE_MSG0(PCD, "UDC_INT call udc_disable_interrupts");
++ au_inten(0);
++ return;
++ }
++#endif
++ while (( intstat = au_readl(USBD_INTSTAT) & au1x00_inten)) { // read and reset interrupt status register
++
++ int epn;
++#if 1
++ for (epn = 2; epn < 6; epn++) {
++ CONTINUE_IF (!(intstat & (1 << epn)));
++#else
++ // NOT TESTED
++ u32 local_intstat = intstat;
++ TRACE_MSG2(PCD, "INTSTAT: %04x %04x", intstat, au_readl(USBD_INTEN));
++ while (local_intstat & 0x3f) {
++ int epn = 31 - au_clz(local_intstat);
++ local_intstat &= ~(1<<epn);
++#endif
++ if (udc_saw_bus_activity) {
++ udc_saw_bus_activity = 0;
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_ACTIVITY, 0);
++ au_inten(0x0033|USBDEV_INT_SOF);
++ }
++ ep = &ep_regs[epn];
++ switch(ep->eptype) {
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ //TRACE_MSG2(PCD, "BULK IN %d %02x", epn, ep->eptype);
++ au_in_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ //TRACE_MSG2(PCD, "ISO IN %d %02x", epn, ep->eptype);
++ au_in_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ //TRACE_MSG2(PCD, "BULK OUT %d %02x", epn, ep->eptype);
++ au_out_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ //TRACE_MSG2(PCD, "ISO OUT %d %04d", epn, au_readl(NUSBD_FRAMENUM));
++ au_out_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
++ break;
++ }
++ }
++ au_writel(intstat, USBD_INTSTAT); // Only clear the interrupt(s) AFTER servicing OUT
++ /* even though we disable the bulk-in interrupt (endpoint 2) prior to enabling
++ * DMA we always see one additional interrupt that is a NAK on that endpoint.
++ */
++ CONTINUE_IF(!(intstat & au1x00_inten));
++ /* handle control endpoint and suspend interrupt
++ */
++ if (intstat & ( ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | USBDEV_INT_SOF))) {
++ if (intstat & (1 << 0))
++ au_out_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
++ if (intstat & (1 << 1))
++ au_in_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
++ if (intstat & USBDEV_INT_SOF)
++ if (USBD_SUSPENDED == pcd_instance->bus->status) {
++ TRACE_MSG0(PCD, "SUS - ACTIVITY");
++ udc_saw_bus_activity++;
++ }
++ }
++#if defined(MAX_INTR_LOOP_STATS)
++ loopcount += 1; // Gather stats on how many times this loop is performed.
++#endif
++ }
++#if defined(MAX_INTR_LOOP_STATS)
++ interrupt_loop_stats[MIN(loopcount, MAX_INTR_LOOP_STATS)]++;
++#endif
++#if defined(CHECK_LATENCY)
++ TRACE_MSG1(PCD, "USB IRQ - %d", read_c0_count(CP0_COUNT) - cp0_count);
++#endif
++#if defined(RECORD_LATENCY)
++ cp0_record = read_c0_count(CP0_COUNT);
++#endif
++}
++
++/* au_int_sus -suspend interrupt handler
++ */
++static void au_int_sus (int irq, void *dev_id, struct pt_regs *regs)
++{
++ ocd_ops.interrupts++;
++ TRACE_MSG2(PCD, "SUS - INACTIVE device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
++ switch(pcd_instance->bus->status) {
++ case USBD_OPENING:
++ case USBD_OK:
++ au_inten(0x0033);
++ usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_INACTIVE, 0);
++ break;
++ default:
++ break;
++ }
++}
++/* ********************************************************************************************* */
++/*
++ * au_connect - enable pullup resistor
++ * Turn on the USB connection by enabling the pullup resistor.
++ *
++ * au_disconnect - disable pullup resistor
++ * Turn off the USB connection by disabling the pullup resistor.
++ */
++
++#if defined(CONFIG_MIPS_PICOENGINE_MVCI)
++void au_connect (struct pcd_instance *pcd)
++{
++ extern void pico_mvci_set_usb_pullup(int);
++ pico_mvci_set_usb_pullup(1);
++}
++
++void au_disconnect (struct pcd_instance *pcd)
++{
++ extern void pico_mvci_set_usb_pullup(int);
++ pico_mvci_set_usb_pullup(0);
++}
++
++#elif defined(CONFIG_MIPS_FREEHAND_NATIVE)
++void au_connect (struct pcd_instance *pcd)
++{
++ au1000gpio_set(GPIO01);
++}
++
++void au_disconnect (struct pcd_instance *pcd)
++{
++ au1000gpio_clear(GPIO01);
++}
++#elif defined(CONFIG_AMX_MORDOR)
++void au_connect (struct pcd_instance *pcd)
++{
++ au_writel(0x00000008, SYS_OUTPUTSET);
++}
++
++void au_disconnect (struct pcd_instance *pcd)
++{
++ au_writel(0x00000008, SYS_OUTPUTCLR);
++}
++#else
++void au_connect (struct pcd_instance *pcd)
++{
++}
++void au_disconnect (struct pcd_instance *pcd)
++{
++}
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
++#undef read_c0_prid
++#define read_c0_prid() read_32bit_cp0_register(CP0_PRID)
++#endif
++#undef read_c0_COUNT
++#ifndef read_c0_count
++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
++#endif
++/* au_loc_conn - used to enable or disable peripheral connecting to bus
++ *
++ */
++void au_loc_conn(struct otg_instance *otg, u8 flag)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)otg->pcd;
++ TRACE_MSG0(PCD, "--");
++ TRACE_MSG1(PCD, "PCD: %x", (int)pcd);
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_SET");
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Enable DP PULLUP");
++ au_connect(pcd);
++ break;
++
++ case RESET:
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET");
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Disable DP PULLUP");
++ au_disconnect(pcd);
++ break;
++
++ case PULSE:
++ TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_PULSE");
++ break;
++ }
++}
++
++/* ********************************************************************************************* */
++/* au_ticks - get current ticks
++* */
++u64 au_ticks (void)
++{
++ return read_c0_count();
++}
++
++/* au_elapsed - return micro-seconds between two tick values
++ */
++u64 au_elapsed(u64 *t1, u64 *t2)
++{
++ u64 ticks = (*t1 > *t2) ? (*t1 - *t2) : (*t2 - *t1);
++ ticks = (u32)((u32) ticks / (u32) CONFIG_OTG_AU1X00_SCLOCK);
++ return ticks;
++}
++
++/* au_framenum - get current framenum
++ */
++u16 au_framenum (void)
++{
++ return au_readl(NUSBD_FRAMENUM);
++}
++
++
++/* ********************************************************************************************* */
++/* au_start_endpoint_in - start transmit
++ */
++void au_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
++ case USB_ENDPOINT_CONTROL:
++ au_in_ep0(endpoint, ep);
++ break;
++ case USB_ENDPOINT_BULK:
++ case USB_ENDPOINT_INTERRUPT:
++ au_start_in_bulk(epn, endpoint, ep);
++ break;
++ case USB_ENDPOINT_ISOCHRONOUS:
++ au_start_in_iso(epn, endpoint, ep);
++ break;
++ }
++ if (au1x00_new_silicon)
++ au_epn_interrupt_enable(epn);
++}
++
++/* au_start_endpoint_out - start receive
++ */
++void au_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ int epn = epl2p[endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
++ case USB_ENDPOINT_CONTROL:
++ break;
++ case USB_ENDPOINT_BULK:
++ case USB_ENDPOINT_INTERRUPT:
++ au_start_out_bulk(epn, endpoint, ep);
++ au_epn_interrupt_enable(epn);
++ break;
++ case USB_ENDPOINT_ISOCHRONOUS:
++ au_start_out_iso(epn, endpoint, ep);
++ break;
++ }
++}
++
++void au_cancel_in_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
++{
++ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ au_in_bulk(epn, ep, urb->endpoint);
++}
++
++void au_cancel_out_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
++{
++ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
++ struct ep_regs *ep = &ep_regs[epn];
++ au_out_bulk(epn, ep, urb->endpoint);
++}
++
++/* au_serial_init - set a serial number if available
++ */
++int au_serial_init (struct pcd_instance *pcd)
++{
++#if defined(CONFIG_MIPS_FREEHAND)
++ int length;
++ long data[16]; /* yeah a hack, but we KNOW it's 16 */
++ struct i2c_client *client;
++ char chData[16];
++ int i;
++
++ if (!(client = getFreeHandEepromClient())) {
++ printk(KERN_INFO"eeprom not ready when au_serial_init called\n");
++ return -EINVAL;
++ }
++ eeprom_contents(client, SENSORS_PROC_REAL_READ, EEPROM_SYSCTL1, &length, (long *)data);
++
++ /* serial number is first 9 longs. But each long is just an ASCII char
++ * convert this to a string and then extract a 4 byte value from it
++ */
++ for (i = 0; i < 9; chData[i] = (char)data[i], i++); /* trunc, is ok */
++ chData[9] = 0; /* terminate string */
++ printk(KERN_INFO"%s: %s\n", __FUNCTION__, chData);
++ pcd_instance->bus->serial_number_str = lstrdup(chData);
++ return 0;
++#else
++ return -EINVAL;
++#endif
++}
++
++
++#ifdef DBDMA
++static int request_dma(int ep, int src, int dest, char *str, void dma_done(int , void *, struct pt_regs *))
++{
++ unsigned int dma;
++
++ if ((dma = au1xxx_dbdma_chan_alloc(src, dest, dma_done, (void *)ep)) < 0) {
++ printk(KERN_INFO"request_io[%d] dma: %X src: %x dest: %x %s FAILED\n", ep, dma, src, dest, str);
++ return -1;
++ }
++
++ au1xxx_dbdma_set_devwidth(dma, 16);
++
++ if(au1xxx_dbdma_ring_alloc(dma, 4) == 0) {
++ printk(KERN_INFO"Ring Buffer Allocation for dma: %X src: %x dest: %x %s FAILED\n", ep, dma, src, dest, str);
++ return -1;
++ }
++ printk(KERN_INFO"request_io[%d] dma: %X src: %x dest: %x %s SUCCEDED\n", ep, dma, src, dest, str);
++ return dma;
++}
++#else /* DBDMA */
++static int request_dma(int ep, int id, char *str, void dma_done(int , void *, struct pt_regs *))
++{
++ int dma = request_au1000_dma(id, str, dma_done, SA_INTERRUPT, (void *)ep);
++ if (dma >= 0) return dma;
++ printk(KERN_INFO"request_io[%d] dma: %d id: %x %s FAILED\n", ep, dma, id, str);
++ return -1;
++}
++#endif /* DBDMA */
++
++/* au_start - start session
++ */
++void au_start (struct pcd_instance *pcd)
++{
++ au_inten(0x0033|USBDEV_INT_SOF); // Only enable receive interrupts.
++}
++
++/* au_stop - stop session
++ */
++void au_stop (struct pcd_instance *pcd)
++{
++ au_inten(0);
++}
++
++int au_assign_endpoint( u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
++ u16 wMaxPacketSize, u16 transferSize)
++{
++ struct ep_regs *ep = &ep_regs[physicalEndpoint];
++ RETURN_EINVAL_IF(used[physicalEndpoint]);
++ endpoint_map->bEndpointAddress[0] = epp2l[physicalEndpoint];
++ endpoint_map->physicalEndpoint[0] = physicalEndpoint;
++ endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
++ endpoint_map->transferSize[0] = transferSize;
++ endpoint_map->bmAttributes[0] = bmAttributes;
++ used[physicalEndpoint]++;
++ ep->eptype = bmAttributes & 0x83;
++ return 0;
++}
++
++int au_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested,
++ struct usbd_endpoint_request *requestedEndpoints)
++{
++ struct usbd_device_description *device_description;
++ int i, j;
++ int used[UDC_MAX_ENDPOINTS];
++ memset(used, 0, sizeof(used));
++ for (j = 0, i = 0; i < endpointsRequested; i++, j++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ u8 bmAttributes = requestedEndpoints[i].bmAttributes;
++ u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
++ RETURN_EINVAL_UNLESS(j < UDC_MAX_ENDPOINTS);
++ switch(bmAttributes) {
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ break;
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ break;
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, transferSize, transferSize));
++ break;
++ }
++ CONTINUE_IF(bmAttributes & USB_ENDPOINT_OPT);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++int au_set_endpoints(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
++{
++ int i, j;
++ u8 config[25];
++ u8 *cp;
++ memcpy(config, au1x00_config_bulk, sizeof(config));
++ for (i = 0; i < endpointsRequested; i++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ int epreq = endpoint_map->bmAttributes[0];
++ int eptype = epreq & USB_ENDPOINT_MASK;
++ int epdir = epreq & USB_ENDPOINT_DIR_MASK ? 0x8 : 0;
++ int epsize = endpoint_map->wMaxPacketSize[0];
++ int epaddr = epp2l[endpoint_map->physicalEndpoint[0]];
++ CONTINUE_IF(!endpoint_map->physicalEndpoint[0] || (endpoint_map->physicalEndpoint[0] > 5));
++ cp = config + ((endpoint_map->physicalEndpoint[0] - 1) * 5);
++ cp[0] = (epaddr & 0xf) << 4 | 0x4;
++ cp[1] = (eptype << 4) | epdir | (epsize & 0x380) >> 7;
++ cp[2] = (epsize & 0x7F) << 1;
++ }
++ au_inten(0); // disable interrupts
++ au_writel(0x0002, USBD_ENABLE); // reset controller
++ udelay(100);
++ au_writel(0x0003, USBD_ENABLE); // enable controller
++ udelay(100);
++ for (cp = config, i = 0; i < 25; i++, au_writel(*cp++, USBD_CONFIG)); // feed the config into the UDC
++ return 0;
++}
++/* ********************************************************************************************* */
++/* au_mod_init
++ */
++int au_mod_init (void)
++{
++ int dev = request_irq (AU1000_USB_DEV_REQ_INT, au_int_req, SA_INTERRUPT, UDC_NAME "UDC Req", NULL);
++ int sus = request_irq (AU1000_USB_DEV_SUS_INT, au_int_sus, SA_INTERRUPT, UDC_NAME "UDC Sus", NULL);
++ u32 cp0_prid = read_c0_prid();
++ int i;
++
++
++ if (dev || sus) { // check if either request irq failed
++ if (!dev) free_irq (AU1000_USB_DEV_REQ_INT, NULL); // free irqs that might have
++ if (!sus) free_irq (AU1000_USB_DEV_SUS_INT, NULL); // been successfully allocated
++ return -EINVAL;
++ }
++#ifdef DBDMA
++ for (i = 0; i < 6; i++) {
++ ep_regs[i].indma = ep_regs[i].tx_id ?
++ request_dma(i, DBDMA_MEM_CHAN, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
++ ep_regs[i].outdma = ep_regs[i].rx_id ?
++ request_dma(i, ep_regs[i].rx_id, DBDMA_MEM_CHAN, ep_regs[i].rx_str, NULL) : -1;
++ }
++#else /*DBMA */
++ for (i = 0; i < 6; i++) {
++ ep_regs[i].indma = ep_regs[i].tx_id ? request_dma(i, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
++ ep_regs[i].outdma = ep_regs[i].rx_id ? request_dma(i, ep_regs[i].rx_id, ep_regs[i].rx_str, NULL) : -1;
++ }
++#endif /*DBMA */
++ switch (cp0_prid & CP0_PRID_SOC_MASK) {
++ case CP0_PRID_AU1000:
++ case CP0_PRID_AU1100:
++ au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 4;
++ printk(KERN_INFO"%s: AU1100 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
++ break;
++ case CP0_PRID_AU1500:
++ au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 2;
++ printk(KERN_INFO"%s: AU1500 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
++ break;
++ case CP0_PRID_AU1550:
++ au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 0;
++ printk(KERN_INFO"%s: AU1550 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
++ break;
++ default:
++ printk(KERN_INFO"%s: UNKNOWN CPU cp0_prid: %08x UNKNOWN UDC\n", __FUNCTION__, cp0_prid);
++ break;
++ }
++ return 0;
++}
++
++/* au_mod_exit
++ */
++void au_mod_exit (void)
++{
++ int j;
++ au_writel(0x0000, USBD_ENABLE);
++ for (j = 0; j < 6; j++) {
++ struct ep_regs *ep = &ep_regs[j];
++#ifdef DBDMA
++ if (ep->indma != -1) {
++ au1xxx_dbdma_chan_free(ep->indma);
++ ep->indma = -1;
++ }
++ if (ep->outdma != -1) {
++ au1xxx_dbdma_chan_free(ep->outdma);
++ ep->outdma = -1;
++ }
++#else /*DBMA */
++ if (ep->indma != -1) {
++ free_au1000_dma(ep->indma);
++ ep->indma = -1;
++ }
++ if (ep->outdma != -1) {
++ free_au1000_dma(ep->outdma);
++ ep->outdma = -1;
++ }
++#endif /*DBMA */
++ }
++ free_irq (AU1000_USB_DEV_REQ_INT, NULL);
++ free_irq (AU1000_USB_DEV_SUS_INT, NULL);
++#if defined(MAX_INTR_LOOP_STATS)
++ {
++ u32 lc;
++ for (lc = 0; lc <= MAX_INTR_LOOP_STATS; lc++)
++ if (interrupt_loop_stats[lc])
++ printk(KERN_ERR "%s: interrupt loopcount[%02u] %9u\n", __FUNCTION__, lc,interrupt_loop_stats[lc]);
++ printk(KERN_INFO"%s: halt_dma_expired: %d\n", __FUNCTION__, au_halt_dma_expired);
++ }
++#endif
++#ifdef RECORD_LATENCY
++ {
++ int i;
++ for (i = 0; i < CP0_COUNTS; i++)
++ if (cp0_counts[i])
++ printk(KERN_INFO"%s: cp0_counts[%d] %d\n", __FUNCTION__, i, cp0_counts[i]);
++ }
++#endif
++}
++
++/* ********************************************************************************************* */
++struct usbd_pcd_ops usbd_pcd_ops = {
++ max_endpoints: UDC_MAX_ENDPOINTS,
++ ep0_packetsize: EP0_PACKETSIZE,
++ name: UDC_NAME,
++ start: au_start,
++ stop: au_stop,
++ start_endpoint_in: au_start_endpoint_in,
++ start_endpoint_out: au_start_endpoint_out,
++ request_endpoints: au_request_endpoints,
++ set_endpoints: au_set_endpoints,
++ cancel_in_irq: au_cancel_in_irq,
++ cancel_out_irq: au_cancel_out_irq,
++ serial_init: au_serial_init,
++};
++
++struct pcd_ops pcd_ops = {
++ pcd_en_func: pcd_en_func,
++ mod_init: au_mod_init,
++ mod_exit: au_mod_exit,
++};
++
++struct ocd_ops ocd_ops = {
++ #if defined(CONFIG_OTG_TR_AUTO)
++ capabilities: OCD_CAPABILITIES_TR | OCD_CAPABILITIES_AUTO,
++ #else
++ capabilities: OCD_CAPABILITIES_TR,
++ #endif
++ ticks: au_ticks,
++ elapsed: au_elapsed,
++};
++
++struct tcd_ops tcd_ops = {
++ dp_pullup_func: au_loc_conn,
++};
++
+diff -uNr linux/drivers/no-otg/ocd/au1x00/au1x00.h linux/drivers/otg/ocd/au1x00/au1x00.h
+--- linux/drivers/no-otg/ocd/au1x00/au1x00.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/au1x00/au1x00.h 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,112 @@
++/*
++ * otg/ocd/au1x00/au1100.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++ /*!
++ * @defgroup AU1X00 AMD AU1X00
++ * @ingroup pcdgroup
++ */
++
++/*!
++ * @file otg/ocd/au1x00/au1x00.h
++ * @brief AU1X00 Header
++ *
++ * This file contains the private defines and structures for the AU1X00
++ * Drivers.
++ *
++ * @ingroup AU1X00
++ */
++
++
++
++/*
++ *
++ * au1100
++ *
++ * The au1100 does not seem to work properly with an 8 byte
++ * packetsize. So 16, 32 or 64 are the only valid values.
++ *
++ * Unfortunately this means that a DMA channel is required for
++ * EP0 transmit.
++ */
++
++#define EP0_PACKETSIZE 0x8
++
++#define UDC_MAX_ENDPOINTS 6
++
++#define UDC_NAME "AU1100"
++
++#define NUSBD_EP0RD 0xB0200000
++#define NUSBD_EP0WR 0xB0200004
++#define NUSBD_EP1WR 0xB0200008
++#define NUSBD_EP2WR 0xB020000C
++#define NUSBD_EP3RD 0xB0200010
++#define NUSBD_EP4RD 0xB0200014
++
++#define NUSBD_EP0CS 0xB0200024
++#define NUSBD_EP1CS 0xB0200028
++#define NUSBD_EP2CS 0xB020002C
++#define NUSBD_EP3CS 0xB0200030
++#define NUSBD_EP4CS 0xB0200034
++
++#define NUSBD_EP0RDSTAT 0xB0200040
++#define NUSBD_EP0WRSTAT 0xB0200044
++#define NUSBD_EP1WRSTAT 0xB0200048
++#define NUSBD_EP2WRSTAT 0xB020004C
++#define NUSBD_EP3RDSTAT 0xB0200050
++#define NUSBD_EP4RDSTAT 0xB0200054
++
++#define NUSBD_FRAMENUM 0xB0200038
++
++enum {
++ NDMA_ID_UART0_TX = 0,
++ NDMA_ID_UART0_RX,
++ NDMA_ID_GP04,
++ NDMA_ID_GP05,
++ NDMA_ID_AC97C_TX,
++ NDMA_ID_AC97C_RX,
++ NDMA_ID_UART3_TX,
++ NDMA_ID_UART3_RX,
++ NDMA_ID_USBDEV_EP0_RX,
++ NDMA_ID_USBDEV_EP0_TX,
++ NDMA_ID_USBDEV_EP1_TX,
++ NDMA_ID_USBDEV_EP2_TX,
++ NDMA_ID_USBDEV_EP3_RX,
++ NDMA_ID_USBDEV_EP4_RX,
++ NDMA_ID_I2S_TX,
++ NDMA_ID_I2S_RX,
++ NDMA_NUM_DEV
++};
++
++typedef struct ep_regs {
++ int rd;
++ int wr;
++ int cs;
++ int rds;
++ int wrs;
++ int rx_id;
++ int tx_id;
++ char * rx_str;
++ char * tx_str;
++ u32 indma;
++ u32 outdma;
++ int last;
++ int eptype;
++} ep_regs_t;
++
++#define MAX_EPN_PACKET_SIZE 64
++#define CP0_PRID_SOC_MASK 0xff000000
++#define CP0_PRID_AU1000 0x00000000
++#define CP0_PRID_AU1500 0x01000000
++#define CP0_PRID_AU1100 0x02000000
++#define CP0_PRID_AU1550 0x03000000 /* AMX */
++
++#define CP0_PRID_REV_MASK 0x000000ff
++
+diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-hcd.c linux/drivers/otg/ocd/fsotg/fs-hcd.c
+--- linux/drivers/no-otg/ocd/fsotg/fs-hcd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/fsotg/fs-hcd.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,1527 @@
++/*
++ * otg/hcd/fsotg/fs-hcd.c - Freescale USBOTG aware Host Controller Driver (HCD)
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ */
++/*!
++ * @file otg/ocd/fsotg/fs-hcd.c
++ * @brief Freescale USB Host Controller Driver
++ *
++ * This is the hardware specific component of the HCD. It knows nothing
++ * about URBs, and deals with "transfers". This is not because it shouldn't
++ * know about them, but because URBs are generic, and so it seems reasonable
++ * to keep as much generic code in the hardware independent portion as
++ * possible. As a result, the parameter list to hcd_hw_start_transfer()
++ * is really fat.
++ *
++ * This is not compiled as a self contained module, but is linked with
++ * the generic component hc_xfer.o.
++ *
++ * There is some processor specific code here to support the alternate processors
++ * that implement this type of USB support.
++ *
++ * There is no board or platform level code here.
++ *
++ * @ingroup FSOTG
++ * @{
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/pci.h> // For DMA directions
++//#include <linux/slab.h>
++#include <linux/errno.h>
++
++#include <linux/usb.h>
++#include <linux/delay.h>
++#include <asm/arch/mx2.h>
++
++#include <otg/otg-compat.h>
++
++#include "../core/hcd.h"
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-utils.h>
++
++#include <otg/otg-hcd.h>
++#include <otg/hcd-l26.h>
++#include <otg/hcd-rh.h>
++#include <otg/hcd-hw.h>
++
++#include <otghw/fsotg-hardware.h>
++
++#ifndef CONFIG_OTG_ROOTHUB_VENDORID
++#define CONFIG_OTG_ROOTHUB_VENDORID 0x15ec
++#endif
++#ifndef CONFIG_OTG_ROOTHUB_PRODUCTID
++#define CONFIG_OTG_ROOTHUB_PRODUCTID 0xf010
++#endif
++#ifndef CONFIG_OTG_ROOTHUB_BCDDEVICE
++#define CONFIG_OTG_ROOTHUB_BCDDEVICE 0x0100
++#endif
++
++
++#define STATIC static
++extern void hcd_trace_mem(otg_tag_t tag, char *fn, char *msg, int len, volatile void *data);
++
++// Start of hardware specific components....
++
++/* ********************************************************************************************* */
++
++// Globals for debug
++static u32 monitoring_etd_mask = 0; // 0 == no monitoring
++static u32 monitoring_etd_num;
++#define MAX_ETD_FRAMES 3
++static u32 current_etd_frame;
++static u32 done_flags[1+MAX_ETD_FRAMES];
++static u32 done_status[1+MAX_ETD_FRAMES];
++static endpoint_transfer_descriptor mon_etd[1+MAX_ETD_FRAMES];
++
++
++
++/*!
++ * @struct cc_name
++ * @brief Map CC values to names
++ */
++static char *cc_name[] = {
++ "no error", "CRC error", "bitstuff error", "data toggle error",
++ "stall", "device not responding", "PID failure" "reserved",
++ "data overrun", "data underrun", "ACK", "NAK", "buffer overrun",
++ "buffer underrun", "schedule overrun" "not accessed"
++};
++
++
++/*!
++ * comp_code_to_status() - map condition cod3 to errno value
++ * @param cc condition code
++ * @return errno value
++ */
++STATIC int comp_code_to_status(int cc)
++{
++ //
++ if (cc)
++ TRACE_MSG2(HCD,"NON-ZERO CC=%d %s", cc,cc_name[cc]);
++
++ switch (cc) {
++ case ETD_CC_NOERROR: return 0;
++ case ETD_CC_CRCERR: return -EILSEQ;
++ case ETD_CC_BITSTUFFERR: return -EPROTO;
++ case ETD_CC_DATATOGERR: return -EPROTO; // I guess, nothing else looks better.
++ case ETD_CC_STALL: return -EPIPE;
++ case ETD_CC_DEVNOTRESPONDING: return -ETIMEDOUT;
++ case ETD_CC_PIDFAILURE: return -EPROTO;
++ case ETD_CC_DATAOVERRUN: return -EOVERFLOW;
++ case ETD_CC_DATAUNDERRUN: return -EREMOTEIO;
++ case ETD_CC_ACK: return -EPROTO; // For lack of anything better
++ case ETD_CC_NAK: return -EPROTO; // For lack of anything better
++ case ETD_CC_BUFFEROVERRUN: return -ECOMM;
++ case ETD_CC_BUFFERUNDERRUN: return -ENOSR;
++ case ETD_CC_SCHEDOVERRUN: return -ENOSPC;
++ case ETD_CC_NOTACCESSED: return -EPROTO; // For lack of anything better
++ default: return -EINVAL;
++ }
++}
++
++/*!
++ * rel_etd() - release etd
++ * {get,rel}_etd maintain a free list of ETDs by saving the index of the next free ETD in the
++ * etd->xbufsrtad field. The list is terminated by 0x0000ffff. List manipulation needs to be
++ * protected by irq_lock, since ETDs are released in the interrupt handler, but allocated at
++ * regular priority.
++ * @param fs_hcpriv
++ * @param etdn
++ */
++STATIC void rel_etd(fs_hcpriv *fs_hcpriv, int etdn)
++{
++ fs_wl(etd_word(etdn, 0), 0);
++ fs_wl(etd_word(etdn, 2), 0);
++ fs_wl(etd_word(etdn, 3), 0);
++ fs_wl(etd_word(etdn, 1), fs_hcpriv->free_etds);
++ fs_hcpriv->free_etds = etdn;
++}
++
++/*!
++ * get_etd() - get etd
++ * {get,rel}_etd maintain a free list of ETDs by saving the index of the next free ETD in the
++ * etd->xbufsrtad field. The list is terminated by 0x0000ffff. List manipulation needs to be
++ * protected by irq_lock, since ETDs are released in the interrupt handler, but allocated at
++ * regular priority.
++ * @param fs_hcpriv
++ * @return int
++ */
++STATIC int get_etd(fs_hcpriv *fs_hcpriv)
++{
++ // Return the index of an available ETD, or -1 if none are available.
++ unsigned long flags;
++ int etdn = -1;
++ local_irq_save(flags);
++ // Is list is empty?
++ if (0x0000ffff != (etdn = fs_hcpriv->free_etds))
++ fs_hcpriv->free_etds = fs_rl(etd_word(etdn, 1));
++ local_irq_restore(flags);
++ return etdn;
++}
++
++/* ********************************************************************************************* */
++/*
++ * For the generic transfer aware framework.
++ */
++
++// For debugging...
++static int num_urbs_started = 0;
++#define MAX_URBS_STARTED 0
++static char *dirpid_name[4] = {"SETUP","OUT","IN","WRONG"};
++//static char *direct_name[4] = {"TD00","OUT","IN","TD11"};
++static char *etd_urb_state_name[] = {"COMPLETED","SETUP_STATUS","SETUP_DATA","SETUP_PKT","BULK","INTERRUPT","ISOC","WRONG"};
++static char *format_name[4] = { "CONTROL", "ISO", "BULK", "INT", };
++
++
++/*!
++ * start_etd() - start an etd
++ * @param etdn
++ * @param len
++ * @param data
++ * @param out
++ */
++STATIC void start_etd(int etdn, int len, void *data, int out)
++{
++ if (len) {
++ consistent_sync(data,len, (out ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE));
++ fs_wl(OTG_DMA_ETD_MSA(etdn), virt_to_bus(data));
++ }
++ if (len || out)
++ fs_wl(OTG_DMA_ETD_EN, ETD_MASK(etdn));
++
++ fs_orl(OTG_HOST_IINT, ETD_MASK(etdn)); // Don't wait until SOF, interrupt ASAP.
++ fs_orl(OTG_HOST_ETD_DONE, ETD_MASK(etdn)); // Interrupt on ETD done (forget DMA interrupt).
++ fs_wl(OTG_HOST_ETD_EN, ETD_MASK(etdn));
++}
++
++/*!
++ * hcd_hw_start_transfer() - start a transfer
++ * Return 0..MAX_ACTIVE_XFERS-1 if the transfer is successfully started,
++ * -1 if there is something wrong with the requested transfer,
++ * -2 if there are no resources available at this time, but resubmission is OK.
++ *
++ * @param bus_hcpriv
++ * @param len length of data region
++ * @param data virtual address of data region
++ * @param toggle toggle value to start the xfer with
++ * @param maxps max packet size of endpoint
++ * @param slow 1 ==> slow speed, 0 ==> full speed QQSV verify: (((urb->pipe) >> 26) & 1)
++ * @param endpoint endpoint number
++ * @param address USB device address
++ * @param pid USB_PID_{OUT,IN,SETUP}
++ * @param format PIPE_{CONTROL,BULK,INTERRUPT,ISOCHRONOUS}
++ * @param other value depending on format
++ *
++ * PIPE_CONTROL: other == address of setup packet.
++ * PIPE_BULK: other == ZLP at end (T/F),
++ * PIPE_INTERRUPT: other == poll interval
++ */
++int hcd_hw_start_transfer(struct bus_hcpriv *bus_hcpriv, int len, void *data, int toggle, int maxps,
++ int slow, int endpoint, int address, int pid, int format, u32 other)
++{
++ fs_hcpriv *fs_hcpriv = (struct fs_hcpriv *) (bus_hcpriv->hw_hci);
++ fs_data_buff *x = NULL;
++ fs_data_buff *y = NULL;
++ int fmt = 0;
++ int out;
++ int etdn;
++ //int rc = 0;
++ int dir = 0;
++ endpoint_transfer_descriptor *sdp = NULL;
++ transfer_descriptor td;
++ int sdp_out = FALSE;
++
++ //TRACE_MSG8(HCD, "len: %d toggle: %d endpoint: %02x pid: %d format: %d address: %d %s %s",
++ // len, toggle, endpoint, pid, format, address, dirpid_name[pid], format_name[format]);
++
++ // data address needs to be on a 32-bit boundary.
++ if (0x3 & (u32)data) {
++ printk(KERN_ERR "%s: invalid data alignment for urb, urb rejected.\n",__FUNCTION__);
++ TRACE_MSG1(HCD, "invalid data alignment for urb (%08x), urb rejected.",(u32)data);
++ return -1;
++ }
++ num_urbs_started += 1;
++ if ((MAX_URBS_STARTED > 0) && (num_urbs_started > MAX_URBS_STARTED)) {
++ // Can the urb, don't touch the HW
++ printk(KERN_ERR "%s: ignoring urb %d\n",__FUNCTION__,num_urbs_started);
++ return -1;
++ }
++
++ /* Check pid, setup pid and out flags
++ */
++ switch (pid) {
++ case USB_PID_SETUP:
++ pid = ETD_DIRPID_SETUP;
++ out = TRUE;
++ break;
++ case USB_PID_OUT:
++ pid = ETD_DIRPID_OUT;
++ out = TRUE;
++ break;
++ case USB_PID_IN:
++ pid = ETD_DIRPID_IN;
++ out = FALSE;
++ break;
++ default:
++ TRACE_MSG1(HCD,"invalid PID %x",pid);
++ return -1;
++ }
++ switch (format) {
++ case PIPE_CONTROL:
++ case PIPE_BULK:
++ case PIPE_INTERRUPT:
++ td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len));
++ break;
++ default:
++ return -1;
++ }
++
++ /*
++ * 1. Allocate resources:
++ * a. X,Y buffers
++ * b. ETD (& matching DMA)
++ * 2. Set the registers
++ */
++ UNLESS ((x = get_data_buff(fs_hcpriv)) && (y = get_data_buff(fs_hcpriv)) && (0 <= (etdn = get_etd(fs_hcpriv)))) {
++ // Resource allocation failure, retry later is OK.
++ TRACE_MSG0(HCD,"resource allocation failure -> resubmit OK");
++ y = rel_data_buff(fs_hcpriv,y);
++ x = rel_data_buff(fs_hcpriv,x);
++ return -2;
++ }
++
++ // OK, we've got all we need.
++ td.w1.bufsrtad.y = data_buff_boff(y);
++ td.w1.bufsrtad.x = data_buff_boff(x);
++
++ switch (format) {
++ case PIPE_CONTROL:
++ fmt = ETD_FORMAT_CONTROL;
++ dir = ETD_DIRECT_TD00;
++
++ /* build setup data/status phase ETD for use after completion of 8 byte setup packet
++ */
++ fs_hcpriv->sdp_data[etdn] = data; // address of data phase buffer.
++ data = (void *) other; // address of setup packet.
++ sdp = &fs_hcpriv->sdp_etd[etdn];
++ memset((void*)sdp, 0, sizeof(endpoint_transfer_descriptor));
++
++ /* toggle is constant 0 for setup packet, and 1 for data and status phases,
++ * so toggle was overloaded to handle data phase direction. If len == 0, there
++ * is no data phase, so direction is IN.
++ */
++ sdp_out = (toggle && len > 0);
++ sdp->td.w1.val = td.w1.val;
++ sdp->td.w2.cb.flags = ETD_SET_DATATOGL((0x2|1)) | // toggle is always 1, for data or status phases.
++ ETD_SET_DELAYINT(0) | // when done, interrupt ASAP (wait for 0 frames)
++ ETD_SET_BUFROUND(1) | // Allow short recv xfers
++ ETD_SET_DIRPID((sdp_out?ETD_DIRPID_OUT:ETD_DIRPID_IN));
++ sdp->td.w2.cb.reserved = 0;
++ sdp->td.w2.cb.rtrydelay = 1; // Number of frames to wait before retry on failure.
++ sdp->td.w3.val = ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len);
++
++ /* build SETUP ETD for initial 8 byte setup packet
++ */
++ len = 8;
++ td.w2.cb.flags = ETD_SET_DATATOGL((0x2|0)) | // starting toggle is here, not TOGCRY, and is always 0.
++ ETD_SET_DELAYINT(0) | // when done, interrupt ASAP (wait for 0 frames)
++ ETD_SET_BUFROUND(1) | // Allow short recv xfers
++ ETD_SET_DIRPID(pid);
++ td.w2.cb.reserved = 0;
++ td.w2.cb.rtrydelay = 1; // Number of frames to wait before retry on failure.
++ td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len));
++
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_SETUP_START;
++
++ //TRACE_MSG3(HCD,"SETUP pkt, len=%d : %08x : %08x",len,*((u32*)(void*)data),*(1+(u32*)(void*)data));
++
++ /* Complete the setup data phase ETD.
++ */
++ sdp->epd = ETD_SET_MAXPKTSIZ(maxps) |
++ ETD_SET_TOGCRY(0) |
++ ETD_SET_FORMAT(ETD_FORMAT_BULK) |
++ ETD_SET_SPEED((slow?ETD_SPEED_LOW:ETD_SPEED_FULL)) |
++ ETD_SET_DIRECT(ETD_DIRECT_TD00) |
++ ETD_SET_ENDPNT(endpoint) |
++ ETD_SET_ADDRESS(address);
++
++ break;
++
++ case PIPE_BULK:
++ fmt = ETD_FORMAT_BULK;
++ dir = ETD_DIRECT_TD00;
++
++ //TRACE_MSG1(HCD,"BULK, starting toggle %x",toggle);
++ td.w2.cb.flags = ETD_SET_DATATOGL((0x2|toggle)) | // starting toggle is here, not TOGCRY
++ ETD_SET_DELAYINT(0) | // when done, interrupt ASAP (wait for 0 frames)
++ ETD_SET_BUFROUND(1) | // Allow short recv xfers
++ ETD_SET_DIRPID(pid);
++ td.w2.cb.reserved = 0;
++ td.w2.cb.rtrydelay = 0; // Number of frames to wait before retry on failure.
++
++ /* Set the state to indicate if a trailing ZLP is required.
++ */
++ fs_hcpriv->etd_urb_state[etdn] = ((other && out && 0 ==
++ (len % maxps)) ? ETD_URB_BULKWZLP_START : ETD_URB_BULK_START);
++ break;
++
++ case PIPE_INTERRUPT:
++ fmt = ETD_FORMAT_INTERRUPT;
++ dir = ETD_DIRECT_TD00;
++
++ //TRACE_MSG1(HCD,"INTERRUPT, starting toggle %x",toggle);
++ td.w2.intr.flags = ETD_SET_DATATOGL((0x2|toggle)) | // starting toggle is here, not TOGCRY
++ ETD_SET_DELAYINT(0) | // when done, interrupt ASAP (wait for 0 frames)
++ ETD_SET_BUFROUND(1) | // Allow short recv xfers
++ ETD_SET_DIRPID(pid);
++
++ td.w2.intr.relpolpos = (fs_rl(OTG_HOST_FRM_NUM) + 1) & 0xff; // Start next frame
++
++ td.w2.intr.polinterv = other & 0xff;
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_INTERRUPT_START;
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ fmt = ETD_FORMAT_ISOC;
++ dir = out ? ETD_DIRECT_OUT : ETD_DIRECT_IN;
++ td.w2.isoc.startfrm = (fs_rl(OTG_HOST_FRM_NUM) + 1) & 0xffff; // next frame
++ if (len > 1023) {
++ // Two frames needed, send 1023 in the first, remainder in the second.
++ td.w2.isoc.flags = ETD_SET_DELAYINT(0) | ETD_SET_AUTOISO(0) | ETD_SET_FRAMECNT(1);
++ td.w3.isoc.pkt0 = ETD_SET_PKTLEN(1023);
++ td.w3.isoc.pkt1 = ETD_SET_PKTLEN(len-1023);
++ }
++ else {
++ // Only one frame needed, send it all at once.
++ td.w2.isoc.flags = ETD_SET_DELAYINT(0) | ETD_SET_AUTOISO(0) | ETD_SET_FRAMECNT(0);
++ td.w3.isoc.pkt0 = ETD_SET_PKTLEN(len);
++ td.w3.isoc.pkt1 = 0;
++ }
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_ISOC_START;
++ break;
++ }
++
++ fs_wl(etd_word(etdn, 0), ETD_SET_MAXPKTSIZ(maxps) | ETD_SET_TOGCRY(0) | ETD_SET_FORMAT(fmt) |
++ ETD_SET_SPEED((slow ? ETD_SPEED_LOW : ETD_SPEED_FULL)) |
++ ETD_SET_DIRECT(dir) | ETD_SET_ENDPNT(endpoint) | ETD_SET_ADDRESS(address));
++
++ fs_wl(etd_word(etdn, 1), td.w1.val);
++ fs_wl(etd_word(etdn, 2), td.w2.val);
++ fs_wl(etd_word(etdn, 3), td.w3.val);
++
++ //TRACE_MSG5(HCD, "ETD[%02d] %08x %08x %08x %08x", etdn,
++ // fs_rl(etd_word(etdn, 0)), fs_rl(etd_word(etdn, 1)),
++ // fs_rl(etd_word(etdn, 2)), fs_rl(etd_word(etdn, 3)));
++
++ start_etd(etdn, len, data, out);
++ return etdn;
++}
++
++/*!
++ * finish_urb_irq() - called to complete transfer
++ * @param fs_hcpriv
++ * @param etdn
++ * @param killed
++ */
++STATIC void finish_urb_irq(fs_hcpriv *fs_hcpriv, int etdn, int killed)
++{
++ int cc = 0;
++ int next_toggle = 0;
++ int format = 0;
++ u32 remaining = 0;
++ fs_data_buff *x,*y;
++ endpoint_transfer_descriptor res;
++
++ TRACE_MSG5(HCD, "etdn=%d state=%d %s nus=%u %s", etdn, fs_hcpriv->etd_urb_state[etdn],
++ etd_urb_state_name[fs_hcpriv->etd_urb_state[etdn]], num_urbs_started, (killed?"KILLED":""));
++
++ if (monitoring_etd_mask == ETD_MASK(etdn))
++ monitoring_etd_mask = 0;
++
++
++ /* Disable/Abort DMA. R1: sec 23.13.16 pg 23-103
++ * (supposed to auto-clear on DMA completion, but this shouldn't hurt).
++ */
++ fs_wl(OTG_DMA_ETD_CH_CLR, ETD_MASK(etdn));
++
++ if (fs_rl(OTG_HOST_ETD_EN) & ETD_MASK(etdn))
++ fs_andl(OTG_HOST_ETD_EN, ~ETD_MASK(etdn)); // This register IS write 0 to disable. Really.
++
++ if ( fs_rl(OTG_HOST_ETD_DONE) & ETD_MASK(etdn))
++ fs_andl(OTG_HOST_ETD_DONE, ~ETD_MASK(etdn)); // This register IS write 0 to disable. Really.
++
++ // Hardware should have disabled ETD, but it doesn't hurt to check.
++ if (fs_rl(OTG_HOST_ETD_EN) & ETD_MASK(etdn))
++ fs_wl(OTG_HOST_ETD_EN, ETD_MASK(etdn)); // This register IS write 1 to clear. Really.
++
++ if (fs_rl(OTG_HOST_XINT_STAT) & ETD_MASK(etdn))
++ fs_wl(OTG_HOST_XINT_STAT, ETD_MASK(etdn)); // This register IS write 1 to clear. Really.
++
++ if (fs_rl(OTG_HOST_YINT_STAT) & ETD_MASK(etdn))
++ fs_wl(OTG_HOST_YINT_STAT, ETD_MASK(etdn)); // This register should be write 1 to clear.
++
++
++ if (fs_rl(OTG_HOST_XYINT_STEN) & ETD_MASK(etdn))
++ fs_andl(OTG_HOST_XYINT_STEN, ~ETD_MASK(etdn)); // This register should be write 0 to disable.
++
++ if (fs_rl(OTG_HOST_XFILL_STAT) & ETD_MASK(etdn))
++ fs_wl(OTG_HOST_XFILL_STAT, ETD_MASK(etdn)); // This register IS write 1 to clear. Really.
++
++ if (fs_rl(OTG_HOST_YFILL_STAT) & ETD_MASK(etdn))
++ fs_wl(OTG_HOST_YFILL_STAT, ETD_MASK(etdn)); // This register should be write 1 to clear.
++
++
++ // Extract results
++ res.epd = fs_rl(etd_word(etdn, 0));
++ res.td.w1.val = fs_rl(etd_word(etdn, 1));
++ res.td.w2.val = fs_rl(etd_word(etdn, 2));
++ res.td.w3.val = fs_rl(etd_word(etdn, 3));
++
++ fs_wl(OTG_HOST_EP_DSTAT, ETD_MASK(etdn));
++
++ //TRACE_MSG1(HCD,"OTG_HOST_ETD_DONE: %08x", fs_rl(OTG_HOST_ETD_DONE));
++
++ if ((ETD_URB_BULK_START == fs_hcpriv->etd_urb_state[etdn] ||
++ (ETD_URB_BULKWZLP_START == fs_hcpriv->etd_urb_state[etdn])) &&
++ (ETD_GET_DIRPID(res.td.w2.cb.flags) != ETD_DIRPID_IN)
++ )
++ TRACE_MSG4(HCD,"RES: epd: %08x w1: %08x w2: %08x w3: %08x", res.epd,res.td.w1.val,res.td.w2.val,res.td.w3.val);
++
++ if (ETD_GET_HALTED(res.epd))
++ TRACE_MSG0(HCD,"endpoint HALTED");
++
++ format = ETD_GET_FORMAT(res.epd);
++
++ switch (fs_hcpriv->etd_urb_state[etdn]) {
++ case ETD_URB_SETUP_START:
++ /* Just finished the setup packet.
++ * Go to data or status phase of setup packet while we still have the ETD and data buffers allocated.
++ */
++ if (!killed && ETD_CC_NOERROR == (cc = ETD_GET_COMPCODE(res.td.w2.cb.flags))) {
++
++ endpoint_transfer_descriptor *sdp = &fs_hcpriv->sdp_etd[etdn];
++ int len = ETD_GET_TOTBYECNT(sdp->td.w3.val);
++ void *data = fs_hcpriv->sdp_data[etdn];
++ fs_hcpriv->etd_urb_state[etdn] = ((len > 0) ? ETD_URB_SETUP_DATA : ETD_URB_SETUP_STATUS);
++
++ // Copy into the active ETD and start it.
++ fs_wl(etd_word(etdn, 0), sdp->epd);
++ fs_wl(etd_word(etdn, 1), sdp->td.w1.val);
++ fs_wl(etd_word(etdn, 2), sdp->td.w2.val);
++ fs_wl(etd_word(etdn, 3), sdp->td.w3.val);
++ // watch out for ETD_DIRPID_SETUP
++ start_etd(etdn, len,data,(ETD_GET_DIRPID(sdp->td.w2.cb.flags)!=ETD_DIRPID_IN));
++ TRACE_MSG1(HCD,"SETUP %s Phase started",((len > 0) ? "DATA" : "STATUS"));
++ return;
++ }
++ /* Something is wrong, finish the URB as is.
++ */
++ remaining = ETD_GET_TOTBYECNT(fs_rl(etd_word(etdn, 3)));
++ format = PIPE_CONTROL;
++ break;
++
++ case ETD_URB_SETUP_DATA:
++ /* Go to status phase of setup packet while we still have the ETD and data buffers allocated.
++ * Save the data phase length for after status.
++ */
++ if (!killed && ETD_CC_NOERROR == (cc = ETD_GET_COMPCODE(res.td.w2.cb.flags))) {
++ endpoint_transfer_descriptor *sdp = &fs_hcpriv->sdp_etd[etdn];
++ fs_hcpriv->sdp_data[etdn] = (void *) ETD_GET_TOTBYECNT(res.td.w3.val);
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_SETUP_STATUS;
++
++ /* Rebuild data phase sdp for status phase with opposite direction, and 0 length.
++ */
++
++ sdp->td.w2.cb.flags = ETD_FLIP_DIRPID(sdp->td.w2.cb.flags);
++ sdp->td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(0));
++
++ /* Copy into the active ETD and start it.
++ */
++ fs_wl(etd_word(etdn, 0), sdp->epd);
++ fs_wl(etd_word(etdn, 1), sdp->td.w1.val);
++ fs_wl(etd_word(etdn, 2), sdp->td.w2.val);
++ fs_wl(etd_word(etdn, 3), sdp->td.w3.val);
++ start_etd(etdn, 0,NULL,(ETD_GET_DIRPID(sdp->td.w2.cb.flags)!=ETD_DIRPID_IN));
++ TRACE_MSG0(HCD,"SETUP STATUS Phase started");
++ return;
++ }
++ // Something is wrong, finish the URB as is.
++ remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
++ format = PIPE_CONTROL;
++ break;
++
++ case ETD_URB_SETUP_STATUS:
++ cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
++ // Fetch saved length.
++ remaining = (u32) fs_hcpriv->sdp_data[etdn];
++ format = PIPE_CONTROL;
++ break;
++
++ case ETD_URB_BULKWZLP_START:
++ // Need a trailing ZLP.
++ next_toggle = ETD_GET_TOGCRY(res.epd);
++ if (!killed && ETD_CC_NOERROR == ETD_GET_COMPCODE(res.td.w2.cb.flags)) {
++ // Since TOTBYECNT should be 0, re-enabling the same ETD ought to give a ZLP.
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_BULKWZLP;
++ // Save the data phase length for after ZLP.
++ // fs_hcpriv->sdp_data[etdn] = (void *) ETD_GET_TOTBYECNT(res.td.w3.val);
++ // FIXME - verify toggle OK
++
++ start_etd(etdn, 0,NULL,TRUE/*always OUT*/);
++
++ TRACE_MSG0(HCD,"ZLP started");
++ return;
++ }
++ // Something is wrong, finish the URB as is.
++ remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
++ format = PIPE_BULK;
++ break;
++
++ case ETD_URB_BULKWZLP:
++ // Trailing ZLP now finished.
++ cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
++ next_toggle = ETD_GET_TOGCRY(res.epd);
++ // Fetch saved length (it was zero, or we wouldn't be here).
++ remaining = 0;
++ format = PIPE_BULK;
++ break;
++
++ case ETD_URB_BULK_START:
++ cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
++ next_toggle = ETD_GET_TOGCRY(res.epd);
++ remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
++ format = PIPE_BULK;
++ break;
++
++ case ETD_URB_INTERRUPT_START:
++ cc = ETD_GET_COMPCODE(res.td.w2.intr.flags);
++ remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
++ format = PIPE_INTERRUPT;
++ break;
++
++ case ETD_URB_ISOC_START:
++ // This probably needs more work, best guess only here.
++ remaining = ETD_GET_PKTLEN(res.td.w3.isoc.pkt0);
++ cc = ETD_GET_COMPCODE(res.td.w3.isoc.pkt0);
++ if (ETD_GET_FRAMECNT(res.td.w2.isoc.flags)) {
++ // There were two packets in this transfer
++ remaining += ETD_GET_PKTLEN(res.td.w3.isoc.pkt1);
++ }
++ format = PIPE_ISOCHRONOUS;
++ }
++
++ fs_hcpriv->etd_urb_state[etdn] = ETD_URB_COMPLETED;
++
++ /* Convert completion code to HW independent value.
++ */
++ if (killed) {
++ cc = -ENOENT;
++ remaining = 0;
++ }
++ else
++ cc = comp_code_to_status(cc);
++
++ /* Return ETD and X,Y buffers to free list.
++ */
++ y = data_buff_addr(res.td.w1.bufsrtad.y);
++ x = data_buff_addr(res.td.w1.bufsrtad.x);
++ y = rel_data_buff(fs_hcpriv,y);
++ x = rel_data_buff(fs_hcpriv,x);
++ rel_etd(fs_hcpriv, etdn);
++
++ /* Forward results to the layers above.
++ */
++ //TRACE_MSG4(HCD,"completing urb on ETD %d cc=%d remaining=%d next_toggle=%d", etdn, cc, remaining,next_toggle);
++ hcd_transfer_complete(fs_hcpriv->bus_hcpriv, etdn, format, cc, remaining, next_toggle);
++}
++
++/*!
++ * hcd_hw_unlink_urb() - unlink urb
++ * Called in irq_lock
++ * @param bus_hcpriv
++ * @param u
++ */
++int hcd_hw_unlink_urb(struct bus_hcpriv *bus_hcpriv, int u)
++{
++ unsigned long flags;
++ struct fs_hcpriv *fs_hcpriv;
++ RETURN_EINVAL_UNLESS ((fs_hcpriv = (struct fs_hcpriv *) bus_hcpriv->hw_hci));
++ local_irq_save(flags);
++ finish_urb_irq(fs_hcpriv, u, TRUE);
++ local_irq_restore(flags);
++ return 0;
++}
++
++/*!
++ * hcd_hw_frame_number() - return current frame number
++ * @param bus_hcpriv
++ * @return u32 ???
++ */
++u32 hcd_hw_frame_number(struct bus_hcpriv *bus_hcpriv)
++{
++ return(fs_rl(OTG_HOST_FRM_NUM));
++}
++
++/* ********************************************************************************************* */
++
++/*!
++ * MX21_PORT_CHANGED() - send otg event information to state machine
++ * @param name
++ * @param cs
++ * @param changed
++ * @param status
++ * @param set
++ * @param reset
++ */
++void MX21_PORT_CHANGED(char *name, u32 cs, u32 changed, u32 status, u64 set, u64 reset)
++{
++ RETURN_UNLESS(cs & changed);
++ TRACE_MSG2(HCD, "%s%s", name, (cs & (1 << status)) ? "" : "/");
++ if (cs & (1 << status) && set)
++ otg_event(hcd_instance->otg, set, HCD, name);
++ if (!(cs & (1 << status)) && reset)
++ otg_event(hcd_instance->otg, reset, HCD, name);
++}
++
++/*!
++ * update_shadow_rh() - Update shadow _status_ info (change info already updated).
++ * @param bus_hcpriv
++ * @param port_num - 1-N based port number
++ * @param cs
++ *
++ */
++STATIC void update_shadow_rh(struct bus_hcpriv *bus_hcpriv, int port_num, u32 cs)
++{
++ u32 msk_and = 0; // bits to turn off
++ u32 msk_or = 0; // bits to turn on
++
++ TRACE_MSG2(HCD,"port: %d cs: %08x", port_num, cs);
++
++ /* PORT_STATUS_PRTRSTSC (20) - PORT_RESET (4) changed
++ * PORT_RESET (4) status change, end of reset, PORT_ENABLE may (should) be on.
++ */
++ MX21_PORT_CHANGED("PORT_RESET", cs, PORT_STATUS_PRTRSTSC, PORT_RESET,
++ BUS_RESET, BUS_RESET_);
++
++ if (cs & (1 << C_PORT_RESET)) {
++ TRACE_MSG1(HCD,"port: %d PORT_RESET complete (s.b. enabled)", port_num);
++ if (cs & (1 << PORT_ENABLE)) {
++ TRACE_MSG1(HCD,"port: %d enabled", port_num);
++ //otg_write_info_message("port update C_PORT_RESET");
++ msk_or |= (1 << PORT_ENABLE);
++ }
++ else {
++ TRACE_MSG1(HCD,"port: %d NOT enabled!!!", port_num);
++ //otg_write_info_message("update C_PORT_RESET/");
++ }
++
++ /* Clear the PORT_RESET bit too, since it's over.
++ */
++ msk_and |= (1 << PORT_RESET);
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
++ }
++
++ /* PORT_OVER_CURRENT (3) bit has changed (either direction).
++ * PORT_STATUS_OVRCURIC (19) - PORT_OVER_CURRENT (3) changed
++ */
++ MX21_PORT_CHANGED("PORT_OVER_CURRENT", cs, PORT_STATUS_OVRCURIC, PORT_OVER_CURRENT, (u64) 0, (u64) 0);
++ if (cs & (1 << C_PORT_OVER_CURRENT)) {
++ /* OVER_CURRENT has come on.
++ */
++ if (cs & (1 << PORT_OVER_CURRENT)) {
++ TRACE_MSG1(HCD,"port: %d over current ON", port_num);
++ msk_or |= (1 << PORT_OVER_CURRENT);
++ }
++ /* OVER_CURRENT has gone away.
++ */
++ else {
++ TRACE_MSG1(HCD,"port: %d over current OFF", port_num);
++ msk_and |= (1 << PORT_OVER_CURRENT);
++ }
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
++ }
++
++ /* PORT_SUSPEND (2) Resume sequence has completed....
++ * PORT_STATUS_PRTSTATSC (18) - PORT_SUSPEND (2) changed
++ */
++ MX21_PORT_CHANGED("PORT_SUSPEND", cs, PORT_STATUS_PRTSTATSC, PORT_SUSPEND,
++ BUS_SUSPENDED, BUS_SUSPENDED_);
++
++ if (cs & (1 << C_PORT_SUSPEND)) {
++ // FIXME - figure this out when we get to suspend/resume....
++
++ }
++
++
++ /* PORT_ENABLE (1) has been __cleared__ by some HW event
++ * PORT_STATUS_PRTENBLSC (17) - PORT_ENABLE (1) changed
++ */
++ MX21_PORT_CHANGED("PORT_ENABLE", cs, PORT_STATUS_PRTENBLSC, PORT_ENABLE, (u64) 0, (u64) 0);
++ if (cs & (1 << C_PORT_ENABLE)) {
++ //otg_write_info_message("update C_PORT_ENABLE");
++ TRACE_MSG1(HCD,"port: %d disabled (by HW)", port_num);
++ if (!(cs & (1 << PORT_ENABLE)))
++ msk_and |= ( 1 << PORT_ENABLE);
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
++ }
++
++ /* PORT_CONNECTION (0) bit has changed (either direction).
++ * PORT_STATUS_CONNECTSC (16) - PORT_CONNECTION (0) changed
++ */
++ MX21_PORT_CHANGED("PORT_CONNECTION", cs, PORT_STATUS_CONNECTSC, PORT_CONNECTION,
++ HUB_PORT_CONNECT, HUB_PORT_CONNECT_ );
++
++ if (cs & (1 << C_PORT_CONNECTION)) {
++ /* CONNECT has come on.
++ */
++ if (cs & (1 << PORT_CONNECTION)) {
++ TRACE_MSG1(HCD,"port: %d new connection", port_num);
++ msk_or |= (1 << PORT_CONNECTION);
++ if (cs & (1 << PORT_LOW_SPEED)) {
++ TRACE_MSG1(HCD,"port: %d low speed device", port_num);
++ msk_or |= (1 << PORT_LOW_SPEED);
++ }
++ //otg_write_info_message("update PORT_CONNECTION");
++ //printk(KERN_INFO"%s: AAA\n", __FUNCTION__);
++ //otg_event(hcd_instance->otg, HUB_PORT_CONNECT, HCD, "HUB_PORT_CONNECT (mx21 hw)");
++ //printk(KERN_INFO"%s: BBB\n", __FUNCTION__);
++ }
++ /* CONNECT has gone away.
++ */
++ else {
++ TRACE_MSG1(HCD,"port: %d disconnection", port_num);
++ //otg_write_info_message("update PORT_CONNECTION/");
++ msk_and |= (1 << PORT_CONNECTION) | (1 << PORT_LOW_SPEED);
++ //otg_event(hcd_instance->otg, HUB_PORT_CONNECT_, HCD, "HUB_PORT_CONNECT/ (mx21 hw)");
++ }
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
++ //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
++ }
++
++ TRACE_MSG5(HCD, "port: %d shadow port_change_status: ((%08x & ~%04x) | %04x) hpcs: %04x",
++ port_num, bus_hcpriv->rh_hcpriv->port_change_status[port_num - 1],
++ msk_and, msk_or, bus_hcpriv->rh_hcpriv->hub_port_change_status);
++}
++
++/* ********************************************************************************************* */
++static int num_host_interrupts = 0;
++#define MAX_HOST_INTERRUPTS 0
++static int num_psc_interrupts = 0;
++#define MAX_PSC_INTERRUPTS 0
++
++extern struct bus_hcpriv fs_bus_hcpriv;
++
++/*!
++ * hcd_hw_int_hndlr() - interrupt handler for hcd controller
++ * @param irq
++ * @param dev_id
++ * @param regs
++ */
++irqreturn_t hcd_hw_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) &fs_bus_hcpriv;
++ struct fs_hcpriv *fs_hcpriv = (struct fs_hcpriv *) bus_hcpriv->hw_hci;
++ u32 host_sint; // C.f. 23.11.11 Host Interrupt Register
++
++ if (OTG_USBDMA == irq) {
++ // HOST DMA error interrupt
++ u32 err_stat = fs_rl(OTG_DMA_ETD_ERR);
++ TRACE_MSG1(HCD,"host DMA interrupt, error status %08x",err_stat);
++ if (0 != err_stat) {
++ // Disable the matching DMA channels and clear the interrupt
++ fs_wl(OTG_DMA_ETD_CH_CLR, err_stat);
++ fs_wl(OTG_DMA_ETD_ERR, err_stat);
++ }
++ // local_irq_restore(flags);
++ return IRQ_HANDLED;
++ }
++
++ /* FIXME - should check fs_hcpriv->mm->otg.OTG_Module_Interrupt_Status & (0x1 << 3) | 0x1;
++ * for Host (async + regular) Interrupt - enable clock on async.
++ */
++
++ num_host_interrupts += 1;
++ if (MAX_HOST_INTERRUPTS > 0 && num_host_interrupts > MAX_HOST_INTERRUPTS) {
++ // Host (async + regular) Interrupt Disable
++
++ fs_wl(OTG_HOST_SINT_STEN, 0);
++ fs_andl(OTG_CORE_CINT_STEN, ~(/*(0x1 << 3) |*/ 0x1));
++ }
++
++ while ((host_sint = fs_rl(OTG_HOST_SINT_STAT))) {
++
++ while (HOST_DONEINT & host_sint) {
++ u32 etds_done;
++
++ TRACE_MSG1(HCD,"HOST_DONEINT: %08x", fs_rl(OTG_HOST_EP_DSTAT));
++ fs_wl(OTG_HOST_SINT_STAT, HOST_DONEINT);
++ host_sint = fs_rl(OTG_HOST_SINT_STAT);
++ while ((etds_done = fs_rl(OTG_HOST_EP_DSTAT)))
++ finish_urb_irq(fs_hcpriv, fls(etds_done) - 1, FALSE);
++ }
++
++ host_sint = fs_rl(OTG_HOST_SINT_STAT);
++
++ /* Start Of Frame.
++ * Note: this interrupt seems to happen even if disabled when there is a frame number overflow.
++ */
++ if (host_sint & HOST_SOFINT) {
++ if (0 == (fs_hcpriv->sof_count & (4096 - 1))) {
++ TRACE_MSG1(HCD,"SOF %08lx",fs_hcpriv->sof_count);
++ }
++ fs_hcpriv->sof_count += 1;
++ if (monitoring_etd_mask != 0) {
++ // This ETD needs to be watched....
++ current_etd_frame += 1;
++
++ done_flags[current_etd_frame] = fs_rl(OTG_HOST_ETD_EN);
++ done_status[current_etd_frame] = fs_rl(OTG_HOST_EP_DSTAT);
++
++ mon_etd[current_etd_frame].epd = fs_rl(etd_word(monitoring_etd_num, 0));
++ mon_etd[current_etd_frame].td.w1.val = fs_rl(etd_word(monitoring_etd_num, 1));
++ mon_etd[current_etd_frame].td.w2.val = fs_rl(etd_word(monitoring_etd_num, 2));
++ mon_etd[current_etd_frame].td.w3.val = fs_rl(etd_word(monitoring_etd_num, 3));
++
++ if (current_etd_frame >= MAX_ETD_FRAMES) {
++ // This has taken too long!
++ int i,u;
++ u = ((mon_etd[0].td.w3.val == mon_etd[1].td.w3.val) &&
++ (mon_etd[1].td.w3.val == mon_etd[2].td.w3.val) &&
++ (mon_etd[2].td.w3.val == mon_etd[3].td.w3.val));
++
++ TRACE_MSG5(HCD,"SOF: OUT urb TIMEOUT at %d/%d frames, mask: %08x num=%u u=%d",
++ current_etd_frame,MAX_ETD_FRAMES,monitoring_etd_mask,monitoring_etd_num,u);
++
++ for (i = 0; i <= MAX_ETD_FRAMES; i++)
++ TRACE_MSG7(HCD,"SOF: %d epd: %08x w1: %08x w2: %08x w3: %08x ef: %08x st: %08x",
++ i, mon_etd[i]. epd, mon_etd[i]. td.w1.val, mon_etd[i].td.w2.val,
++ mon_etd[i].td.w3.val, done_flags[i], done_status[i]);
++ // Disable monitoring by killing the urb. FUTURE, look into restarting it.
++ finish_urb_irq(fs_hcpriv, monitoring_etd_num,TRUE);
++ }
++ }
++ }
++
++ /* Frame Number Overflow.
++ */
++ if (host_sint & HOST_FMOFINT) {
++ //TRACE_MSG0(HCD,"Frame Number Overflow");
++ //printk(KERN_ERR "%s: Frame Number Overflow\n",__FUNCTION__);
++ }
++
++ /* Port Status Change.
++ */
++ if (host_sint & HOST_PSCINT) {
++ int port_num;
++ num_psc_interrupts += 1;
++
++ /* Clear the interrupt by clearing the port(s) in question.
++ * Reflect any changes in the shadow values.
++ */
++ for (port_num = 1; port_num <= bus_hcpriv->num_ports; port_num++) {
++
++ u32 cs = fs_rl(fs_host_port_stat(port_num));
++ u32 cm = cs & 0xFFFF0000;
++
++ CONTINUE_UNLESS (cm);
++ fs_wl(fs_host_port_stat(port_num), cm);
++ bus_hcpriv->rh_hcpriv->port_change_status[port_num - 1] |= cm;
++ update_shadow_rh(bus_hcpriv, port_num, cs);
++ }
++
++ /* Tell the RH to scan for changes in shadow data. (schedule bottom half handler)
++ */
++ hcd_rh_int_hndlr(irq,bus_hcpriv,NULL);
++ }
++
++ /* Overrun
++ */
++ if (host_sint & (HOST_SORINT | HOST_HERRINT)) {
++ if (host_sint & HOST_SORINT) {
++ TRACE_MSG0(HCD,"Scheduling Overrun");
++ printk(KERN_ERR "%s: Scheduling Overrun\n",__FUNCTION__);
++ }
++ if (host_sint & HOST_HERRINT) {
++ TRACE_MSG0(HCD,"Host Scheduling Error");
++ printk(KERN_ERR "%s: Host Scheduling Error\n",__FUNCTION__);
++ }
++ }
++ /* Resume Detected.
++ */
++ if (host_sint & HOST_RESDETINT) {
++ TRACE_MSG0(HCD,"Resume Detected");
++ }
++ /* Clear by writing back the ones we've checked for since the last read.
++ */
++ fs_wl(OTG_HOST_SINT_STAT, host_sint & (HOST_RESDETINT | HOST_FMOFINT | HOST_SORINT |
++ HOST_HERRINT | HOST_PSCINT | HOST_SOFINT));
++ }
++ return IRQ_HANDLED;
++}
++
++/* ********************************************************************************************* */
++
++
++/*!
++ * hcd_hw_rh_hub_attributes() - get root hub attributes
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u16 hcd_hw_rh_hub_attributes(struct bus_hcpriv *bus_hcpriv)
++{
++ // R1: sec 23.11.27
++ return 0xFFFF & (fs_rl(OTG_HOST_ROOTHUB_DESCA) >> 8);
++}
++
++/*!
++ * hcd_hw_rh_power_delay() - get power delay attributes
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u8 hcd_hw_rh_power_delay(struct bus_hcpriv *bus_hcpriv)
++{
++ // R1: sec 23.11.27
++ return fs_rl(OTG_HOST_ROOTHUB_DESCA) >> 24;
++}
++
++/*!
++ * hcd_hw_rh_contr_current() - get contr current attributes
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u8 hcd_hw_rh_hub_contr_current(struct bus_hcpriv *bus_hcpriv)
++{
++ return 0x0;
++}
++
++/*!
++ * hcd_hw_rh_DeviceRemovalbe() - get DeviceRemovalbe attributes
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u8 hcd_hw_rh_DeviceRemovable(struct bus_hcpriv *bus_hcpriv)
++{
++ // USB2.0 pg 418 ==> bit 0 reserved, 1..7 for ports
++ // R1: sec 23.11.28
++ return 0xFF & fs_rl(OTG_HOST_ROOTHUB_DESCB);
++}
++
++/*!
++ * hcd_hw_rh_PortPwrCtrlMask() - get DeviceRemovalbe attributes
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u8 hcd_hw_rh_PortPwrCtrlMask(struct bus_hcpriv *bus_hcpriv)
++{
++ // USB2.0 pg 418 ==> all 1s??? QQSV
++ // R1: sec 23.11.28
++ return 0xFF & fs_rl(OTG_HOST_ROOTHUB_DESCB);
++}
++
++
++/*!
++ * hcd_hw_rh_get_hub_change_status() - get change status
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ */
++u32 hcd_hw_rh_get_hub_change_status(struct bus_hcpriv *bus_hcpriv)
++{
++ // R1: sec 23.11.29 pg 23-62, USB2.0 11.24.2.6 pg 425
++ return fs_rl(OTG_HOST_ROOTHUB_STATUS & (ROOTHUB_STATUS_LOCPWRSC | ROOTHUB_STATUS_DEVCONWUE |
++ ROOTHUB_STATUS_OVRCURI | ROOTHUB_STATUS_LOCPWRS));
++}
++
++/*!
++ * hcd_hw_rh_hub_feature() - get hub feature
++ * These provide access to the real root hub.
++ * @param bus_hcpriv
++ * @param feat_selector
++ * @param set_flag
++ */
++void hcd_hw_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, int feat_selector, int set_flag)
++{
++ if (set_flag) {
++ // SET feature USB2.0 11.24.2.12 pg 434 and USB2.0 11.24.2 tbl 11-17 pg 421
++ // R1: sec 23.11.29 pg 23-62
++ switch (feat_selector) {
++ // case C_HUB_OVER_CURRENT: MX21 doesn't support SW setting the over current feature
++ // case C_HUB_LOCAL_POWER: MX21 doesn't support local power
++ default:
++ // Error, but ignore.
++ TRACE_MSG1(HCD,"SET invalid feature %d",feat_selector);
++ break;
++ }
++ }
++ else {
++ // CLEAR feature USB2.0 11.24.2.1 pg 422 and USB2.0 11.24.2 tbl 11-17 pg 421
++ // R1: sec 23.11.29 pg 23-62
++ switch (feat_selector) {
++ case C_HUB_OVER_CURRENT:
++ fs_wl(OTG_HOST_ROOTHUB_STATUS, ROOTHUB_STATUS_OVRCURCHG);
++ break;
++
++ // case C_HUB_LOCAL_POWER: MX21 doesn't support local power
++ default:
++ // Error, but ignore.
++ TRACE_MSG1(HCD,"CLEAR invalid feature %d",feat_selector);
++ break;
++ }
++ }
++}
++
++/*!
++ * hcd_hw_rh_get_port_change_status() - get port change status
++ * R1: High 16 bits == change, low 16 == status
++ * Change & Status bits in register match USB2.0 spec on (read).
++ * @param bus_hcpriv
++ * @param wIndex is 1-origin
++ */
++u32 hcd_hw_rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, int wIndex)
++{
++ u32 port_status = fs_rl(fs_host_port_stat(wIndex));
++
++ TRACE_MSG8(HCD,"port %d cs: %08lx %s %s %s %s %s %s",
++ wIndex, port_status,
++ port_status & PORT_STATUS_CONNECTSC ? "CHANGE" : "",
++ port_status & PORT_STATUS_PRTPWRST ? "POWER" : "",
++ port_status & PORT_STATUS_PRTRSTST ? "RESET" : "",
++ port_status & PORT_STATUS_PRTSUSPST ? "SUSPEND" : "",
++ port_status & PORT_STATUS_PRTENABST ? "ENABLE" : "",
++ port_status & PORT_STATUS_CURCONST ? "CONNECT" : ""
++ );
++
++ return fs_rl(fs_host_port_stat(wIndex));
++}
++
++extern char *port_feature_name[];
++
++/*!
++ * hcd_hw_rh_port_feature() - get rh port feature
++ * @param bus_hcpriv
++ * @param wValue is feature selector
++ * @param wIndex is port number (1-N)
++ * @param set_flag
++ */
++void hcd_hw_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag)
++{
++ char buf[64];
++ sprintf(buf, "port feature %s %s", port_feature_name[wValue], set_flag ? "SET" : "RESET");
++ //otg_write_info_message(buf);
++
++ TRACE_MSG4(HCD, "mx21 %s (%d) %s port_stat: %8x", port_feature_name[wValue], wValue, set_flag ? "SET" : "RESET",
++ fs_rl(fs_host_port_stat(wIndex)));
++ if (set_flag) {
++ // SET feature
++ switch (wValue) {
++ case PORT_SUSPEND:
++ otg_event(hcd_instance->otg, BUS_SUSPENDED, HCD, "HUB_PORT_SUSPEND (mx21 hw)");
++ fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
++ break;
++ case PORT_RESET:
++ case PORT_POWER:
++ fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
++ break;
++ default:
++ // Error, but ignore.
++ TRACE_MSG2(HCD,"SET port %d invalid feature %d", wIndex, wValue);
++ break;
++ }
++ }
++ else {
++ // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
++ switch (wValue) {
++ case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
++ wValue++; // yes, really. this clears PORT_SUSPEND
++ fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
++ otg_event(hcd_instance->otg, BUS_SUSPENDED_, HCD, "HUB_PORT_SUSPEND/ (mx21 hw)");
++ break;
++
++ case PORT_POWER: // Put port in powered-off state.
++ wValue++; // yes, really. this clears PORT_POWER
++ fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
++ break;
++
++ case PORT_ENABLE: // Disable port.
++ //wValue--;
++ break;
++ default:
++ break;
++ }
++ switch (wValue) {
++ case PORT_POWER: // Put port in powered-off state.
++ case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
++ case PORT_ENABLE: // Disable port.
++ case PORT_INDICATOR: // ind_selector gives which indicator to clear
++ case C_PORT_SUSPEND: // clear the PORT_SUSPEND change bit
++ case C_PORT_CONNECTION: // clear the PORT_CONNECTION change bit
++ case C_PORT_RESET: // clear the PORT_RESET change bit
++ case C_PORT_ENABLE: // clear the PORT_ENABLE change bit
++ case C_PORT_OVER_CURRENT: // clear the PORT_OVERCURRENT change bit
++ fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
++ break;
++ default:
++ // Error, but ignore.
++ TRACE_MSG2(HCD,"CLEAR port %d invalid feature %d", wIndex, wValue);
++ break;
++ }
++ }
++
++ TRACE_MSG3(HCD, "mx21 %s %s port_stat: %8x", port_feature_name[wValue], set_flag ? "SET" : "RESET",
++ fs_rl(fs_host_port_stat(wIndex)));
++}
++
++/* ********************************************************************************************* */
++/* Hardware Initialization - this is used by the OTG state machine to
++ * enable and disable the host controller hardware
++ */
++void rh_hcd_en_func(struct otg_instance *otg, u8 flag);
++
++extern void fs_host_clock_on(void);
++extern void fs_host_clock_off(void);
++
++/*!
++ * fs_hcd_en_func() - otg hcd enable output function
++ * @param otg
++ * @param flag
++ */
++void fs_hcd_en_func(struct otg_instance *otg, u8 flag)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
++ fs_hcpriv *fs_hcpriv = bus_hcpriv->hw_hci;
++ int i;
++ u32 hwmode = fs_rl(OTG_CORE_HWMODE);
++ unsigned long flags;
++
++ /* puts OTG capable port into a state where host is enabled */
++
++ fs_andl(OTG_CORE_HWMODE, 0xffffff0f); // clear
++
++ switch (flag) {
++ case SET:
++ local_irq_save(flags);
++ printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ if (hwmode & MODULE_CRECFG_HOST) {
++ printk(KERN_INFO"%s: warning FUNC STILL SET\n", __FUNCTION__);
++ }
++ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_HOST); // set to software hnp
++ local_irq_restore(flags);
++ break;
++ case RESET:
++ local_irq_save(flags);
++ printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
++ fs_andl(OTG_CORE_HWMODE, ~MODULE_CRECFG_HOST); // set to software hnp
++ local_irq_restore(flags);
++ break;
++ }
++
++ TRACE_MSG1(HCD, "HWMODE: %08x", fs_rl(OTG_CORE_HWMODE));
++}
++
++
++void rh_loc_sof_func(struct otg_instance *otg, u8 flag);
++void rh_loc_suspend_func(struct otg_instance *otg, u8 flag);
++
++/*!
++ * fs_loc_suspend() - otg loc suspend output function
++ * @param otg
++ * @param flag
++ */
++void fs_loc_suspend_func(struct otg_instance *otg, u8 flag)
++{
++ unsigned long flags;
++ switch (flag) {
++ case SET:
++
++ fs_orl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_SUSPEND);
++ break;
++
++ case RESET:
++ break;
++ }
++
++ rh_loc_suspend_func(otg, flag);
++
++ switch (flag) {
++ case SET:
++ break;
++
++ case RESET:
++ local_irq_save(flags);
++ fs_andl(OTG_HOST_CONTROL, ~HOST_CONTROL_HCUSBSTE_SUSPEND);
++ fs_orl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_OPERATIONAL);
++ local_irq_restore(flags);
++ break;
++ }
++}
++
++/*!
++ * fs_loc_sof_func() - otg loc sof output function
++ * @param otg
++ * @param flag
++ */
++void fs_loc_sof_func(struct otg_instance *otg, u8 flag)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
++ fs_hcpriv *fs_hcpriv = bus_hcpriv->hw_hci;
++ int i;
++ u32 mask;
++ unsigned long flags;
++
++ switch (flag) {
++ case SET:
++ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ //TRACE_MSG0(HCD, "-----------------------------------------");
++
++ local_irq_save(flags);
++
++ /* reset the host core
++ */
++ fs_wl_clr(HCD, OTG_CORE_RST_CTRL, MODULE_RSTRH | MODULE_RSTHSIE | MODULE_RSTHC);
++ while (fs_rl(OTG_CORE_RST_CTRL));
++
++ fs_host_clock_on();
++
++ for (i = 0; i < NUM_DATA_BUFFS; i++)
++ (void) rel_data_buff(fs_hcpriv, ((fs_data_buff *)OTG_DATA_BASE)+i);
++
++ for (i = 0; i < NUM_ETDS; i++)
++ rel_etd(fs_hcpriv,i);
++
++ fs_wl(OTG_HOST_CONTROL, HOST_CONTROL_HCRESET | HOST_CONTROL_RMTWUEN |
++ HOST_CONTROL_HCUSBSTE_RESET | HOST_CONTROL_CTLBLKSR_11);
++
++
++ //TRACE_MSG0(HCD, "HW HCD_ENABLE_SET");
++ fs_andl(OTG_CORE_HNP_CSTAT, ~(MODULE_MASTER | MODULE_SLAVE | MODULE_CMPEN |
++ MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ));
++ fs_rl(OTG_CORE_HNP_CSTAT);
++
++ fs_orl(OTG_CORE_HNP_CSTAT, MODULE_MASTER | MODULE_CMPEN | MODULE_BGEN | MODULE_ABBUSREQ);
++ fs_orl(OTG_CORE_HNP_CSTAT, MODULE_ARMTHNPE | MODULE_BHNPEN); // XXX
++
++ fs_wl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_OPERATIONAL);
++
++ //hcd_hw_enable_interrupts(bus_hcpriv);
++
++ mask = (HOST_PSCINT_EN | HOST_FMOFINT_EN | HOST_HERRINT_EN |
++ HOST_RESDETINT_EN | /* HOST_SOFINT_EN | */ HOST_DONEINT_EN | HOST_SORINT_EN);
++
++ // R1: sec 23.11.15 pg 23-54
++ fs_rl(OTG_CORE_HNP_CSTAT);
++ fs_rl(OTG_HOST_CONTROL);
++ fs_rl(OTG_HOST_ROOTHUB_STATUS);
++ fs_rl(OTG_HOST_PORT_STATUS_1);
++ fs_rl(OTG_HOST_PORT_STATUS_2);
++ fs_rl(OTG_HOST_PORT_STATUS_3);
++
++ fs_wl(OTG_HOST_SINT_STEN, mask);
++ fs_rl(OTG_HOST_SINT_STEN);
++ local_irq_restore(flags);
++ }
++
++ rh_loc_sof_func(otg, flag);
++
++ switch (flag) {
++ case RESET:
++ local_irq_save(flags);
++
++ //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
++ //TRACE_MSG0(HCD, "HW HCD_ENABLE_RESET");
++
++ //hcd_hw_disable_interrupts(bus_hcpriv);
++ // R1: sec 23.11.15 pg 23-54
++ fs_wl(OTG_HOST_SINT_STAT, 0);
++
++ fs_andl(OTG_HOST_CONTROL, ~HOST_CONTROL_HCUSBSTE_OPERATIONAL);
++
++ // Shut down hardware if not already shut down....
++ //hcd_hw_disable_interrupts(bus_hcpriv);
++
++ fs_host_clock_off();
++ local_irq_restore(flags);
++ break;
++ }
++}
++/* ********************************************************************************************* */
++/* Module init
++ *
++ * Define the global data structures and call the initialization functions required
++ * to start the generic hcd layer and register with the otg core.
++ *
++ */
++
++void rh_suspend_func(struct otg_instance *otg, u8 on);
++void hcd_init_func (struct otg_instance *otg, u8 flag);
++int hcd_probe(struct usb_interface *intf, const struct usb_device_id *id);
++void hcd_disconnect(struct usb_interface *intf);
++
++int fs_mod_init(void);
++#ifdef MODULE
++void fs_mod_exit(void);
++#endif
++
++#if !defined(OTG_C99)
++
++static struct usb_driver mx2_usb_driver;
++fs_hcpriv priv_mx21;
++struct bus_hcpriv fs_bus_hcpriv;
++struct hcd_ops hcd_ops;
++
++
++/*!
++ * fs_hcd_global_init() - initialize global vars for non C99 systems
++ */
++void fs_hcd_global_init(void)
++{
++ ZERO(mx2_usb_driver);
++ mx2_usb_driver.owner = THIS_MODULE;
++ mx2_usb_driver.name = "MX21_HCD";
++ mx2_usb_driver.probe = hcd_probe;
++ mx2_usb_driver.disconnect = hcd_disconnect;
++
++ ZERO(priv_mx21);
++ priv_mx21.free_buffs = 0xffff;
++ priv_mx21.free_etds = 0x0000ffff;
++ priv_mx21.bus_hcpriv = &fs_bus_hcpriv;
++
++ ZERO(fs_bus_hcpriv);
++ fs_bus_hcpriv.hw_hci = &priv_mx21;
++ fs_bus_hcpriv.usb_driver = &mx2_usb_driver;
++ fs_bus_hcpriv.bus_device.driver = &mx2_usb_driver.driver;
++ fs_bus_hcpriv.bus_device.parent = NULL;
++ fs_bus_hcpriv.bus_device.bus = &usb_bus_type; // struct bus_type *
++#if 0
++ strncpy(fs_bus_hcpriv.bus_device.name, "MX21 HOST", sizeof(fs_bus_hcpriv.bus_device.name));
++#endif
++ fs_bus_hcpriv.num_ports = 1;
++ fs_bus_hcpriv.otg_port = 1;
++ fs_bus_hcpriv.otg_capable_mask = (1 << 1);
++ fs_bus_hcpriv.rh_serial = "000001";
++ fs_bus_hcpriv.rh_product = "Virtual Root Hub";
++ fs_bus_hcpriv.rh_manufacturer = "Belcarra Technologies";
++ fs_bus_hcpriv.rh_vendorid = CONFIG_OTG_ROOTHUB_VENDORID;
++ fs_bus_hcpriv.rh_productid = CONFIG_OTG_ROOTHUB_PRODUCTID;
++ fs_bus_hcpriv.rh_bcddevice = CONFIG_OTG_ROOTHUB_BCDDEVICE;
++ fs_bus_hcpriv.rh_bmAttributes = 0x0;
++ fs_bus_hcpriv.rh_bMaxPower = 0;
++
++ fs_bus_hcpriv.max_active_transfers = NUM_ETDS;
++ fs_bus_hcpriv.max_active_urbs = NUM_ETDS;
++
++ ZERO(hcd_ops);
++ hcd_ops.name = "MX21 HCD";
++ hcd_ops.max_ports = 1;
++ hcd_ops.capabilities = 0;
++ // module
++ hcd_ops.mod_init = fs_mod_init; // called for module init
++#ifdef MODULE
++ hcd_ops.mod_exit = fs_mod_exit; // called for module exit
++#endif
++ // otg state machine
++ hcd_ops.hcd_init_func = hcd_init_func; // initialize when otg enabled
++ hcd_ops.hcd_en_func = fs_hcd_en_func; // setup hardware as host
++ hcd_ops.loc_suspend_func = rh_loc_suspend_func; // enable port on hub
++ hcd_ops.loc_sof_func = fs_loc_sof_func; // enable port on hub
++};
++
++#else /* !defined(OTG_C99) */
++
++static struct usb_driver mx2_usb_driver = {
++ .owner = THIS_MODULE,
++ .name = "MX21_HCD",
++ .probe = hcd_probe,
++ .disconnect = hcd_disconnect,
++};
++
++extern struct bus_hcpriv fs_bus_hcpriv;
++fs_hcpriv priv_mx21 = {
++ .free_buffs = 0xffff,
++ .free_etds = 0x0000ffff,
++ .bus_hcpriv = &fs_bus_hcpriv,
++};
++
++struct bus_hcpriv fs_bus_hcpriv = {
++
++ .hw_hci = &priv_mx21,
++ .usb_driver = &mx2_usb_driver,
++ .bus_device.driver = &mx2_usb_driver.driver,
++ .bus_device.parent = NULL,
++ .bus_device.bus = &usb_bus_type, // struct bus_type *
++ .bus_device.name = "MX21 HOST",
++
++ .num_ports = 1,
++ .otg_port = 1,
++ .otg_capable_mask = (1 << 1),
++ .rh_serial = "000001",
++ .rh_product = "Virtual Root Hub",
++ .rh_manufacturer = "Belcarra Technologies",
++ .rh_vendorid = CONFIG_OTG_ROOTHUB_VENDORID,
++ .rh_productid = CONFIG_OTG_ROOTHUB_PRODUCTID,
++ .rh_bcddevice = CONFIG_OTG_ROOTHUB_BCDDEVICE,
++ .rh_bmAttributes = 0x0,
++ .rh_bMaxPower = 0,
++
++ .max_active_transfers = NUM_ETDS,
++ .max_active_urbs = NUM_ETDS,
++};
++
++struct hcd_ops hcd_ops = {
++
++ .name = "MX21 HCD",
++ .max_ports = 1,
++ .capabilities = 0,
++ // module
++ .mod_init = fs_mod_init, // called for module init
++#ifdef MODULE
++ .mod_exit = fs_mod_exit, // called for module exit
++#endif
++ .hcd_init_func = hcd_init_func, // initialize when otg enabled
++ .hcd_en_func = fs_hcd_en_func, // setup hardware as host
++ .loc_suspend_func = rh_loc_suspend_func, // enable port on hub
++ .loc_sof_func = fs_loc_sof_func, // enable port on hub
++};
++#endif /* !defined(OTG_C99) */
++
++
++extern int hcd_init(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver);
++extern void hcd_exit(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver);
++
++/*!
++ * fs_mod_init() - initialize mx2 hcd
++ *
++ * This calls hcd_init() with the mx2 data structures.
++ */
++int fs_mod_init(void)
++{
++ RETURN_ENOMEM_IF(hcd_init(&fs_bus_hcpriv, &mx2_usb_driver));
++
++ hcd_instance->privdata = &fs_bus_hcpriv;
++ return 0;
++}
++
++#ifdef MODULE
++/*!
++ * fs_mod_exit() - de-initialize mx2 hcd
++ *
++ * This calls hcd_exit() with the mx2 data structures.
++ */
++void fs_mod_exit(void)
++{
++ hcd_exit(&fs_bus_hcpriv, &mx2_usb_driver);
++}
++#endif
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-ocd.c linux/drivers/otg/ocd/fsotg/fs-ocd.c
+--- linux/drivers/no-otg/ocd/fsotg/fs-ocd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/fsotg/fs-ocd.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,263 @@
++/*
++ * otg/ocd/fsotg/fs-ocd.c -- USB Device Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/fsotg/fs-ocd.c
++ * @brief Freescale USB OTG Controller Driver
++ * This is the OTG Controller Driver.
++ *
++ * This implements overall configuration and control of the Freescale OTG hardware
++ * and implements the main interrupt handler.
++ *
++ * There is some processor specific code here to support the alternate processors
++ * that implement this type of USB support.
++ *
++ * There is no board or platform level code here.
++ *
++ * @ingroup FSOTG
++ *
++ * @{
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <asm/arch/mx2.h>
++#undef GPT_BASE_ADDR
++#include <asm/arch/gpt.h>
++#include <asm/arch/clk.h>
++
++#include <otghw/fsotg-hardware.h>
++
++
++/* ********************************************************************************************* */
++#define TIMEOUT_VALUE 1000
++/*!
++ * fs_func_clock_on() - enable function controller clock
++ */
++void fs_func_clock_on(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "FUNC CLOCK ON:");
++ fs_orl(OTG_CORE_CLK_CTRL, MODULE_FUNC_CLK);
++ while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_FUNC_CLK)) { timeout--; if (!timeout) break; }
++
++ //fs_orl(OTG_CORE_CINT_STEN, MODULE_ASFCINT_EN |MODULE_FCINT_EN);
++}
++
++/*!
++ * fs_host_clock_on() - enable host controller clock
++ */
++void fs_host_clock_on(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "HOST CLOCK ON");
++ fs_orl(OTG_CORE_CLK_CTRL, MODULE_HOST_CLK);
++ while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_HOST_CLK)) { timeout--; if (!timeout) break; }
++}
++
++/*!
++ * fs_func_clock_off() - disable function controller clock
++ */
++void fs_func_clock_off(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "FUNC CLOCK OFF");
++ fs_andl(OTG_CORE_CLK_CTRL, 0x0);
++ while((fs_rl(OTG_CORE_CLK_CTRL) & (MODULE_FUNC_CLK | MODULE_MAIN_CLK))) { timeout--; if (!timeout) break; }
++}
++
++/*!
++ * fs_host_clock_off() - disable host controller clock
++ */
++void fs_host_clock_off(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "HOST CLOCK OFF");
++ fs_andl(OTG_CORE_CLK_CTRL, 0x0);
++ while((fs_rl(OTG_CORE_CLK_CTRL) & (MODULE_HOST_CLK | MODULE_MAIN_CLK))) { timeout--; if (!timeout) break; }
++}
++
++/*!
++ * fs_main_clock_on() - enable main clock
++ */
++void fs_main_clock_on(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "MAINFUNC CLOCK ON");
++ fs_orl(OTG_CORE_CLK_CTRL, MODULE_MAIN_CLK);
++ while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_MAIN_CLK)) { timeout--; if (!timeout) break; }
++}
++
++/*!
++ * fs_main_clock_off() - disable main clock
++ */
++void fs_main_clock_off(void)
++{
++ u32 timeout = TIMEOUT_VALUE;
++ //TRACE_MSG0(OCD, "MAIN CLOCK OFF");
++ fs_wl_set(OCD, OTG_CORE_CLK_CTRL, 0);
++ while((fs_rl(OTG_CORE_CLK_CTRL) & MODULE_MAIN_CLK)) { timeout--; if (!timeout) break; }
++}
++
++/* ********************************************************************************************* */
++
++/*!
++ * fs_disable_interrupts() - disable interrupts
++ */
++void fs_disable_interrupts (void)
++{
++ fs_wl(OTG_CORE_CINT_STEN, 0 );
++ fs_wl(OTG_CORE_HINT_STEN, 0 );
++ fs_wl(OTG_HOST_SINT_STEN, 0 );
++ fs_wl(OTG_HOST_XYINT_STEN, 0 );
++ fs_wl(OTG_HOST_ETD_EN, 0);
++ fs_wl(OTG_HOST_ETD_DONE, 0 );
++ fs_wl(OTG_FUNC_SINT_STEN, 0 );
++ fs_wl(OTG_FUNC_XYINT_STEN, 0 );
++ fs_wl(OTG_FUNC_EP_EN, 0 );
++ fs_wl(OTG_FUNC_EP_DEN, 0 );
++}
++
++/* ********************************************************************************************* */
++
++/* ********************************************************************************************* */
++/*!
++ * fs_init() - initial tcd setup
++ * Allocate interrupts and setup hardware.
++ */
++void fs_init (void)
++{
++ int timeout;
++ unsigned long flags;
++
++ TRACE_MSG0(OCD, "MX2_MOD_OCD_INIT");
++ local_irq_save (flags);
++
++ fs_wl(OTG_SYS_CTRL, 0x0);
++
++ /* 2. Ensure hardware is reset and cleared
++ */
++ fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_DMA_BASE), (32*16/4));
++ //fs_clear((void *)MX2_IO_ADDRESS(OTG_FUNC_BASE), 0x200);
++ fs_main_clock_off();
++
++ fs_wl_clr(OCD, OTG_CORE_RST_CTRL, MODULE_RSTI2C | 0x3f);
++ while (fs_rl(OTG_CORE_RST_CTRL));
++
++ /* 3. OTG Hardware Mode and clocks
++ * set to diff, diff and Configure the OTG to behave as function
++ */
++ TRACE_MSG0(OCD, "3. OTG Software Mode and clock");
++ fs_andl(OTG_CORE_HWMODE, 0xffffff0f); // clear
++ fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_SHNP); // set to software hnp
++ fs_rl(OTG_CORE_HWMODE);
++
++ fs_andl(OTG_CORE_HNP_CSTAT, ~0x00000800);
++ fs_rl(OTG_CORE_HNP_CSTAT);
++
++ fs_wl_set(OCD, OTG_CORE_HNP_T3PCR, 0x00000000);
++ fs_rl(OTG_CORE_HNP_T3PCR);
++
++ TRACE_MSG0(OCD, "6. Enable ");
++ TRACE_MSG0(OCD, "enable core interrupts");
++
++ fs_wl(OTG_CORE_CINT_STEN, 0);
++
++ fs_wl(OTG_CORE_CINT_STEN, MODULE_ASHNPINT_EN |
++ MODULE_ASHCINT_EN | MODULE_HNPINT_EN | MODULE_HCINT);
++
++
++ TRACE_MSG0(OCD, "enable host interrupts");
++ fs_wl(OTG_CORE_HINT_STEN, HNP_I2COTGINT_EN | HNP_AWAITBTO_EN |
++ HNP_AIDLEBDTO_EN | HNP_SRPSUCFAIL_EN | HNP_SRPINT_EN | HNP_VBUSERROR_EN |
++ HNP_ABSEVAILD_EN | HNP_ABUSVALID_EN | HNP_MASSLVCHG_EN | HNP_IDCHANGE_EN);
++
++ TRACE_MSG0(OCD, "disable various host interrupts");
++ fs_wl(OTG_HOST_XYINT_STEN, 0);
++ fs_wl(OTG_HOST_ETD_EN, 0);
++ fs_wl(OTG_HOST_ETD_DONE, 0);
++ fs_wl(OTG_HOST_SINT_STEN, 0);
++
++ TRACE_MSG0(OCD, "disable various function interrupts");
++ fs_wl(OTG_FUNC_XYINT_STEN, 0);
++ fs_wl(OTG_FUNC_EP_EN, 0);
++ fs_wl(OTG_FUNC_EP_DEN, 0);
++
++ fs_wl(OTG_DMA_DINT_STEN, 0x3);
++ //fs_wb(I2C_MASTER_INT_REG_ADD, 0xf0);
++ //fs_wb(I2C_MASTER_INT_REG_ADD, 0x00);
++
++ // XXX note that newer designs than the mx21 will also need to check
++ // and/or set OTG_CORE_INTERRUPT_STEN
++
++
++ TRACE_MSG0(OCD, "--");
++ TRACE_MSG0(OCD, "8. Ready ");
++ TRACE_MSG0(OCD, "--");
++
++ local_irq_restore (flags);
++}
++
++extern void fs_stop_ep(int epn, int dir);
++
++/*!
++ * fs_exit() - de-initialize
++ */
++void fs_exit(void)
++{
++ int i;
++ unsigned long flags;
++ TRACE_MSG0(OCD, "MX2_MOD_OCD_EXIT");
++
++ fs_disable_interrupts();
++ //_reg_CRM_PCCR1 &= ~(1<<27); // disable GPT3
++
++ local_irq_save (flags);
++ for (i = 0; i < 16; i++) {
++ fs_stop_ep(i, USB_DIR_IN);
++ fs_stop_ep(i, USB_DIR_OUT);
++ }
++ fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_EP_BASE), (32*16/4));
++ //fs_clear((void *)MX2_IO_ADDRESS(OTG_EP_BASE), 0x200);
++ //fs_clear((volatile u32 *)MX2_IO_ADDRESS(OTG_DMA_BASE), 32*16);
++ //fs_clear((void *)MX2_IO_ADDRESS(OTG_FUNC_BASE), 0x200);
++ fs_wl( OTG_CORE_HWMODE, 0xa3);
++ fs_main_clock_off();
++ local_irq_restore (flags);
++}
++
++
++/*!
++ * fs_ocd_init() - used to initialize/enable or disable the tcd driver
++ * @param otg
++ * @param flag
++ */
++void fs_ocd_init(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(OCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(OCD, "MX2_OCD_EN SET");
++ fs_init();
++ otg_event(otg, TCD_OK | ID_FLOAT, OCD, "OCD_OK");
++ break;
++ case RESET:
++ fs_exit();
++ TRACE_MSG0(OCD, "MX2_OCD_EN RESET");
++ otg_event(otg, TCD_OK | ID_FLOAT, OCD, "OCD_OK");
++ break;
++ }
++}
++
++/* ********************************************************************************************* */
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-pcd.c linux/drivers/otg/ocd/fsotg/fs-pcd.c
+--- linux/drivers/no-otg/ocd/fsotg/fs-pcd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/fsotg/fs-pcd.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,793 @@
++/*
++ * otg/ocd/fsotg/fs-pcd.c -- Freescale USBOTG Peripheral Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/fsotg/fs-pcd.c
++ * @brief Freescale USB Peripheral Controller Driver
++ * This implements the Freescale USBOTG Peripheral Controller Driver.
++ *
++ * There is some processor specific code here to support the alternate processors
++ * that implement this type of USB support.
++ *
++ * There is no board or platform level code here.
++ *
++ * @ingroup FSOTG
++ *
++ * @{
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <asm/arch/mx2.h>
++
++#include <otghw/fsotg-hardware.h>
++
++void fs_func_clock_on(void); /* defined in mx2-ocd.c */
++void fs_func_clock_off(void); /* defined in mx2-ocd.c */
++
++u8 fs_new_address, fs_usb_address; /* used to save and set USB address */
++
++/* ********************************************************************************************* */
++/*!
++ * fs_ep_config() - configure and enable an endpoint to send or receive data
++ * First setup the endpoint descriptor words, and then enable the endpoint and done interrupt
++ * @param epn - endpoint number
++ * @param dir - direction IN or OUT
++ * @param ep_num -
++ * @param wMaxPacketSize
++ * @param format
++ * @param ttlbtecnt
++ * @param stall
++ */
++static void inline
++fs_ep_config(int epn, int dir, u32 ep_num, int wMaxPacketSize, int format, int ttlbtecnt, int stall)
++{
++ TRACE_MSG6(PCD, "epn: %02x dir: %02x sz: %d fmt: %x cnt: %d stall: %d",
++ epn, dir, wMaxPacketSize, format, ttlbtecnt, stall);
++
++ fs_wl(ep_word(epn, dir, 0), ((stall ? 1 : 0) << 31) | (wMaxPacketSize << 16) | ((format & 3) << 14));
++ fs_wl(ep_word(epn, dir, 1), ttlbtecnt ? (data_y_buf(epn, dir) << 16) | data_x_buf(epn, dir): 0);
++ fs_wl(ep_word(epn, dir, 3), ((wMaxPacketSize-1) << 21) | ttlbtecnt);
++ fs_orl(OTG_FUNC_IINT, ep_num); // issue done status interrupts immediately
++ fs_orl(OTG_FUNC_EP_DEN, ep_num); // enable endpoint done interrupt
++ fs_orl(OTG_FUNC_EP_EN, ep_num); // enable the interrupt
++}
++
++/*!
++ * fs_ep_config_dma() - configure and enable an endpoint to send or receive data
++ * Check the RDY bit and clear if necessary, setup dma, do common setup and then set RDY.
++ * @param epn - endpoint number
++ * @param dir - direction IN or OUT
++ * @param wMaxPacketSize
++ * @param format
++ * @param ttlbtecnt
++ * @param bp
++ */
++static void inline
++fs_ep_config_dma(int epn, int dir, int wMaxPacketSize, int format, int ttlbtecnt, u8 *bp)
++{
++ u32 ep_num = ep_num_dir(epn, dir);
++ u32 dma_num = dma_num_dir(epn, dir);
++ TRACE_MSG2(PCD, "EP CONFIG DMA: epn: %02x num: %02x", epn, ep_num);
++ if (fs_rl(OTG_FUNC_EP_RDY) & ep_num) fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num);
++ fs_wl(OTG_DMA_EPN_MSA(dma_num), (int)bp);
++ fs_wl_set(PCD, OTG_DMA_EP_EN, ep_num);
++ fs_ep_config(epn, dir, ep_num, wMaxPacketSize, format, ttlbtecnt, 0);
++ fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num); // toggle ready bit
++}
++
++/*!
++ * fs_ep_config_nodma() - configure and enable an endpoint to send or receive data
++ * Non-DMA setup, optional stall, ready etc.
++ * @param epn - endpoint number
++ * @param dir
++ * @param stall - stall endpoint
++ * @param wMaxPacketSize
++ * @param format
++ * @param ttlbtecnt
++ * @param rdy1
++ * @param rdy2
++ */
++static void
++fs_ep_config_nodma(int epn, int dir, int stall, int wMaxPacketSize, int format, int ttlbtecnt, int rdy1, int rdy2)
++{
++ u32 ep_num = ep_num_dir(epn, dir);
++ TRACE_MSG5(PCD, "EP CONFIG NODMA: epn: %02x num: %02x stall: %d r1: %d r2: %d", epn, ep_num, stall, rdy1, rdy2);
++ #if 1
++ // XXX This should work, but enumeratation fails after disable/enable
++ if (rdy1) {
++ TRACE_MSG3(PCD, "EP CONFIG NODMA: epn: %02x num: %02x checking RDY: %02x",
++ epn, ep_num, rdy1 && fs_rl(OTG_FUNC_EP_RDY) & ep_num);
++ RETURN_IF (rdy1 && (fs_rl(OTG_FUNC_EP_RDY) & ep_num));
++ }
++ #endif
++ UNLESS(epn)
++ fs_orl(OTG_FUNC_XYINT_STEN, ep_num); // enable x or y buffer interrupt
++
++ fs_ep_config(epn, dir, ep_num, wMaxPacketSize, format, ttlbtecnt, stall);
++ RETURN_UNLESS(rdy2);
++ UNLESS (fs_rl(OTG_FUNC_EP_RDY) & ep_num) fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num); // toggle ready bit
++}
++
++/*!
++ * fs_sendzlp() - start sending a buffer on a specified endpoint
++ * Toggle XFILL_STAT or YFILL_STAT bit, then call fs_ep_config_nodma().
++ * @param epn - endpoint number
++ * @param endpoint - endpoint instance
++ * @param wMaxPacketSize
++ */
++static void inline
++fs_sendzlp (int epn, struct usbd_endpoint_instance *endpoint, int wMaxPacketSize)
++{
++ u32 ep_num_in = ep_num_in(epn);
++ TRACE_MSG0(PCD, "ZLP");
++ if (!(fs_rl(OTG_FUNC_XFILL_STAT) & ep_num_in)) {
++ //TRACE_MSG0(PCD, "EMPTY Y BUFFER: ZLP");
++ fs_wl_set(PCD, OTG_FUNC_XFILL_STAT, ep_num_in);
++ }
++ else if (!(fs_rl(OTG_FUNC_YFILL_STAT) & ep_num_in)) {
++ //TRACE_MSG0(PCD, "EMPTY Y BUFFER: ZLP");
++ fs_wl_set(PCD, OTG_FUNC_YFILL_STAT, ep_num_in);
++ }
++ fs_ep_config_nodma(epn, USB_DIR_IN, 0, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 1, 1);
++}
++
++/*!
++ * fs_stop_ep() - stop endpoint
++ * @param epn - endpoint number
++ * @param dir - direction IN or OUT
++ */
++static void fs_stop_ep(int epn, int dir)
++{
++ int ep_num = ep_num_dir(epn, dir);
++
++ TRACE_MSG3(PCD, "STOP EP: %08x dir: %02x [%08x]", ep_num, dir, fs_rl(ep_word(epn, dir, 0)));
++
++ //fs_wl(ep_word(epn, dir, 0), ((stall ? 1 : 0) << 31) | (wMaxPacketSize << 16) | ((format & 3) << 14));
++
++ if (fs_rl(OTG_FUNC_EP_RDY) & ep_num)
++ fs_wl_clr(PCD, OTG_FUNC_EP_RDY, ep_num);
++ fs_andl(OTG_FUNC_XYINT_STEN, ~ep_num);
++ fs_andl(OTG_FUNC_IINT, ~ep_num);
++ if (fs_rl(OTG_FUNC_XINT_STAT) & ep_num) {
++ fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, ep_num);
++ fs_wl_clr(PCD, OTG_FUNC_XFILL_STAT, ep_num);
++ }
++ else if (fs_rl(OTG_FUNC_YINT_STAT) & ep_num) {
++ fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, ep_num);
++ fs_wl_clr(PCD, OTG_FUNC_YFILL_STAT, ep_num);
++ }
++}
++
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_setup_ep() - setup endpoint
++ * @param pcd - pcd instance
++ * @param epn - endpoint number
++ * @param endpoint - endpoint instance
++ */
++static void inline
++fs_pcd_setup_ep (struct pcd_instance *pcd, unsigned int epn, struct usbd_endpoint_instance *endpoint)
++{
++ TRACE_MSG2(PCD, "START EPN: config %d %02x", epn, endpoint->bEndpointAddress);
++ if (epn && endpoint->bEndpointAddress)
++ fs_ep_config_nodma(endpoint->bEndpointAddress & 0x7f, endpoint->bEndpointAddress & USB_DIR_IN, 0,
++ endpoint->wMaxPacketSize, endpoint->bmAttributes&0x3, 0, 0, 0);
++}
++
++/*!
++ * fs_pcd_start_ep0_setup() - enable ep0 for receiving SETUP request
++ * Unless already ready, configure ep0 to receive.
++ * @param endpoint - endpoint instance
++ */
++static void inline
++fs_pcd_start_ep0_setup (struct usbd_endpoint_instance *endpoint)
++{
++ TRACE_MSG0(PCD, "START EP0: config");
++ fs_ep_config_nodma(0, USB_DIR_OUT, 0, endpoint->wMaxPacketSize, endpoint->bmAttributes&0x3,
++ endpoint->wMaxPacketSize, 0, 1); // XXX rdy1 must be zero
++}
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_start_endpoint_out() - start receive
++ * @param pcd - pcd instance
++ * @param endpoint - endpoint number
++ */
++static void
++fs_pcd_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
++ int epn = endpoint->bEndpointAddress & 0x7f;
++ UNLESS (rcv_urb) {
++ UNLESS (!epn) fs_pcd_start_ep0_setup(endpoint); // if EP0 then restart for receive setup
++ return;
++ }
++ rcv_urb->pcimap = (void *)pci_map_single (NULL, (void *) rcv_urb->buffer, rcv_urb->buffer_length, PCI_DMA_FROMDEVICE);
++ fs_ep_config_dma(epn, USB_DIR_OUT, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3,
++ rcv_urb->buffer_length, rcv_urb->pcimap);
++ TRACE_MSG3(PCD, "START OUT: %02x rcv_urb: %x length: %d", endpoint->bEndpointAddress, rcv_urb, rcv_urb->actual_length);
++}
++
++/*!
++ * fs_pcd_stop_out() - process interrupt for received buffer
++ * @param pcd - pcd instance
++ * @param epn - endpoint number
++ * @param endpoint - endpoint instance
++ */
++static void
++fs_pcd_stop_out (struct pcd_instance *pcd, int epn, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
++ u32 ep3 = fs_rl(ep_word(epn, USB_DIR_OUT, 3));
++ u32 ep_num_out = ep_num_out(epn);
++ fs_stop_ep(epn, USB_DIR_OUT);
++ RETURN_UNLESS (rcv_urb);
++ pcd_rcv_finished_irq (endpoint,rcv_urb->buffer_length - (ep3 & 0xffff), 0); // XXX fix mask
++ if (!epn)
++ fs_sendzlp(epn, endpoint, endpoint->wMaxPacketSize); // ZLP
++ else
++ fs_pcd_start_endpoint_out(pcd, endpoint); // restart
++}
++/* fs_pcd_cancel_out_irq - cancel OUT urb
++ */
++static void
++fs_pcd_cancel_out_irq (struct pcd_instance *pcd,struct usbd_urb *urb)
++{
++ struct usbd_endpoint_instance *endpoint = urb->endpoint;
++ int epn = endpoint->bEndpointAddress & 0x7f;
++ TRACE_MSG3(PCD, "urb: %x endpoint: %x epn: %d", urb, endpoint, epn);
++ fs_pcd_stop_out (pcd, epn, endpoint);
++}
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_start_endpoint_in() - start transmit
++ * Get next tx_urb (completing old one if there is one) and start sending it.
++ * @param pcd - pcd instance
++ * @param endpoint - endpoint instance
++ */
++static void
++fs_pcd_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
++ int epn = endpoint->bEndpointAddress & 0x7f;
++
++ UNLESS (tx_urb) {
++ TRACE_MSG1(PCD, "START IN: %02x finished", endpoint->bEndpointAddress);
++ UNLESS (epn) { // if not EP0 we are done
++ if (fs_new_address != fs_usb_address) {
++ fs_usb_address = fs_new_address;
++ //TRACE_MSG1(PCD, "START IN: SETTING ADDRESS %x", fs_usb_address);
++ fs_wl(OTG_FUNC_DEV_ADDR, fs_usb_address);
++ }
++ fs_pcd_start_ep0_setup(endpoint); // if EP0 then restart for receive setup
++ }
++ return;
++ }
++
++ if (pcd_tx_sendzlp(endpoint)) { // check if we need to send ZLP
++ TRACE_MSG1(PCD, "START IN: ZLP tx_urb: %x", tx_urb);
++ fs_sendzlp(epn, endpoint, endpoint->wMaxPacketSize); // ZLP
++ return;
++ }
++ endpoint->last = tx_urb->actual_length;
++ consistent_sync (tx_urb->buffer, tx_urb->actual_length, PCI_DMA_BIDIRECTIONAL);
++ fs_ep_config_dma(epn, USB_DIR_IN, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3,
++ tx_urb->actual_length, tx_urb->buffer);
++
++ TRACE_MSG4(PCD, "START IN: %02x tx_urb: %x length: %d %s",
++ endpoint->bEndpointAddress, tx_urb, tx_urb->actual_length,
++ (tx_urb->flags & USBD_URB_SENDZLP) ? "ZLP": "");
++}
++
++/*!
++ * fs_pcd_stop_in() - process interrupt for transmitted buffer
++ * @param pcd - pcd instance
++ * @param epn -endpoint number
++ * @param endpoint - endpoint instance
++ */
++static void inline
++fs_pcd_stop_in (struct pcd_instance *pcd, int epn, struct usbd_endpoint_instance *endpoint)
++{
++ fs_stop_ep(epn, USB_DIR_IN);
++ fs_pcd_start_endpoint_in(pcd, endpoint);
++}
++/*!
++ * fs_pcd_cancel_in_irq() - cancel IN urb
++ */
++static void inline
++fs_pcd_cancel_in_irq (struct pcd_instance *pcd,struct usbd_urb *urb)
++{
++ struct usbd_endpoint_instance *endpoint = urb->endpoint;
++ int epn = endpoint->bEndpointAddress & 0x7f;
++ TRACE_MSG3(PCD, "urb: %x endpoint: %x epn: %d", urb, endpoint, epn);
++ fs_pcd_stop_in (pcd, epn, endpoint);
++}
++
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_stop_ep0_setup() - setup endpoint zero
++ * @param pcd - pcd instance
++ * @param endpoint - endpoint instance
++ */
++static void
++fs_pcd_stop_ep0_setup (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ static struct usbd_device_request request;
++ u8 *cp = (u8 *) &request;
++ u32 ep0 = fs_rl(ep_word(0, USB_DIR_OUT, 0));
++ u32 ep3 = fs_rl(ep_word(0, USB_DIR_OUT, 3));
++
++ fs_andl(OTG_FUNC_XYINT_STEN, ~ep_num_both(0));
++ fs_andl(OTG_FUNC_IINT, ~ep_num_both(0));
++ UNLESS (ep0 & EP0_SETUP) { // check if SETUP flag set
++ fs_pcd_stop_out(pcd, 0, endpoint);
++ return;
++ }
++ TRACE_MSG1(PCD, "EP0 - SETUP: size: %x", ep3 & 0xffff);
++ pcd_tx_cancelled_irq(endpoint);
++ pcd_rcv_cancelled_irq(endpoint);
++ fs_orl(OTG_FUNC_EP_TOGGLE, 0x2); // XXX is this required?
++
++ /* get request from x or y buffer
++ */
++ if (fs_rl(OTG_FUNC_XINT_STAT) & ep_num_out(0)) {
++ TRACE_MSG0(PCD, "READ X SETUP");
++ fs_memcpy((u8 *)&request, (u8 *)data_x_address(0, USB_DIR_OUT), 8);
++ fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, ep_num_out(0));
++ fs_wl_clr(PCD, OTG_FUNC_XFILL_STAT, ep_num_out(0));
++ fs_rl(OTG_FUNC_XFILL_STAT);
++ }
++ else if (fs_rl(OTG_FUNC_YINT_STAT) & ep_num_out(0)) {
++ TRACE_MSG0(PCD, "READ Y SETUP");
++ fs_memcpy((u8 *)&request, (u8 *)data_y_address(0, USB_DIR_OUT), 8);
++ fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, ep_num_out(0));
++ fs_wl_clr(PCD, OTG_FUNC_YFILL_STAT, ep_num_out(0));
++ fs_rl(OTG_FUNC_YFILL_STAT);
++ }
++ else
++ TRACE_MSG0(PCD, "READ NO SETUP"); // XXX what should we do here?
++ if (pcd_recv_setup_irq(pcd, &request)) { // process setup packet
++ TRACE_MSG0(PCD, "pcd_ep0: STALLING");
++ fs_rl(OTG_FUNC_XINT_STAT);
++ fs_ep_config_nodma(0, USB_DIR_IN, 1, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 1, 1);
++ return;
++ }
++ RETURN_IF (request.wLength); // fs_pcd_start_endpoint_in() will start xfer
++ if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
++ //RETURN_IF (request.wLength); // fs_pcd_start_endpoint_in() will start xfer
++ fs_sendzlp(0, endpoint, endpoint->wMaxPacketSize); // wLength zero, so send ZLP
++ return;
++ }
++ fs_pcd_start_ep0_setup(endpoint); // restart endpoint
++}
++/* ********************************************************************************************* */
++static int pcd_resetdet_count;
++/*!
++ * fs_pcd_int_hndlr() - interrupt handler
++ * @param irq
++ * @param dev_id
++ * @param regs
++ * @return interrupt handled status
++ */
++static irqreturn_t
++fs_pcd_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct pcd_instance *pcd = pcd_instance;
++ u32 cmd_stat, sint_stat, ep_dstat, ep_stats, mask;
++
++ /* Reset and process any System interrupts
++ */
++ if ((sint_stat = fs_rl(OTG_FUNC_SINT_STAT)))
++ fs_wl_clr(PCD, OTG_FUNC_SINT_STAT, sint_stat);
++
++ cmd_stat = fs_rl(OTG_FUNC_CMD_STAT);
++
++ TRACE_MSG2(PCD, "FUNC INT sint: %08x cmd: %08x", sint_stat, cmd_stat);
++
++ if ((cmd_stat & COMMAND_RESETDET) || (sint_stat & SYSTEM_RESETINT)) {
++ TRACE_MSG1(PCD, "RESETDET: %08x", sint_stat);
++ usbd_bus_event_handler_irq (pcd->bus, DEVICE_RESET, 0);
++ fs_wl(OTG_FUNC_DEV_ADDR, 0);
++ fs_new_address = fs_usb_address = 0;
++ fs_wl(OTG_FUNC_XYINT_STEN, 0);
++ fs_wl(OTG_FUNC_IINT, 0);
++ //fs_wl(OTG_FUNC_EP_DEN, 0); // XXX this fails,
++ fs_wl(OTG_FUNC_EP_TOGGLE, 0);
++ fs_wl_clr(PCD, OTG_FUNC_EP_RDY, fs_rl(OTG_FUNC_EP_RDY));
++ fs_wl_clr(PCD, OTG_FUNC_EP_DSTAT, fs_rl(OTG_FUNC_EP_DSTAT));
++ fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, fs_rl(OTG_FUNC_XINT_STAT));
++ fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, fs_rl(OTG_FUNC_YINT_STAT));
++ if (pcd_resetdet_count++ > 10) {
++
++ //printk(KERN_INFO"%s: SINT: %08x %08x CINT: %08x\n", __FUNCTION__,
++ // sint_stat, fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
++ fs_func_clock_on();
++ fs_wl(OTG_FUNC_SINT_STEN, 0);
++ fs_wl(OTG_CORE_CINT_STEN, 0);
++ fs_wl(OTG_FUNC_XYINT_STEN, 0);
++ fs_wl(OTG_FUNC_EP_EN, 0);
++ fs_wl(OTG_FUNC_EP_DEN, 0);
++ fs_func_clock_off();
++ //printk(KERN_INFO"%s: SINT: %08x %08x CINT: %08x RESET\n", __FUNCTION__,
++ // sint_stat, fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
++ }
++ }
++ if ((cmd_stat & COMMAND_RSMINPROG) || (sint_stat & SYSTEM_RSMFININT)) {
++ TRACE_MSG1(PCD, "RSMINPRO: %08x", sint_stat);
++ fs_wl_set(PCD, OTG_FUNC_SINT_STAT,SYSTEM_RSMFININT);
++ fs_func_clock_on();
++ usbd_bus_event_handler_irq (pcd->bus, DEVICE_BUS_ACTIVITY, 0);
++ }
++ if ((cmd_stat & COMMAND_SUPDET) || (sint_stat & SYSTEM_SUSPDETINT)) {
++ int timeout = 0;
++ TRACE_MSG1(PCD, "SUSPENDDET: %08x", sint_stat);
++ fs_wl_set(PCD, OTG_FUNC_SINT_STAT,SYSTEM_SUSPDETINT);
++ fs_func_clock_off();
++ usbd_bus_event_handler_irq (pcd->bus, DEVICE_BUS_INACTIVE, 0);
++ }
++ ep_dstat = fs_rl(OTG_FUNC_EP_DSTAT);
++ ep_stats = ep_dstat | fs_rl(OTG_FUNC_XINT_STAT) | fs_rl(OTG_FUNC_YINT_STAT);
++ if (ep_stats) {
++ int i;
++
++ pcd_resetdet_count = 0;
++
++ /* clear the done status flags
++ */
++ TRACE_MSG1(PCD, "EP STATS: %08x", ep_stats);
++ fs_wl_clr(PCD, OTG_FUNC_EP_DSTAT, ep_dstat);
++
++ /* check ep0 first - special handling for control endpoint, need to check dstat, y/x stats
++ */
++ if (ep_stats & EP_OUT) fs_pcd_stop_ep0_setup(pcd, pcd->bus->endpoint_array);
++ if (ep_stats & EP_IN) fs_pcd_stop_in(pcd, 0, pcd->bus->endpoint_array);
++
++ /* now check all of the data endpoints, only if in dstat
++ */
++ for (i = 1, ep_dstat >>= 2; ep_dstat && (i < 16); i++, ep_dstat >>= 2) {
++ if (ep_dstat & EP_OUT) fs_pcd_stop_out(pcd, i, pcd->bus->endpoint_array + (2 * i));
++ if (ep_dstat & EP_IN) fs_pcd_stop_in(pcd, i, pcd->bus->endpoint_array + (2 * i) + 1);
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_set_address() - set the USB address for this device
++ * @param pcd
++ * @param address
++ */
++static void inline
++fs_pcd_set_address (struct pcd_instance *pcd, u8 address)
++{
++ fs_usb_address = 0;
++ fs_new_address = address; /* this will be used in the interrupt handler */
++}
++
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_en_func() - enable
++ * This is called to enable / disable the PCD and USBD stack.
++ * @param otg - otg instance
++ * @param flag - SET or RESET
++ */
++static void
++fs_pcd_en_func (struct otg_instance *otg, u8 flag)
++{
++ unsigned long flags;
++ struct pcd_instance *pcd = otg->pcd;
++ struct usbd_bus_instance *bus = pcd->bus;
++ u32 hwmode = fs_rl(OTG_CORE_HWMODE);
++
++
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(PCD, "PCD_EN: SET");
++ local_irq_save (flags);
++ fs_andl(OTG_CORE_HWMODE, 0xffffff0f); // clear
++
++ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ if (hwmode & MODULE_CRECFG_HOST) {
++ printk(KERN_INFO"%s: warning HOST STILL SET\n", __FUNCTION__);
++ }
++ fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_FUNC); // set to software hnp
++
++ /* reset the function core
++ */
++ //fs_wl_clr(PCD, OTG_CORE_RST_CTRL, MODULE_RSTFSIE | MODULE_RSTFC);
++ //while (fs_rl(OTG_CORE_RST_CTRL));
++
++ fs_func_clock_on();
++
++ fs_pcd_start_ep0_setup(pcd->bus->endpoint_array);
++
++ /* C.f. L3 12.1 - enable Slave, Band Gap enable, and Comparator enable.
++ * C.f. SCM-11 version of the USBOTG specification, ABBusReq enables the charge pump
++ */
++ fs_andl(OTG_CORE_HNP_CSTAT, ~(MODULE_MASTER | MODULE_SLAVE |
++ MODULE_CMPEN | MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ));
++
++ fs_orl(OTG_CORE_HNP_CSTAT, MODULE_SLAVE | MODULE_CMPEN | MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ);
++ fs_rl(OTG_CORE_HNP_CSTAT);
++
++ fs_orl(OTG_FUNC_SINT_STEN, ( /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
++ SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN));
++
++ fs_orl(OTG_CORE_CINT_STEN, MODULE_FCINT_EN | MODULE_ASFCINT_EN);
++ //printk(KERN_INFO"%s: SINT: %08x CINT: %08x SET\n", __FUNCTION__,
++ // fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
++ local_irq_restore (flags);
++
++ break;
++
++ case RESET:
++ TRACE_MSG0(PCD, "PCD_EN: RESET");
++ //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
++
++ //fs_andl(OTG_FUNC_SINT_STEN, ~( /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
++ // SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN));
++
++ local_irq_save (flags);
++ fs_func_clock_on();
++ fs_andl(OTG_FUNC_SINT_STEN, 0);
++ fs_andl(OTG_CORE_CINT_STEN, ~(MODULE_FCINT_EN | MODULE_ASFCINT_EN));
++
++ fs_func_clock_off();
++ //printk(KERN_INFO"%s: SINT: %08x CINT: %08x RESET\n", __FUNCTION__,
++ // fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
++
++ /* reset the function core
++ */
++ fs_wl_clr(PCD, OTG_CORE_RST_CTRL, MODULE_RSTFSIE | MODULE_RSTFC);
++ while (fs_rl(OTG_CORE_RST_CTRL));
++ fs_andl(OTG_CORE_HWMODE, ~MODULE_CRECFG_FUNC); // set to software hnp
++ local_irq_restore (flags);
++
++ usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
++
++ break;
++ }
++ TRACE_MSG1(PCD, "HWMODE: %08x", fs_rl(OTG_CORE_HWMODE));
++}
++
++/*!
++ * fs_remote_wakeup() - perform remote wakeup.
++ * Initiate a remote wakeup to the host.
++ * @param otg - otg instance
++ * @param flag - SET or RESET
++ */
++static void
++fs_remote_wakeup(struct otg_instance *otg, u8 flag)
++{
++ unsigned long flags;
++ TRACE_MSG0(PCD, "MX2_REMOTE_WAKEUP: ");
++ local_irq_save (flags);
++ fs_wl_set(PCD, OTG_FUNC_CMD_STAT, COMMAND_RSMINPROG);
++ fs_wl(OTG_FUNC_CMD_STAT, COMMAND_RSMINPROG);
++ local_irq_restore (flags);
++}
++
++/* ********************************************************************************************* */
++/*!
++ * fs_pcd_start() - start the UDC
++ * @param pcd
++ */
++static void
++fs_pcd_start (struct pcd_instance *pcd)
++{
++ //TRACE_MSG0(PCD, "UDC START");
++ fs_rl(OTG_FUNC_SINT_STEN);
++ //fs_pcd_start_ep0_setup(pcd_instance->bus->endpoint_array);
++}
++
++/*!
++ * fs_pcd_stop() - stop the UDC
++ * @param pcd
++ */
++static void
++fs_pcd_stop (struct pcd_instance *pcd)
++{
++ TRACE_MSG0(PCD, "UDC STOP");
++}
++
++/*!
++ * pcd_assign_endpoint()
++ */
++static int
++pcd_assign_endpoint(u8 physicalEndpoint, int used[UDC_MAX_ENDPOINTS],
++ struct usbd_endpoint_map *endpoint_map, u8 bmAttributes, u16 wMaxPacketSize, u16 transferSize)
++{
++ RETURN_EINVAL_IF( used[physicalEndpoint] );
++ endpoint_map->bEndpointAddress[0] = physicalEndpoint | (USB_DIR_IN & bmAttributes);
++ endpoint_map->physicalEndpoint[0] = (physicalEndpoint * 2) + ((USB_DIR_IN & bmAttributes) ? 1 : 0);
++ endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
++ endpoint_map->transferSize[0] = transferSize;
++ endpoint_map->bmAttributes[0] = bmAttributes;
++ used[physicalEndpoint]++;
++ TRACE_MSG4(PCD, "ASSIGN: index: %02x phys: %02x addr: %02x", physicalEndpoint,
++ endpoint_map->physicalEndpoint[0], endpoint_map->bEndpointAddress[0], 0);
++ return 0;
++}
++
++/*!
++ * fs_pcd_request_endpoints()
++ * @param pcd
++ * @param endpoint_map_array
++ * @param endpointsRequested
++ * @param requestedEndpoints
++ */
++static int
++fs_pcd_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested,
++ struct usbd_endpoint_request *requestedEndpoints)
++{
++ struct usbd_device_description *device_description;
++ int i, in, out;
++ int in_used[UDC_MAX_ENDPOINTS];
++ int out_used[UDC_MAX_ENDPOINTS];
++ memset(in_used, 0, sizeof(in_used));
++ memset(out_used, 0, sizeof(out_used));
++ TRACE_MSG1(PCD, "REQUEST ENDPOINTS: %d", endpointsRequested);
++ for (in = out = 1, i = 0; i < endpointsRequested; i++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ u8 bmAttributes = requestedEndpoints[i].bmAttributes;
++ u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
++ switch(bmAttributes) {
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ CONTINUE_IF(!pcd_assign_endpoint(in++, in_used, endpoint_map, bmAttributes, 0x40, transferSize));
++ THROW(error);
++
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ CONTINUE_IF(!pcd_assign_endpoint(out++, out_used, endpoint_map, bmAttributes, 0x40, transferSize));
++ //CONTINUE_IF(!pcd_assign_endpoint(in++, out_used, endpoint_map, bmAttributes, 0x40, transferSize));
++ THROW(error);
++
++ case USB_ENDPOINT_CONTROL:
++ continue;
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ THROW(error);
++ }
++ THROW(error);
++ CATCH(error) {
++ printk(KERN_ERR"%s: FAILED num: %d bmAttributes: %02x transferSize: %02x\n",
++ __FUNCTION__, i, bmAttributes, transferSize);
++ return -EINVAL;
++ }
++ }
++ return 0;
++}
++
++/*!
++ * fs_pcd_set_endpoints() - setup the physical endpoints for the endpoint map
++ * @param pcd
++ * @param endpointsRequested
++ * @param endpoint_map_array
++ */
++static int
++fs_pcd_set_endpoints (struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
++{
++ fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_EP_BASE), (32*16/4));
++ //fs_clear((void *)MX2_IO_ADDRESS(OTG_EP_BASE), 0x200);
++ TRACE_MSG0(PCD, "Enable system control interrupts");
++ fs_wl(OTG_SYS_CTRL, SYS_CTRL_I2C_WU_INT_EN | SYS_CTRL_OTG_WU_INT_EN | SYS_CTRL_HOST_WU_INT_EN | SYS_CTRL_FNT_WU_INT_EN);
++ return 0;
++}
++
++/*!
++ * fs_pcd_framenum() - get current framenum
++ */
++static u16
++fs_pcd_framenum (void)
++{
++ return fs_rl(OTG_FUNC_FRM_NUM);
++}
++
++/*
++ * fs_endpoint_halted() - is endpoint halted
++ */
++static int
++fs_endpoint_halted (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
++{
++ int epn = endpoint->bEndpointAddress & 0x7f;
++ int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
++
++ TRACE_MSG2(PCD, "epn: %02x dir: %x", epn, dir);
++ return fs_rl(ep_word(epn, dir, 0)) & (1 << 31) ? TRUE : FALSE;
++}
++
++/* fs_halt_endpoint - halt endpoint
++ */
++int fs_halt_endpoint(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint, int flag)
++{
++ int epn = endpoint->bEndpointAddress & 0x7f;
++ int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
++ TRACE_MSG3(PCD, "epn: %02x dir: %x flag: %d", epn, dir, flag);
++ fs_ep_config_nodma(epn, USB_DIR_IN, flag, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 0, 1);
++ return 0;
++}
++
++/* ********************************************************************************************* */
++
++#if !defined(OTG_C99)
++struct usbd_pcd_ops usbd_pcd_ops;
++struct pcd_ops pcd_ops;
++
++/*!
++ * fs_pcd_global_init() - initialize globals
++ */
++static void
++fs_pcd_global_init(void)
++{
++ ZERO(usbd_pcd_ops);
++ usbd_pcd_ops.bmAttributes = USB_OTG_HNP_SUPPORTED | USB_OTG_SRP_SUPPORTED;
++ usbd_pcd_ops.max_endpoints = UDC_MAX_ENDPOINTS;
++ usbd_pcd_ops.ep0_packetsize = EP0_PACKETSIZE;
++ usbd_pcd_ops.capabilities = REMOTE_WAKEUP_SUPPORTED;
++ usbd_pcd_ops.name = UDC_NAME;
++ usbd_pcd_ops.start = fs_pcd_start;
++ usbd_pcd_ops.stop = fs_pcd_stop;
++ usbd_pcd_ops.start_endpoint_in = fs_pcd_start_endpoint_in;
++ usbd_pcd_ops.start_endpoint_out = fs_pcd_start_endpoint_out;
++ usbd_pcd_ops.request_endpoints = fs_pcd_request_endpoints;
++ usbd_pcd_ops.set_endpoints = fs_pcd_set_endpoints;
++ usbd_pcd_ops.set_address = fs_pcd_set_address;
++ usbd_pcd_ops.setup_ep = fs_pcd_setup_ep;
++ usbd_pcd_ops.halt_endpoint = fs_halt_endpoint;
++ usbd_pcd_ops.endpoint_halted = fs_endpoint_halted;
++
++ usbd_pcd_ops.cancel_in_irq = fs_pcd_cancel_in_irq;
++ usbd_pcd_ops.cancel_out_irq = fs_pcd_cancel_out_irq;
++
++ ZERO(pcd_ops);
++ pcd_ops.pcd_en_func = fs_pcd_en_func;
++ pcd_ops.pcd_init_func = pcd_init_func;
++ pcd_ops.remote_wakeup_func = fs_remote_wakeup;
++ pcd_ops.framenum = fs_pcd_framenum;
++}
++#else /* !defined(OTG_C99) */
++static struct
++usbd_pcd_ops usbd_pcd_ops = {
++ .bmAttributes = USB_OTG_HNP_SUPPORTED | USB_OTG_SRP_SUPPORTED,
++ .max_endpoints = UDC_MAX_ENDPOINTS,
++ .ep0_packetsize = EP0_PACKETSIZE,
++ .capabilities = REMOTE_WAKEUP_SUPPORTED,
++ .name = UDC_NAME,
++ .start = fs_pcd_start,
++ .stop = fs_pcd_stop,
++ .start_endpoint_in = fs_pcd_start_endpoint_in,
++ .start_endpoint_out = fs_pcd_start_endpoint_out,
++ .request_endpoints = fs_pcd_request_endpoints,
++ .set_endpoints = fs_pcd_set_endpoints,
++ .set_address = fs_pcd_set_address,
++ .setup_ep = fs_pcd_setup_ep,
++ .halt_endpoint = fs_halt_endpoint,
++ .endpoint_halted = fs_endpoint_halted,
++
++ .cancel_in_irq = fs_pcd_cancel_in_irq,
++ .cancel_out_irq = fs_pcd_cancel_out_irq,
++};
++
++struct pcd_ops pcd_ops = {
++ .pcd_en_func = fs_pcd_en_func,
++ .pcd_init_func = pcd_init_func,
++ .remote_wakeup_func = fs_remote_wakeup,
++ .framenum = fs_pcd_framenum,
++};
++#endif /* !defined(OTG_C99) */
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/ocd/gen/gen.c linux/drivers/otg/ocd/gen/gen.c
+--- linux/drivers/no-otg/ocd/gen/gen.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/gen/gen.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,268 @@
++/*
++ * otg/ocd/gen/gen.c -- USB Device Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/gen/gen.c
++ * @brief Sample driver
++ *
++ *
++ * @ingroup USBP
++ */
++
++#include <udc.h>
++#include <asm/hardware.h>
++#include "gen.h"
++
++
++static unsigned char usb_address;
++
++/* ********************************************************************************************* */
++/* udc_write_buffer - write a buffer to the udc fifo
++ */
++static void udc_write_buffer (unsigned char ep, unsigned char *b, unsigned char size)
++{
++}
++
++/* udc_read_buffer - fill a buffer from the udc fifo
++ */
++static void udc_read_buffer (unsigned char ep, unsigned char *b, unsigned char size)
++{
++}
++
++/* udc_out - process an OUT interrupt
++ */
++static void udc_out (struct usbd_endpoint_instance *endpoint)
++{
++}
++
++/* udc_in - process an IN interrupt
++ */
++static void udc_in (struct usbd_endpoint_instance *endpoint)
++{
++}
++
++/* ********************************************************************************************* */
++/* udc_in_ep0 - start transmit of ep0 Control Read data
++ */
++static void udc_in_ep0 (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb = pcd_tx_complete_irq (endpoint, 0);
++ if (!tx_urb || pcd_tx_sendzlp (endpoint)) {
++ udc_write_buffer (0, NULL, 0);
++ return;
++ }
++ TRACE_MSG16("EP0 IN: actual: %d sent: %d", endpoint->tx_urb->actual_length, endpoint->sent);
++ endpoint->last = MIN (tx_urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
++ udc_write_buffer (0, tx_urb->buffer + endpoint->sent, endpoint->last);
++}
++
++/* udc_out_ep0 - start receive of ep0 Control Write data
++ */
++static void udc_out_ep0 (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *rcv_urb = pcd_rcv_next_irq (endpoint);
++ int size = 0;
++ RETURN_IF(!rcv_urb);
++ TRACE_MSG8("OUT EP0: actual: %d buffer_length: %d size: %d", rcv_urb->actual_length, rcv_urb->buffer_length, size, 0);
++ udc_read_buffer (0, rcv_urb->buffer + rcv_urb->actual_length, size);
++ if (!pcd_rcv_complete_irq (endpoint, size, 0))
++ endpoint->state = WAIT_FOR_SETUP;
++}
++
++/* udc_ep0_setup - process a Control Setup command
++ */
++static void udc_ep0_setup (struct usbd_endpoint_instance *endpoint)
++{
++ static struct usbd_device_request request;
++ u8 *cp = (u8 *) &request;
++ int i;
++ TRACE_MSG32("EP0 SETUP: tx_urb: %p", (int)endpoint->tx_urb);
++ pcd_tx_cancelled_irq (endpoint);
++ pcd_rcv_cancelled_irq (endpoint);
++ if (pcd_recv_setup_irq (&request)) { // process setup packet
++ TRACE_MSG("udc_ep0: setup failed");
++ //udc_stall_ep (0);
++ endpoint->state = WAIT_FOR_SETUP;
++ return;
++ }
++ if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
++ TRACE_MSG32("udc_ep0: send zlp %d", le16_to_cpu (request.wLength)); // XXX
++ //ctrl_outb (EP0s_RDFN, USBTRG);
++ RETURN_IF(pcd_rcv_next_irq (endpoint));
++ //and_b (~EP0o_TS, USBIER0);
++ return;
++ }
++}
++/* ********************************************************************************************* */
++/* udc_int_hndlr - interrupt handler
++ */
++static void udc_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ trace_ops.interrupts++;
++#if 0
++ if (trace_ops.interrupts > 1000) { udc_disable_interrupts (); udc_disable (); TRACE_MSG("UDC DISABLE"); return; }
++#endif
++}
++/* ********************************************************************************************* */
++/* udc_start_endpoint_in - start transmit
++ */
++void udc_start_endpoint_in (struct usbd_endpoint_instance *endpoint)
++{
++}
++
++/* udc_start_endpoint_out - start receive
++ */
++void udc_start_endpoint_out (struct usbd_endpoint_instance *endpoint)
++{
++}
++/* ********************************************************************************************* */
++/* udc_attached - is the USB cable attached
++ * Return non-zero if cable is attached.
++ */
++int udc_attached (void)
++{
++ return 0;
++}
++
++static int udc_connect_status;
++
++/* udc_connected - is the USB pullup enabled
++ * Return non-zero if pullup is enabled.
++ */
++int udc_connected (void)
++{
++ return udc_connect_status;
++}
++
++/* udc_connect - enable pullup resistor
++ */
++void udc_connect (void)
++{
++ udc_connect_status = 1;
++}
++
++/* udc_disconnect - disable pullup resistor
++ */
++void udc_disconnect (void)
++{
++ udc_connect_status = 0;
++}
++
++/* udc_start - start session
++ */
++void udc_start (void)
++{
++ // udc_enable_interrupts ();
++}
++
++/* udc_stop - stop session
++ */
++void udc_stop (void)
++{
++ // udc_disable_interrupts ();
++}
++
++/* udc_enable - enable the UDC
++ */
++void udc_enable (void)
++{
++}
++
++/* udc_disable - disable the UDC
++ */
++void udc_disable (void)
++{
++}
++
++/* udc_init - initialize
++ * Return non-zero if we cannot see device.
++ */
++int udc_init (void)
++{
++ return 0;
++}
++
++/* udc_exit - disable the UDC
++ */
++void udc_exit (void)
++{
++}
++
++/* ********************************************************************************************* */
++/* udc_assign_endpoint
++ */
++int udc_assign_endpoint (u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
++ u16 wMaxPacketSize, u16 transferSize)
++{
++ RETURN_EINVAL_IF(used[physicalEndpoint]);
++ endpoint_map->bEndpointAddress[0] = physicalEndpoint | (bmAttributes & USB_IN_DIR);
++ endpoint_map->physicalEndpoint[0] = physicalEndpoint;
++ endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
++ endpoint_map->transferSize[0] = transferSize;
++ endpoint_map->bmAttributes[0] = bmAttributes;
++ used[physicalEndpoint]++;
++ return 0;
++}
++
++/* udc_request_endpoints - process endpoint request list
++ */
++int udc_request_endpoints (struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested,
++ struct usbd_endpoint_request *requestedEndpoints)
++{
++ struct usbd_device_description *device_description;
++ int i, j;
++ int used[UDC_MAX_ENDPOINTS];
++ memset (used, 0, sizeof (used));
++ for (j = 0, i = 0; i < endpointsRequested; i++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ u8 bmAttributes = requestedEndpoints[i].bmAttributes;
++ u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
++ switch (bmAttributes) {
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ case USB_DIR_IN | USB_ENDPOINT_BULK:
++ case USB_DIR_OUT | USB_ENDPOINT_BULK:
++ BREAK_IF(!udc_assign_endpoint (j++, used, endpoint_map, bmAttributes, 0x40, transferSize));
++ return -EINVAL;
++ case USB_ENDPOINT_CONTROL:
++ continue;
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
++ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
++ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
++ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
++ return -EINVAL;
++ }
++ return -EINVAL;
++ }
++ RETURN_EINVAL_UNLESS (j < UDC_MAX_ENDPOINTS);
++ }
++ return 0;
++}
++/* ********************************************************************************************* */
++struct udc_ops udc_ops = {
++ max_endpoints: UDC_MAX_ENDPOINTS,
++ ep0_packetsize: EP0_PACKETSIZE,
++ name: UDC_NAME,
++ init: udc_init,
++ exit: udc_exit,
++ enable: udc_enable,
++ disable: udc_disable,
++ start: udc_start,
++ stop: udc_stop,
++ start_endpoint_in: udc_start_endpoint_in,
++ start_endpoint_out: udc_start_endpoint_out,
++ request_endpoints: udc_request_endpoints,
++ attached: udc_attached,
++ connected: udc_connected,
++ connect: udc_connect,
++ disconnect: udc_disconnect,
++};
++
+diff -uNr linux/drivers/no-otg/ocd/gen/gen.h linux/drivers/otg/ocd/gen/gen.h
+--- linux/drivers/no-otg/ocd/gen/gen.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/gen/gen.h 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * otg/ocd/gen/gen.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @file otg/ocd/gen/gen.h
++ * @brief Private structures and defines for Intel PXA-270
++ *
++ * Notes
++ *
++ * 1. This is a minmal outline for a simple UDC driver.
++ *
++ *
++ * @ingroup BVD
++ */
++
++
++#define UDC_NAME "GEN"
++#define UDC_MAX_ENDPOINTS 3
++#define EP0_PACKETSIZE 8
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/Config.in linux/drivers/otg/ocd/isp1301/Config.in
+--- linux/drivers/no-otg/ocd/isp1301/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/Config.in 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,17 @@
++
++#
++# Copyright (c) 2004 Belcarra
++#
++# ISP 1301 TCD
++
++if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
++ mainmenu_option next_comment
++
++ comment 'ISP 1301 (i2c)'
++
++ dep_bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFS $CONFIG_OTG_ISP1301
++
++ endmenu
++else
++ define_bool CONFIG_OTG_ISP1301_PROCFS n
++fi
+diff -uNr linux/drivers/no-otg/ocd/isp1301/Kconfig linux/drivers/otg/ocd/isp1301/Kconfig
+--- linux/drivers/no-otg/ocd/isp1301/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/Kconfig 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,15 @@
++
++#
++# Copyright (c) 2004 Belcarra
++#
++
++# OMAP 1610 H2 development board
++#
++config OTG_ISP1301_OMAP_H2
++ tristate "OMAP 1610 H2 Development board - ISP 1301 (i2c)"
++ depends on I2C && OTG && ARCH_OMAP && OMAP_H2
++
++config OTG_ISP1301_MX2ADS
++ tristate "MX2ADS Development board - ISP 1301 (i2c)"
++ depends on I2C && OTG && ARCH_MX2ADS
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/Makefile linux/drivers/otg/ocd/isp1301/Makefile
+--- linux/drivers/no-otg/ocd/isp1301/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/Makefile 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,96 @@
++#
++# Makefile for the kernel USBD (device not host) drivers.
++#
++# Copyright (c) 2004 Belcarra
++
++# Subdirs.
++# This is a bit complex, because some subdirs are for
++# proprietary code, and are simply not present in a
++# general distribution.
++
++# The all-CAPS *_DIRS get nuked in the new versions
++# of Rules.make, so use only the subdir-* methods.
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++# The target object and module list name.
++
++O_TARGET := isp1301_target.o
++list-multi := isp1301_tcd.o
++
++# Objects that export symbols.
++
++# Multipart objects.
++
++omap_h2_tcd-objs := tcd-init-l24.o tcd-omap-h2.o isp1301.o i2c-l26.o tcd.o isp1301-procfs.o
++mainstone_tcd-objs := tcd-init-l24.o tcd-mainstone.o tcd.o i2c-l26.o isp1301.o isp1301-procfs.o thread-l24.o
++
++# Optional parts of multipart objects.
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_ISP1301_OMAP_H2) += omap_h2_tcd.o
++obj-$(CONFIG_OTG_ISP1301_MAINSTONE) += mainstone_tcd.o
++
++# Object files in subdirectories
++
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++DOT_DIR=$(TCD_DIR)/isp1301
++
++include $(TOPDIR)/Rules.make
++OTG=$(TOPDIR)/drivers/otg
++OCD_DIR=$(OTG)/ocd
++INCLUDE_DIRS = -I$(OTG)
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++
++PCD=$(OTG)/ocd/otg-pcd
++vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD)
++
++
++# Link rules for multi-part drivers.
++
++omap_h2_tcd.o: $(omap_h2_tcd-objs)
++ $(LD) -r -o $@ $(iomap_h2_tcd-objs)
++
++mainstone_tcd.o: $(mainstone_tcd-objs)
++ $(LD) -r -o $@ $(mainstone_tcd-objs)
++
++# dependencies:
++
++# local
++
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/Makefile-l26 linux/drivers/otg/ocd/isp1301/Makefile-l26
+--- linux/drivers/no-otg/ocd/isp1301/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/Makefile-l26 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,26 @@
++#
++# Makefile for the kernel USBD (device not host) drivers.
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++DOT_DIR=$(TCD_DIR)/isp1301
++
++OTG=$(TOPDIR)/drivers/otg
++HCD_DIR=$(OTG)/hcd
++TCD_DIR=$(OTG)/tcd
++USBDCORE_DIR=$(OTG)/usbdcore
++OTGCORE_DIR=$(OTG)/otgcore
++INCLUDE_DIRS = -I$(OTG)
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++
++vpath %.c $(USBDCORE_DIR) $(OCD_DIR)
++
++
++# Link rules for multi-part drivers.
++
++omap_h2_tcd-objs := ../tcd-init-l24.o tcd-omap-h2.o isp1301.o i2c-l26.o ../tcd.o
++obj-$(CONFIG_OTG_ISP1301_OMAP_H2) += omap_h2_tcd.o
++
++
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/isp1301-procfs.c linux/drivers/otg/ocd/isp1301/isp1301-procfs.c
+--- linux/drivers/no-otg/ocd/isp1301/isp1301-procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/isp1301-procfs.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,385 @@
++/*
++ * otg/ocd/isp1301/isp1301-procfs.c - USB Device Core Layer
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @file otg/ocd/isp1301/isp1301-procfs.c
++ * @brief Implement /proc/isp1301 to dump ISP1301 registers.
++ *
++ *
++ * @ingroup ISP1301TCD
++ */
++
++
++#include <otg/pcd-include.h>
++#include "otghw/isp1301-hardware.h"
++#include <otghw/isp1301.h>
++
++#ifdef CONFIG_ARCH_MX2ADS
++#include <asm/arch/mx2.h>
++#define MX2_OTG_XCVR_DEVAD 0x18
++#define MX2_SEQ_OP_REG 0x19
++#define MX2_SEQ_RD_STARTAD 0x1a
++#define MX2_I2C_OP_CTRL_REG 0x1b
++#define MX2_SCLK_TO_SCL_HPER 0x1e
++#define MX2_I2C_INTERRUPT_AND_CTRL 0x1f
++
++#define OTG_BASE_ADDR 0x10024000
++//#define OTG_I2C_BASE (OTG_BASE_ADDR+0x100)
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++#ifdef CONFIG_OTG_ISP1301_PROCFS
++/* Proc Filesystem *************************************************************************** */
++
++extern struct isp1301_private isp1301_private;
++
++#define MAX_HISTORY 6
++struct reg_list {
++ u8 reg;
++ u8 size;
++ char *name;
++ u32 values[MAX_HISTORY];
++};
++
++#define REG(r, s) {r, s, #r, }
++
++struct reg_list isp1301_prod_list[] = {
++ REG(ISP1301_VENDOR_ID, 2),
++ REG(ISP1301_PRODUCT_ID, 2),
++ REG(ISP1301_VERSION_ID, 2),
++ { 0, 1, NULL,},
++};
++struct reg_list isp1301_reg_list[] = {
++ REG(ISP1301_OTG_CONTROL_SET, 1),
++ REG(ISP1301_INTERRUPT_SOURCE, 1),
++ REG(ISP1301_INTERRUPT_LATCH_SET, 1),
++ REG(ISP1301_INTERRUPT_ENABLE_LOW_SET, 1),
++ REG(ISP1301_INTERRUPT_ENABLE_HIGH_SET, 1),
++ REG(ISP1301_MODE_CONTROL_1_SET, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list isp1301_spec_list[] = {
++ REG(ISP1301_MODE_CONTROL_2_SET, 1),
++ REG(ISP1301_OTG_STATUS, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list max3301e_spec_list[] = {
++ REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
++ REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
++ { 0, 1, NULL,},
++};
++#ifdef CONFIG_ARCH_MX2ADS
++struct reg_list mx21_spec_list[] = {
++ REG(MX2_OTG_XCVR_DEVAD, 1),
++ REG(MX2_SEQ_OP_REG, 1),
++ REG(MX2_SEQ_RD_STARTAD, 1),
++ REG(MX2_I2C_OP_CTRL_REG, 1),
++ REG(MX2_SCLK_TO_SCL_HPER, 1),
++ REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
++ { 0, 1, NULL,},
++};
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void isp1301_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ TRACE_MSG1(TCD, "list: %s", list->name);
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ switch(list->size) {
++ case 1:
++ list->values[0] = i2c_readb(list->reg);
++ break;
++ case 2:
++ list->values[0] = i2c_readw(list->reg);
++ break;
++ case 4:
++ list->values[0] = i2c_readl(list->reg);
++ break;
++ }
++ }
++}
++
++#ifdef CONFIG_ARCH_MX2ADS
++static u8 __inline__ mx2_rb(u32 port)
++{
++ return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
++}
++
++
++void mx21_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ list->values[0] = mx2_rb(list->reg);
++ }
++}
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void isp1301_update_all(void)
++{
++ isp1301_update(isp1301_reg_list);
++ switch (isp1301_private.transceiver_map->transceiver_type) {
++ case isp1301:
++ isp1301_update(isp1301_spec_list);
++ break;
++ case max3301e:
++ isp1301_update(max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ mx21_update(mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++
++}
++
++
++
++/*
++ * dohex
++ *
++ */
++static void dohexdigit (char *cp, unsigned char val)
++{
++ if (val < 0xa)
++ *cp = val + '0';
++ else if ((val >= 0x0a) && (val <= 0x0f))
++ *cp = val - 0x0a + 'a';
++}
++
++/*
++ * dohex
++ *
++ */
++static void dohexval (char *cp, unsigned char val)
++{
++ dohexdigit (cp++, val >> 4);
++ dohexdigit (cp++, val & 0xf);
++}
++
++int isp1301_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
++{
++ int len = 0, i;
++ len += sprintf (buf + len, "%-20s %-34s [%03x]: ", name, reg->name, reg->reg);
++ len += sprintf (buf + len, fmt, reg->values[0]);
++ for (i = 1; i < MAX_HISTORY; i++)
++ if (reg->values[i - 1] == reg->values[i])
++ len += sprintf (buf + len, " ");
++ else
++ len += sprintf (buf + len, fmt, reg->values[i]);
++ len += sprintf (buf + len, "\n");
++ return len;
++}
++
++int isp1301_dump_list(char * buf, char *name, struct reg_list *list)
++{
++ int len = 0;
++ for (; list && list->name; list++)
++ switch(list->size) {
++ case 1: len += isp1301_dump(buf + len, name, " %02x", list); break;
++ case 2: len += isp1301_dump(buf + len, name, " %04x", list); break;
++ case 4: len += isp1301_dump(buf + len, name, " %08x", list); break;
++ }
++ return len;
++}
++
++char *isp1301_otg_control[8] = {
++ "DP_PULLUP",
++ "DM_PULLUP",
++ "DP_PULLDOWN",
++ "DM_PULLDOWN",
++ "ID_PULLDOWN",
++ "VBUS_DRV",
++ "VBUS_DISCHRG",
++ "VBUS_CHRG",
++};
++char *isp1301_interrupt_source[8] = {
++ "VBUS_VLD",
++ "SESS_VLD",
++ "DP_HI",
++ "ID_GND",
++ "DM_HI",
++ "ID_FLOAT",
++ "BDIS_ACON",
++ "CR_INT",
++};
++
++char *isp1301_mode_control_1[8] = {
++ "SPEED_REG",
++ "SUSPEND_REG",
++ "DAT_SE0",
++ "TRANSP_EN",
++ "BDIS_ACON_EN",
++ "OE_INT_EN",
++ "UART_EN",
++ NULL,
++};
++
++char *isp1301_otg_status[8] = {
++ NULL, NULL, NULL, NULL, NULL, NULL,
++ "B_SESS_END",
++ "B_SESS_VLD",
++};
++
++int isp1301_detailed(char *buf, char *name, u8 reg, char **detail)
++{
++ u8 val;
++ int i;
++ int len = 0;
++
++ val = i2c_readb(reg);
++ for (i = 7; i >= 0; i--) {
++
++ if (3 == (i % 4))
++ len += sprintf (buf + len, "\n%-20s [%02d] ", name, reg);
++
++ if (detail[i])
++ len += sprintf (buf + len, "%14s%s ", detail[i], (val & (1 << i)) ? " " : "/");
++ else
++ len += sprintf (buf + len, "%14s%s ", "", " ");
++ }
++ len += sprintf (buf + len, "\n", name);
++
++ return len;
++}
++
++int isp1301_dump_all(char *buf)
++{
++ int len = 0;
++ len += isp1301_dump_list(buf + len, "ISP1301 Standard", isp1301_reg_list);
++ switch (isp1301_private.transceiver_map->transceiver_type) {
++ case isp1301:
++ len += isp1301_dump_list(buf + len, "ISP1301 Extra", isp1301_spec_list);
++ break;
++ case max3301e:
++ len += isp1301_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ len += isp1301_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++ return len;
++}
++
++int isp1301_dump_detail(char *buf)
++{
++ int len = 0;
++
++ len += isp1301_detailed(buf + len, "MODE CONTROL 1", ISP1301_MODE_CONTROL_1, isp1301_mode_control_1);
++ len += isp1301_detailed(buf + len, "INTERRUPT ENABLE", ISP1301_INTERRUPT_ENABLE_HIGH, isp1301_interrupt_source);
++
++ len += isp1301_detailed(buf + len, "OTG CONTROL", ISP1301_OTG_CONTROL_SET, isp1301_otg_control);
++ len += isp1301_detailed(buf + len, "INTERRUPT SOURCE", ISP1301_INTERRUPT_SOURCE, isp1301_interrupt_source);
++ len += isp1301_detailed(buf + len, "OTG STATUS", ISP1301_OTG_STATUS, isp1301_otg_status);
++ return len;
++}
++
++
++/*!
++ * isp1301_device_proc_read - implement proc file system read.
++ *
++ * Standard proc file system read function.
++ *
++ * We let upper layers iterate for us, *pos will indicate which device to return
++ * statistics for.
++ */
++static ssize_t isp1301_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int i;
++ u32 r;
++
++ int config_size;
++
++ // get a page, max 4095 bytes of data...
++ RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
++
++ len = 0;
++ index = (*pos)++;
++
++ //printk(KERN_INFO"%s: index: %d\n", __FUNCTION__, index);
++ switch(index) {
++ case 0:
++ len += sprintf ((char *) page + len, "ISP1301 Transceiver Registers\n");
++
++ TRACE_MSG0(TCD, "UPDATING");
++ isp1301_update_all();
++ TRACE_MSG0(TCD, "UPDATE FINISHED");
++ len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n",
++ isp1301_private.vendor, isp1301_private.product,
++ isp1301_private.revision, isp1301_private.transceiver_map->name
++ );
++
++ len += isp1301_dump_all((char *) page + len);
++ len += sprintf ((char *) page + len, "\n");
++
++ break;
++
++ case 1:
++ len += sprintf ((char *) page + len, "\n--\n");
++ len += isp1301_dump_detail((char *) page + len);
++ len += sprintf ((char *) page + len, "\n");
++ break;
++
++ default:
++ break;
++
++ }
++
++ //printk(KERN_INFO"%s: len: %d\n", __FUNCTION__, len);
++
++ if (len > count)
++ len = -EINVAL;
++
++ else if ((len > 0) && copy_to_user (buf, (char *) page, len))
++ len = -EFAULT;
++
++ //printk(KERN_INFO"%s: len: %d\n", __FUNCTION__, len);
++ free_page (page);
++ return len;
++}
++
++static struct file_operations isp1301_device_proc_operations_functions = {
++ read:isp1301_device_proc_read_functions,
++};
++
++/* Module init ******************************************************************************* */
++
++static int isp1301_procfs_init (void)
++{
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry ("isp1301", 0, 0)) == NULL)
++ return -ENOMEM;
++
++ p->proc_fops = &isp1301_device_proc_operations_functions;
++
++ isp1301_update_all();
++
++ return 0;
++}
++static void isp1301_procfs_exit (void)
++{
++ remove_proc_entry ("isp1301", NULL);
++}
++#else
++static int isp1301_procfs_init (void) { return 0;
++}
++static void isp1301_procfs_exit (void) { }
++#endif
+diff -uNr linux/drivers/no-otg/ocd/isp1301/isp1301.c linux/drivers/otg/ocd/isp1301/isp1301.c
+--- linux/drivers/no-otg/ocd/isp1301/isp1301.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/isp1301.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,923 @@
++/*
++ * otg/ocd/isp1301/isp1301.c -- USB Transceiver Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/isp1301/isp1301.c
++ * @brief ISP1301 OTG Transceiver Driver.
++ *
++ * This is the generic ISP1301 TCD core support.
++ *
++ * Notes:
++ *
++ * 1. The ISP1301 can control the speed and suspend directly, would it be
++ * appropriate to allow state machine to control this.
++ *
++ * 2. The ISP1301 has auto connect feature, can this be used without change
++ * to state machine.
++ *
++ * 3. The ISP1301 can control the ADR/PSW pin to enable / disable external
++ * charge pump.
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/otg-compat.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <linux/i2c.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-ocd.h>
++#include <otg/otg-pcd.h>
++
++#include <otghw/isp1301-hardware.h>
++#include <otghw/isp1301.h>
++
++#ifdef CONFIG_OMAP_H2
++#include <asm/arch/gpio.h>
++#include <asm/arch/mux.h>
++#endif /* CONFIG_OMAP_H2 */
++
++struct otg_transceiver_map isp1301_transceiver_map[] = {
++ { isp1301, 0x4cc, 0x1301, 0x00, "Phillips ISP1301", },
++ { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
++ { 0, 0, 0, 0, "Unknown Transceiver", },
++};
++
++struct isp1301_private isp1301_private;
++
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
++
++
++/*! isp1301_int_src - update interrupt source test mask
++ *
++ * This sets the current mask and updates the interrupt registers to match.
++ */
++void isp1301_int_src(u8 int_src)
++{
++ TRACE_MSG1(TCD, "setting int_src %02x", int_src);
++ isp1301_private.int_src = int_src;
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, ~int_src);
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, ~int_src);
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_SET, int_src);
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_SET, int_src);
++ i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, int_src);
++}
++
++/*! isp1301_int_src_set - add to the interrupt source mask
++ *
++ */
++void isp1301_int_src_set(u8 int_src)
++{
++ isp1301_int_src(int_src |= isp1301_private.int_src);
++}
++
++/*! isp1301_int_src_clr - remove from the interrup source mask
++ */
++void isp1301_int_src_clr(u8 int_src)
++{
++ isp1301_int_src(int_src = isp1301_private.int_src & ~int_src);
++}
++
++/* ********************************************************************************************* */
++
++typedef struct isp1301_test {
++ u32 input;
++ char *name;
++ u8 mask;
++} isp1301_test_t;
++
++#define OV(i, m) {i, #i, m}
++
++struct isp1301_test isp1301_int_src_tests[9] = {
++
++ OV(VBUS_VLD, ISP1301_VBUS_VLD),
++ OV(A_SESS_VLD, ISP1301_SESS_VLD),
++ OV(DP_HIGH, ISP1301_DP_HI),
++ OV(ID_GND, ISP1301_ID_GND),
++ OV(DM_HIGH, ISP1301_DM_HI),
++ OV(ID_FLOAT, ISP1301_ID_FLOAT),
++ OV(BDIS_ACON, ISP1301_BDIS_ACON),
++ OV(CR_INT_DET, ISP1301_CR_INT),
++ {0, NULL, 0},
++};
++
++struct isp1301_test isp1301_otg_status_tests[3] = {
++
++ OV(B_SESS_END, ISP1301_B_SESS_END),
++ OV(B_SESS_VLD, ISP1301_B_SESS_VLD),
++ {0, NULL, 0},
++};
++
++/*! isp1301_event() - set input bit based on current settings and interrupt mask
++ */
++u64 isp1301_event(struct otg_instance *otg, struct isp1301_test *tests, int val, int testmask, char *msg)
++{
++ int i;
++ u64 inputs = 0;
++ TRACE_MSG3(TCD, "val: %02x mask: %02x %s", val, testmask, msg);
++ for (i = 0; tests[i].mask; i++) {
++ u64 input = tests[i].input;
++ u8 mask = tests[i].mask;
++ CONTINUE_UNLESS(mask & testmask);
++ inputs |= (val & mask) ? input : _NOT(input);
++ TRACE_MSG6(TCD, "%s%s %02x %08x inputs: %08x %08x",
++ tests[i].name, (val & mask) ? "" : "/", tests[i].mask, tests[i].input,
++ (u32) (inputs >> 32), (u32)(inputs & 0xffffffff)
++ );
++ }
++ return inputs;
++}
++
++
++
++int isp1301_bh_first;
++int isp1301_debounce;
++u64 isp1301_ticks;
++
++void isp1301_info(char *msg, u8 value)
++{
++ u64 new_ticks = otg_tmr_ticks();
++ u64 ticks = otg_tmr_elapsed(&new_ticks, &isp1301_ticks);
++
++ if (ticks < 10000)
++ TRACE_MSG3(PCD, "ISP1301 %d uS %s: %02x", (u32)(ticks & 0xffffffff), msg, value);
++ else if (ticks < 10000000)
++ TRACE_MSG3(PCD, "ISP1301 %d mS %s: %02x", (u32)((ticks >> 10) & 0xffffffff), msg, value);
++ else
++ TRACE_MSG3(PCD, "ISP1301 %d S %s: %02x", (u32)((ticks >> 20) & 0xffffffff), msg, value);
++
++ isp1301_ticks = new_ticks;
++}
++
++
++void isp1301_trace(u8 int_src, u8 int_changed, char *msg)
++{
++
++ u64 new_ticks = otg_tmr_ticks();
++ u64 ticks = otg_tmr_elapsed(&new_ticks, &isp1301_ticks);
++
++ if (ticks < 10000)
++ TRACE_MSG4(PCD, "ISP1301 %d uS %s: src: %02x chng: %02x",
++ (u32)(ticks & 0xffffffff), msg, int_src, int_changed);
++ else if (ticks < 10000000)
++ TRACE_MSG4(PCD, "ISP1301 %d mS %s src: %02x chng: %02x",
++ (u32)((ticks >> 10) & 0xffffffff), msg, int_src, int_changed);
++ else
++ TRACE_MSG4(PCD, "ISP1301 %d S %s src: %02x chng: %02x ",
++ (u32)((ticks >> 20) & 0xffffffff), msg, int_src, int_changed);
++
++ isp1301_ticks = new_ticks;
++}
++
++/*! isp1301_bh
++ */
++void isp1301_bh(void *arg)
++{
++ u64 inputs = 0;
++ u8 int_lat, int_src1 = 0, int_src2 = 0, otg_status = 0, special_function_22 = 0;
++ static u8 int_src_saved, otg_status_saved, special_function_22_saved;
++
++ //TRACE_MSG0(TCD, "--");
++ /* read the interrupt latch and and clear latch and update otg
++ */
++ if ((int_lat = i2c_readb(ISP1301_INTERRUPT_LATCH_SET))) {
++ //TRACE_MSG1(TCD, "CLEARING INT LAT: %02x", int_lat);
++ isp1301_info("INT LAT", int_lat);
++ i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, int_lat);
++ }
++
++ isp1301_info("INT_LAT", int_lat);
++
++ /* If int_lat shows a change or we are forcing an update, read interrupt source.
++ * Note that we mask DP_HI and DM_HI when LOC_CONN is set, we don't want them
++ * when USB Bus is in use.
++ *
++ * Mask with bits we are currently interested in.
++ *
++ * Ensure that we have two matching reads to ensure that value is stable.
++ * Also ensure that interrupt source is non-zero.
++ */
++
++ int_src1 = i2c_readb(ISP1301_INTERRUPT_SOURCE);
++ isp1301_trace(int_src1, int_src_saved ^ int_src1, "INT_SRC_1");
++
++ do {
++ int_src2 = i2c_readb(ISP1301_INTERRUPT_SOURCE); // re-read interrupt source
++ BREAK_IF(int_src1 && (int_src1 & (ISP1301_ID_GND | ISP1301_ID_FLOAT)) &&
++ (int_src1 == int_src2)); // finished if non-zero and same
++ isp1301_trace(int_src2, int_src_saved ^ int_src2, "INT_SRC_2");
++ int_src1 = int_src2; // save most recent read value
++ } while (1);
++
++
++ #if 0
++ while ( (int_src1 != (int_src2 = i2c_readb(ISP1301_INTERRUPT_SOURCE) & isp1301_private.int_src))) {
++ isp1301_trace(int_src2, int_src_saved ^ int_src2, "INT_SRC_2");
++ int_src1 = int_src2;
++ }
++ #endif
++
++ if (isp1301_bh_first || int_src_saved ^ (int_src1 & isp1301_private.int_src)) {
++ int_src_saved = int_src1;
++ inputs |= isp1301_event(tcd_instance->otg, isp1301_int_src_tests, int_src1,
++ isp1301_private.int_src, "ISP1301 INT SRC");
++ if (int_src1 & ISP1301_VBUS_VLD) {
++ TRACE_MSG0(TCD, "VBUS_VLD, setting B_SESS_VLD");
++ inputs |= B_SESS_VLD;
++ }
++ else if (!(int_src1 & ISP1301_SESS_VLD)) {
++ TRACE_MSG0(TCD, "A_SESS_VLD/, setting B_SESS_VLD/");
++ inputs |= B_SESS_VLD_;
++ }
++ }
++
++ /* further work if B-Device
++ */
++ if ( !(int_src1 & ISP1301_ID_GND) || !(int_src_saved & ISP1301_ID_GND) ) {
++ /* read the otg_status register and update otg state machine
++ *
++ * XXX this needs to be conditional on Transceiver type. The
++ * MAX3301E for example supports sess_end in a separate register.
++ */
++ switch (isp1301_private.transceiver_map->transceiver_type) {
++ case isp1301:
++ otg_status = i2c_readb(ISP1301_OTG_STATUS);
++ isp1301_trace(otg_status, int_src_saved ^ int_src1, "OTG_STATUS");
++ TRACE_MSG3(TCD, "otg_status_saved: %02x otg_status: %02x chng: %02x",
++ otg_status_saved, otg_status, otg_status_saved ^ otg_status);
++
++ if (isp1301_bh_first || (otg_status_saved ^ otg_status)) {
++ inputs |= isp1301_event(tcd_instance->otg, isp1301_otg_status_tests, otg_status, 0xff,
++ "ISP1301 OTG STATUS");
++ otg_status_saved = otg_status;
++ }
++
++ #if 0
++ isp1301_info("OTG STATUS", otg_status);
++ if (isp1301_bh_first)
++ otg_status_saved = ~otg_status;
++
++ otg_status_saved = isp1301_update_otg_status( tcd_instance->otg, otg_status,
++ otg_status_saved ^ otg_status);
++ #endif
++ break;
++
++ // XXX
++ case max3301e:
++ special_function_22 = i2c_readb(MAX3301E_SPECIAL_FUNCTION_2_SET);
++ break;
++ case unknown_transceiver:
++ break;
++ }
++ }
++ if (inputs) otg_event(tcd_instance->otg, inputs, TCD, "ISP1301");
++ isp1301_bh_first = 0;
++}
++
++
++/*! isp1301_bh_wakeup - wakeup the isp1301 bottom half
++ */
++void isp1301_bh_wakeup(int first)
++{
++ //TRACE_MSG0(TCD, "--");
++ isp1301_bh_first |= first;
++ SCHEDULE_WORK(isp1301_private.bh);
++}
++
++
++/* ********************************************************************************************** */
++/*! isp1301_vbus - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int isp1301_vbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++/*! isp1301_id - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int isp1301_idvbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++
++/* ********************************************************************************************* */
++/*! isp1301_tcd_en() - used to enable
++ *
++ */
++void isp1301_tcd_en(struct otg_instance *otg, u8 flag)
++{
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "SET");
++ break;
++ case PULSE:
++ TRACE_MSG0(TCD, "PULSE");
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "RESET");
++ break;
++ }
++ isp1301_bh_wakeup(TRUE);
++}
++
++
++/*! isp1301_chrg_vbus - used to enable or disable B-device Vbus charging
++ */
++void isp1301_chrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_SET");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_CHRG);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
++ break;
++ case PULSE:
++ break;
++ }
++}
++
++/*! isp1301_drv_vbus - used to enable or disable A-device driving Vbus
++ */
++void isp1301_drv_vbus(struct otg_instance *otg, u8 flag)
++{
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "DRV_VBUS_SET");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DRV);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "DRV_VBUS_RESET");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
++ break;
++ }
++}
++
++/*! isp1301_dischrg_vbus - used to enable Vbus discharge
++ */
++void isp1301_dischrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DISCHRG);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
++ break;
++ }
++}
++
++/*! isp1301_mx21_vbus_drain - used to enable Vbus discharge
++ */
++void isp1301_mx21_vbus_drain_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DISCHRG);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
++ break;
++ }
++}
++
++/*! isp1301_dp_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
++ *
++ * host peripheral
++ * d+ pull-up clr set
++ * d+ pull-down set clr
++ *
++ * d- pull-up clr clr
++ * d- pull-down set set
++ *
++ */
++void isp1301_dp_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ isp1301_private.flags |= ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DP PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLUP);
++ break;
++
++ case RESET:
++ isp1301_private.flags &= ~ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DP PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLUP);
++ break;
++ }
++}
++
++/*! isp1301_dm_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ */
++void isp1301_dm_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ isp1301_private.flags |= ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DM PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLUP);
++ break;
++
++ case RESET:
++ isp1301_private.flags &= ~ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DM PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DM_PULLUP);
++ break;
++ }
++}
++
++/*! isp1301_dp_pulldown_func - used to enable or disable peripheral connecting to bus
++ *
++ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
++ *
++ * host peripheral
++ * d+ pull-up clr set
++ * d+ pull-down set clr
++ *
++ * d- pull-up clr clr
++ * d- pull-down set set
++ *
++ */
++void isp1301_dp_pulldown_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ isp1301_private.flags |= ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DP PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLDOWN);
++ break;
++
++ case RESET:
++ isp1301_private.flags &= ~ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DP PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLDOWN);
++ break;
++ }
++}
++
++/*! isp1301_dm_pulldown_func - used to enable or disable peripheral connecting to bus
++ *
++ */
++void isp1301_dm_pulldown_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ isp1301_private.flags |= ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DM PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN);
++ break;
++
++ case RESET:
++ isp1301_private.flags &= ~ISP1301_LOC_CONN;
++ TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DM PULLUP");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DM_PULLDOWN);
++ break;
++ }
++}
++
++/*! isp1301_peripheral_host_func - used to enable or disable peripheral connecting to bus
++ *
++ * A-Device D+ pulldown D- pulldown
++ * idle set set
++ * host set set
++ * peripheral reset set
++ *
++ * B-Device
++ * idle set set
++ * host set set
++ * peripheral reset set
++ */
++void isp1301_peripheral_host_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET: // peripheral
++ TRACE_MSG0(TCD, "SET - CLR DP PULLDOWN");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLDOWN);
++ break;
++
++ case RESET: // host
++ TRACE_MSG0(TCD, "RESET - SET DM PULLDOWN");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLDOWN);
++ break;
++ }
++}
++
++/*! isp1301_dm_det_func - used to enable or disable D- detect
++ *
++ */
++void isp1301_dm_det_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting DM_HI detect");
++ isp1301_int_src_set(ISP1301_DM_HI);
++ isp1301_bh_wakeup(TRUE);
++ isp1301_debounce = 0;
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting DM_HI detect");
++ isp1301_int_src_clr(ISP1301_DM_HI);
++ isp1301_bh_wakeup(TRUE);
++ isp1301_debounce = 1;
++ break;
++ }
++}
++
++/*! isp1301_dp_det_func - used to enable or disable D+ detect
++ *
++ */
++void isp1301_dp_det_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting DP_HI detect");
++ isp1301_int_src_set(ISP1301_DP_HI);
++ isp1301_bh_wakeup(TRUE);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting DP_HI detect");
++ isp1301_int_src_clr(ISP1301_DP_HI);
++ isp1301_bh_wakeup(TRUE);
++ break;
++ }
++}
++
++/*! isp1301_cr_det_func - used to enable or disable D+ detect
++ *
++ */
++void isp1301_cr_det_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting CR_INT detect");
++ isp1301_int_src_set(ISP1301_CR_INT);
++ isp1301_bh_wakeup(TRUE);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting CR_INT detect");
++ isp1301_int_src_clr(ISP1301_CR_INT);
++ isp1301_bh_wakeup(TRUE);
++ break;
++ }
++}
++
++/*! isp1301_bdis_acon_func - used to enable or disable auto a-connect
++ *
++ */
++void isp1301_bdis_acon_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting BDIS ACON");
++ isp1301_int_src_set(ISP1301_BDIS_ACON);
++ i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_BDIS_ACON_EN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting BDIS ACON");
++ i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ISP1301_BDIS_ACON_EN);
++ isp1301_int_src_clr(ISP1301_BDIS_ACON);
++ break;
++ }
++}
++
++/*! isp1301_id_pulldown_func - used to enable or disable ID pulldown
++ *
++ */
++void isp1301_id_pulldown_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting ID PULLDOWN");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_ID_PULLDOWN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting ID PULLDOWN");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_ID_PULLDOWN);
++ break;
++ }
++}
++
++/*! isp1301_audio_func - used to enable or disable Carkit Interrupt
++ *
++ */
++void isp1301_audio_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "SET AUDIO_EN");
++ //isp1301_int_src_set(ISP1301_CR_INT);
++ i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_AUDIO_EN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "RESET AUDIO_EN");
++ i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_AUDIO_EN);
++ //isp1301_int_src_clr(ISP1301_CR_INT);
++ break;
++ }
++}
++
++/*! isp1301_uart_func - used to enable or disable transparent uart mode
++ *
++ */
++void isp1301_uart_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting UART_EN");
++ i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_UART_EN);
++ /* XXX enable uart */
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting UART_EN");
++ i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ISP1301_UART_EN);
++ /* XXX disable uart */
++ break;
++ }
++}
++
++/*! isp1301_mono_func - used to enable or disable mono audio connection
++ *
++ */
++void isp1301_mono_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ //TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting MONO");
++ /* XXX enable mono output */
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting MONO");
++ /* XXX disable mono output */
++ break;
++ }
++}
++
++
++/* ********************************************************************************************* */
++extern int isp1301_procfs_init (void);
++extern void isp1301_procfs_exit (void);
++
++extern void mx2_isp1301_bh(void *arg);
++
++/*! isp1301_mod_init
++ */
++int isp1301_mod_init(WORK_PROC bh_proc)
++//int isp1301_mod_init(void)
++{
++ /* for interrupt bottom half handler
++ */
++ //PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
++
++ UNLESS(bh_proc)
++ bh_proc = &isp1301_bh;
++
++ PREPARE_WORK_ITEM(isp1301_private.bh, bh_proc, NULL);
++
++ //else
++ // PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
++
++ /* setup isp1301, enable interrupts, clear latch
++ * XXX when and how do we do DM_HI and DP_HI, when ID is present?
++ */
++
++ isp1301_int_src(ISP1301_ID_FLOAT | ISP1301_DM_HI | ISP1301_ID_GND | ISP1301_DP_HI | ISP1301_SESS_VLD | ISP1301_VBUS_VLD);
++
++ //isp1301_int_src(ISP1301_INT_SRC);
++ //isp1301_int_src(ISP1301_NO_SE1_INT);
++ //isp1301_int_src_clr(ISP1301_CR_INT);
++
++ //i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
++
++#ifdef CONFIG_OTG_ISP1301_PROCFS
++ isp1301_procfs_init ();
++#endif /* CONFIG_OTG_ISP1301_PROCFS */
++
++ return 0;
++}
++
++/*! isp1301_mod_exit
++ */
++void isp1301_mod_exit(void)
++{
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xff);
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
++ //i2c_close();
++#ifdef CONFIG_OTG_ISP1301_PROCFS
++ isp1301_procfs_exit ();
++#endif /* CONFIG_OTG_ISP1301_PROCFS */
++
++ while (PENDING_WORK_ITEM(isp1301_private.bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++
++}
++
++/* ********************************************************************************************* */
++/*! isp1301_configure - configure the ISP1301 for this host
++ * @param tx_mode - the type of connection between the host USB and the ISP1301
++ * @param spd_ctrl - suspend control method
++ */
++void isp1301_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
++{
++ u16 vendor = 0, product = 0, revision = 0;
++ u8 mode1, mode2, control;
++
++ struct otg_transceiver_map *map = isp1301_transceiver_map;
++
++
++#if defined(CONFIG_OTG_ISP1301_MX2ADS) || defined(CONFIG_OTG_ISP1301_MX2ADS_MODULE)
++ u32 vp;
++ TRACE_MSG0(TCD, "1. Read Transceiver ID's with long read");
++ vp = i2c_readl(ISP1301_VENDOR_ID);
++ isp1301_private.vendor = vp & 0xffff;
++ isp1301_private.product = vp >> 16;
++ isp1301_private.revision = i2c_readw(ISP1301_VERSION_ID);
++ mode1 = i2c_readb(ISP1301_MODE_CONTROL_1_SET);
++ mode2 = i2c_readb(ISP1301_MODE_CONTROL_2_SET);
++
++ TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
++ vendor, product, revision, mode1, mode2);
++
++#else /* defined(CONFIG_OTG_ISP1301_MX2ADS) */
++
++ isp1301_private.vendor = i2c_readw(ISP1301_VENDOR_ID);
++ isp1301_private.product = i2c_readw(ISP1301_PRODUCT_ID);
++ isp1301_private.revision = i2c_readw(ISP1301_VERSION_ID);
++ mode1 = i2c_readb(ISP1301_MODE_CONTROL_1_SET);
++ mode2 = i2c_readb(ISP1301_MODE_CONTROL_2_SET);
++
++ TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
++ isp1301_private.vendor, isp1301_private.product, isp1301_private.revision, mode1, mode2);
++
++#endif /* defined(CONFIG_OTG_ISP1301_MX2ADS) */
++
++ for ( ; map && map->transceiver_type != unknown_transceiver; map++) {
++ CONTINUE_UNLESS ((isp1301_private.vendor == map->vendor) && (isp1301_private.product == map->product));
++ TRACE_MSG1(TCD, "Found Transceiver: %s", map->name);
++ isp1301_private.transceiver_map = map;
++ break;
++ }
++ UNLESS (isp1301_private.transceiver_map)
++ isp1301_private.transceiver_map = isp1301_transceiver_map;
++
++ TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, 0xff); // clear
++
++ TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
++
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_DM_PULLUP | ISP1301_DP_PULLUP);
++
++
++ TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
++ i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, 0xff);
++ //i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xeb);
++ //i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xeb);
++ isp1301_int_src_set(0xeb);
++
++ /* The PSW_OE enables the ADR/PSW pin for output driving either high
++ * or low depending on the address.
++ *
++ * ADR ADR_REG Address PSW_OE=0 PSW_OE=1
++ *
++ * low 0 0x2c LOW HIGH
++ *
++ * high 1 0x2d HIGH LOW
++ *
++ *
++ * The i2c address by tying the ADR/PSW pin either high or low.
++ * Setting the PSW_OE drives the ADR/PSW into the opposite of the
++ * default wiring.
++ *
++ * On the MX21ADS the ADR/PSW pin is wired high which enables the
++ * charge pump. So enabling the PSW_OE is required to disable Vbus
++ * generation on the Charge Pump.
++ *
++ * The MAX3355E will only enable Vbus when this signal is high AND
++ * the ID signal is low. So it may be safe to leave enabled when
++ * operating as a B-device (ID floating.)
++ */
++
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_PSW_OE); // PSW_OE - OFFVBUS low
++
++
++ TRACE_MSG1(TCD, "6. tx_mode: %02x", tx_mode);
++ switch (tx_mode) {
++ case vp_vm_bidirectional:
++ break;
++ case dat_se0_unidirectional:
++ i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_BI_DI);
++ case dat_se0_bidirectional:
++ i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_DAT_SE0);
++ break;
++ }
++ TRACE_MSG0(TCD, "6. tx_mode done");
++
++ TRACE_MSG1(TCD, "7. spd_ctrl: %02x", spd_ctrl);
++ switch (spd_ctrl) {
++ case spd_susp_pins:
++ i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_SPD_SUSP_CTRL);
++ break;
++ case spd_susp_reg:
++ i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_SPD_SUSP_CTRL);
++ break;
++ }
++
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_PSW_OE); // PSW_OE - OFFVBUS low
++
++ TRACE_MSG0(TCD, "7. spd_ctrl done");
++
++ TRACE_MSG1(TCD, "8. transceiver_type: %02x", isp1301_private.transceiver_map);
++
++ TRACE_MSG1(TCD, "8. transceiver_type: %02x", isp1301_private.transceiver_map->transceiver_type);
++ switch (isp1301_private.transceiver_map->transceiver_type) {
++ case isp1301:
++ break;
++ case max3301e:
++ i2c_writeb(MAX3301E_SPECIAL_FUNCTION_1_SET, MAX3301E_SESS_END);
++ break;
++ case unknown_transceiver:
++ break;
++ }
++ TRACE_MSG0(TCD, "8. transceiver_type done");
++}
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/tcd-mainstone.c linux/drivers/otg/ocd/isp1301/tcd-mainstone.c
+--- linux/drivers/no-otg/ocd/isp1301/tcd-mainstone.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/tcd-mainstone.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,177 @@
++/*
++ * otg/ocd/mx2/tcd-mainstone.c -- Mainstone ISP1301 Transceiver Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/isp1301/tcd-mainstone.c
++ * @brief Mainstone ISP1301 driver.
++ *
++ * This implements the ISP1301 Transceiver Controller Driver for the Mainstone
++ * using the USBOTG I2C controller for access.
++ *
++ * Notes
++ *
++ * 1. The interrupt source is handled by the OCD driver so we just publish
++ * an interrupt handler for it to call.
++ *
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <otghw/isp1301-hardware.h>
++#include "mx2.h"
++#include "otghw/bvd-hardware.h"
++#include <otghw/isp1301.h>
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++
++/* ********************************************************************************************* */
++
++
++/*! isp1301_int_hndlr
++ */
++static irqreturn_t isp1301_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ TRACE_MSG0(TCD, "--");
++
++ SCHEDULE_WORK(isp1301_private.bh);
++
++ return IRQ_HANDLED;
++}
++
++
++/* ********************************************************************************************* */
++
++/*! mainstone_tcd_init - used to initialize/enable or disable the tcd driver
++ */
++void mainstone_tcd_init(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "MAINSTONE_TCD_EN SET");
++ otg_event(otg, TCD_OK, TCD, "TCD_OK");
++ isp1301_thread_wakeup(1, 1);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "MAINSTONE_TCD_EN RESET");
++ isp1301_thread_wakeup(0, 0);
++ otg_event(otg, TCD_OK, TCD, "TCD_OK");
++ break;
++ }
++}
++
++
++struct tcd_ops tcd_ops;
++struct tcd_instance *mainstone_tcd_instance;
++//wait_queue_head_t mx2_i2c_wait; // wait structure for i2c i/o interrupt
++
++#define ADAPTOR_NAME "PXA-I2C-Adapter"
++
++/*! mainstone_mod_init
++ */
++int mainstone_mod_init(void)
++{
++ struct otg_instance *otg;
++ int i2c = i2c_configure(ADAPTOR_NAME, ISP1301_I2C_ADDR_HIGH);
++ int irq = request_irq (GPIOX_TO_IRQ(35), isp1301_int_hndlr, SA_INTERRUPT, "ISP1301", NULL);
++
++ TRACE_MSG0(TCD, "--");
++
++ THROW_IF(i2c, error);
++
++ TRACE_MSG0(TCD, "1. Enable Mainstone external OTG Transceiver!");
++
++ TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
++ MST_MSCWR2 |= MSCWR2_USB_OTG_SEL | MSCWR2_USB_OTG_RST;
++ TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
++
++
++ TRACE_MSG0(TCD, "2. configure i2c driver!");
++ isp1301_configure(dat_se0_bidirectional, spd_susp_reg);
++
++ TRACE_MSG0(TCD, "3. configure isp1301!");
++ isp1301_mod_init();
++
++ TRACE_MSG0(TCD, "4. set ops");
++ THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
++ THROW_UNLESS(mainstone_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
++
++ /* Success!
++ */
++ TRACE_MSG0(TCD, "5. Success!");
++
++ otg_init(otg);
++ //otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_AUTO);
++
++ // XXX TESTING
++ //isp1301_dp_pullup_func(otg, 1);
++
++ /* XXX start thread to monitor for changes - not needed once gpio interrupt implmented
++ */
++ isp1301_thread_init(isp1301_bh);
++
++ /* error handling
++ */
++ CATCH(error) {
++ //if (irq) free_irq(GPIO_2_80_TO_IRQ(35), NULL);
++ if (irq) free_irq(GPIOX_TO_IRQ(35), NULL);
++ if (i2c) i2c_close();
++ }
++ return 0;
++}
++
++/*! mainstone_mod_exit
++ */
++void mainstone_mod_exit(void)
++{
++ //free_irq(GPIO_2_80_TO_IRQ(35), NULL);
++ free_irq(GPIOX_TO_IRQ(35), NULL);
++
++ /* XXX stop thread - not needed once gpio interrupt implmented
++ */
++ isp1301_thread_exit(NULL);
++
++ isp1301_mod_exit();
++ TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
++ MST_MSCWR2 &= ~(MSCWR2_USB_OTG_SEL | MSCWR2_USB_OTG_RST);
++ TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
++ //isp1301_thread_exit();
++ i2c_close();
++
++}
++
++/* ********************************************************************************************* */
++
++struct tcd_ops tcd_ops = {
++
++ vbus: isp1301_vbus,
++
++ mod_init: mainstone_mod_init,
++ mod_exit: mainstone_mod_exit,
++
++ tcd_init_func: mainstone_tcd_init,
++
++ dischrg_vbus_func: isp1301_dischrg_vbus,
++ chrg_vbus_func: isp1301_chrg_vbus,
++ drv_vbus_func: isp1301_drv_vbus,
++ dp_pullup_func: isp1301_dp_pullup_func,
++ dm_pullup_func: isp1301_dm_pullup_func,
++ dm_det_func: isp1301_dm_det_func,
++ dp_det_func: isp1301_dp_det_func,
++
++};
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/tcd-omap-h2.c linux/drivers/otg/ocd/isp1301/tcd-omap-h2.c
+--- linux/drivers/no-otg/ocd/isp1301/tcd-omap-h2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/tcd-omap-h2.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++ * otg/ocd/isp1301/tcd-omap-h2.c -- USB Transceiver Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/isp1301/tcd-omap-h2.c
++ * @brief OMAP H2 ISP1301 driver.
++ *
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <otghw/isp1301-hardware.h>
++#include "otghw/bvd-hardware.h"
++#include <otghw/isp1301.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <linux/i2c.h>
++
++#include <asm/arch/gpio.h>
++#include <asm/arch/mux.h>
++//struct isp1301_private isp1301_private;
++
++/* ********************************************************************************************* */
++
++
++static irqreturn_t isp1301_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ TRACE_MSG0(TCD, "--");
++
++ SCHEDULE_WORK(isp1301_private.bh);
++
++ return IRQ_HANDLED;
++}
++
++
++/* ********************************************************************************************* */
++
++struct tcd_ops tcd_ops;
++
++#define ADAPTOR_NAME "OMAP I2C"
++
++/*! omap_mod_init
++ */
++int omap_mod_init(void)
++{
++ int i2c = i2c_configure(ADAPTOR_NAME, ISP1301_I2C_ADDR_HIGH);
++
++ int gpio = omap_request_gpio (ISP1301_GPIO);
++ int irq = 0;
++
++ TRACE_MSG0(TCD, "--");
++
++ /* did we get gpio and i2c?
++ */
++ THROW_IF(gpio || i2c, error);
++
++ /* for interrupt bottom half handler
++ */
++ // moved isp1301.c - PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
++
++ /*
++ * See H2 C.f. Figure 17 USBOTG Interface Connection
++ * GPIO2 M14
++ * setup gpio 2 and request interrupt for it
++ */
++ omap_set_gpio_direction(ISP1301_GPIO, 1);
++ //omap_cfg_reg(M14_1510_GPIO2);
++ omap_set_gpio_edge_ctrl(ISP1301_GPIO, OMAP_GPIO_FALLING_EDGE);
++ irq = request_irq (OMAP_GPIO_IRQ(ISP1301_GPIO), isp1301_int_hndlr, SA_INTERRUPT, "ISP1301", NULL);
++ THROW_IF(irq, error);
++
++ #ifdef CONFIG_OTG_OMAP_H2_3_WIRE
++
++ /* OTG on Pin Group 1 Using 3-Wire OTG Transceiver C.f. Figure 15-59
++ * See also H2 C.f. Figure 17 USBOTG Interface Connection
++ * DAT_SE0 mode
++ * Set DAT_SE0, SUSPEND_REG and BI_DI
++ */
++ //i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_DAT_SE0 | ISP1301_SUSPEND_REG);
++ //i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ~(ISP1301_DAT_SE0 | ISP1301_SUSPEND_REG));
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_BI_DI);
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ~ISP1301_BI_DI);
++
++ isp1301_configure(dat_se0_bidirectional, spd_susp_pins);
++
++ #elif CONFIG_OTG_OMAP_H2_4_WIRE
++
++ /* OTG on Pin Group 1 Using 4-Wire OTG Transceiver C.f. Figure 15-60
++ * See also H2 C.f. Figure 17 USBOTG Interface Connection
++ * VP_VM mode
++ * Reset DAT_SE0
++ * Set SUSPEND_REG and BI_DI
++ */
++ //i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_SUSPEND_REG);
++ //i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ~ISP1301_SUSPEND_REG);
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_BI_DI);
++ //i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ~ISP1301_BI_DI);
++
++ isp1301_configure(vp_vm_bidirectional);
++
++ #else
++ #error "ISP1301 Connection style not selected!"
++ #endif /* CONFIG_OTG_OMAP_H2_4_WIRE */
++
++ isp1301_mod_init();
++
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
++
++ /* Success!
++ */
++
++ TRACE_MSG0(TCD, "5. Success!");
++
++ otg_init(otg);
++
++ /* error handling
++ */
++ CATCH(error) {
++ if (irq) free_irq(OMAP_GPIO_IRQ(ISP1301_GPIO), NULL);
++ if (gpio) omap_free_gpio(ISP1301_GPIO);
++ if (i2c) i2c_close();
++ }
++ return 0;
++}
++
++/*! omap_mod_exit
++ */
++void omap_mod_exit(void)
++{
++ #if 0
++ // moved to isp1301.c
++ while (PENDING_WORK_ITEM(isp1301_private.bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++ #endif
++
++ isp1301_mod_exit();
++
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xff);
++ i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
++ i2c_close();
++ free_irq(OMAP_GPIO_IRQ(ISP1301_GPIO), NULL);
++ omap_free_gpio(ISP1301_GPIO);
++}
++
++/* ********************************************************************************************* */
++
++struct tcd_ops tcd_ops = {
++
++ //initial_state: tr_init,
++ vbus: isp1301_vbus,
++
++ mod_init: omap_mod_init,
++ mod_exit: omap_mod_exit,
++
++ dischrg_vbus_func: isp1301_dischrg_vbus,
++ chrg_vbus_func: isp1301_chrg_vbus,
++ drv_vbus_func: isp1301_drv_vbus,
++ dp_pullup_func: isp1301_dp_pullup_func,
++ dm_pullup_func: isp1301_dm_pullup_func,
++ dm_det_func: isp1301_dm_det_func,
++ dp_det_func: isp1301_dp_det_func,
++
++};
++
+diff -uNr linux/drivers/no-otg/ocd/isp1301/thread-l24.c linux/drivers/otg/ocd/isp1301/thread-l24.c
+--- linux/drivers/no-otg/ocd/isp1301/thread-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/isp1301/thread-l24.c 2006-09-01 21:41:31.000000000 +0200
+@@ -0,0 +1,144 @@
++/*
++ * otg/ocd/isp1301/thread-l24.c -- MX21ADS ISP1301 Transceiver Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/isp1301/thread-l24.c
++ * @brief Implement a kernel thread for checking ISP1301.
++ *
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/pcd-include.h>
++#include <otg/otg-module.h>
++#include <linux/pci.h>
++//#include <asm/arch/mx2.h>
++#include <otghw/isp1301-hardware.h>
++//#include "mx2.h"
++//#include "otghw/mx2-hardware.h"
++
++
++/* isp1301_bh
++ */
++extern void isp1301_bh(void *arg);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++/* I2C Thread
++ * The mx21 USBOTG module does not seem to be able to keep uptodate with the OTG Transceiver
++ * registers. This kernel thread will iterated endlessly reading the appropriate registers.
++ *
++ * If this is successful we can assume that the USBOTG module will correctly monitor the appropriate
++ * registers and allow us to follow them via the normal USBOTG interrupts and registers.
++ *
++ * Otherwise we can monitor here and issue the otg events directly.
++ */
++//#define ISP1301_THREAD_TIMEOUT_EN (10)
++#define ISP1301_THREAD_TIMEOUT_EN (1*HZ)
++#define ISP1301_THREAD_TIMEOUT_DIS (1*HZ)
++
++int isp1301_terminate;
++int mx2_pid;
++wait_queue_head_t isp1301_wait;
++static DECLARE_COMPLETION(mx2_exited);
++int isp1301_en;
++
++void (*isp1301_bh_proc)(void *);
++
++/*! isp1301_thread - implement a kernel task to monitor isp1301 for changes
++ */
++int isp1301_thread(void *data)
++{
++ u8 int_src_saved = 0, otg_status_saved = 0, int_src, otg_status;
++ TRACE_MSG0(TCD, "--");
++ daemonize();
++ reparent_to_init();
++ sprintf(current->comm, "isp1301_thread");
++
++ /* loop until told to terminate
++ */
++ while (!isp1301_terminate) {
++
++ #if 0
++ // XXX TESTING
++ static int count = 0;
++ count++;
++ if (!(count % 5))
++ isp1301_dp_pullup_func(tcd_instance->otg, !(count % 10)? 1 : 2);
++ #endif
++
++ /* sleep for a while if not enabled
++ */
++ if (!isp1301_en) {
++ TRACE_MSG1(TCD, "WAITING: %d", ISP1301_THREAD_TIMEOUT_DIS);
++ interruptible_sleep_on_timeout(&isp1301_wait, ISP1301_THREAD_TIMEOUT_DIS);
++ continue;
++ }
++
++ /* update 1301
++ */
++ if (isp1301_bh_proc)
++ isp1301_bh_proc(NULL);
++
++ //TRACE_MSG1(TCD, "SLEEPING: %d", ISP1301_THREAD_TIMEOUT_EN);
++ interruptible_sleep_on_timeout(&isp1301_wait, ISP1301_THREAD_TIMEOUT_EN);
++ //TRACE_MSG0(TCD, "RUNNING");
++ }
++ TRACE_MSG0(TCD, "Exiting");
++ complete_and_exit(&mx2_exited, 0);
++}
++
++extern int isp1301_bh_first;
++/*! isp1301_thread_wakeup - wakeup the isp1301 task
++ */
++void isp1301_thread_wakeup(int enabled, int first)
++{
++ TRACE_MSG0(TCD, "--");
++ isp1301_bh_first |= first;
++ isp1301_en = enabled;
++ wake_up(&isp1301_wait);
++}
++
++/* ********************************************************************************************* */
++
++/*! isp1301_thread_init - initial tcd setup
++ * Allocate interrupts and setup hardware.
++ */
++int isp1301_thread_init (void (bh_proc)(void *))
++{
++ isp1301_terminate = 0;
++ TRACE_MSG0(TCD, "--");
++ isp1301_bh_proc = bh_proc;
++ init_waitqueue_head(&isp1301_wait);
++ THROW_IF((mx2_pid = kernel_thread(&isp1301_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) < 0, error);
++ isp1301_thread_wakeup(0, 0);
++
++ CATCH(error) {
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*! isp1301_thread_exit - de-initialize
++ */
++void isp1301_thread_exit (wait_queue_head_t *wait_queue)
++{
++ TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT - terminating");
++ isp1301_bh_proc = NULL;
++ isp1301_terminate = 1;
++ if (wait_queue)
++ wake_up_interruptible(wait_queue); // wakeup waiting bottom half handler
++ isp1301_thread_wakeup(0, 0);
++ wait_for_completion(&mx2_exited);
++ TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT - terminated");
++}
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/Config.in linux/drivers/otg/ocd/max3353e/Config.in
+--- linux/drivers/no-otg/ocd/max3353e/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/Config.in 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,19 @@
++
++#
++# @(#) balden@belcarra.com|otg/ocd/max3353e/Config.in|20060831021117|26677
++# Copyright (c) 2004 Belcarra
++# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++#
++# MAX 3353E TCD
++
++if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
++ mainmenu_option next_comment
++
++ comment 'MAX 3353E (i2c)'
++
++ dep_bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFS $CONFIG_OTG_MAX3353E
++
++ endmenu
++else
++ define_bool CONFIG_OTG_MAX3353E_PROCFS n
++fi
+diff -uNr linux/drivers/no-otg/ocd/max3353e/Makefile linux/drivers/otg/ocd/max3353e/Makefile
+--- linux/drivers/no-otg/ocd/max3353e/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/Makefile 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,100 @@
++#
++# Makefile for the kernel USBD (device not host) drivers.
++# @(#) balden@belcarra.com|otg/ocd/max3353e/Makefile-l24|20060831021117|12633
++#
++# Copyright (c) 2004 Belcarra
++# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++
++# Subdirs.
++# This is a bit complex, because some subdirs are for
++# proprietary code, and are simply not present in a
++# general distribution.
++
++# The all-CAPS *_DIRS get nuked in the new versions
++# of Rules.make, so use only the subdir-* methods.
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++# The target object and module list name.
++
++O_TARGET := max3353e_target.o
++list-multi := max3353e_tcd.o
++
++# Objects that export symbols.
++
++export-objs := i2c-max3353e.o max3353e.o
++
++# Multipart objects.
++
++#db1550_tcd-objs := tcd-init-l24.o tcd-omap-h2.o max3353e.o i2c-l26.o tcd.o max3353e-procfs.o
++#db1550_tcd-objs := tcd-init-l24.o tcd-db1550.o tcd-mx2ads.o max3353e.o i2c-l26.o tcd.o max3353e-procfs.o
++db1550_tcd-objs := tcd-init-l24.o max3353e.o tcd-db1550.o i2c-max3353e.o
++# Optional parts of multipart objects.
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG_MAX3353E_DB1550) += db1550_tcd.o
++
++
++# Object files in subdirectories
++
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++DOT_DIR=$(TCD_DIR)/max3353e
++
++include $(TOPDIR)/Rules.make
++OTG=$(TOPDIR)/drivers/otg
++OCD_DIR=$(OTG)ocd/
++OTGLIB=$(OTG)/ocd/otglib
++INCLUDE_DIRS = -I$(OTG)
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++
++I2C=$(OTG)/ocd/otg-i2c
++PCD=$(OTG)/ocd/otg-pcd
++TCD=$(OTG)/ocd/otg-tcd
++vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD) $(TCD) $(OTGLIB)
++
++
++# Link rules for multi-part drivers.
++
++db1550_tcd.o: $(db1550_tcd-objs)
++ $(LD) -r -o $@ $(db1550_tcd-objs)
++
++# dependencies:
++
++# local
++
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/Makefile-l26 linux/drivers/otg/ocd/max3353e/Makefile-l26
+--- linux/drivers/no-otg/ocd/max3353e/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/Makefile-l26 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# Makefile for the kernel USBD (device not host) drivers.
++# @(#) balden@belcarra.com|otg/ocd/max3353e/Makefile-l26|20060831021117|56045
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++
++DOT_DIR=$(TCD_DIR)/max3353e
++
++OTG=$(TOPDIR)/drivers/otg
++HCD_DIR=$(OTG)/hcd
++TCD_DIR=$(OTG)/tcd
++USBDCORE_DIR=$(OTG)/usbdcore
++OTGCORE_DIR=$(OTG)/otgcore
++INCLUDE_DIRS = -I$(OTG)
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
++
++vpath %.c $(USBDCORE_DIR) $(OCD_DIR)
++
++
++# Link rules for multi-part drivers.
++
++db1550_tcd-objs := ../tcd-init-l24.o max3353e.o i2c-l26.o ../tcd.o
++obj-$(CONFIG_OTG_MAX3353E_DB1550) += db1550_tcd.o
++
++
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/README linux/drivers/otg/ocd/max3353e/README
+--- linux/drivers/no-otg/ocd/max3353e/README 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/README 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,9 @@
++Some notes for using max3353 tranciever in DB1550 development board
++1- Patch kernel with AMD DB1550 i2c driver.
++2- Patch arch/mips/au1000/db1x00/irqmap.c
++#if defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_MTX2)
++ { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 IRQ#
++ { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 1 IRQ#
++ { AU1500_GPIO_207, INTC_INT_FALL_EDGE, 0 }, // OTG tranciever
++#else
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/i2c-max3353e.c linux/drivers/otg/ocd/max3353e/i2c-max3353e.c
+--- linux/drivers/no-otg/ocd/max3353e/i2c-max3353e.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/i2c-max3353e.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,178 @@
++/* @(#) balden@belcarra.com|otg/ocd/max3353e/i2c-max3353e.c|20060831021117|42179
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ */
++#include <otg/otg-compat.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <linux/i2c.h>
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <otghw/max3353e-hardware.h>
++//#include "isp1301.h"
++
++/*
++ * N.B. i2c functions must not be called from interrupt handlers
++ */
++
++static struct file *i2c_file;
++static struct i2c_client *db1550_i2c_client;
++static int initstate_i2c;
++static int initstate_region;
++#define MAX_I2C 16
++
++#ifdef CONFIG_OMAP_H2
++#define ADAPTOR_NAME "OMAP I2C"
++#endif /* CONFIG_OMAP_H2 */
++#ifdef CONFIG_ARCH_MAINSTONE
++#define ADAPTOR_NAME "PXA-I2C-Adapter"
++#endif /* CONFIG_ARCH_MAINSTONE */
++#ifdef CONFIG_OTG_DB1550_J15
++#define ADAPTOR_NAME "pb1550 adapter"
++#endif /* CONFIG_OTG_DB1550_J15 */
++
++void i2c_writeb(u8 subaddr, u8 buf)
++{
++ char tmpbuf[2];
++ int ret;
++
++ tmpbuf[0] = subaddr; /*register number */
++ tmpbuf[1] = buf; /*register data */
++
++ ret = i2c_master_send(db1550_i2c_client, &tmpbuf[0], 2);
++ while (ret != 2){
++ ret = i2c_master_send(db1550_i2c_client, &tmpbuf[0], 2);
++ }
++ TRACE_MSG1(TCD, "I2C write %d\n", ret);
++
++}
++
++void i2c_close()
++{
++ if (initstate_i2c)
++ filp_close(i2c_file, NULL);
++ initstate_i2c = 0;
++
++}
++
++int i2c_configure (char *name, int addr)
++{
++ char filename[20];
++ int tmp;
++
++ RETURN_ZERO_IF(initstate_i2c);
++
++ /*find the I2C driver we need
++ */
++ for (tmp = 0; tmp < MAX_I2C; tmp++) {
++
++ sprintf(filename, "/dev/i2c-%d", tmp);
++
++ printk(KERN_INFO"%s: %s\n", __FUNCTION__, filename);
++
++ UNLESS (IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {
++
++ //printk(KERN_INFO"%s: %s found\n", __FUNCTION__, filename);
++
++ /*found some driver */
++ db1550_i2c_client = (struct i2c_client *)i2c_file->private_data;
++
++ printk(KERN_INFO"%s: found %s\n", __FUNCTION__, db1550_i2c_client->adapter->name);
++ if (strlen(db1550_i2c_client->adapter->name) >= 8) {
++ if (!strncmp(db1550_i2c_client->adapter->name, name, strlen(name)))
++ break; /*we found our driver! */
++ }
++ db1550_i2c_client = NULL;
++ filp_close(i2c_file, NULL);
++ }
++ printk(KERN_INFO"%s: %s %d\n", __FUNCTION__, filename, i2c_file);
++ }
++ if (tmp == MAX_I2C) { // Nothing found
++ printk(KERN_ERR"%s: cannot find I2C driver", __FUNCTION__);
++ return -ENODEV;
++ }
++ db1550_i2c_client->addr = addr;
++ initstate_i2c = 1;
++ return 0;
++}
++
++/*! i2c_readb
++ * Read byte from i2c device
++ * @param subaddr
++ */
++u8 i2c_readb(u8 subaddr)
++{
++int ret;
++
++ u8 buf = 0;
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ while (ret != 1){
++// printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ }
++ // printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_recv(db1550_i2c_client, &buf, 1);
++ while (ret != 1){
++ // printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ while (ret != 1){
++ // printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ }
++ ret = i2c_master_recv(db1550_i2c_client, &buf, 1);
++ }
++ // printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
++ TRACE_MSG2(TCD, "addr: %02x buf: %02x", subaddr, buf);
++ return buf;
++}
++
++
++/*! i2c_readl
++ * Read long from i2c device
++ * @param subaddr
++ */
++u32 i2c_readl(u8 subaddr)
++{
++ int ret;
++ // u32 buf = 0;
++ u8 buf[5];
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ while (ret != 1){
++ printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ }
++ printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_recv(db1550_i2c_client, buf, 4);
++ while (ret != 4){
++ printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ while (ret != 1){
++ printk(KERN_INFO"send return %d\n", ret);
++ ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
++ }
++ ret = i2c_master_recv(db1550_i2c_client, buf, 4);
++ }
++ printk(KERN_INFO"rec return %d with %02x %02x %02x %02x\n", ret, buf[0], buf[1], buf[2], buf[3]);
++ TRACE_MSG2(TCD, "addr: %02x buf: %08x", subaddr, buf);
++ return buf;
++}
++
++int i2c_readw (int addr)
++{
++ int data;
++
++ data = 0;
++
++ return data;
++}
++
++
++EXPORT_SYMBOL(i2c_writeb);
++EXPORT_SYMBOL(i2c_readw);
++EXPORT_SYMBOL(i2c_readb);
++EXPORT_SYMBOL(i2c_readl);
++EXPORT_SYMBOL(i2c_configure);
++EXPORT_SYMBOL(i2c_close);
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353-procfs.c linux/drivers/otg/ocd/max3353e/max3353-procfs.c
+--- linux/drivers/no-otg/ocd/max3353e/max3353-procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353-procfs.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,303 @@
++/*
++ * otg/ocd/max3353e/max3353-procfs.c - USB Device Core Layer
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353-procfs.c|20060831021117|57336
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/max3353-procfs.c
++ * @brief Implement /proc/max3353 to dump MAX3353 registers.
++ *
++ *
++ * @ingroup MAX3353TCD
++ */
++
++
++#include <otg/pcd-include.h>
++#include "otghw/max3353-hardware.h"
++#include "max3353.h"
++
++#ifdef CONFIG_ARCH_MX2ADS
++#include <asm/arch/mx2.h>
++#define MX2_OTG_XCVR_DEVAD 0x18
++#define MX2_SEQ_OP_REG 0x19
++#define MX2_SEQ_RD_STARTAD 0x1a
++#define MX2_I2C_OP_CTRL_REG 0x1b
++#define MX2_SCLK_TO_SCL_HPER 0x1e
++#define MX2_I2C_INTERRUPT_AND_CTRL 0x1f
++
++#define OTG_BASE_ADDR 0x10024000
++//#define OTG_I2C_BASE (OTG_BASE_ADDR+0x100)
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++/* Proc Filesystem *************************************************************************** */
++
++extern struct max3353_private max3353_private;
++
++#define MAX_HISTORY 6
++struct reg_list {
++ u8 reg;
++ u8 size;
++ char *name;
++ u32 values[MAX_HISTORY];
++};
++
++#define REG(r, s) {r, s, #r, }
++
++struct reg_list max3353_prod_list[] = {
++ REG(MAX3353_VENDOR_ID, 2),
++ REG(MAX3353_PRODUCT_ID, 2),
++ REG(MAX3353_VERSION_ID, 2),
++ { 0, 1, NULL,},
++};
++struct reg_list max3353_reg_list[] = {
++ REG(MAX3353_OTG_CONTROL_SET, 1),
++ REG(MAX3353_INTERRUPT_SOURCE, 1),
++ REG(MAX3353_INTERRUPT_LATCH_SET, 1),
++ REG(MAX3353_INTERRUPT_ENABLE_LOW_SET, 1),
++ REG(MAX3353_INTERRUPT_ENABLE_HIGH_SET, 1),
++ REG(MAX3353_MODE_CONTROL_1_SET, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list max3353_spec_list[] = {
++ REG(MAX3353_MODE_CONTROL_2_SET, 1),
++ REG(MAX3353_OTG_STATUS, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list max3301e_spec_list[] = {
++ REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
++ REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
++ { 0, 1, NULL,},
++};
++#ifdef CONFIG_ARCH_MX2ADS
++struct reg_list mx21_spec_list[] = {
++ REG(MX2_OTG_XCVR_DEVAD, 1),
++ REG(MX2_SEQ_OP_REG, 1),
++ REG(MX2_SEQ_RD_STARTAD, 1),
++ REG(MX2_I2C_OP_CTRL_REG, 1),
++ REG(MX2_SCLK_TO_SCL_HPER, 1),
++ REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
++ { 0, 1, NULL,},
++};
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void max3353_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ switch(list->size) {
++ case 1:
++ list->values[0] = i2c_readb(list->reg);
++ break;
++ case 2:
++ list->values[0] = i2c_readw(list->reg);
++ break;
++ case 4:
++ list->values[0] = i2c_readl(list->reg);
++ break;
++ }
++ }
++}
++
++#ifdef CONFIG_ARCH_MX2ADS
++static u8 __inline__ mx2_rb(u32 port)
++{
++ return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
++}
++
++
++void mx21_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ list->values[0] = mx2_rb(list->reg);
++ }
++}
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void max3353_update_all(void)
++{
++ max3353_update(max3353_reg_list);
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ max3353_update(max3353_spec_list);
++ break;
++ case max3301e:
++ max3353_update(max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ mx21_update(mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++}
++
++
++
++/*
++ * dohex
++ *
++ */
++static void dohexdigit (char *cp, unsigned char val)
++{
++ if (val < 0xa)
++ *cp = val + '0';
++ else if ((val >= 0x0a) && (val <= 0x0f))
++ *cp = val - 0x0a + 'a';
++}
++
++/*
++ * dohex
++ *
++ */
++static void dohexval (char *cp, unsigned char val)
++{
++ dohexdigit (cp++, val >> 4);
++ dohexdigit (cp++, val & 0xf);
++}
++
++int max3353_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
++{
++ int len = 0, i;
++ len += sprintf (buf + len, "%-20s %-34s [%03x]: ", name, reg->name, reg->reg);
++ len += sprintf (buf + len, fmt, reg->values[0]);
++ for (i = 1; i < MAX_HISTORY; i++)
++ if (reg->values[i - 1] == reg->values[i])
++ len += sprintf (buf + len, " ");
++ else
++ len += sprintf (buf + len, fmt, reg->values[i]);
++ len += sprintf (buf + len, "\n");
++ return len;
++}
++
++int max3353_dump_list(char * buf, char *name, struct reg_list *list)
++{
++ int len = 0;
++ for (; list && list->name; list++)
++ switch(list->size) {
++ case 1: len += max3353_dump(buf + len, name, " %02x", list); break;
++ case 2: len += max3353_dump(buf + len, name, " %04x", list); break;
++ case 4: len += max3353_dump(buf + len, name, " %08x", list); break;
++ }
++ return len;
++}
++
++int max3353_dump_all(char *buf)
++{
++ int len = 0;
++ len += max3353_dump_list(buf + len, "MAX3353 Standard", max3353_reg_list);
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ len += max3353_dump_list(buf + len, "MAX3353 Extra", max3353_spec_list);
++ break;
++ case max3301e:
++ len += max3353_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ len += max3353_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++ return len;
++}
++
++
++
++/*!
++ * max3353_device_proc_read - implement proc file system read.
++ *
++ * Standard proc file system read function.
++ *
++ * We let upper layers iterate for us, *pos will indicate which device to return
++ * statistics for.
++ */
++static ssize_t max3353_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int i;
++ u32 r;
++
++ int config_size;
++
++ // get a page, max 4095 bytes of data...
++ RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
++
++ len = 0;
++ index = (*pos)++;
++
++ switch(index) {
++ case 0:
++ len += sprintf ((char *) page + len, "MAX3353 Transceiver Registers\n");
++
++ max3353_update_all();
++ len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n",
++ max3353_private.vendor, max3353_private.product,
++ max3353_private.revision, max3353_private.transceiver_map->name
++ );
++
++ len += max3353_dump_all((char *) page + len);
++ len += sprintf ((char *) page + len, "\n");
++
++ break;
++
++ case 1:
++ break;
++
++ }
++
++ if (len > count) {
++ len = -EINVAL;
++ }
++ else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
++ len = -EFAULT;
++ }
++ else {
++ }
++ free_page (page);
++ return len;
++}
++
++static struct file_operations max3353_device_proc_operations_functions = {
++ read:max3353_device_proc_read_functions,
++};
++
++/* Module init ******************************************************************************* */
++
++static int max3353_procfs_init (void)
++{
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry ("max3353", 0, 0)) == NULL)
++ return -ENOMEM;
++
++ p->proc_fops = &max3353_device_proc_operations_functions;
++
++ max3353_update_all();
++
++ return 0;
++}
++static void max3353_procfs_exit (void)
++{
++ remove_proc_entry ("max3353", NULL);
++}
++#else
++static int max3353_procfs_init (void) { return 0;
++}
++static void max3353_procfs_exit (void) { }
++#endif
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353.c linux/drivers/otg/ocd/max3353e/max3353.c
+--- linux/drivers/no-otg/ocd/max3353e/max3353.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,706 @@
++/*
++ * otg/ocd/max3353e/max3353.c -- USB Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353.c|20060831021117|27226
++ *
++ * Copyright (c) 2003-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/max3353.c
++ * @brief MAX3353 OTG Transceiver Driver.
++ *
++ * This is the generic MAX3353 TCD core support.
++ *
++ * Notes:
++ *
++ * 1. The MAX3353 can control the speed and suspend directly, would it be
++ * appropriate to allow state machine to control this.
++ *
++ * 2. The MAX3353 has auto connect feature, can this be used without change
++ * to state machine.
++ *
++ * 3. The MAX3353 can control the ADR/PSW pin to enable / disable external
++ * charge pump.
++ *
++ * @ingroup MAX3353TCD
++ */
++
++#include <otg/otg-compat.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <linux/i2c.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-ocd.h>
++#include <otg/otg-pcd.h>
++
++#include <otghw/max3353-hardware.h>
++#include "max3353.h"
++
++
++struct otg_transceiver_map max3353_transceiver_map[] = {
++ { max3353, 0x4cc, 0x1301, 0x00, "Phillips MAX3353", },
++ { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
++ { 0, 0, 0, 0, "Unknown Transceiver", },
++};
++
++struct max3353_private max3353_private;
++
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
++
++
++/*! max3353_int_src - update interrupt source test mask
++ *
++ * This sets the current mask and updates the interrupt registers to match.
++ */
++void max3353_int_src(u8 int_src)
++{
++ TRACE_MSG1(TCD, "setting int_src %02x", int_src);
++ max3353_private.int_src = int_src;
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, ~int_src);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, ~int_src);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_SET, int_src);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_SET, int_src);
++ i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, int_src);
++}
++
++/*! max3353_int_src_set - add to the interrupt source mask
++ *
++ */
++void max3353_int_src_set(u8 int_src)
++{
++ max3353_int_src(int_src |= max3353_private.int_src);
++}
++
++/*! max3353_int_src_clr - remove from the interrup source mask
++ */
++void max3353_int_src_clr(u8 int_src)
++{
++ max3353_int_src(int_src = max3353_private.int_src & ~int_src);
++}
++
++/* ********************************************************************************************* */
++
++
++/*! max3353_event_set_irq
++ */
++void max3353_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *mset, char *mreset)
++{
++ TRACE_MSG5(TCD, "changed: %x flag: %x input: %08x %s %s", changed, flag, input,
++ flag ? mset: mreset,
++ changed ? "": "(ignored)");
++
++ otg_event_set_irq(otg, changed, flag, input, tag, flag ? mset : mreset);
++}
++
++/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 Interrupt Source Register
++ */
++u8 max3353_update_int_src(struct otg_instance *otg, u8 int_src, u8 changed)
++{
++ UNLESS (changed) return int_src;
++ TRACE_MSG2(TCD, "CHANGED INTERRUPT_SOURCE: %02x (%02x) ", int_src, changed);
++
++ /* Core events
++ */
++ max3353_event_set_irq(otg, MAX3353_ID_GND & changed, MAX3353_ID_GND & int_src,
++ ID_GND, TCD, "ID_GND", "ID_GND/");
++ max3353_event_set_irq(otg, MAX3353_ID_FLOAT & changed, MAX3353_ID_FLOAT & int_src,
++ ID_FLOAT, TCD, "ID_FLOAT", "ID_FLOAT/");
++ max3353_event_set_irq(otg, MAX3353_VBUS_VLD & changed, MAX3353_VBUS_VLD & int_src,
++ VBUS_VLD, TCD, "VBUS_VLD", "VBUS_VLD/");
++ max3353_event_set_irq(otg, MAX3353_SESS_VLD & changed, MAX3353_SESS_VLD & int_src,
++ A_SESS_VLD, TCD, "A_SESS_VLD", "A_SESS_VLD/");
++
++ max3353_event_set_irq(otg, MAX3353_DM_HI & changed, MAX3353_DM_HI & int_src,
++ DM_HIGH, TCD, "DM_HIGH", "DM_HIGH/");
++
++ max3353_event_set_irq(otg, MAX3353_DP_HI & changed, MAX3353_DP_HI & int_src,
++ DP_HIGH, TCD, "DP_HIGH", "DP_HIGH/");
++
++ //max3353_event_set_irq(otg, MAX3353_SE1 & changed, ((MAX3353_SE1 & int_src) == 0), SE0_DET, TCD, "SE0", "SE0/");
++
++ /* carkit
++ */
++ max3353_event_set_irq(otg, MAX3353_CR_INT & changed, !(MAX3353_CR_INT & int_src),
++ CR_INT_DET, TCD, "CR_INT", "CR_INT/");
++
++ //TRACE_MSG3(TCD, "MAX3353_SE1: %02x & int_src: %02x = %02x", MAX3353_SE1, int_src, MAX3353_SE1 & int_src);
++ //max3353_event_set_irq(otg, MAX3353_SE1 & changed, ((MAX3353_SE1 & int_src) == MAX3353_SE1),
++ // SE1_DET, TCD, "SE1", "SE1/");
++
++
++ /* A-Device
++ */
++ max3353_event_set_irq(otg, MAX3353_BDIS_ACON & changed, !(MAX3353_BDIS_ACON & int_src),
++ BDIS_ACON, TCD, "BDIS_ACON", "BDIS_ACON/" );
++
++ return int_src;
++}
++
++/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 OTG Status Register
++ */
++u8 max3353_update_otg_status(struct otg_instance *otg, u8 otg_status, u8 changed)
++{
++ UNLESS (changed) return otg_status;
++ TRACE_MSG2(TCD, "CHANGED OTG_STATUS_REG: %02x (%02x) ", otg_status, changed);
++
++ max3353_event_set_irq(otg, MAX3353_B_SESS_VLD & changed, MAX3353_B_SESS_VLD & otg_status,
++ B_SESS_VLD, TCD, "B_SESS_VLD", "B_SESS_VLD/");
++ max3353_event_set_irq(otg, MAX3353_B_SESS_END & changed, MAX3353_B_SESS_END & otg_status,
++ B_SESS_END, TCD, "B_SESS_END", "B_SESS_END/");
++
++ //otg_b_sess_vld(otg, first || (MAX3353_B_SESS_VLD & changed), MAX3353_B_SESS_VLD & otg_status, MAX3353_NAME );
++ return otg_status;
++}
++
++int max3353_bh_first;
++
++
++/*! max3353_bh
++ */
++void max3353_bh(void *arg)
++{
++ u8 int_lat, int_src = 0, otg_status = 0, special_function_22 = 0;
++ static u8 int_src_saved, otg_status_saved, special_function_22_saved;
++
++ //TRACE_MSG0(TCD, "--");
++ /* read the interrupt latch and and clear latch and update otg
++ */
++ if ((int_lat = i2c_readb(MAX3353_INTERRUPT_LATCH_SET))) {
++ //TRACE_MSG1(TCD, "CLEARING INT LAT: %02x", int_lat);
++ i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, int_lat);
++ }
++
++ /* If int_lat shows a change or we are forcing an update, read interrupt source.
++ * Note that we mask DP_HI and DM_HI when LOC_CONN is set, we don't want them
++ * when USB Bus is in use.
++ *
++ * Mask with bits we are currently interested in.
++ */
++ int_src = i2c_readb(MAX3353_INTERRUPT_SOURCE) & max3353_private.int_src;
++
++ UNLESS ( max3353_private.flags & MAX3353_LOC_CONN) {
++ }
++
++
++ /* further work if B-Device and VBUS_VLD
++ */
++ if ( (!(int_src & MAX3353_ID_GND) && (int_src & MAX3353_VBUS_VLD)) ||
++ (!(int_src_saved & MAX3353_ID_GND) && (int_src_saved & MAX3353_VBUS_VLD)) )
++ {
++ /* read the otg_status register and update otg state machine
++ *
++ * XXX this needs to be conditional on Transceiver type. The
++ * MAX3301E for example supports sess_end in a separate register.
++ */
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ otg_status = i2c_readb(MAX3353_OTG_STATUS);
++ if (max3353_bh_first)
++ otg_status_saved = ~otg_status;
++ otg_status_saved = max3353_update_otg_status(tcd_instance->otg, otg_status,
++ otg_status_saved ^ otg_status);
++ break;
++ case max3301e:
++ // XXX
++ special_function_22 = i2c_readb(MAX3301E_SPECIAL_FUNCTION_2_SET);
++ break;
++ case unknown_transceiver:
++ break;
++ }
++ }
++ if (max3353_bh_first)
++ int_src_saved = ~int_src;
++
++ int_src_saved = max3353_update_int_src(tcd_instance->otg, int_src, int_src_saved ^ int_src);
++
++ max3353_bh_first = 0;
++}
++
++/* ********************************************************************************************** */
++/*! max3353_vbus - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int max3353_vbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++/*! max3353_id - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int max3353_idvbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++
++/* ********************************************************************************************* */
++
++/*! max3353_chrg_vbus - used to enable or disable B-device Vbus charging
++ */
++void max3353_chrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_SET");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_VBUS_CHRG);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_VBUS_CHRG);
++ break;
++ case PULSE:
++ break;
++ }
++}
++
++/*! max3353_drv_vbus - used to enable or disable A-device driving Vbus
++ */
++void max3353_drv_vbus(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "DRV_VBUS_SET");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_VBUS_DRV);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "DRV_VBUS_RESET");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_VBUS_DRV);
++ break;
++ }
++}
++
++/*! max3353_dischrg_vbus - used to enable Vbus discharge
++ */
++void max3353_dischrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_VBUS_DISCHRG);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, MAX3353_VBUS_DISCHRG);
++ break;
++ }
++}
++
++/*! max3353_dp_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
++ *
++ * host peripheral
++ * d+ pull-up clr set
++ * d+ pull-down set clr
++ *
++ * d- pull-up clr clr
++ * d- pull-down set set
++ *
++ */
++void max3353_dp_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ printk(KERN_INFO"%s: --\n", __FUNCTION__);
++ max3353_private.flags |= MAX3353_LOC_CONN;
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Clr DP PULLDOWN");
++ //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DP_PULLDOWN);
++ //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) (MAX3353_DP_PULLDOWN | MAX3353_DM_PULLDOWN) );
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DP PULLUP");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_DP_PULLUP);
++ break;
++
++ case RESET:
++ max3353_private.flags &= ~MAX3353_LOC_CONN;
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN RESET - Clr DP PULLUP");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8)MAX3353_DP_PULLUP);
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DP PULLDOWN");
++ //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8)MAX3353_DP_PULLDOWN);
++ //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) (MAX3353_DP_PULLDOWN | MAX3353_DM_PULLDOWN) );
++ break;
++
++ case PULSE:
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
++ break;
++ }
++}
++
++/*! max3353_dm_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ */
++void max3353_dm_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ max3353_private.flags |= MAX3353_LOC_CONN;
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Clr DM PULLDOWN");
++ //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DM_PULLDOWN);
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DM PULLUP");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_DM_PULLUP);
++ break;
++
++ case RESET:
++ max3353_private.flags &= ~MAX3353_LOC_CONN;
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN RESET - Clr DM PULLUP");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8)MAX3353_DM_PULLUP);
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DM PULLDOWN");
++ //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8)MAX3353_DM_PULLDOWN);
++ break;
++
++ case PULSE:
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
++ break;
++ }
++}
++
++/*! max3353_dm_det_func - used to enable or disable D- detect
++ *
++ */
++void max3353_dm_det_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting DM_HI detect");
++ max3353_int_src_set(MAX3353_DM_HI);
++ max3353_bh_first = 1;
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting DM_HI detect");
++ max3353_int_src_clr(MAX3353_DM_HI);
++ break;
++ }
++}
++
++/*! max3353_dp_det_func - used to enable or disable D+ detect
++ *
++ */
++void max3353_dp_det_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting DP_HI detect");
++ max3353_int_src_set(MAX3353_DP_HI);
++ max3353_bh_first = 1;
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting DP_HI detect");
++ max3353_int_src_clr(MAX3353_DP_HI);
++ break;
++ }
++}
++
++/*! max3353_bdis_acon_func - used to enable or disable auto a-connect
++ *
++ */
++void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting BDIS ACON");
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_ID_PULLDOWN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting BDIS ACON");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, MAX3353_ID_PULLDOWN);
++ break;
++ }
++}
++
++/*! max3353_id_pulldown_func - used to enable or disable ID pulldown
++ *
++ */
++void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting ID PULLDOWN");
++ i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_BDIS_ACON_EN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting ID PULLDOWN");
++ i2c_writeb(MAX3353_MODE_CONTROL_1_CLR, MAX3353_BDIS_ACON_EN);
++ break;
++ }
++}
++
++/*! max3353_audio_func - used to enable or disable Carkit Interrupt
++ *
++ */
++void max3353_audio_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting CARKIT INT");
++ i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_AUDIO_EN);
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting CARKIT INT");
++ i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_AUDIO_EN);
++ break;
++ }
++}
++
++/*! max3353_uart_func - used to enable or disable transparent uart mode
++ *
++ */
++void max3353_uart_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting UART");
++ i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_UART_EN);
++ /* XXX enable uart */
++ break;
++
++ case RESET:
++ MAX3353SG0(TCD, "reseting UART");
++ i2c_writeb(MAX3353_MODE_CONTROL_1_CLR, MAX3353_UART_EN);
++ /* XXX disable uart */
++ break;
++ }
++}
++
++/*! max3353_mono_func - used to enable or disable mono audio connection
++ *
++ */
++void max3353_mono_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "setting MONO");
++ /* XXX enable mono output */
++ break;
++
++ case RESET:
++ TRACE_MSG0(TCD, "reseting MONO");
++ /* XXX disable mono output */
++ break;
++ }
++}
++
++
++/* ********************************************************************************************* */
++extern int max3353_procfs_init (void);
++extern void max3353_procfs_exit (void);
++
++/*! max3353_mod_init
++ */
++int max3353_mod_init(void)
++{
++ /* for interrupt bottom half handler
++ */
++ PREPARE_WORK_ITEM(max3353_private.bh, &max3353_bh, NULL);
++
++ /* setup max3353, enable interrupts, clear latch
++ * XXX when and how do we do DM_HI and DP_HI, when ID is present?
++ */
++ max3353_int_src(MAX3353_INT_SRC);
++ //max3353_int_src(MAX3353_NO_SE1_INT);
++
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_DM_PULLDOWN | MAX3353_DP_PULLDOWN);
++
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++ max3353_procfs_init ();
++#endif /* CONFIG_OTG_MAX3353_PROCFS */
++
++ return 0;
++}
++
++/*! max3353_mod_exit
++ */
++void max3353_mod_exit(void)
++{
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, 0xff);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
++ //i2c_close();
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++ max3353_procfs_exit ();
++#endif /* CONFIG_OTG_MAX3353_PROCFS */
++
++ while (PENDING_WORK_ITEM(max3353_private.bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++
++}
++
++/* ********************************************************************************************* */
++/*! max3353_configure - configure the MAX3353 for this host
++ * @param tx_mode - the type of connection between the host USB and the MAX3353
++ * @param spd_ctrl - suspend control method
++ */
++void max3353_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
++{
++ u16 vendor = 0, product = 0, revision = 0;
++ u8 mode1, mode2, control;
++
++ struct otg_transceiver_map *map = max3353_transceiver_map;
++
++
++#if defined(CONFIG_OTG_MAX3353_MX2ADS) || defined(CONFIG_OTG_MAX3353_MX2ADS_MODULE)
++ u32 vp;
++ MAX3353SG0(TCD, "1. Read Transceiver ID's with long read");
++ vp = i2c_readl(MAX3353_VENDOR_ID);
++ max3353_private.vendor = vp & 0xffff;
++ max3353_private.product = vp >> 16;
++ max3353_private.revision = i2c_readw(MAX3353_VERSION_ID);
++ mode1 = i2c_readb(MAX3353_MODE_CONTROL_1_SET);
++ mode2 = i2c_readb(MAX3353_MODE_CONTROL_2_SET);
++
++ TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
++ vendor, product, revision, mode1, mode2);
++
++#else /* defined(CONFIG_OTG_MAX3353_MX2ADS) */
++
++ max3353_private.vendor = i2c_readw(MAX3353_VENDOR_ID);
++ max3353_private.product = i2c_readw(MAX3353_PRODUCT_ID);
++ max3353_private.revision = i2c_readw(MAX3353_VERSION_ID);
++ mode1 = i2c_readb(MAX3353_MODE_CONTROL_1_SET);
++ mode2 = i2c_readb(MAX3353_MODE_CONTROL_2_SET);
++
++ TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
++ max3353_private.vendor, max3353_private.product, max3353_private.revision, mode1, mode2);
++
++#endif /* defined(CONFIG_OTG_MAX3353_MX2ADS) */
++
++ for ( ; map && map->transceiver_type != unknown_transceiver; map++) {
++ CONTINUE_UNLESS ((max3353_private.vendor == map->vendor) && (max3353_private.product == map->product));
++ TRACE_MSG1(TCD, "Found Transceiver: %s", map->name);
++ max3353_private.transceiver_map = map;
++ break;
++ }
++ UNLESS (max3353_private.transceiver_map)
++ max3353_private.transceiver_map = max3353_transceiver_map;
++
++ TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, 0xff); // clear
++
++ TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
++
++ i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_DM_PULLDOWN | MAX3353_DP_PULLDOWN);
++ i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DM_PULLUP | MAX3353_DP_PULLUP);
++
++
++ TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
++ i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, 0xff);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, 0xeb);
++ i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, 0xeb);
++
++ /* The PSW_OE enables the ADR/PSW pin for output driving either high
++ * or low depending on the address.
++ *
++ * ADR ADR_REG Address PSW_OE=0 PSW_OE=1
++ *
++ * low 0 0x2c LOW HIGH
++ *
++ * high 1 0x2d HIGH LOW
++ *
++ *
++ * The i2c address by tying the ADR/PSW pin either high or low.
++ * Setting the PSW_OE drives the ADR/PSW into the opposite of the
++ * default wiring.
++ *
++ * On the MX21ADS the ADR/PSW pin is wired high which enables the
++ * charge pump. So enabling the PSW_OE is required to disable Vbus
++ * generation on the Charge Pump.
++ *
++ * The MAX3355E will only enable Vbus when this signal is high AND
++ * the ID signal is low. So it may be safe to leave enabled when
++ * operating as a B-device (ID floating.)
++ */
++
++ //i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_PSW_OE); // PSW_OE - OFFVBUS low
++
++
++ TRACE_MSG1(TCD, "6. tx_mode: %02x", tx_mode);
++ switch (tx_mode) {
++ case vp_vm_bidirectional:
++ break;
++ case dat_se0_unidirectional:
++ i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_BI_DI);
++ MAX3353t_se0_bidirectional:
++ i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_DAT_SE0);
++ break;
++ }
++ TRACE_MSG0(TCD, "6. tx_mode done");
++
++ TRACE_MSG1(TCD, "7. spd_ctrl: %02x", spd_ctrl);
++ switch (spd_ctrl) {
++ case spd_susp_pins:
++ i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_SPD_SUSP_CTRL);
++ break;
++ case spd_susp_reg:
++ i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_SPD_SUSP_CTRL);
++ break;
++ }
++
++ //i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_PSW_OE); // PSW_OE - OFFVBUS low
++
++ TRACE_MSG0(TCD, "7. spd_ctrl done");
++
++ TRACE_MSG1(TCD, "8. transceiver_type: %02x", max3353_private.transceiver_map);
++
++ TRACE_MSG1(TCD, "8. transceiver_type: %02x", max3353_private.transceiver_map->transceiver_type);
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ break;
++ case max3301e:
++ i2c_writeb(MAX3301E_SPECIAL_FUNCTION_1_SET, MAX3301E_SESS_END);
++ break;
++ case unknown_transceiver:
++ break;
++ }
++ TRACE_MSG0(TCD, "8. transceiver_type done");
++}
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353.h linux/drivers/otg/ocd/max3353e/max3353.h
+--- linux/drivers/no-otg/ocd/max3353e/max3353.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353.h 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,132 @@
++/*
++ * otg/ocd/max3353/max3353.h -- USB Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353.h|20060831021117|56821
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++
++/*!
++ * @file otg/ocd/max3353e/max3353.h
++ * @brief Private structures and defines for MAX3353 Transciever Controller Driver.
++ *
++ * This file contains the private defines and structures for the MAX3353 Transceiver
++ * Driver.
++ *
++ * @ingroup MAX3353TCD
++ */
++
++
++#ifdef CONFIG_XXXXX
++#define MAX3353_GPIO (2)
++#define TCD_MAX3353_I2C_ADDR MAX3353_I2C_ADDR_HIGH;
++#endif
++
++#define MAX3353_NAME "max3353"
++
++#define MAX3353_LOC_CONN 0x01
++
++#define MAX3353_INT_SRC 0xeb
++
++//#define MAX3353_ALL_INT_SRC 0xff
++//#define MAX3353_NO_SE1_INT 0xeb
++//#define MAX3353_NO_SE1_INT 0xfb /* do not pay attention to DP_HI */
++
++typedef enum otg_transceiver {
++ unknown_transceiver,
++ max3353,
++ max3301e
++} otg_transceiver_t;
++
++struct otg_transceiver_map {
++ otg_transceiver_t transceiver_type;
++ u16 vendor;
++ u16 product;
++ u16 revision;
++ char *name;
++};
++
++struct max3353_private {
++ WORK_STRUCT bh;
++ u16 vendor;
++ u16 product;
++ u16 revision;
++ u32 flags;
++ u8 int_src;
++ struct otg_transceiver_map *transceiver_map;
++};
++
++/*! tx_mode
++ * This defines the various ways that the MAX3353 can be
++ * wired into the host USB.
++ */
++typedef enum tx_mode {
++ dat_se0_bidirectional, /*!< 3-Wire */
++ vp_vm_bidirectional, /*!< 4-Wire */
++ dat_se0_unidirectional /*!< 6-Wire */
++} tx_mode_t;
++
++/*! spd_ctrl
++ * This defines how the speed and suspend pins are controlled
++ * for this host.
++ */
++typedef enum spd_ctrl {
++ spd_susp_pins, /*!< controlled by SPEED and SUSPEND pins */
++ spd_susp_reg, /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
++} spd_ctrl_t;
++
++
++extern struct tcd_ops tcd_ops;
++extern struct max3353_private max3353_private;
++extern struct tcd_instance *tcd_instance;
++
++/* max3353.c */
++extern int max3353_mod_init(void);
++extern void max3353_mod_exit(void);
++extern void max3353_chrg_vbus(struct otg_instance *, u8 );
++extern void max3353_drv_vbus(struct otg_instance *, u8 );
++extern void max3353_dischrg_vbus(struct otg_instance *, u8 );
++extern void max3353_dp_pullup_func(struct otg_instance *, u8 );
++extern void max3353_dm_pullup_func(struct otg_instance *, u8 );
++extern void max3353_dm_det_func(struct otg_instance *, u8 );
++extern void max3353_dp_det_func(struct otg_instance *, u8 );
++extern void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag);
++extern void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag);
++extern void max3353_audio_func(struct otg_instance *otg, u8 flag);
++extern void max3353_uart_func(struct otg_instance *otg, u8 flag);
++extern void max3353_mono_func(struct otg_instance *otg, u8 flag);
++
++extern void max3353_otg_timer(struct otg_instance *, u8 );
++extern void max3353_bh(void *);
++extern int max3353_id (struct otg_instance *);
++extern int max3353_vbus (struct otg_instance *);
++extern void max3353_configure(tx_mode_t, spd_ctrl_t );
++
++/* thread */
++extern int max3353_thread_init (void (bh_proc)(void *));
++extern void max3353_thread_exit (wait_queue_head_t *);
++extern void max3353_thread_wakeup(int enabled, int first);
++
++
++
++/* i2c-xxx.c */
++int i2c_configure(char *name, int addr);
++extern void i2c_close(void);
++extern u8 i2c_readb(u8 );
++extern u16 i2c_readw(u8 );
++extern u32 i2c_readl(u8 );
++extern int i2c_writeb(u8 , u8 );
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e-procfs.c linux/drivers/otg/ocd/max3353e/max3353e-procfs.c
+--- linux/drivers/no-otg/ocd/max3353e/max3353e-procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353e-procfs.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,303 @@
++/*
++ * otg/ocd/max3353/max3353-procfs.c - USB Device Core Layer
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e-procfs.c|20060831021117|57336
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/max3353e-procfs.c
++ * @brief Implement /proc/max3353 to dump MAX3353 registers.
++ *
++ *
++ * @ingroup MAX3353TCD
++ */
++
++
++#include <otg/pcd-include.h>
++#include "otghw/max3353-hardware.h"
++#include "max3353.h"
++
++#ifdef CONFIG_ARCH_MX2ADS
++#include <asm/arch/mx2.h>
++#define MX2_OTG_XCVR_DEVAD 0x18
++#define MX2_SEQ_OP_REG 0x19
++#define MX2_SEQ_RD_STARTAD 0x1a
++#define MX2_I2C_OP_CTRL_REG 0x1b
++#define MX2_SCLK_TO_SCL_HPER 0x1e
++#define MX2_I2C_INTERRUPT_AND_CTRL 0x1f
++
++#define OTG_BASE_ADDR 0x10024000
++//#define OTG_I2C_BASE (OTG_BASE_ADDR+0x100)
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++/* Proc Filesystem *************************************************************************** */
++
++extern struct max3353_private max3353_private;
++
++#define MAX_HISTORY 6
++struct reg_list {
++ u8 reg;
++ u8 size;
++ char *name;
++ u32 values[MAX_HISTORY];
++};
++
++#define REG(r, s) {r, s, #r, }
++
++struct reg_list max3353_prod_list[] = {
++ REG(MAX3353_VENDOR_ID, 2),
++ REG(MAX3353_PRODUCT_ID, 2),
++ REG(MAX3353_VERSION_ID, 2),
++ { 0, 1, NULL,},
++};
++struct reg_list max3353_reg_list[] = {
++ REG(MAX3353_OTG_CONTROL_SET, 1),
++ REG(MAX3353_INTERRUPT_SOURCE, 1),
++ REG(MAX3353_INTERRUPT_LATCH_SET, 1),
++ REG(MAX3353_INTERRUPT_ENABLE_LOW_SET, 1),
++ REG(MAX3353_INTERRUPT_ENABLE_HIGH_SET, 1),
++ REG(MAX3353_MODE_CONTROL_1_SET, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list max3353_spec_list[] = {
++ REG(MAX3353_MODE_CONTROL_2_SET, 1),
++ REG(MAX3353_OTG_STATUS, 1),
++ { 0, 1, NULL,},
++};
++struct reg_list max3301e_spec_list[] = {
++ REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
++ REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
++ { 0, 1, NULL,},
++};
++#ifdef CONFIG_ARCH_MX2ADS
++struct reg_list mx21_spec_list[] = {
++ REG(MX2_OTG_XCVR_DEVAD, 1),
++ REG(MX2_SEQ_OP_REG, 1),
++ REG(MX2_SEQ_RD_STARTAD, 1),
++ REG(MX2_I2C_OP_CTRL_REG, 1),
++ REG(MX2_SCLK_TO_SCL_HPER, 1),
++ REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
++ { 0, 1, NULL,},
++};
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void max3353_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ switch(list->size) {
++ case 1:
++ list->values[0] = i2c_readb(list->reg);
++ break;
++ case 2:
++ list->values[0] = i2c_readw(list->reg);
++ break;
++ case 4:
++ list->values[0] = i2c_readl(list->reg);
++ break;
++ }
++ }
++}
++
++#ifdef CONFIG_ARCH_MX2ADS
++static u8 __inline__ mx2_rb(u32 port)
++{
++ return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
++}
++
++
++void mx21_update(struct reg_list *list)
++{
++ for (; list && list->name; list++) {
++ memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
++ list->values[0] = mx2_rb(list->reg);
++ }
++}
++
++#endif /* CONFIG_ARCH_MX2ADS */
++
++void max3353_update_all(void)
++{
++ max3353_update(max3353_reg_list);
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ max3353_update(max3353_spec_list);
++ break;
++ case max3301e:
++ max3353_update(max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ mx21_update(mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++}
++
++
++
++/*
++ * dohex
++ *
++ */
++static void dohexdigit (char *cp, unsigned char val)
++{
++ if (val < 0xa)
++ *cp = val + '0';
++ else if ((val >= 0x0a) && (val <= 0x0f))
++ *cp = val - 0x0a + 'a';
++}
++
++/*
++ * dohex
++ *
++ */
++static void dohexval (char *cp, unsigned char val)
++{
++ dohexdigit (cp++, val >> 4);
++ dohexdigit (cp++, val & 0xf);
++}
++
++int max3353_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
++{
++ int len = 0, i;
++ len += sprintf (buf + len, "%-20s %-34s [%03x]: ", name, reg->name, reg->reg);
++ len += sprintf (buf + len, fmt, reg->values[0]);
++ for (i = 1; i < MAX_HISTORY; i++)
++ if (reg->values[i - 1] == reg->values[i])
++ len += sprintf (buf + len, " ");
++ else
++ len += sprintf (buf + len, fmt, reg->values[i]);
++ len += sprintf (buf + len, "\n");
++ return len;
++}
++
++int max3353_dump_list(char * buf, char *name, struct reg_list *list)
++{
++ int len = 0;
++ for (; list && list->name; list++)
++ switch(list->size) {
++ case 1: len += max3353_dump(buf + len, name, " %02x", list); break;
++ case 2: len += max3353_dump(buf + len, name, " %04x", list); break;
++ case 4: len += max3353_dump(buf + len, name, " %08x", list); break;
++ }
++ return len;
++}
++
++int max3353_dump_all(char *buf)
++{
++ int len = 0;
++ len += max3353_dump_list(buf + len, "MAX3353 Standard", max3353_reg_list);
++ switch (max3353_private.transceiver_map->transceiver_type) {
++ case max3353:
++ len += max3353_dump_list(buf + len, "MAX3353 Extra", max3353_spec_list);
++ break;
++ case max3301e:
++ len += max3353_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
++ break;
++ default:
++ break;
++ }
++#ifdef CONFIG_ARCH_MX2ADS
++ len += max3353_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
++#endif /* CONFIG_ARCH_MX2ADS */
++ return len;
++}
++
++
++
++/*!
++ * max3353_device_proc_read - implement proc file system read.
++ *
++ * Standard proc file system read function.
++ *
++ * We let upper layers iterate for us, *pos will indicate which device to return
++ * statistics for.
++ */
++static ssize_t max3353_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int i;
++ u32 r;
++
++ int config_size;
++
++ // get a page, max 4095 bytes of data...
++ RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
++
++ len = 0;
++ index = (*pos)++;
++
++ switch(index) {
++ case 0:
++ len += sprintf ((char *) page + len, "MAX3353 Transceiver Registers\n");
++
++ max3353_update_all();
++ len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n",
++ max3353_private.vendor, max3353_private.product,
++ max3353_private.revision, max3353_private.transceiver_map->name
++ );
++
++ len += max3353_dump_all((char *) page + len);
++ len += sprintf ((char *) page + len, "\n");
++
++ break;
++
++ case 1:
++ break;
++
++ }
++
++ if (len > count) {
++ len = -EINVAL;
++ }
++ else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
++ len = -EFAULT;
++ }
++ else {
++ }
++ free_page (page);
++ return len;
++}
++
++static struct file_operations max3353_device_proc_operations_functions = {
++ read:max3353_device_proc_read_functions,
++};
++
++/* Module init ******************************************************************************* */
++
++static int max3353_procfs_init (void)
++{
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry ("max3353", 0, 0)) == NULL)
++ return -ENOMEM;
++
++ p->proc_fops = &max3353_device_proc_operations_functions;
++
++ max3353_update_all();
++
++ return 0;
++}
++static void max3353_procfs_exit (void)
++{
++ remove_proc_entry ("max3353", NULL);
++}
++#else
++static int max3353_procfs_init (void) { return 0;
++}
++static void max3353_procfs_exit (void) { }
++#endif
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e.c linux/drivers/otg/ocd/max3353e/max3353e.c
+--- linux/drivers/no-otg/ocd/max3353e/max3353e.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353e.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,657 @@
++/*
++ * otg/ocd/max3353/max3353.c -- USB Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e.c|20060831021117|08740
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/max3353e.c
++ * @brief MAX3353 OTG Transceiver Driver.
++ *
++ * This is the generic MAX3353 TCD core support.
++ *
++ * Notes:
++ *
++ * 1. The MAX3353 can control the speed and suspend directly, would it be
++ * appropriate to allow state machine to control this.
++ *
++ * 2. The MAX3353 has auto connect feature, can this be used without change
++ * to state machine.
++ *
++ * 3. The MAX3353 can control the ADR/PSW pin to enable / disable external
++ * charge pump.
++ *
++ * @ingroup MAX3353TCD
++ */
++
++#include <otg/otg-compat.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <linux/i2c.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-ocd.h>
++#include <otg/otg-pcd.h>
++
++#include <otghw/max3353e-hardware.h>
++#include "max3353e.h"
++
++
++struct otg_transceiver_map max3353_transceiver_map[] = {
++ { max3353, 0x4cc, 0x1301, 0x00, "Phillips MAX3353", },
++ { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
++ { 0, 0, 0, 0, "Unknown Transceiver", },
++};
++
++struct max3353_private max3353_private;
++
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
++
++
++/*! max3353_int_src - update interrupt source test mask
++ *
++ * This sets the current mask and updates the interrupt registers to match.
++ */
++void max3353_int_src(u8 int_src)
++{
++ TRACE_MSG1(TCD, "setting int_src %02x", int_src);
++ max3353_private.int_src = int_src;
++ i2c_writeb(MAX3353E_INTERRUPT_MASK, int_src);
++ i2c_writeb(MAX3353E_INTERRUPT_EDGE, 3); //detect on positive edge
++ i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0);
++}
++
++/*! max3353_int_src_set - add to the interrupt source mask
++ *
++ */
++void max3353_int_src_set(u8 int_src)
++{
++ max3353_int_src(int_src |= max3353_private.int_src);
++}
++
++/*! max3353_int_src_clr - remove from the interrup source mask
++ */
++void max3353_int_src_clr(u8 int_src)
++{
++ max3353_int_src(int_src = max3353_private.int_src & ~int_src);
++}
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++
++
++typedef struct max3353_test {
++ u32 input;
++ char *name;
++ u8 mask;
++} max3353_test_t;
++
++#define OV(i, m) {i, #i, m}
++#define MAX3353E_B_SESS_END 1<<4
++#define MAX3353E_B_SESS_VLD 1<<6
++#define MAX3353E_A_SESS_VLD 1<<5
++
++
++struct max3353_test max3353_int_src_tests[5] = {
++ OV(VBUS_VLD, MAX3353E_VBUS_VALID),
++ OV(ID_GND, MAX3353E_ID_GND),
++ OV(ID_FLOAT, MAX3353E_ID_FLOAT),
++ OV(BDIS_ACON, MAX3353E_A_HNP),
++ {0, NULL, 0},
++};
++
++struct max3353_test max3353_otg_status_tests[4] = {
++ OV(B_SESS_END, MAX3353E_B_SESS_END),
++ OV(B_SESS_VLD, MAX3353E_B_SESS_VLD),
++ OV(A_SESS_VLD, MAX3353E_A_SESS_VLD),
++ {0, NULL, 0},
++};
++
++u64 max3353_event(struct otg_instance *otg, struct max3353_test *tests, int val, char *msg)
++{
++ int i;
++ u64 inputs = 0;
++ TRACE_MSG2(TCD, "%02x %s", val, msg);
++ for (i = 0; tests[i].mask; i++) {
++ u64 input = tests[i].input;
++ u8 mask = tests[i].mask;
++ inputs |= (val & mask) ? input : _NOT(input);
++ TRACE_MSG5(TCD, "%d - %s%s %02x %08x", i, tests[i].name, (val & mask) ? "" : "/", tests[i].mask, tests[i].input);
++ }
++ return inputs;
++}
++
++/*! max3353_event_set_irq
++ */
++void max3353_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *mset, char *mreset)
++{
++ TRACE_MSG5(TCD, "changed: %x flag: %x input: %08x %s %s", changed, flag, input,
++ flag ? mset: mreset,
++ changed ? "": "(ignored)");
++
++ otg_event_set_irq(otg, changed, flag, input, tag, flag ? mset : mreset);
++}
++
++/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 Interrupt Source Register
++ */
++u8 max3353_update_int_src(struct otg_instance *otg, u8 int_src, u8 changed)
++{
++ UNLESS (changed) return int_src;
++ TRACE_MSG2(TCD, "CHANGED INTERRUPT_SOURCE: %02x (%02x) ", int_src, changed);
++
++ /* Core events
++ */
++ max3353_event_set_irq(otg, MAX3353E_ID_GND & changed, MAX3353E_ID_GND & int_src,
++ ID_GND, TCD, "ID_GND", "ID_GND/");
++ max3353_event_set_irq(otg, MAX3353E_ID_FLOAT & changed, MAX3353E_ID_FLOAT & int_src,
++ ID_FLOAT, TCD, "ID_FLOAT", "ID_FLOAT/");
++ max3353_event_set_irq(otg, MAX3353E_VBUS_VALID & changed, MAX3353E_VBUS_VALID & int_src,
++ VBUS_VLD, TCD, "VBUS_VLD", "VBUS_VLD/");
++ max3353_event_set_irq(otg, MAX3353E_SESSION_END & changed, MAX3353E_SESSION_END & int_src,
++ A_SESS_VLD, TCD, "A_SESS_VLD", "A_SESS_VLD/");
++
++
++ return int_src;
++}
++
++/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 OTG Status Register
++ */
++u8 max3353_update_otg_status(struct otg_instance *otg, u8 otg_status, u8 changed)
++{
++ UNLESS (changed) return otg_status;
++ TRACE_MSG2(TCD, "CHANGED OTG_STATUS_REG: %02x (%02x) ", otg_status, changed);
++
++ max3353_event_set_irq(otg, MAX3353E_SESSION_VALID_EN & changed, MAX3353E_SESSION_VALID_EN & otg_status,
++ B_SESS_VLD, TCD, "B_SESS_VLD", "B_SESS_VLD/");
++ max3353_event_set_irq(otg, MAX3353E_SESSION_END & changed, MAX3353E_SESSION_END & otg_status,
++ B_SESS_END, TCD, "B_SESS_END", "B_SESS_END/");
++
++ return otg_status;
++}
++
++
++int max3353_bh_first;
++
++/*! max3353_bh
++ */
++void max3353_bh(void *arg)
++{
++
++ u64 inputs = 0;
++ u8 int_lat,status_reg,otg_reg;
++ u8 reg1,reg2;
++
++ au_writel(0x40000000, IC1_MASKCLR); //disable interrupt
++ au_writel(0x40000000, IC1_FALLINGCLR);
++ au_writel(0x40000000, IC1_RISINGCLR);
++ TRACE_MSG0(TCD, "--MAX3353 ISR start");
++// printk(KERN_INFO"ISR Start .......\n");
++
++ /* read the interrupt latch and and clear latch and update otg
++ */
++ if ((int_lat = i2c_readb(MAX3353E_INTERRUPT_LATCH))) {
++ TRACE_MSG1(TCD, "INT LAT: %02x", int_lat);
++ i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0);
++ }
++
++ status_reg = i2c_readb(MAX3353E_STATUS_REGISTER);
++ inputs |= max3353_event(tcd_instance->otg, max3353_int_src_tests, status_reg, "MAX3353 STAT SRC");
++ TRACE_MSG1(TCD, "inputs after applying status register %02x\n", inputs);
++
++
++ otg_reg = 0;
++
++ if (status_reg & MAX3353E_SESSION_VALID_EN) { //1.4,,4.5
++ TRACE_MSG0(TCD, "Setting B_SESS_VLD");
++ otg_reg |= MAX3353E_B_SESS_VLD;
++ }
++ if (status_reg & MAX3353E_SESSION_END) {
++ TRACE_MSG0(TCD, "Setting B_SESS_END");
++ otg_reg |= MAX3353E_B_SESS_END;
++ }
++ if (!(status_reg & MAX3353E_SESSION_END)) { //0.8<<1.4
++ if (!(status_reg & MAX3353E_SESSION_VALID_EN)){
++ TRACE_MSG0(TCD, "Setting A_SESS_VLD");
++ otg_reg |= MAX3353E_A_SESS_VLD;
++ }
++ }
++
++
++
++ inputs |= max3353_event(tcd_instance->otg, max3353_otg_status_tests, otg_reg, "MAX3353 OTG SRC");
++ TRACE_MSG1(TCD, "inputs after applying otg register %02x\n", inputs);
++
++
++
++ TRACE_MSG0(TCD, "--MAX3353 ISR end");
++ if (inputs) otg_event(tcd_instance->otg, inputs, TCD, "MAX3353");
++ au_writel(0x40000000, IC1_MASKSET); //enable interrupt
++}
++
++
++
++/* ********************************************************************************************** */
++/*! max3353_vbus - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int max3353_vbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++/*! max3353_id - Do we have Vbus (cable attached?)
++ * Return non-zero if Vbus is detected.
++ *
++ */
++int max3353_idvbus (struct otg_instance *otg)
++{
++ return 0;
++}
++
++
++/* ********************************************************************************************* */
++
++/*! max3353_chrg_vbus - used to enable or disable B-device Vbus charging
++ */
++void max3353_chrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ u8 reg2;
++
++ TRACE_MSG0(TCD, "--");
++ reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
++ TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_SET");
++ reg2 |= MAX3353E_VBUS_CHG2;
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
++ reg2 &= (~MAX3353E_VBUS_CHG2);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case PULSE:
++ break;
++ }
++ TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
++}
++
++/*! max3353_drv_vbus - used to enable or disable A-device driving Vbus
++ */
++void max3353_drv_vbus(struct otg_instance *otg, u8 flag)
++{
++u8 reg2;
++
++ TRACE_MSG0(TCD, "--");
++ reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
++ TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "DRV_VBUS_SET");
++ reg2 |= MAX3353E_VBUS_DRV;
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "DRV_VBUS_RESET");
++ reg2 &= (~MAX3353E_VBUS_DRV);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case PULSE:
++ break;
++ }
++ TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
++}
++
++/*! max3353_dischrg_vbus - used to enable Vbus discharge
++ */
++void max3353_dischrg_vbus(struct otg_instance *otg, u8 flag)
++{
++ u8 reg2;
++
++ TRACE_MSG0(TCD, "--");
++ reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
++ TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "DISCHG_VBUS_SET");
++ reg2 |= MAX3353E_VBUS_DISCHG;
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "DISCHG_VBUS_RESET");
++ reg2 &= (~MAX3353E_VBUS_DISCHG);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
++ break;
++ case PULSE:
++ break;
++ }
++ TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
++}
++
++/*! max3353_dp_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
++ *
++ * host peripheral
++ * d+ pull-up clr set
++ * d+ pull-down set clr
++ *
++ * d- pull-up clr clr
++ * d- pull-down set set
++ *
++ */
++void max3353_dp_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "-- ");
++ switch (flag) {
++ case SET:
++ printk(KERN_INFO"%s: --\n", __FUNCTION__);
++ max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG0(TCD, "Clr DP PULLDOWN");
++ max3353_private.flags &= (~MAX3353E_DP_PULLDOWN);
++ TRACE_MSG0(TCD, "Set DP PULLUP");
++ max3353_private.flags |= (MAX3353E_DP_PULLUP);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ break;
++
++ case RESET:
++ max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG0(TCD, "Clr DP PULLUP");
++ max3353_private.flags &= (~MAX3353E_DP_PULLUP);
++ TRACE_MSG0(TCD, "Set DP PULLDOWN");
++ max3353_private.flags |= (MAX3353E_DP_PULLDOWN);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ break;
++
++ case PULSE:
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
++ break;
++ }
++ int temp = 0;
++ temp = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG1(TCD, "Control Register 1: %02x", temp);
++
++}
++
++/*! max3353_dm_pullup_func - used to enable or disable peripheral connecting to bus
++ *
++ */
++void max3353_dm_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG0(TCD, "Clr DM PULLDOWN");
++ max3353_private.flags &= (~MAX3353E_DM_PULLDOWN);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ TRACE_MSG0(TCD, "Set DM PULLUP");
++ max3353_private.flags |= (MAX3353E_DM_PULLUP);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ break;
++
++ case RESET:
++ max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG0(TCD, "Clr DM PULLUP");
++ max3353_private.flags &= (~MAX3353E_DM_PULLUP);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ TRACE_MSG0(TCD, "Set DM PULLDOWN");
++ max3353_private.flags |= (MAX3353E_DM_PULLDOWN);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ break;
++
++ case PULSE:
++ TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
++ break;
++ }
++ int temp = 0;
++ temp = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG1(TCD, "Control Register 1 %02x", temp);
++}
++
++/*! max3353_dm_det_func - used to enable or disable D- detect
++ *
++ */
++void max3353_dm_det_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_dp_det_func - used to enable or disable D+ detect
++ *
++ */
++void max3353_dp_det_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_bdis_acon_func - used to enable or disable auto a-connect
++ *
++ */
++void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_id_pulldown_func - used to enable or disable ID pulldown
++ *
++ */
++void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_audio_func - used to enable or disable Carkit Interrupt
++ *
++ */
++void max3353_audio_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_uart_func - used to enable or disable transparent uart mode
++ *
++ */
++void max3353_uart_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++/*! max3353_mono_func - used to enable or disable mono audio connection
++ *
++ */
++void max3353_mono_func(struct otg_instance *otg, u8 flag)
++{
++ return;
++}
++
++
++/* ********************************************************************************************* */
++extern int max3353_procfs_init (void);
++extern void max3353_procfs_exit (void);
++
++/*! max3353_mod_init
++ */
++int max3353_mod_init(void)
++{
++ int ret;
++
++ TRACE_MSG0(TCD, "Initilize");
++ /* for interrupt bottom half handler
++ */
++ PREPARE_WORK_ITEM(max3353_private.bh, &max3353_bh, NULL);
++
++ /* setup max3353, enable interrupts, clear latch
++ * XXX when and how do we do DM_HI and DP_HI, when ID is present?
++ */
++ max3353_int_src_set(0x1f);
++ //max3353_int_src(MAX3353_NO_SE1_INT);
++ /*Turn on the max3353 and discharge the bus*/
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, 0x0);
++ int status = i2c_readb(MAX3353E_STATUS_REGISTER);
++ if ((status & 0x1) == 0){
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x10);
++ }
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN);
++
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++ TRACE_MSG0(TCD, "MAX3353 Procfs");
++ max3353_procfs_init ();
++#endif /* CONFIG_OTG_MAX3353_PROCFS */
++
++ au_sync();
++
++ // au_writel(0x1, IC1_TESTBIT); //disable test bit for low leve interrupt
++ //All this done when define type of interrupt in irqmap.c
++ /*au_writel(0x40000000, IC1_CFG0CLR); //low level activation
++ au_writel(0x40000000, IC1_CFG1SET);
++ au_writel(0x40000000, IC1_CFG2CLR);
++ au_writel(0x40000000, IC1_MASKSET);//enable interrupt
++ */
++ //au_writel(0x40000000, IC1_SRCCLR);//set test bit as a source
++ au_writel(0x40000000, IC1_SRCSET);//set source to original
++ //au_writel(0x0, IC1_TESTBIT);
++ //au_writel(0x1, IC1_TESTBIT);
++
++#if 0
++ ret = au_readl(IC0_CFG0RD);
++ printk (KERN_INFO"IC0 Reg 0 : %08x\n", ret);
++ ret = au_readl(IC0_CFG1RD);
++ printk (KERN_INFO"IC0 Reg 1 : %08x\n", ret);
++ ret = au_readl(IC0_CFG2RD);
++ printk (KERN_INFO"IC0 Reg 2 : %08x\n", ret);
++ ret = au_readl(IC0_SRCRD);
++ printk (KERN_INFO"IC0 Source : %08x\n", ret);
++ ret = au_readl(IC0_ASSIGNRD);
++ printk (KERN_INFO"IC0 Assign : %08x\n", ret);
++ ret = au_readl(IC0_WAKERD);
++ printk (KERN_INFO"IC0 Wakeup : %08x\n", ret);
++ ret = au_readl(IC0_MASKRD);
++ printk (KERN_INFO"IC0 Mask : %08x\n", ret);
++
++ ret = au_readl(IC1_CFG0RD);
++ printk (KERN_INFO"IC1 Reg 0 : %08x\n", ret);
++ ret = au_readl(IC1_CFG1RD);
++ printk (KERN_INFO"IC1 Reg 1 : %08x\n", ret);
++ ret = au_readl(IC1_CFG2RD);
++ printk (KERN_INFO"IC1 Reg 2 : %08x\n", ret);
++ ret = au_readl(IC1_SRCRD);
++ printk (KERN_INFO"IC1 Source : %08x\n", ret);
++ ret = au_readl(IC1_ASSIGNRD);
++ printk (KERN_INFO"IC1 Assign : %08x\n", ret);
++ ret = au_readl(IC1_WAKERD);
++ printk (KERN_INFO"IC1 Wakeup : %08x\n", ret);
++ ret = au_readl(IC1_MASKRD);
++ printk (KERN_INFO"IC1 Mask : %08x\n", ret);
++
++#endif
++
++ return 0;
++}
++
++/*! max3353_mod_exit
++ */
++void max3353_mod_exit(void)
++{
++ i2c_writeb(MAX3353E_INTERRUPT_MASK, 0x0);
++ //i2c_close();
++#ifdef CONFIG_OTG_MAX3353_PROCFS
++ max3353_procfs_exit ();
++#endif /* CONFIG_OTG_MAX3353_PROCFS */
++
++ while (PENDING_WORK_ITEM(max3353_private.bh)) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++
++}
++
++/* ********************************************************************************************* */
++/*! max3353_configure - configure the MAX3353 for this host
++ * @param tx_mode - the type of connection between the host USB and the MAX3353
++ * @param spd_ctrl - suspend control method
++ */
++void max3353_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
++{
++ u16 vendor = 0, product = 0, revision = 0;
++ u8 mode1, mode2, control;
++
++ struct otg_transceiver_map *map = max3353_transceiver_map;
++ TRACE_MSG0(TCD, "Configure");
++
++ //#if defined(CONFIG_OTG_MAX3353_MX2ADS) || defined(CONFIG_OTG_MAX3353_MX2ADS_MODULE)
++ u32 vp;
++ u8 vb=0;
++ TRACE_MSG0(TCD, "1. Read Transceiver ID's with long read");
++ vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_0);
++ max3353_private.vendor = vb;
++ vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_1);
++ max3353_private.vendor += vb<<8;
++ vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_2);
++ max3353_private.vendor += vb<<16;
++ vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_3);
++ max3353_private.vendor += vb<<24;
++
++ vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_0);
++ max3353_private.product = vb;
++ vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_1);
++ max3353_private.product += vb<<8;
++ vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_2);
++ max3353_private.product += vb<<16;
++ vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_3);
++ max3353_private.product += vb<<24;
++
++ mode1 = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ mode2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
++
++ TRACE_MSG4(TCD, "2. OTG Transceiver: vendor: %08x product: %08x mode1: %02x mode2: %02x",
++ max3353_private.vendor, max3353_private.product, mode1, mode2);
++
++ TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, 0x0); // clear
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0); // clear
++
++ TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
++
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN);
++ max3353_private.flags = MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN;
++
++ TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
++ i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0x0);
++ max3353_int_src_set(0x1f);
++
++
++
++}
++
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e.h linux/drivers/otg/ocd/max3353e/max3353e.h
+--- linux/drivers/no-otg/ocd/max3353e/max3353e.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/max3353e.h 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,134 @@
++/*
++ * otg/ocd/max3353/max3353.h -- USB Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e.h|20060831021118|62926
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup MAX3353TCD TCD - Maxim MAX3353
++ * @ingroup platformgroup
++ */
++/*!
++ * @file otg/ocd/max3353e/max3353e.h
++ * @brief Private structures and defines for MAX3353 Transciever Controller Driver.
++ *
++ * This file contains the private defines and structures for the MAX3353 Transceiver
++ * Driver.
++ *
++ * @ingroup MAX3353TCD
++ */
++
++
++#ifdef CONFIG_XXXXX
++#define MAX3353_GPIO (2)
++#define TCD_MAX3353_I2C_ADDR MAX3353_I2C_ADDR_HIGH;
++#endif
++
++#define MAX3353_NAME "max3353"
++
++#define MAX3353_LOC_CONN 0x01
++
++#define MAX3353_INT_SRC 0xeb
++
++//#define MAX3353_ALL_INT_SRC 0xff
++//#define MAX3353_NO_SE1_INT 0xeb
++//#define MAX3353_NO_SE1_INT 0xfb /* do not pay attention to DP_HI */
++
++typedef enum otg_transceiver {
++ unknown_transceiver,
++ max3353,
++ max3301e
++} otg_transceiver_t;
++
++struct otg_transceiver_map {
++ otg_transceiver_t transceiver_type;
++ u16 vendor;
++ u16 product;
++ u16 revision;
++ char *name;
++};
++
++struct max3353_private {
++ WORK_STRUCT bh;
++ u16 vendor;
++ u16 product;
++ u16 revision;
++ u32 flags;
++ u8 int_src;
++ struct otg_transceiver_map *transceiver_map;
++};
++
++/*! tx_mode
++ * This defines the various ways that the MAX3353 can be
++ * wired into the host USB.
++ */
++typedef enum tx_mode {
++ dat_se0_bidirectional, /*!< 3-Wire */
++ vp_vm_bidirectional, /*!< 4-Wire */
++ dat_se0_unidirectional /*!< 6-Wire */
++} tx_mode_t;
++
++/*! spd_ctrl
++ * This defines how the speed and suspend pins are controlled
++ * for this host.
++ */
++typedef enum spd_ctrl {
++ spd_susp_pins, /*!< controlled by SPEED and SUSPEND pins */
++ spd_susp_reg, /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
++} spd_ctrl_t;
++
++
++extern struct tcd_ops tcd_ops;
++extern struct max3353_private max3353_private;
++extern struct tcd_instance *tcd_instance;
++
++/* max3353.c */
++extern int max3353_mod_init(void);
++extern void max3353_mod_exit(void);
++extern void max3353_chrg_vbus(struct otg_instance *, u8 );
++extern void max3353_drv_vbus(struct otg_instance *, u8 );
++extern void max3353_dischrg_vbus(struct otg_instance *, u8 );
++extern void max3353_dp_pullup_func(struct otg_instance *, u8 );
++extern void max3353_dm_pullup_func(struct otg_instance *, u8 );
++extern void max3353_dm_det_func(struct otg_instance *, u8 );
++extern void max3353_dp_det_func(struct otg_instance *, u8 );
++extern void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag);
++extern void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag);
++extern void max3353_audio_func(struct otg_instance *otg, u8 flag);
++extern void max3353_uart_func(struct otg_instance *otg, u8 flag);
++extern void max3353_mono_func(struct otg_instance *otg, u8 flag);
++
++extern void max3353_otg_timer(struct otg_instance *, u8 );
++extern void max3353_bh(void *);
++extern int max3353_id (struct otg_instance *);
++extern int max3353_vbus (struct otg_instance *);
++extern void max3353_configure(tx_mode_t, spd_ctrl_t );
++
++/* thread */
++extern int max3353_thread_init (void (bh_proc)(void *));
++extern void max3353_thread_exit (wait_queue_head_t *);
++extern void max3353_thread_wakeup(int enabled, int first);
++
++
++
++/* i2c-xxx.c */
++int i2c_configure(char *name, int addr);
++extern void i2c_close(void);
++extern u8 i2c_readb(u8 );
++extern u16 i2c_readw(u8 );
++extern u32 i2c_readl(u8 );
++extern int i2c_writeb(u8 , u8 );
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/tcd-db1550.c linux/drivers/otg/ocd/max3353e/tcd-db1550.c
+--- linux/drivers/no-otg/ocd/max3353e/tcd-db1550.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/tcd-db1550.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,227 @@
++/*
++ * otg/ocd/max3353e/tcd-db1550.c -- USB Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/tcd-db1550.c|20060831021118|37213
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/tcd-db1550.c
++ * @brief DB1550 MAX3353 driver.
++ *
++ *
++ * @ingroup MAX3353TCD
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <otghw/max3353e-hardware.h>
++#include "otghw/bvd-hardware.h"
++#include "max3353e.h"
++#include <asm/au1000.h>
++#include <linux/i2c.h>
++#include <linux/i2c-dev.h>
++
++struct ocd_instance *ocd_instance;
++otg_tag_t OCD;
++
++#if 0
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/hcd.h>
++#include <otg/tcd.h>
++#include <otg/ocd.h>
++#include <otg/pcd.h>
++
++#include <otghw/isp1301-hardware.h>
++#include "isp1301.h"
++
++#endif
++/*SP
++#include <asm/arch/gpio.h>
++#include <asm/arch/mux.h>
++*/
++//struct isp1301_private isp1301_private;
++
++#ifdef CONFIG_OMAP_H2
++#define ADAPTOR_NAME "OMAP I2C"
++#endif /* CONFIG_OMAP_H2 */
++#ifdef CONFIG_ARCH_MAINSTONE
++#define ADAPTOR_NAME "PXA-I2C-Adapter"
++#endif /* CONFIG_ARCH_MAINSTONE */
++#ifdef CONFIG_OTG_DB1550_J15
++#define ADAPTOR_NAME "pb1550 adapter"
++#endif /* CONFIG_OTG_DB1550_J15 */
++
++/* ********************************************************************************************* */
++
++
++static irqreturn_t max3353_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ TRACE_MSG0(TCD, "--");
++
++ SCHEDULE_WORK(max3353_private.bh);
++
++ return IRQ_HANDLED;
++}
++
++
++/* ********************************************************************************************* */
++
++struct ocd_ops ocd_ops;
++struct tcd_instance *db1550_tcd_instance;
++
++//#define ADAPTOR_NAME "pb1550 adapter"
++
++/*! tcd_mod_init
++ */
++int tcd_mod_init(void)
++{
++
++ struct otg_instance *otg;
++
++ int i2c = i2c_configure(ADAPTOR_NAME, MAX3353E_I2C_ADDR_HIGH);
++ int irq = request_irq (AU1500_GPIO_207, max3353_int_hndlr, SA_INTERRUPT, "MAX3353", NULL);
++ THROW_IF(irq, error);
++
++ TRACE_MSG0(TCD, "--");
++
++ THROW_IF(i2c, error);
++
++ TRACE_MSG0(TCD, "1. Enable db1550 external OTG Transceiver!");
++
++
++ TRACE_MSG0(TCD, "2. configure i2c driver!");
++ max3353_configure(dat_se0_bidirectional, spd_susp_reg);
++
++ TRACE_MSG0(TCD, "3. configure max3353!");
++ max3353_mod_init();
++
++ TRACE_MSG0(TCD, "4. set ops");
++ THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
++ THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
++ THROW_UNLESS(db1550_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
++
++#if 0 //test for making pulse on DP
++ for (;;){
++ max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
++ TRACE_MSG0(TCD, "Clr DP PULLDOWN");
++ max3353_private.flags &= (~MAX3353E_DP_PULLDOWN);
++ TRACE_MSG0(TCD, "Set DP PULLUP");
++ max3353_private.flags |= (MAX3353E_DP_PULLUP);
++ i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
++ }
++#endif
++
++
++ /* Success!
++ */
++
++ TRACE_MSG0(TCD, "5. Success!");
++
++ otg_init(otg);
++
++ //In device mode only this part makes a virtual interrupt, while the cable is
++ //and modules are loaded.
++ au_writel (0x40000000, IC1_SRCCLR);
++ au_writel (0x0, IC1_TESTBIT);
++ au_writel (0x1, IC1_TESTBIT);
++ au_writel (0x0, IC1_TESTBIT);
++ au_writel (0x40000000, IC1_SRCSET);
++
++
++ /* error handling
++ */
++ CATCH(error) {
++ printk(KERN_INFO"Error in tcd initilization\n");
++ if (irq) free_irq(AU1500_GPIO_207, NULL);
++ if (i2c) i2c_close();
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*! tcd_mod_exit
++ */
++void tcd_mod_exit(void)
++{
++ struct otg_instance *otg = tcd_instance->otg;
++ TRACE_MSG0(TCD, "Exit.");
++
++ otg_event(otg, enable_otg_, OCD, "enable_otg_");
++ //if (otg)
++ // otg_exit(otg);
++
++ db1550_tcd_instance = otg_set_tcd_ops(NULL);
++ free_irq(AU1500_GPIO_207, NULL);
++ max3353_mod_exit();
++
++ i2c_writeb(MAX3353E_INTERRUPT_MASK, 0xff);
++ i2c_close();
++
++ if (otg)
++ otg_exit(otg);
++}
++/* ********************************************************************************************* */
++struct tcd_ops tcd_ops = {
++
++// vbus: max3353_vbus,
++
++ mod_init: tcd_mod_init,
++ mod_exit: tcd_mod_exit,
++
++ dischrg_vbus_func: max3353_dischrg_vbus,
++ chrg_vbus_func: max3353_chrg_vbus,
++ drv_vbus_func: max3353_drv_vbus,
++ dp_pullup_func: max3353_dp_pullup_func,
++ dm_pullup_func: max3353_dm_pullup_func,
++
++};
++
++#if 0
++
++struct tcd_ops tcd_ops;
++
++
++void db1550_tcd_global_init(void)
++{
++ ZERO(tcd_ops);
++
++ tcd_ops.id = max3353_id;
++ tcd_ops.vbus = max3353_vbus;
++ tcd_ops.chrg_vbus_func = max3353_chrg_vbus;
++ tcd_ops.dischrg_vbus_func = max3353_dischrg_vbus;
++ tcd_ops.dp_pullup_func = max3353_dp_pullup_func;
++ tcd_ops.dm_pullup_func = max3353_dm_pullup_func;
++ tcd_ops.dp_pulldown_func = max3353_dp_pulldown_func;
++ tcd_ops.dm_pulldown_func = max3353_dm_pulldown_func;
++ tcd_ops.overcurrent_func = NULL;
++ tcd_ops.dm_det_func = max3353_dm_det_func;
++ tcd_ops.dp_det_func = max3353_dp_det_func;
++ tcd_ops.cr_det_func = max3353_cr_det_func;
++
++ tcd_ops.peripheral_host_func = max3353_peripheral_host_func;
++
++ tcd_ops.id_pulldown_func = max3353_id_pulldown_func;
++ tcd_ops.audio_func = max3353_audio_func;
++ tcd_ops.uart_func = max3353_uart_func;
++ tcd_ops.mono_func = max3353_mono_func;
++
++ tcd_ops.mod_init = tcd_mod_init;
++ tcd_ops.mod_exit = tcd_mod_exit;
++}
++
++
++#endif
++
++
++
++
+diff -uNr linux/drivers/no-otg/ocd/max3353e/tcd-mx2ads.c linux/drivers/otg/ocd/max3353e/tcd-mx2ads.c
+--- linux/drivers/no-otg/ocd/max3353e/tcd-mx2ads.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/max3353e/tcd-mx2ads.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,541 @@
++/*
++ * otg/ocd/max3353e/tcd-mx2ads.c -- MX21ADS ISP1301 Transceiver Controller driver
++ * @(#) balden@belcarra.com|otg/ocd/max3353e/tcd-mx2ads.c|20060831021118|46922
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Shahrad Payandeh <sp@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/max3353e/tcd-mx2ads.c
++
++ * @brief MX2ADS ISP1301 driver.
++ *
++ * This implements the ISP1301 Transceiver Controller Driver for the mx21
++ * using the USBOTG I2C controller for access.
++ *
++ * Notes
++ *
++ * 1. There are two interrupt sources, the I2C IO completion type generated when either of NOACK
++ * or RWREADY is set and the XCVR activity type generated when there is a OTG transceiver
++ * generated interrupt.
++ *
++ * It is important to only enable a single source at a time. By default we leave the XCVR
++ * interrupt enabled for normal operation and only enable the I2C IO type when we are actively
++ * waiting for an I2C IO operation to complete.
++ *
++ * 2. The USBOTG module can also interact with the OTG Transceiver, attempting to do register
++ * reads for various conditions (such as XCVR interrupts.) These interfere and cause problems so
++ * we keep the the I2C Controller interface in software mode at all times.
++ *
++ * 3. Because we must wait several hundred micro-seconds for I/O operations to complete, the i2c
++ * implementation is only usable from non-interrupt contexts. This means that all work that
++ * needs to be done needs to be pushed to a bottom half handler. A generic i2cWrite_irq() is
++ * provided where simple writes are all that are required.
++ *
++ * 4. The handling of the ISC_INTERRUPT_AND_CTRL register is complicated because the top nibble
++ * is r/w controlling the interrupt source enables while the bottom nibble is write 1 to clear
++ * to reset two of the three interrupt source bits (NOACK and RWREADY).
++ *
++ *
++ * TODO
++ *
++ * 1. The MX2ADS seems to have a hardware problem, when operating as a B-Device, Vbus does not
++ * drop to zero when disconnected (unplugged.) A 22kohm resister across C133 is suggested.
++ * Alternately I am just enabling VBUS_DISCHRG in LOC_CONN when we enable DP_PULLUP. Hopefully
++ * this will not be required in production code.
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <asm/arch/mx2.h>
++#include <otghw/isp1301-hardware.h>
++#include "mx2.h"
++#include <otghw/mx2-hardware.h>
++#include "isp1301.h"
++//#include <otg/otg-ops.h>
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++/*! mx2_urb
++ */
++u8 mx2_urbv(u32 port)
++{
++ u8 val = mx2_rb(port);
++ TRACE_MSG2(TCD, "PORT: %08x %02x", port, val);
++ return val;
++}
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/* I2C Bottom Half I/O
++ *
++ * These are the I2C I/O routines that can be used from any non-interrupt
++ * context, typically from a bottom half handler.
++ *
++ * There is an interrupt safe, delayed i2cWrite function, it queues the
++ * writes and schedules work via a bottom half handler that can safely call
++ * the i2cWrite function.
++ */
++#define MX2_I2C_TIMEOUT 1
++#define I2C_READ_MASK 0x80
++#define I2C_MAX_WRITE 100
++
++DECLARE_MUTEX(i2c_sem); // semaphore to prevent overlapped i2c i/o
++wait_queue_head_t mx2_i2c_wait; // wait structure for i2c i/o interrupt
++struct WORK_STRUCT mx2_i2c_io_work_struct; // work structure for queued i2c writes
++
++int i2c_Write_Queued;
++u8 i2c_Write_Data[I2C_MAX_WRITE];
++u32 i2c_Write_Addr[I2C_MAX_WRITE];
++char * i2c_Write_Msg[I2C_MAX_WRITE];
++
++/*! i2c_read - read from otg transceiver
++ * This programs the I2C controller to do a read, waits for the completion
++ * interrupt, cleans up and returns the value for the specified register.
++ */
++void i2c_read(u32 port, int ops)
++{
++ u8 i2c_interrupt_and_ctrl;
++ u8 ctrl_reg;
++ int count;
++ RETURN_IF(i2c_Write_Queued < 0);
++ down(&i2c_sem); // pass through semaphore
++#if 1
++ if ((ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x4) {
++ TRACE_MSG1(TCD, "bad ctrl_reg: %02x", ctrl_reg);
++ }
++ for (count = 0; (count < 100) && (ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x80; count++) {
++ TRACE_MSG1(TCD, "busy ctrl_reg: %02x", ctrl_reg);
++ }
++#endif
++ mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, 0x6); // reset and disable interrupts
++ mx2_wb(MX2_SEQ_OP_REG, ops); // set number of sequential operations to 1
++ mx2_wb(MX2_SEQ_RD_STARTAD, port); // sequential read start address
++ mx2_wb(MX2_OTG_XCVR_DEVAD, I2C_READ_MASK | MX2_I2C_DEV_ADDR); // receiver address
++ mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_NOACK_EN | I2C_RWREADY_EN); // enable i2x I/O interrupt
++ interruptible_sleep_on_timeout(&mx2_i2c_wait, MX2_I2C_TIMEOUT); // wait for signal from i2c io interrupt handler
++ up(&i2c_sem);
++}
++
++/*! i2c_readb - read a byte from otg transceiver
++ * This programs the I2C controller to do a single byte read, waits for the
++ * completion interrupt, cleans up and returns the value for the specified
++ * register.
++ */
++u8 i2c_readb(u8 port)
++{
++ u8 data;
++ u32 addr = OTG_I2C_BASE + port;
++ i2c_read(addr, 1);
++ data = mx2_rb(addr); // read the register
++ //TRACE_MSG2(TCD, "port: %08x data: %02x", port, data);
++ return data;
++}
++
++/*! i2c_readw - read two bytes from otg transceiver
++ * This programs the I2C controller to do a two byte read, waits for the
++ * completion interrupt, cleans up and returns the value for the specified
++ * registers.
++ */
++u16 i2c_readw(u8 port)
++{
++ u16 data;
++ u32 addr = OTG_I2C_BASE + port;
++ i2c_read(addr, 2);
++ data = mx2_rb(addr) | (mx2_rb(addr + 1) << 8); // read the register
++ //TRACE_MSG2(TCD, "port: %08x data: %04x", port, data);
++ return data;
++}
++
++/*! i2c_readl - read two bytes from otg transceiver
++ * This programs the I2C controller to do a two byte read, waits for the
++ * completion interrupt, cleans up and returns the value for the specified
++ * registers.
++ */
++u32 i2c_readl(u8 port)
++{
++ u32 data;
++ u32 addr = OTG_I2C_BASE + port;
++ i2c_read(addr, 2);
++ data = mx2_rb(addr) | (mx2_rb(addr + 1) << 8) | (mx2_rb(addr + 2) << 16) | (mx2_rb(addr + 3) << 24);
++ //TRACE_MSG2(TCD, "port: %08x data: %04x", port, data);
++ return data;
++}
++
++/*! i2cWrite - write a byte to otg transceiver
++ * This writes the data to the shadow register, programs the I2C controller
++ * to do a single byte write, waits for the completion interrupt, cleans up
++ * and exits.
++ */
++void i2cWrite(u32 port, u8 data, char *msg)
++{
++ u8 i2c_interrupt_and_ctrl;
++ u8 test;
++ u8 ctrl_reg;
++ int count;
++ //TRACE_FMSG3(TCD, msg, "i2cWrite: port: %s (%08x) data: %02x", mx2_ureg_name(port), port, data);
++ TRACE_FMSG2(TCD, msg, "i2cWrite: (%08x) data: %02x", port, data);
++
++ //test = i2c_readb(port & 0xfffffffe);
++ //TRACE_MSG2(TCD, "i2cWrite: %02x before %02x", port, test);
++
++ down(&i2c_sem); // pass through semaphore
++
++#if 1
++ if ((ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x4) {
++ TRACE_MSG1(TCD, "bad ctrl_reg: %02x", ctrl_reg);
++ }
++ for (count = 0; (count < 10) && (ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x80; count++) {
++ TRACE_MSG1(TCD, "busy ctrl_reg: %02x", ctrl_reg);
++ }
++#endif
++ mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, 0x6); // reset and disable interrupts
++ mx2_wb(port, data); // write the register
++ mx2_wb(MX2_SEQ_OP_REG, 1); // set number of sequential operations to 1
++ mx2_wb(MX2_SEQ_RD_STARTAD, port); // sequential read start address
++ mx2_wb(MX2_OTG_XCVR_DEVAD, MX2_I2C_DEV_ADDR); // receiver address
++ mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_NOACK_EN | I2C_RWREADY_EN); // enable i2x I/O interrupt
++ interruptible_sleep_on_timeout(&mx2_i2c_wait, MX2_I2C_TIMEOUT); // wait for signal from i2c io interrupt handler
++ up(&i2c_sem);
++
++ //test = i2c_readb(port & 0xfffffffe);
++ //TRACE_MSG2(TCD, "i2cWrite: %02x after %02x", port, test);
++}
++
++/*! mx2_i2c_io_bh - bottom half handler to use i2cWrite on queued data
++ */
++void mx2_i2c_io_bh(void *arg)
++{
++ while (i2c_Write_Queued > 0) {
++ u8 write = i2c_Write_Data[0];
++ u32 port = i2c_Write_Addr[0];
++ char *msg = i2c_Write_Msg[0];
++ u8 data;
++ unsigned long flags; // atomic update of counter and saved values
++ local_irq_save (flags);
++ i2c_Write_Queued--;
++ memcpy(i2c_Write_Data, i2c_Write_Data + 1, sizeof(i2c_Write_Data) - 1);
++ memcpy(i2c_Write_Addr, i2c_Write_Addr + 1, sizeof(i2c_Write_Addr) - 4);
++ memcpy(i2c_Write_Msg, i2c_Write_Msg + 1, sizeof(i2c_Write_Msg) - 4);
++ local_irq_restore (flags);
++ i2cWrite(port, write, msg); // perform write
++ }
++}
++
++/*! i2cWrite_irq - queue data for i2cWrite bottom half handler
++ */
++void i2cWrite_irq(u32 port, u8 data, char *msg)
++{
++ RETURN_IF(i2c_Write_Queued < 0);
++ if ((i2c_Write_Queued == I2C_MAX_WRITE)) {
++ TRACE_MSG3(TCD, "TOO MANY QUEUED CANNOT WRITE port: %08x data: %02x active: %d", port, data, i2c_Write_Queued);
++ return;
++ }
++ i2c_Write_Addr[i2c_Write_Queued] = port;
++ i2c_Write_Data[i2c_Write_Queued] = data;
++ i2c_Write_Msg[i2c_Write_Queued] = msg;
++ i2c_Write_Queued++;
++ TRACE_FMSG3(TCD, msg, "i2cWrite_irq: port: %08x data: %02x active: %d", port, data, i2c_Write_Queued);
++ SCHEDULE_WORK(mx2_i2c_io_work_struct);
++}
++
++/*! i2c_writeb
++ */
++int i2c_writeb(u8 subaddr, u8 buf)
++{
++ i2cWrite_irq(OTG_I2C_BASE + subaddr, buf, "i2c_writeb");
++ return 0;
++}
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*! mx2ads_bh
++ */
++void mx2ads_bh(void *arg)
++{
++ isp1301_bh(NULL);
++ //mx2_bh(NULL);
++
++ /* re-enable the OTG XCVRINT
++ */
++ mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_OTGXCVRINT_EN);
++}
++
++
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/* I2C I/O and XCVR Interrupt Handler
++ */
++
++/*! mx2_i2c_int_hndlr
++ * This is called from the main mx21ads interrupt handler to handle the
++ * i2c i/o interrupt. There are two main interrupt sources:
++ *
++ */
++irqreturn_t mx2_i2c_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ //TRACE_MSG0(TCD, "MX2ADS I2C INTERRUPT: WAKEUP");
++ wake_up_interruptible(&mx2_i2c_wait); // wakeup waiting bottom half handler
++ return IRQ_HANDLED;
++}
++
++/*! mx2_tcd_int_hndlr
++ * This is called from the main mx21ads interrupt handler to handle the
++ * i2c i/o interrupt. There are two main interrupt sources:
++ */
++irqreturn_t mx2_tcd_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
++{
++ //TRACE_MSG0(TCD, "MX2ADS TCD INTERRUPT: SCHEDULE WORK");
++ isp1301_thread_wakeup(1, 0); // wakeup kernel thread
++ return IRQ_HANDLED;
++}
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++/*! mx2_tcd_init - used to initialize/enable or disable the tcd driver
++ */
++void mx2_tcd_init(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "MX2_TCD_EN SET");
++ otg_event(otg, TCD_OK | ID_FLOAT, TCD, "TCD_OK");
++ //mx2_i2c_xcvr_schedule(1);
++ isp1301_thread_wakeup(1, 1);
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "MX2_TCD_EN RESET");
++ isp1301_thread_wakeup(0, 0);
++ otg_event(otg, TCD_OK, TCD, "TCD_OK");
++ break;
++ }
++}
++
++/*! mx2_dp_pullup_func - used to enable or disable peripheral connecting to bus
++ */
++void mx2_dp_pullup_func(struct otg_instance *otg, u8 flag)
++{
++ struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "MX2_LOC_CONN SET");
++
++ TRACE_MSG0(TCD, "MX2_LOC_CONN SET - enable function interrupts");
++ mx2_wl(OTG_FUNC_SINT_STEN, /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
++ SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN);
++
++ TRACE_MSG0(TCD, "MX2_LOC_CONN SET - Set VBUS_DISCHRG");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, (u8) ISP1301_VBUS_DISCHRG);
++ break;
++ }
++
++ /* call generic dp pullup function
++ */
++ isp1301_dp_pullup_func(otg, flag);
++
++ switch (flag) {
++ case RESET:
++ TRACE_MSG0(TCD, "MX2_LOC_CONN SET - Clr VBUS_DISCHRG");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_VBUS_DISCHRG);
++ break;
++ }
++
++}
++
++/*! mx2_drv_vbus - used to enable or disable A-device driving Vbus
++ */
++void mx2_drv_vbus(struct otg_instance *otg, u8 flag)
++{
++ TRACE_MSG0(TCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(TCD, "DRV_VBUS_SET");
++ i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_VBUS_DRV);
++ break;
++ }
++
++ /* call generic drv vbus function
++ */
++ isp1301_drv_vbus(otg, flag);
++
++ switch (flag) {
++ case RESET:
++ TRACE_MSG0(TCD, "DRV_VBUS_RESET");
++ i2c_writeb(ISP1301_OTG_CONTROL_SET, (u8) ISP1301_VBUS_DRV);
++ break;
++ }
++}
++
++
++
++/*! mx2_id - return true if id is present
++ */
++int mx2_id(struct otg_instance *otg)
++{
++ /* this will force the bottom half handler to read the interrupt
++ * source register and generate an otg event
++ */
++ TRACE_MSG0(TCD, "ID: 0");
++ //mx2_i2c_xcvr_schedule(1);
++ isp1301_thread_wakeup(1, 1);
++ return 0;
++}
++
++/*! mx2_vbus - return true if Vbus is present
++ */
++int mx2_vbus(struct otg_instance *otg)
++{
++ /* this will force the bottom half handler to read the interrupt
++ * source register and generate an otg event
++ */
++ TRACE_MSG0(TCD, "VBUS: 0");
++ //mx2_i2c_xcvr_schedule(1);
++ isp1301_thread_wakeup(1, 1);
++ return 0;
++}
++
++/* ********************************************************************************************* */
++struct tcd_ops *otg_tcd_ops;
++struct tcd_instance *mx2ads_tcd_instance;
++
++/*! mx2_tcd_mod_init - initial tcd setup
++ * Allocate interrupts and setup hardware.
++ * This is called from mx2-ocd.c
++ */
++int mx2_tcd_mod_init (void)
++{
++ struct otg_instance *otg;
++
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ TRACE_MSG0(TCD, "0. Basic Setup");
++
++
++ init_waitqueue_head(&mx2_i2c_wait);
++ PREPARE_WORK_ITEM(mx2_i2c_io_work_struct, &mx2_i2c_io_bh, NULL);
++ //PREPARE_WORK_ITEM(mx2_i2c_xcvr_work_struct, &mx2_i2c_xcvr_bh, NULL);
++
++ isp1301_thread_init(mx2ads_bh);
++
++
++ TRACE_MSG1(TCD, "i2c_int_hndlr: %x", otg_tcd_ops);
++ TRACE_MSG2(TCD, "i2c_int_hndlr: %x %x", &tcd_ops, tcd_ops.i2c_int_hndlr);
++ TRACE_MSG2(TCD, "tcd_int_hndlr: %x %x", &tcd_ops, tcd_ops.tcd_int_hndlr);
++
++ TRACE_MSG0(TCD, "4. Enable Interrupts");
++
++ mx2_wb(MX2_I2C_OP_CTRL_REG, 0x04); // Software mode, output enabled
++
++ mx2_urbv(MX2_OTG_XCVR_DEVAD);
++ mx2_urbv(MX2_SEQ_OP_REG);
++ mx2_urbv(MX2_SEQ_RD_STARTAD);
++ mx2_urbv(MX2_I2C_OP_CTRL_REG);
++ mx2_urbv(MX2_SCLK_TO_SCL_HPER);
++ mx2_urbv(MX2_I2C_INTERRUPT_AND_CTRL);
++
++ mx2_wb(MX2_I2C_OP_CTRL_REG, 0x01); // Software mode, output enabled
++
++
++
++ mx2_wb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_OTGXCVRINT_EN | I2C_NOACK_EN | I2C_RWREADY_EN);
++
++ isp1301_configure(vp_vm_bidirectional, spd_susp_pins);
++ isp1301_mod_init();
++
++ THROW_UNLESS(tcd_instance && (otg = tcd_instance->otg), error);
++ THROW_UNLESS(mx2ads_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
++
++ /* Success!
++ */
++
++ TRACE_MSG0(TCD, "5. Success!");
++
++ otg_init(otg);
++ //otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_AUTO);
++
++ /*
++ if ((ocd_ops.capabilities & OCD_CAPABILITIES_TR) && (ocd_ops.capabilities & OCD_CAPABILITIES_AUTO)) {
++ otg_event_irq(otg, enable_otg, TCD, "enable_otg");
++ otg_event_irq(otg, bus_req, TCD, "bus_req");
++ }
++ */
++
++ CATCH(error) {
++ printk(KERN_INFO"%s: failed\n", __FUNCTION__);
++ return -EINVAL;
++ }
++
++ TRACE_MSG0(TCD, "MX2_MOD_TCD_INIT FINISHED");
++ return 0;
++}
++
++/*! mx2_tcd_mod_exit - de-initialize
++ * This is called from mx2-ocd.c
++ */
++void mx2_tcd_mod_exit (void)
++{
++ struct otg_instance *otg = tcd_instance->otg;
++ TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT");
++
++ otg_event(otg, enable_otg_, OCD, "enable_otg_");
++ //if (otg)
++ // otg_exit(otg);
++
++ mx2ads_tcd_instance = otg_set_tcd_ops(NULL);
++
++ i2c_Write_Queued = -1;
++ wake_up_interruptible(&mx2_i2c_wait); // wakeup waiting bottom half handler
++
++ while (PENDING_WORK_ITEM(mx2_i2c_io_work_struct) /*|| PENDING_WORK_ITEM(mx2_i2c_xcvr_work_struct)*/ ) {
++ printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
++ schedule_timeout(10 * HZ);
++ }
++ isp1301_thread_exit(&mx2_i2c_wait);
++ isp1301_mod_exit();
++
++ if (otg)
++ otg_exit(otg);
++}
++
++/* ********************************************************************************************* */
++struct tcd_ops tcd_ops = {
++ id: mx2_id,
++ vbus: mx2_vbus,
++
++ tcd_init_func: mx2_tcd_init,
++ tcd_en_func: NULL,
++ chrg_vbus_func: isp1301_chrg_vbus,
++ drv_vbus_func: isp1301_drv_vbus,
++ dischrg_vbus_func: isp1301_dischrg_vbus,
++ dp_pullup_func: mx2_dp_pullup_func,
++ dm_pullup_func: isp1301_dm_pullup_func,
++
++ overcurrent_func: NULL,
++ dm_det_func: isp1301_dm_det_func,
++ dp_det_func: isp1301_dp_det_func,
++ charge_pump_func: NULL,
++ bdis_acon_func: isp1301_bdis_acon_func,
++ id_pulldown_func: isp1301_id_pulldown_func,
++ audio_func: isp1301_audio_func,
++ uart_func: isp1301_uart_func,
++ mono_func: isp1301_mono_func,
++
++ i2c_int_hndlr: mx2_i2c_int_hndlr,
++ tcd_int_hndlr: mx2_tcd_int_hndlr,
++ mod_init: mx2_tcd_mod_init,
++ mod_exit: mx2_tcd_mod_exit,
++};
++
+diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-init-l24.c linux/drivers/otg/ocd/otg-hcd/hcd-init-l24.c
+--- linux/drivers/no-otg/ocd/otg-hcd/hcd-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-hcd/hcd-init-l24.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ * otg/ocd/otg-hcd/hcd-l24-init.c - OTG Host Controller Driver Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-hcd/hcd-init-l24.c
++ * @brief
++ *
++ * This file initializes the low level hardware drivers.
++ *
++ * This is the linux 2.4 version.
++ *
++ * @ingroup OTGHCD
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <otg/otg-compat.h>
++
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-utils.h>
++#include <otg/otg-hcd.h>
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
++MODULE_LICENSE ("GPL");
++#endif
++MODULE_PARM (serial_number_str, "s");
++MODULE_PARM_DESC (serial_number_str, "Serial Number");
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_DESCRIPTION ("USB On-The-Go HCD");
++#endif
++char *serial_number_str;
++
++otg_tag_t HCD;
++extern struct hcd_ops hcd_ops;
++struct hcd_instance *hcd_instance;
++
++/* ************************************************************************************* */
++
++/* hcd_modexit - This is *only* used for drivers compiled and used as a module.
++ */
++static void hcd_modexit (void)
++{
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++ if (hcd_ops.mod_exit) hcd_ops.mod_exit();
++ hcd_instance = otg_set_hcd_ops(NULL);
++ otg_trace_invalidate_tag(HCD);
++}
++
++/* otg_modinit - linux module initialization
++ *
++ * This needs to initialize the hcd, pcd and tcd drivers. This includes tcd and possibly hcd
++ * for some architectures.
++ *
++ */
++static int hcd_modinit (void)
++{
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++ HCD = otg_trace_obtain_tag();
++
++ THROW_UNLESS(hcd_instance = otg_set_hcd_ops(&hcd_ops), error);
++ THROW_IF((hcd_ops.mod_init) ? hcd_ops.mod_init() : 0, error);
++
++ CATCH(error) {
++ hcd_modexit();
++ return -EINVAL;
++ }
++ return 0;
++}
++
++module_init (hcd_modinit);
++#ifdef MODULE
++module_exit (hcd_modexit);
++#endif
++
++
++
+diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-l26.c linux/drivers/otg/ocd/otg-hcd/hcd-l26.c
+--- linux/drivers/no-otg/ocd/otg-hcd/hcd-l26.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-hcd/hcd-l26.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,806 @@
++/*
++ * otg/ocd/otg-hcd/hcd-l26.c - Generic transfer level USBOTG aware Host Controller Driver (HCD)
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Tom Rushworth <tbr@belcara.com>,
++ * Stuart Lynne <sl@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-hcd/hcd-l26.c
++ * @brief Linux Generic Host Controller Driver
++ *
++ * @ingroup OTGHCD
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/usb.h>
++#include <asm/io.h>
++
++
++#include <otg/otg-compat.h>
++
++#include "../core/hcd.h"
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-hcd.h>
++
++#include <otg/hcd-l26.h>
++#include <otg/hcd-rh.h>
++#include <otg/hcd-hw.h>
++
++int hcd_probe(struct usb_interface *intf, const struct usb_device_id *id)
++{
++ return 0;
++}
++
++void hcd_disconnect(struct usb_interface *intf)
++{
++}
++
++#define STATIC static
++
++STATIC __inline__ struct urb *grab_active_urb(struct bus_hcpriv *bus_hcpriv, int u)
++{
++ unsigned long flags;
++ struct urb *urb;
++ // Paranoia.
++ RETURN_NULL_UNLESS(bus_hcpriv && bus_hcpriv->active_urbs && (u < bus_hcpriv->max_active_urbs));
++ local_irq_save(flags);
++ urb = bus_hcpriv->active_urbs[u];
++ bus_hcpriv->active_urbs[u] = NULL;
++ local_irq_restore(flags);
++ return urb;
++}
++
++#define OUT(o,e)((o && e) ? 1 : 0)
++
++STATIC void hcd_queue_urb(struct dev_hcpriv *dev_hcpriv, struct urb *urb, int endpoint, int out)
++{
++ unsigned long flags;
++ // Paranoia.
++ RETURN_UNLESS(dev_hcpriv && urb && (endpoint < 16));
++ local_irq_save(flags);
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] += 1;
++ list_add_tail(&urb->urb_list, &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint]);
++ TRACE_MSG4(HCD,"urb: %08x ep: %d n: %u %s", (u32)(void*)urb,
++ endpoint, dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint], "IN");
++ local_irq_restore(flags);
++}
++
++STATIC struct urb *hcd_next_urb(struct dev_hcpriv *dev_hcpriv, int endpoint, int out)
++{
++ // MUST BE CALLED in_irq()!!
++ struct urb *urb;
++ struct list_head *epq;
++ // Paranoia.
++ RETURN_NULL_UNLESS(dev_hcpriv && (endpoint < 16));
++ epq = &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint];
++ RETURN_NULL_IF(list_empty(epq));
++ urb = list_entry(epq->next, struct urb, urb_list);
++ list_del_init(&urb->urb_list);
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] -= 1;
++ return urb;
++}
++
++STATIC void hcd_finish_urb(struct urb *urb, int reason)
++{
++ /* Call the upper layer completion routine. Decrement the ref count
++ * (release our interest in this urb).
++ */
++ urb->status = reason;
++ if (urb->complete)
++ urb->complete(urb, NULL);
++ usb_put_urb(urb);
++}
++
++STATIC int hcd_submit_to_hw(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int out)
++{
++ // Pass the urb down to the hardware.
++ int rc;
++ void *data;
++ int dev_addr;
++ int endpoint;
++ int format;
++ int len;
++ int pid;
++ int toggle;
++ u32 other;
++ unsigned long flags;
++
++ struct usb_device *dev;
++ struct usb_bus *bus;
++ struct dev_hcpriv *dev_hcpriv;
++ u8 *cp;
++
++ RETURN_EINVAL_UNLESS((dev = urb->dev));
++ RETURN_EINVAL_UNLESS((bus = dev->bus));
++ RETURN_EINVAL_UNLESS((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv)));
++
++ dev_addr = usb_pipedevice(urb->pipe);
++ endpoint = usb_pipeendpoint(urb->pipe);
++
++ TRACE_MSG4(HCD,"urb: %08lx ep: %d %s len: %d", (u32)(void*)urb, endpoint, (out?"OUT":"IN"), urb->actual_length);
++
++ if (out) {
++#if 0
++ int i;
++ u8 *cp = urb->transfer_buffer;
++
++ TRACE_MSG1(HCD, "NEXT TX: length: %d", urb->actual_length);
++
++ for (i = 0; i < urb->actual_length; i+= 8)
++
++ TRACE_MSG8(HCD, "SENT %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++#endif
++ }
++
++ if (usb_endpoint_halted(urb->dev, endpoint, out)) {
++ TRACE_MSG4(HCD,"urb for halted endpoint urb: %08lx dev: %d ep: %d dir: %c",
++ urb, dev_addr, endpoint, (out?'O':'I'));
++ urb->actual_length = 0;
++ hcd_finish_urb(urb,-EPIPE);
++ return -EINVAL;
++ }
++
++ data = urb->transfer_buffer;
++ len = urb->transfer_buffer_length;
++ format = usb_pipetype(urb->pipe);
++ other = 0;
++
++ switch (format) {
++ case PIPE_CONTROL:
++ pid = USB_PID_SETUP;
++ // overload toggle with data phase direction (setup is always toggle 0)
++ // toggle == TRUE --> OUT (HOST2DEVICE --> OUT)
++
++ toggle = ((((struct usbd_device_request *) urb->setup_packet)->bmRequestType & USB_REQ_DIRECTION_MASK) ==
++ USB_REQ_HOST2DEVICE);
++
++ other = (u32) (void *) urb->setup_packet;
++
++ // XXX send set feature otg enable IFF set configuration and
++ // to first device and previously otg descriptor was seen.
++ break;
++
++ case PIPE_BULK:
++ pid = (out ? USB_PID_OUT : USB_PID_IN);
++ toggle = usb_gettoggle(urb->dev,endpoint,out);
++ other = (urb->transfer_flags & URB_ZERO_PACKET);
++ break;
++
++ case PIPE_INTERRUPT:
++ pid = (out ? USB_PID_OUT : USB_PID_IN);
++ toggle = usb_gettoggle(urb->dev,endpoint,out);
++ other = urb->interval;
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ pid = (out ? USB_PID_OUT : USB_PID_IN);
++ toggle = 0;
++ other = urb->interval;
++ break;
++
++ default:
++ pid = 0;
++ toggle = 0;
++ break;
++ }
++
++ /* We need an irq lock here in order to make sure the urb gets saved in
++ bus_hcpriv->active_urbs[] before any possible completion interrupt. */
++ local_irq_save(flags);
++ rc = hcd_hw_start_transfer(bus_hcpriv, len, data, toggle, usb_maxpacket(urb->dev, urb->pipe, out),
++ (((urb->pipe) >> 26) & 1), endpoint,dev_addr, pid, format,other);
++
++ if (rc >= 0 && rc < bus_hcpriv->max_active_urbs) {
++
++ if (!bus_hcpriv->active_urbs[rc])
++ bus_hcpriv->active_urbs[rc] = urb;
++
++ /* Oops, total screw up, we shouldn't ever see this.
++ * (The lower layer just told us it started a second urb in
++ * an already busy slot.)
++ */
++ else
++ TRACE_MSG3(HCD,"ERROR - act: %08x urb: %08x slot: %d",
++ (u32)(void*)(bus_hcpriv->active_urbs[rc]), (u32)(void*)urb, rc);
++ }
++ local_irq_restore(flags);
++ if (rc < 0) {
++ // Resubmit is OK...
++ if (rc == -2) {
++ TRACE_MSG1(HCD,"no ETDs for urb: %08lx",urb);
++ return 1;
++ }
++
++ // Complete the urb as invalid.
++ urb->actual_length = 0;
++ hcd_finish_urb(urb,-EINVAL);
++ // And signal to try again.
++ return -1;
++ }
++ return 0;
++}
++
++STATIC void hcd_queue_start(struct bus_hcpriv *bus_hcpriv, struct dev_hcpriv *dev_hcpriv, int endpoint, int out)
++{
++ unsigned long flags;
++ struct urb *urb = NULL;
++ int rc;
++
++ TRACE_MSG2(HCD, "endpoint: %2x %s", endpoint, out ? "OUT" : "IN");
++
++ // Paranoia.
++ RETURN_UNLESS(dev_hcpriv && endpoint < 16);
++ do {
++ local_irq_save(flags);
++ if (dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] == EPQ_RUNNING) {
++ // There's already an urb for this device/endpoint in the HW, don't start another.
++ urb = NULL;
++ }
++ else if (!(urb = hcd_next_urb(dev_hcpriv, endpoint, out))) {
++ dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_EMPTY;
++ }
++ else {
++ // There is an urb to go, set the state to show the HW is (will be) busy.
++ dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_RUNNING;
++ }
++ local_irq_restore(flags);
++ if (!urb) {
++ // This endpoint is already active in the HW, or doesn't need to be.
++ rc = 0;
++ }
++ else {
++ // Try to pass the urb down to the HW.
++ rc = hcd_submit_to_hw(bus_hcpriv, urb, out);
++ }
++ } while (rc < 0);
++ if (rc > 0) {
++ // We've run out of HW resources, try again later.
++ local_irq_save(flags);
++ list_add(&urb->urb_list, &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint]);
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] += 1;
++ dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_WAITING;
++ TRACE_MSG3(HCD,"urb: %08x ep: %d n: %u WAITING IN",
++ (u32)(void*)urb, endpoint, dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint]);
++ local_irq_restore(flags);
++ /* There should be no need to queue a task to try later, as the HW
++ * should have lots of pending urbs, and urb completion will lead
++ * to a search for new work. There is a small chance that _all_ the
++ * pending urbs will complete between the call to hcd_submit_to_hw(),
++ * but it's unlikely.
++ */
++ }
++}
++
++
++/* ********************************************************************************************** */
++/* Functions provided to the HW dependent layer (below this one).
++ */
++void hcd_transfer_complete(struct bus_hcpriv *bus_hcpriv, int transfer_id, int format, int cc, u32 remaining, int next_toggle)
++{
++ struct urb *urb = grab_active_urb(bus_hcpriv, transfer_id);
++ struct usb_device *dev;
++ struct usb_bus *bus;
++ struct dev_hcpriv *dev_hcpriv;
++ int out;
++
++ int endpoint;
++ u8 *cp;
++
++ UNLESS (urb) {
++ TRACE_MSG1(HCD,"active_urb[%d] NULL",transfer_id);
++ return;
++ }
++
++ RETURN_UNLESS((dev = urb->dev));
++ RETURN_UNLESS((bus = dev->bus));
++ RETURN_UNLESS((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv)));
++
++ out = usb_pipeout(urb->pipe);
++
++ TRACE_MSG5(HCD,"id: %d status: %d tlen: %d rem: %d buffer: %p",
++ transfer_id, cc, urb->transfer_buffer_length, remaining, urb->transfer_buffer);
++ //if (out)
++ if (urb->transfer_buffer) {
++#if 0
++ int i;
++ u8 *cp = urb->transfer_buffer;
++
++ TRACE_MSG1(HCD, "NEXT TX: length: %d", urb->actual_length);
++
++ for (i = 0; i < urb->actual_length; i+= 8)
++
++ TRACE_MSG8(HCD, "RECV %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++#endif
++ }
++
++ if (-ENOENT == cc) {
++ // Cancelled.
++ urb->actual_length = 0;
++ }
++ else {
++ switch (format) {
++ case PIPE_CONTROL:
++ urb->actual_length = urb->transfer_buffer_length - remaining;
++
++ if ((cp = urb->setup_packet))
++ TRACE_MSG8(HCD, "SETUP %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++
++ if ((dev == bus_hcpriv->first_dev) && !cc && urb->setup_packet) {
++ struct usb_ctrlrequest *request = (struct usb_ctrlrequest*) urb->setup_packet;
++ switch (request->bRequest) {
++ case USB_REQ_SET_ADDRESS:
++ otg_event(hcd_instance->otg, ADDRESSED, HCD, "HCD COMPLETE ADDRESSED");
++ break;
++ case USB_REQ_SET_CONFIGURATION:
++ otg_event(hcd_instance->otg, CONFIGURED, HCD, "HCD COMPLETE CONFIGURED");
++ break;
++ // XXX check for GET_CONFIGURATION and otg descriptor here
++ }
++ }
++ break;
++
++ case PIPE_BULK:
++ case PIPE_INTERRUPT:
++ if (0 == cc) {
++ // QQSV needed for BULK, what about interrupt?
++ TRACE_MSG4(HCD,"dev: %d ep: %d dir: %d TOGGLE: %d",urb->dev->devnum,
++ usb_pipeendpoint(urb->pipe),usb_pipeout(urb->pipe),next_toggle);
++ usb_settoggle(urb->dev,usb_pipeendpoint(urb->pipe),usb_pipeout(urb->pipe),next_toggle);
++ }
++ urb->actual_length = urb->transfer_buffer_length - remaining;
++ //hcd_trace_mem(HCD,__FUNCTION__,"BULK/INTERRUPT urb",urb->actual_length,urb->transfer_buffer);
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ urb->actual_length = urb->transfer_buffer_length - remaining; // QQSV
++ break;
++
++ default: // Paranoia.
++ urb->actual_length = 0;
++ break;
++ }
++ }
++ endpoint = usb_pipeendpoint(urb->pipe);
++ hcd_finish_urb(urb, cc);
++
++ // Start the next urb in the queue for this device/endpoint.
++ dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_WAITING;
++
++ TRACE_MSG2(HCD,"queue_start ep: %d %s >>>", endpoint, out ? "OUT" : "IN");
++ hcd_queue_start(bus_hcpriv, dev_hcpriv, endpoint, out);
++
++ //TRACE_MSG1(HCD,"queue_start ep: %d <<<",endpoint);
++ // FIXME - in the future, need to kick off a BH to search other EPs/devs for waiting urbs
++ // if (dev_hcpriv->epq_state[endpoint] == EPQ_EMPTY) {
++ // /* This queue is empty, so its HW resources are now available,
++ // kick off BH to search for other EP's and other devs that are waiting. */
++ // _________
++ // }
++}
++
++/* ********************************************************************************************** */
++/* Functions provided to the USB core layer (above this one).
++ */
++
++/* Allocate space for some USB function plugged into this HC or any hub below it.
++ * Return 0 on success, error code (e.g. -ENOMEM) on failure.
++ */
++STATIC int hcd_allocate(struct usb_device *dev)
++{
++ struct usb_bus *bus;
++ struct bus_hcpriv *bus_hcpriv;
++ struct dev_hcpriv *dev_hcpriv;
++ int endpoint;
++
++ TRACE_MSG1(HCD,"entered devnum: %d", dev->devnum);
++
++ RETURN_ENOMEM_UNLESS((bus = dev->bus));
++ RETURN_ENOMEM_UNLESS((bus_hcpriv = (struct bus_hcpriv *) bus->hcpriv));
++
++ RETURN_ENOMEM_UNLESS(dev_hcpriv = (struct dev_hcpriv *) kmalloc(sizeof(struct dev_hcpriv), GFP_KERNEL));
++
++ memset(dev_hcpriv, 0, sizeof(struct dev_hcpriv));
++ for (endpoint = 0; endpoint < 16; endpoint++) {
++ INIT_LIST_HEAD(&dev_hcpriv->queued_urbs_both[0][endpoint]);
++ INIT_LIST_HEAD(&dev_hcpriv->queued_urbs_both[1][endpoint]);
++ }
++
++ dev->hcpriv = dev_hcpriv;
++ dev_hcpriv->dev = dev;
++
++ UNLESS (bus_hcpriv->roothub_dev)
++ bus_hcpriv->roothub_dev = dev;
++
++ else UNLESS (bus_hcpriv->first_dev)
++ bus_hcpriv->first_dev = dev;
++
++ return 0;
++}
++
++
++STATIC int hcd_deallocate(struct usb_device *dev)
++{
++ struct usb_bus *bus = dev->bus;
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) bus->hcpriv;
++ struct dev_hcpriv *dev_hcpriv;
++
++ if (dev == bus_hcpriv->first_dev)
++ bus_hcpriv->first_dev = NULL;
++
++ if (dev == bus_hcpriv->roothub_dev)
++ bus_hcpriv->roothub_dev = NULL;
++
++ if ((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv))) {
++ dev_hcpriv->dev = NULL;
++ kfree(dev_hcpriv);
++ dev->hcpriv = NULL;
++ }
++ return 0;
++}
++
++
++STATIC void *hcd_buffer_alloc(struct usb_bus *usb_bus, size_t size, int mem_flags, dma_addr_t *dma)
++{
++ return consistent_alloc(0, size, dma);
++}
++
++STATIC void hcd_buffer_free(struct usb_bus *usb_bus, size_t size, void *addr, dma_addr_t dma)
++{
++ RETURN_UNLESS(addr);
++ consistent_free(addr,size,dma);
++}
++
++STATIC int frame_number(struct usb_device *usb_dev)
++{
++ u32 n = hcd_hw_frame_number((struct bus_hcpriv *)(usb_dev->bus->hcpriv));
++ TRACE_MSG1(HCD,"-->: %08lx",n);
++ return n;
++}
++
++STATIC int submit_urb(struct urb *urb, int mem_flags)
++{
++ struct bus_hcpriv *bus_hcpriv;
++ struct dev_hcpriv *dev_hcpriv;
++ int dev_addr;
++ int endpoint;
++ int out;
++
++ RETURN_EINVAL_UNLESS (urb && urb->dev && urb->dev->bus);
++ RETURN_EINVAL_UNLESS ((bus_hcpriv = (struct bus_hcpriv *) (urb->dev->bus->hcpriv)));
++ RETURN_EINVAL_UNLESS ((dev_hcpriv = (struct dev_hcpriv *) (urb->dev->hcpriv)));
++ RETURN_EINVAL_IF (bus_hcpriv->terminating);
++
++ dev_addr = usb_pipedevice(urb->pipe);
++ endpoint = usb_pipeendpoint(urb->pipe);
++ out = usb_pipeout(urb->pipe);
++
++ RETURN_EPIPE_IF (usb_endpoint_halted(urb->dev, endpoint, out));
++
++ /* Divert to root hub if appropriate, (note: NO ref count change).
++ */
++ if (urb->dev == bus_hcpriv->roothub_dev) {
++ TRACE_MSG4(HCD,"root hub --> urb: %08lx dev: %d ep: %d dir: %s", urb, dev_addr, endpoint, (out ? "OUT" : "IN"));
++ return hcd_rh_submit_urb(bus_hcpriv, urb, mem_flags);
++ }
++
++ /* Increase ref count so we own a piece of the URB. Queue the urb,
++ * then make sure the queue is running.
++ */
++ TRACE_MSG4(HCD,"device --> urb: %08lx dev: %d ep: %d dir: %S", urb, dev_addr, endpoint, (out ? "OUT" : "IN"));
++ hcd_queue_urb(dev_hcpriv, usb_get_urb(urb), endpoint, out);
++ hcd_queue_start(bus_hcpriv, dev_hcpriv, endpoint, out);
++ return 0;
++}
++
++STATIC int unlink_urb(struct urb *urb)
++{
++ int u;
++ unsigned long flags;
++ struct bus_hcpriv *bus_hcpriv = NULL;
++ struct dev_hcpriv *dev_hcpriv = NULL;
++ int dev_addr;
++ int endpoint;
++ struct list_head *epq;
++ int out;
++
++ RETURN_EINVAL_UNLESS (urb && urb->dev && urb->dev->bus);
++ RETURN_EINVAL_UNLESS ((dev_hcpriv = (struct dev_hcpriv *) (urb->dev->hcpriv)));
++ RETURN_EINVAL_UNLESS ((bus_hcpriv = (struct bus_hcpriv *) (urb->dev->bus->hcpriv)));
++
++ out = usb_pipeout(urb->pipe);
++
++ dev_addr = usb_pipedevice(urb->pipe);
++
++ /* Does it belong to the root hub?
++ */
++ if (urb->dev == bus_hcpriv->roothub_dev) {
++ TRACE_MSG1(HCD,"root hub --> urb: %08lx",urb);
++ return hcd_rh_unlink_urb(bus_hcpriv,urb);
++ }
++
++ /* Look to see if it is in a device/endpoint queue.
++ */
++ endpoint = usb_pipeendpoint(urb->pipe);
++
++ epq = &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint];
++
++ /* Searching a list while in_irq - yuck. For the time being,
++ * this just assumes that the list is short. In the future,
++ * it may be possible to keep a small amount of state in the
++ * urb itself to indicate if it is in this list, so that all
++ * we need to do in_irq is check the state and delete from the
++ * list if the state indicates we should. The state info will
++ * only needed while this HC "owns" the urb.
++ */
++ local_irq_save(flags);
++
++ if (EPQ_EMPTY != dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint]) {
++ // There are queued urbs, search to see if this is one of them.
++ struct urb *qe;
++ list_for_each_entry(qe, epq, urb_list) {
++ if (qe == urb) {
++ // Found it. It hasn't been sent to the HW yet, so it can be finished here.
++ list_del_init(&urb->urb_list);
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] -= 1;
++ if (list_empty(epq))
++ dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_EMPTY;
++
++ TRACE_MSG3(HCD,"urb: %08x ep: %d n: %u UNLINKED IN",
++ (u32)(void*)urb, endpoint,
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint]);
++ hcd_finish_urb(urb,-ENOENT);
++ local_irq_restore(flags);
++ return 0;
++ }
++ }
++ }
++
++ local_irq_restore(flags);
++
++ /* Look to see if this is one of the active urbs.
++ */
++ if (bus_hcpriv->active_urbs) {
++
++ for (u = 0; u < bus_hcpriv->max_active_urbs; u++) {
++ local_irq_save(flags);
++ /* This is the one we want, unlink from the HW.
++ * HW layer does the completion through hcd_transfer_complete()
++ * in this file, which releases bus_hcpriv->active_urbs[u].
++ */
++ if (urb == bus_hcpriv->active_urbs[u]) {
++ int out;
++ out = usb_pipeout(urb->pipe);
++ u = hcd_hw_unlink_urb(bus_hcpriv, u);
++
++ TRACE_MSG4(HCD,"urb: %08x ep: %d n: %u UNLINKED from HW %s", (u32)(void*)urb, endpoint,
++ dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint], out ? "OUT" : "IN");
++
++ local_irq_restore(flags);
++ // FUTURE - think about starting a search for new work for the released HW slot.
++ return u;
++ }
++ local_irq_restore(flags);
++ }
++ }
++ // The urb isn't ours, or completed while we were looking for it.
++ TRACE_MSG1(HCD,"Already completed, or someone else's urb: %08lx", urb);
++ return -EINVAL;
++}
++
++/* ********************************************************************************************** */
++
++// void disable(struct usb_device *dev, int bEndpointAddress);
++
++static struct usb_operations operations = {
++ .allocate = hcd_allocate,
++ .deallocate = hcd_deallocate,
++ .get_frame_number = frame_number,
++ .submit_urb = submit_urb,
++ .unlink_urb = unlink_urb,
++ .buffer_alloc = hcd_buffer_alloc, /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
++ .buffer_free = hcd_buffer_free,
++ .disable = NULL
++};
++
++
++/* ********************************************************************************************** */
++
++/* Called as a "bottom-half" to do usbcore registration once all the HW is usable.
++ */
++STATIC void hcd_bh_init(void *arg)
++{
++ struct hcd_instance *hcd = (struct hcd_instance *) arg;
++ otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
++ TRACE_MSG0(HCD,"finished");
++}
++
++STATIC void hcd_bh_exit(void *arg)
++{
++ struct hcd_instance *hcd = (struct hcd_instance *) arg;
++ otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT RESET (EXIT) HCD_OK");
++}
++
++
++/*! hcd_init_func - per host controller common initialization
++ *
++ * This is called to initialize / de-initialize the HCD, all except the last
++ * stage of registering the root hub, because that needs to wait until rh_hcd_en_func()
++ *
++ * We start work items to do this.
++ *
++ */
++void hcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ struct hcd_instance *hcd = otg->hcd;
++
++ switch (flag) {
++ case SET:
++ // Schedule BH for hcd_bh_init...
++ TRACE_MSG0(HCD, "HCD_INIT: SET");
++ PREPARE_WORK_ITEM(hcd->bh, hcd_bh_init, hcd);
++ SCHEDULE_WORK(hcd->bh);
++ TRACE_MSG0(HCD, "hcd_bh_init() schedule finished");
++ break;
++
++ case RESET:
++ TRACE_MSG0(HCD, "HCD_INIT: RESET");
++ PREPARE_WORK_ITEM(hcd->bh, hcd_bh_exit, hcd);
++ SCHEDULE_WORK(hcd->bh);
++ break;
++ }
++}
++
++
++/* ********************************************************************************************** */
++
++STATIC void release_hw_rh(struct bus_hcpriv *bus_hcpriv)
++{
++ RETURN_UNLESS (bus_hcpriv);
++
++ hcd_rh_exit(bus_hcpriv);
++
++ // Complete (cancel) any active urbs.
++ if (bus_hcpriv->active_urbs) {
++ int u;
++ for (u = 0; u < bus_hcpriv->max_active_urbs; u++) {
++ struct urb *urb;
++ if ((urb = grab_active_urb(bus_hcpriv,u))) {
++ urb->actual_length = 0;
++ hcd_finish_urb(urb,-ENOENT); // USB_ST_URB_KILLED
++ }
++ }
++ }
++
++ // Release any resources from the layer above.
++ if (bus_hcpriv->usb_bus) {
++ usb_deregister_bus(bus_hcpriv->usb_bus);
++ bus_hcpriv->usb_bus = NULL;
++ }
++
++ // Lastly, release this layer's info.
++ if (bus_hcpriv->active_urbs) {
++ kfree(bus_hcpriv->active_urbs);
++ bus_hcpriv->active_urbs = NULL;
++ }
++}
++
++/* ********************************************************************************************** */
++/*
++ * Note that initialization and cleanup happen in two stages:
++ * 1. Allocation of the basic struct bus_hcpriv, the first level of LDM/USB driver registration, and OTG operations
++ * 2. Everything else - completion of data allocation, USBcore registration, HC HW init, root hub enumeration - when
++ * called back by OTG (after any magic required to access the HCD hardware.)
++ * Only stage 1 is done on module entry.
++ */
++
++int __init hcd_init(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver)
++{
++ struct usb_bus *usb_bus = NULL;
++ int usb_registered = 0;
++ int device_registered = 0;
++ int bus_registered = 0;
++ int rc = 0;
++ struct urb **active_urbs = NULL;
++
++ /* fixup bus_hcpriv structure
++ */
++ bus_hcpriv->usb_driver = usb_driver;
++ bus_hcpriv->bus_device.driver = &usb_driver->driver;
++ bus_hcpriv->max_active_urbs = bus_hcpriv->max_active_transfers;
++ usb_driver->probe = hcd_probe;
++
++ UNLESS (hcd_ops.hcd_init_func) hcd_ops.hcd_init_func = hcd_init_func;
++
++ /* allocate urb array
++ */
++ THROW_UNLESS ((active_urbs = (struct urb **) kmalloc(bus_hcpriv->max_active_urbs*sizeof(struct urb *),GFP_KERNEL)),
++ error);
++
++ bus_hcpriv->active_urbs = active_urbs;
++ memset(bus_hcpriv->active_urbs,0,bus_hcpriv->max_active_urbs*sizeof(struct urb *));
++ TRACE_MSG1(HCD,"active_urbs ok, max active URBs: %d",bus_hcpriv->max_active_urbs);
++
++ /* register with usb core
++ */
++ THROW_UNLESS(usb_registered = usb_register(usb_driver) ? 0 : 1, error);
++ TRACE_MSG0(HCD,"usb_register ok");
++
++ /* We need a bus before we can initialize the root hub.
++ */
++ THROW_UNLESS ((usb_bus = usb_alloc_bus(&operations)), error);
++ bus_hcpriv->usb_bus = usb_bus;
++ TRACE_MSG0(HCD,"usb bus allocated");
++
++ /* register bus
++ */
++ snprintf(bus_hcpriv->bus_device.bus_id, BUS_ID_SIZE, "bus_hcpriv%d", usb_bus->busnum);
++ snprintf(bus_hcpriv->bus_device.name, DEVICE_NAME_SIZE,"%s%d", bus_hcpriv->usb_driver->name, usb_bus->busnum);
++ usb_bus->hcpriv = (void *) bus_hcpriv;
++ usb_bus->controller = &bus_hcpriv->bus_device;
++ THROW_UNLESS ((bus_registered = usb_register_bus(usb_bus)) ? 0 : 1, error);
++ TRACE_MSG0(HCD,"usb bus registered");
++
++ /* All set for the host controller, initialize the virtual root hub.
++ */
++ THROW_IF (hcd_rh_init(bus_hcpriv), error);
++ TRACE_MSG0(HCD,"root hub initialized");
++
++ /* register device
++ */
++ //THROW_IF ((device_registered = device_register(&bus_hcpriv->bus_device) ? 0 : 1), error);
++ if (device_register(&bus_hcpriv->bus_device)) {
++ printk(KERN_ERR"%s: device_register not ok\n", __FUNCTION__);
++ }
++
++ /* Everybody's ready, enable the interrupts.
++ */
++
++ /* Kick off the root hub.
++ */
++ THROW_IF ((rc = usb_register_root_hub(bus_hcpriv->rh_hcpriv->dev, &(bus_hcpriv->bus_device))), error);
++
++ return 0;
++
++ CATCH(error) {
++
++ if (device_registered) device_unregister(&bus_hcpriv->bus_device);
++ if (usb_bus) {
++ if (bus_registered && usb_bus) usb_deregister_bus(usb_bus);
++ kfree(usb_bus);
++ }
++ if (usb_registered) usb_deregister(usb_driver);
++ if (active_urbs) kfree(active_urbs);
++ return -EINVAL;
++ }
++}
++
++#ifdef MODULE
++void hcd_exit(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver)
++{
++ release_hw_rh(bus_hcpriv);
++
++ usb_deregister_bus(bus_hcpriv->usb_bus);
++ device_unregister(&bus_hcpriv->bus_device);
++ usb_deregister(usb_driver);
++}
++#endif
++
+diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-rh.c linux/drivers/otg/ocd/otg-hcd/hcd-rh.c
+--- linux/drivers/no-otg/ocd/otg-hcd/hcd-rh.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-hcd/hcd-rh.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,1068 @@
++/*
++ * otg/ocd/otg-hcd/hcd-rh.c - Generic transfer level USBOTG aware
++ * virtual root hub _FUNCTION_ driver.
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Tom Rushworth <tbr@belcara.com>,
++ * Stuart Lynne <sl@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ */
++/*!
++ * @file otg/ocd/otg-hcd/hcd-rh.c
++ * @brief Root Hub for Generic Host Controller Driver
++ *
++ *
++ *
++ * @ingroup OTGHCD
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/usb.h>
++
++#include <otg/otg-compat.h>
++#include "../core/hcd.h"
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-utils.h>
++#include <otg/otg-hcd.h>
++
++#include <otg/hcd-l26.h>
++#include <otg/hcd-rh.h>
++#include <otg/hcd-hw.h>
++
++#define STATIC static
++
++/* NOTE: This code assumes the root hub has < 8 ports. If it has
++ more some of the descriptors and other structures will have to
++ be re-sized. */
++
++STATIC u8 prepare_str(char *ascii, u8 *str, int str_size)
++{
++ int c;
++ u8 *up = str;
++ u8 *ep = (up + str_size) - 1;
++ while ((c = *ascii++) && up < ep) {
++ *up++ = (c & 0x7F);
++ *up++ = 0;
++ }
++ return (u8)(up - str);
++}
++
++STATIC int hcd_rh_string(struct bus_hcpriv *bus_hcpriv, int strno, u8 *buff, int buff_len)
++{
++ // Provide default strings, but let the HW component override them.
++ char *str;
++ switch (strno) {
++ case 0: // Language ID
++ *buff++ = 4;
++ *buff++ = USB_DT_STRING;
++ *buff++ = 0;
++ *buff++ = 0;
++ return 4;
++ case XHC_RH_STRING_CONFIGURATION:
++ str = "Root hub";
++ break;
++ case XHC_RH_STRING_INTERFACE:
++ str = "Root hub - Status";
++ break;
++ case XHC_RH_STRING_SERIAL:
++ str = bus_hcpriv->rh_serial ? bus_hcpriv->rh_serial : "000001";
++ break;
++ case XHC_RH_STRING_PRODUCT:
++ str = bus_hcpriv->rh_product ? bus_hcpriv->rh_product : "Virtual Root Hub";
++ break;
++ case XHC_RH_STRING_MANUFACTURER:
++ str = bus_hcpriv->rh_manufacturer ? bus_hcpriv->rh_manufacturer : "Belcarra Technologies";
++ break;
++ default:
++ str = "????";
++ }
++
++ buff[0] = 2 + prepare_str(str,buff+2,buff_len-2);
++ buff[1] = USB_DT_STRING;
++ return buff[0];
++}
++
++
++/* ********************************************************************************************** */
++
++
++static char *hub_feature_name[] = {
++ "C_HUB_LOCAL_POWER",
++ "C_HUB_OVER_POWER",
++};
++
++STATIC void hcd_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, int set_flag)
++{
++ unsigned long flags;
++ TRACE_MSG3(HCD,"%s feature %d %s",(set_flag?"SET":"CLR"), wValue, hub_feature_name[wValue]);
++ local_irq_save(flags);
++ if (set_flag) {
++ // SET feature USB2.0 11.24.2.12 pg 434 and USB2.0 11.24.2 tbl 11-17 pg 421
++ // R1: sec 23.11.29 pg 23-62
++ switch (wValue) {
++ // case C_HUB_OVER_CURRENT: ____ FIXME ----
++ // case C_HUB_LOCAL_POWER: ____ FIXME ----
++ default:
++ // Error, but ignore.
++ TRACE_MSG1(HCD,"SET invalid FEATURE %d", wValue);
++ break;
++ }
++ }
++ else {
++ // CLEAR feature USB2.0 11.24.2.1 pg 422 and USB2.0 11.24.2 tbl 11-17 pg 421
++ // R1: sec 23.11.29 pg 23-62
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ bus_hcpriv->rh_hcpriv->hub_change_status &= ~(1 << wValue);
++ TRACE_MSG1(HCD,"CLR C_HUB_OVER_CURRENT hub_change_status: %08x", bus_hcpriv->rh_hcpriv->hub_change_status);
++ break;
++ // case C_HUB_LOCAL_POWER: ____ FIXME ----
++ default:
++ // Error, but ignore.
++ TRACE_MSG1(HCD,"CLR invalid FEATURE %d", wValue);
++ break;
++ }
++ }
++ local_irq_restore(flags);
++ hcd_hw_rh_hub_feature(bus_hcpriv, wValue, set_flag);
++}
++
++/* ********************************************************************************************** */
++
++char *port_feature_name[] = {
++ "PORT_CONNECTION", "PORT_ENABLE", "PORT_SUSPEND", "FEATURE 0x03",
++ "PORT_RESET", "FEATURE 0x05", "FEATURE 0x06", "FEATURE 0x07",
++ "PORT_POWER", "PORT_LOW_SPEED", "FEATURE 0x0a", "FEATURE 0x0b",
++ "FEATURE 0x0c", "FEATURE 0x0d", "FEATURE 0x0e", "FEATURE 0x0f",
++ "C_PORT_CONNECTION", "C_PORT_ENABLE", "C_PORT_SUSPEND", "C_PORT_OVER_CURRENT",
++ "C_PORT_RESET", "PORT_TEST",
++};
++
++void check_port_status_(int feature, u32 change_status, u32 hw_change_status)
++{
++ int mask = (1 << feature);
++ if ((change_status & mask) != (hw_change_status & mask))
++ TRACE_MSG4(HCD, "%-20s %2d %6s %6s MISMATCH", port_feature_name[feature], feature,
++ change_status & mask ? "SET" : "RESET", hw_change_status & mask ? "SET" : "RESET" );
++}
++
++void check_port_status(struct bus_hcpriv *bus_hcpriv, u16 wIndex, char *msg)
++{
++ struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
++ u32 change_status = ((wIndex -1) < bus_hcpriv->num_ports) ? bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1] : 0;
++ u32 hw_change_status = hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex);
++
++ TRACE_MSG4(HCD,"PORT_STATUS[%2d] %08x %08x %s", wIndex,
++ change_status, hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex), msg);
++
++ UNLESS(rh_hcpriv->suspended) {
++ // XXX
++ }
++
++ check_port_status_(PORT_CONNECTION, change_status, hw_change_status);
++ check_port_status_(PORT_ENABLE, change_status, hw_change_status);
++ check_port_status_(PORT_RESET, change_status, hw_change_status);
++ check_port_status_(PORT_POWER, change_status, hw_change_status);
++ check_port_status_(C_PORT_CONNECTION, change_status, hw_change_status);
++ check_port_status_(C_PORT_ENABLE, change_status, hw_change_status);
++ check_port_status_(C_PORT_RESET, change_status, hw_change_status);
++}
++/* ********************************************************************************************** */
++/*
++ * wIndex is port number (1-N)
++ * wValue is feature selector
++ */
++STATIC void hcd_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag)
++{
++ TRACE_MSG4(HCD,"%s port %d FEATURE %02x %s", (set_flag?"SET":"CLR"), wIndex,
++ wValue, port_feature_name[wValue]);
++ /* Not a valid port number
++ */
++ if (wIndex > bus_hcpriv->num_ports) {
++ TRACE_MSG1(HCD, "invalid port: %d", wIndex);
++ return;
++ }
++ /* Feature selector is wValue
++ * wIndex is 1-origin
++ */
++ TRACE_MSG2(HCD, "port_change_status[%d]: -> %08x", wIndex, bus_hcpriv->rh_hcpriv->port_change_status[wIndex -1]);
++ if (set_flag) {
++ // SET feature
++ switch (wValue) {
++ case PORT_SUSPEND:
++ case PORT_RESET:
++ case PORT_POWER:
++ bus_hcpriv->rh_hcpriv->port_change_status[wIndex - 1] |= (1 << wValue);
++ break;
++ }
++ }
++ else {
++ // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
++ switch (wValue) {
++ case PORT_ENABLE: // Disable port.
++ case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
++ case PORT_POWER: // Put port in powered-off state.
++ case C_PORT_CONNECTION: // clear the PORT_CONNECTION change bit
++ case C_PORT_RESET: // clear the PORT_RESET change bit
++ case C_PORT_ENABLE: // clear the PORT_ENABLE change bit
++ case C_PORT_SUSPEND: // clear the PORT_SUSPEND change bit
++ case C_PORT_OVER_CURRENT: // clear the PORT_OVERCURRENT change bit
++ bus_hcpriv->rh_hcpriv->port_change_status[wIndex - 1] &= ~(1 << wValue);
++ break;
++ }
++ }
++ /* update hardware?
++ */
++
++ RETURN_UNLESS (wIndex == bus_hcpriv->otg_port);
++ RETURN_IF (bus_hcpriv->rh_hcpriv->otg_device_mask & (1 << wIndex));
++
++ hcd_hw_rh_port_feature(bus_hcpriv, wValue, wIndex, set_flag);
++
++ TRACE_MSG4(HCD, "OTG Port wValue: %x wIndex: %d %d set: %d", wValue, wIndex, bus_hcpriv->otg_port, set_flag);
++ if (set_flag) {
++ // SET feature
++ switch (wValue) {
++ case PORT_RESET:
++ TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED - PORT_RESET");
++ //otg_event(bus_hcpriv->hcd->otg, HUB_PORT_ENABLED, HCD, "Hub Port Enable (PORT_RESET)");
++ otg_event(hcd_instance->otg, BUS_RESET, HCD, "PORT_RESET (SET Feature)");
++ break;
++ case PORT_SUSPEND:
++ case PORT_POWER:
++ break;
++ }
++ check_port_status(bus_hcpriv, wIndex, "PORT SET");
++ }
++ else {
++ // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
++ switch (wValue) {
++ case C_PORT_CONNECTION: // clear the PORT_CONNECTION change bit
++ TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED/ - C_PORT_CONNECTION");
++ break;
++ case C_PORT_ENABLE: // clear the PORT_ENABLE change bit
++ TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED/ - C_PORT_ENABLE");
++ break;
++ case PORT_ENABLE: // Disable port.
++ case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
++ case PORT_POWER: // Put port in powered-off state.
++ case C_PORT_RESET: // clear the PORT_RESET change bit
++ case C_PORT_SUSPEND: // clear the PORT_SUSPEND change bit
++ case C_PORT_OVER_CURRENT: // clear the PORT_OVERCURRENT change bit
++ break;
++ }
++ check_port_status(bus_hcpriv, wIndex, "PORT CLR");
++ }
++}
++
++/* ********************************************************************************************** */
++/*
++ * Functions for periodic response to the INT URB.
++ * Note that the USB2.0 spec says (sec 11.12.2 pg 337) that a hub controller
++ * will respond to an INT poll as long as the change bits remain set. This
++ * means we have to record them and continue responding periodically (hence
++ * the timer) until the class driver clears them.
++ *
++ */
++
++void hcd_rh_urb_complete(struct bus_hcpriv *bus_hcpriv, struct urb *urb)
++{
++ // Almost not needed (vrh could do this directly), except for tracing.
++ TRACE_MSG1(HCD,"urb %p",urb);
++
++ /* Call the upper layer completion routine.
++ */
++ if (urb->complete)
++ urb->complete(urb,NULL);
++
++ // XXX should we do this here
++ // usb_put_urb(int_urb);
++}
++/* ********************************************************************************************** */
++/*
++ * Some sort of change may have happened on the root hub or one of the ports,
++ * scan for changes in the shadow data, and notify usbcore if there is an
++ * INT URB available to do so with.
++ */
++STATIC void hcd_rh_portstatus_bh(void *data)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) data;
++ struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
++ u8 change_data;
++ struct urb *int_urb;
++
++ u32 hub_port_change_status;
++ unsigned long flags;
++
++ TRACE_MSG1(HCD, "suspended: %d", rh_hcpriv->suspended);
++ RETURN_IF(rh_hcpriv->suspended);
++
++ //printk(KERN_INFO"%s:\n", __FUNCTION__);
++
++ local_irq_save(flags);
++ hub_port_change_status = bus_hcpriv->rh_hcpriv->hub_port_change_status;
++ bus_hcpriv->rh_hcpriv->hub_port_change_status = 0;
++ local_irq_restore(flags);
++
++
++ change_data = (u8) hub_port_change_status & 0xff;
++ //change_data ~= ~bus_hcpriv->rh_hcpriv->otg_device_mask;
++
++ RETURN_UNLESS (change_data && (int_urb = rh_hcpriv->int_urb));
++
++ TRACE_MSG1(HCD,"non-zero change_data: %02x", change_data);
++
++ change_data |= 1; // set hub change bit XXX check
++
++ // Completing the urb will "use it up", so remove the link to it.
++
++ del_timer(&rh_hcpriv->poll_timer);
++ rh_hcpriv->int_urb = NULL;
++
++ *((u8 *)(int_urb->transfer_buffer)) = change_data;
++ int_urb->actual_length = 1;
++
++ /* Completing an INT urb will cause it to be immediately re-submitted, so this will call submit_urb()
++ */
++ hcd_rh_urb_complete(bus_hcpriv, int_urb);
++ usb_put_urb(int_urb);
++}
++/* ********************************************************************************************** */
++STATIC void poll_int_urb(unsigned long data)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) (void *) data;
++ unsigned long flags;
++
++ RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv);
++
++ local_irq_save(flags);
++ PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
++ SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
++ local_irq_restore(flags);
++}
++/* ********************************************************************************************** */
++STATIC u32 rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, u16 wIndex)
++{
++ if ((wIndex != bus_hcpriv->otg_port) || !(bus_hcpriv->rh_hcpriv->otg_device_mask))
++ return hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex);
++
++ TRACE_MSG0(HCD, "USING SHADOW INFORMATION");
++ return bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1];
++}
++
++/*
++ * hcd_rh_submit_urb()
++ * Returns: values as for the generic submit_urb() function, see comp_code_to_status(int cc).
++ */
++int hcd_rh_submit_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int mem_flags)
++{
++ struct rh_hcpriv *rh_hcpriv;
++ unsigned int pipe = urb->pipe;
++ struct usbd_device_request *req;
++ u8 bRequest;
++ u8 bmRequestType;
++ u16 wValue;
++ u16 wIndex;
++ u16 wLength;
++ u8 direction;
++ u8 recipient;
++ u8 type;
++ int rc = 0;
++ int rc_stall = -EPIPE;
++ void *reply = NULL;
++ int rlen = 0;
++ u16 status[2];
++
++ static rh_urb;
++
++ TRACE_MSG1(HCD,"pipe: %08x", pipe);
++
++
++ //printk(KERN_INFO"%s: rh_urb: %d\n", __FUNCTION__);
++ TRACE_MSG1(HCD, "rh_urb: %d", rh_urb++);
++
++ RETURN_ETIMEDOUT_UNLESS(bus_hcpriv && bus_hcpriv->rh_hcpriv);
++
++ rh_hcpriv = bus_hcpriv->rh_hcpriv;
++
++ if (usb_pipeint(pipe)) {
++ // This must be our interrupt endpoint poll.
++ TRACE_MSG1(HCD,"interrupt polling urb: %08lx",urb);
++ urb->status = 0;
++
++ // Increment the ref count, we're keeping this for a while.
++ usb_get_urb(urb);
++ if (rh_hcpriv->int_urb) {
++ // Hmm, a new one while we still have the old...Shouldn't happen, and doesn't work if it does :(.
++ //printk(KERN_INFO "%s: releasing old: %08x\n",__FUNCTION__,(u32)(void*)rh_hcpriv->int_urb);
++ del_timer(&rh_hcpriv->poll_timer);
++ usb_put_urb(rh_hcpriv->int_urb);
++ }
++
++ rh_hcpriv->int_urb = urb;
++ /* Schedule a scan for changes in case anything happened while there was no urb.
++ * This has to be slightly delayed, in case this urb is a response to a completed
++ * scan - usbcore submits a new int urb before clearing the hub/port change status,
++ * relying on the int urb polling delay to give it time to do the clearing.
++ */
++ //printk(KERN_INFO "%s: scheduling PSC poll\n",__FUNCTION__);
++ //init_poll_timer(bus_hcpriv);
++ init_timer(&rh_hcpriv->poll_timer);
++ rh_hcpriv->poll_timer.function = poll_int_urb;
++ rh_hcpriv->poll_timer.data = (unsigned long) (void *) bus_hcpriv;
++ rh_hcpriv->poll_timer.expires = jiffies +
++ ((((rh_hcpriv->int_urb->interval < 10) ? 10 : rh_hcpriv->int_urb->interval) * HZ) / 1000);
++ add_timer(&rh_hcpriv->poll_timer);
++ return rc;
++ }
++
++ TRACE_MSG1(HCD,"req: %08x",(u32)(void*)urb->setup_packet);
++ RETURN_EINVAL_UNLESS((req = (struct usbd_device_request *) urb->setup_packet))
++
++ bRequest = req->bRequest;
++ bmRequestType = req->bmRequestType;
++ wValue = le16_to_cpu(req->wValue);
++ wIndex = le16_to_cpu(req->wIndex);
++ wLength = le16_to_cpu(req->wLength);
++ direction = bmRequestType & USB_REQ_DIRECTION_MASK;
++ recipient = bmRequestType & USB_REQ_RECIPIENT_MASK;
++ type = bmRequestType & USB_REQ_TYPE_MASK;
++
++ TRACE_MSG8(HCD,"urb: %08lx req: %02x reqType: %02x val=%u ndx=%u len=%u dir: %02x recip: %02x",
++ urb,bRequest,bmRequestType, wValue,wIndex,wLength,direction,recipient);
++
++ if (USB_REQ_HOST2DEVICE == direction) {
++ /* these do not require a reply */
++ int set_flag = (USB_REQ_SET_FEATURE == bRequest);
++ TRACE_MSG0(HCD,"H->D");
++ //printk(KERN_INFO "%s: H->D\n",__FUNCTION__);
++ urb->actual_length = 0;
++ switch (recipient) {
++ case USB_RECIP_HUB:
++ switch (bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_FEATURE:
++ if (USB_REQ_TYPE_CLASS == type) {
++ TRACE_MSG2(HCD,"%s hub feature: %04x",(set_flag?"set":"clear"),wValue);
++ //printk(KERN_INFO "%s hub feature: %04x\n",(set_flag?"set":"clear"),wValue);
++ hcd_rh_hub_feature(bus_hcpriv, wValue, set_flag);
++ }
++ else {
++ TRACE_MSG2(HCD,"HUB C/S feature invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_SET_ADDRESS:
++ if (USB_REQ_TYPE_STANDARD == type) {
++ TRACE_MSG1(HCD,"set address %u",wValue);
++ //printk(KERN_INFO "set address %u\n",wValue);
++ bus_hcpriv->root_hub_addr = wValue;
++ }
++ else {
++ TRACE_MSG2(HCD,"HUB SETADDRESS invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_SET_CONFIGURATION:
++ if (USB_REQ_TYPE_STANDARD == type) {
++ TRACE_MSG1(HCD,"set configuration: %02x",wValue);
++ //printk(KERN_INFO "set configuration: %02x\n",wValue);
++ rh_hcpriv->curr_cfg = (u8) (0xFF & wValue);
++ }
++ else {
++ TRACE_MSG2(HCD,"HUB SETCONFIG invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_SET_INTERFACE:
++ // wIndex is interface number
++ if (USB_REQ_TYPE_STANDARD == type) {
++ TRACE_MSG2(HCD,"set interface: %02x to : %02x",wIndex,wValue);
++ //printk(KERN_INFO "set interface: %02x to : %02x\n",wIndex,wValue);
++ rh_hcpriv->curr_itf = (u8) (0xFF & wValue);
++ }
++ else {
++ TRACE_MSG2(HCD,"HUB SETINTERFACE invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ default:
++ TRACE_MSG2(HCD,"HUB invalid request r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_RECIP_PORT:
++ switch (bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_FEATURE:
++ // At this point wIndex == port_num is 1-origin.
++ if (USB_REQ_TYPE_CLASS == type && wIndex <= bus_hcpriv->num_ports && wIndex > 0) {
++ TRACE_MSG3(HCD,"%s port %u FEATURE: %04x",(set_flag?"set":"clear"),wIndex,wValue);
++ hcd_rh_port_feature(bus_hcpriv, wValue, wIndex, set_flag);
++ }
++ else {
++ TRACE_MSG2(HCD,"PORT C/S FEATURE invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ default:
++ TRACE_MSG2(HCD,"PORT invalid request r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_RECIPIENT_ENDPOINT:
++ // Clear stalled endpoint
++ if (USB_REQ_CLEAR_FEATURE != bRequest || 1 != wValue ||
++ USB_REQ_TYPE_STANDARD != type) { // QQSV verify type correct
++ TRACE_MSG3(HCD,"ENDPOINT invalid request,val,type r: %02x t: %02x val=%u",
++ bRequest,bmRequestType,wValue);
++ rc = rc_stall;
++ }
++ // Nothing to really do to "clear" the stalled EP.
++ TRACE_MSG2(HCD,"clear endpoint ndx: %02x val: %02x",wIndex,wValue);
++ //printk(KERN_INFO "clear endpoint ndx: %02x val: %02x\n",wIndex,wValue);
++ break;
++ case USB_REQ_RECIPIENT_INTERFACE:
++ default:
++ TRACE_MSG2(HCD,"H->D invalid recipient r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ }
++ else {
++ /* these do require a reply */
++ TRACE_MSG0(HCD,"H<-D");
++ //printk(KERN_INFO "%s: H<-D\n",__FUNCTION__);
++ switch (recipient) {
++ case USB_RECIP_HUB:
++ switch (bRequest) {
++ case USB_REQ_GET_DESCRIPTOR:
++ if (USB_REQ_TYPE_CLASS == type) {
++ // Return the hub class descriptor
++ TRACE_MSG0(HCD,"get hub class descriptor");
++ //printk(KERN_INFO "get hub class descriptor\n");
++ reply = (void *) rh_hcpriv->hd;
++ rlen = rh_hcpriv->hd->bDescLength;
++ }
++ else if (USB_REQ_TYPE_STANDARD != type) {
++ TRACE_MSG2(HCD,"HUB GETDESCRIPTOR invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ else {
++ // Return one of the other descriptors
++ switch (wValue >> 8) {
++ case USB_DT_DEVICE:
++ TRACE_MSG0(HCD,"get device descriptor");
++ //printk(KERN_INFO "get device descriptor\n");
++ reply = (void *) rh_hcpriv->dd;
++ rlen = rh_hcpriv->dd->bLength;
++ break;
++ case USB_DT_CONFIGURATION:
++ TRACE_MSG0(HCD,"get configuration descriptor");
++ reply = (void *) rh_hcpriv->cd;
++ rlen = USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE;
++ break;
++ case USB_DT_STRING:
++ TRACE_MSG1(HCD,"get string descriptor %u",wValue);
++ reply = urb->transfer_buffer;
++ rlen = hcd_rh_string(bus_hcpriv,(wValue & 0xFF),reply,wLength);
++ break;
++ default:
++ TRACE_MSG1(HCD,"HUB GETDESCRIPTOR invalid wValue: %04x",wValue);
++ rc = rc_stall;
++ }
++ }
++ break;
++ case USB_REQ_GET_STATUS:
++ if (USB_REQ_TYPE_CLASS == type) {
++ u32 change_status = bus_hcpriv->rh_hcpriv->hub_change_status;
++ status[0] = cpu_to_le16(change_status & 0xFFFF);
++ status[1] = cpu_to_le16(change_status >> 16);
++ reply = (void *) &status[0];
++ rlen = 4;
++ TRACE_MSG1(HCD,"GET HUB_CHANGE_STATUS: %08x", bus_hcpriv->rh_hcpriv->hub_change_status);
++ }
++ else {
++ TRACE_MSG2(HCD,"HUB GETSTATUS invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_GET_INTERFACE:
++ // FIXME Verify type and interface number (wIndex)
++ TRACE_MSG1(HCD,"get interface %u",wIndex);
++ reply = (void *) &rh_hcpriv->curr_itf;
++ rlen = 1;
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ // FIXME Verify type
++ TRACE_MSG0(HCD,"get configuration");
++ // Return a single byte value
++ reply = (void *) &rh_hcpriv->curr_cfg;
++ rlen = 1;
++ break;
++ default:
++ TRACE_MSG2(HCD,"H<-D HUB invalid request r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_RECIP_PORT:
++ switch (bRequest) {
++ case USB_REQ_GET_STATUS:
++ if (USB_REQ_TYPE_CLASS == type) {
++ /* USB2.0 11.24.2.7 pg 426 says first hword of reply are status (Tbl 11-21),
++ second hword is change (Tbl 11-22). */
++ u32 change_status = ((wIndex -1) < bus_hcpriv->num_ports) ?
++ bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1] : 0;
++ u32 hw_change_status = ((wIndex -1) < bus_hcpriv->num_ports) ?
++ rh_get_port_change_status(bus_hcpriv, wIndex) : 0;
++
++ check_port_status(bus_hcpriv, wIndex, "HOST POLL");
++
++ status[0] = cpu_to_le16(hw_change_status & 0xFFFF);
++ status[1] = cpu_to_le16(change_status >> 16);
++ reply = (void *) &status[0];
++ rlen = 4;
++
++ TRACE_MSG3(HCD,"GET PORT_CHANGE_STATUS[%2d] %04x %04x", wIndex, status[0], status[1]);
++ }
++ else {
++ TRACE_MSG2(HCD,"PORT GETSTATUS invalid type r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ default:
++ TRACE_MSG2(HCD,"H<-D PORT invalid request r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ break;
++ case USB_REQ_RECIPIENT_INTERFACE:
++ case USB_REQ_RECIPIENT_ENDPOINT:
++ default:
++ TRACE_MSG2(HCD,"H<-D invalid recipient r: %02x t: %02x",bRequest,bmRequestType);
++ rc = rc_stall;
++ }
++ if (!rc && reply) {
++ // There is a reply to copy into place.
++ if (rlen > wLength) {
++ // Truncate the reply (used to get part of a descriptor).
++ rlen = wLength;
++ }
++ if (rlen > 0 && reply != urb->transfer_buffer) {
++ memcpy(urb->transfer_buffer,reply,rlen);
++ }
++ urb->actual_length = rlen;
++ }
++ }
++ // All done, "complete" it.
++ urb->status = rc;
++ TRACE_MSG3(HCD,"urb: %08lx completing status=%d len=%d",urb,urb->status,urb->actual_length);
++ hcd_rh_urb_complete(bus_hcpriv,urb);
++ TRACE_MSG2(HCD,"urb: %08lx completed->%d",urb,rc);
++ return rc;
++}
++
++/*
++ * hcd_rh_unlink_urb()
++ */
++int hcd_rh_unlink_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb)
++{
++ struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
++ RETURN_EINVAL_UNLESS(urb && (urb == rh_hcpriv->int_urb));
++ del_timer(&rh_hcpriv->poll_timer);
++ rh_hcpriv->int_urb = NULL;
++ urb->status = -ENOENT; // Cancelled
++ hcd_rh_urb_complete(bus_hcpriv,urb);
++ usb_put_urb(urb);
++ return 0;
++}
++/* ********************************************************************************************** */
++/*
++ * For the hardware specific root hub component.
++ */
++irqreturn_t hcd_rh_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) dev_id;
++
++ // Assume port status change.
++ //printk(KERN_INFO "%s: scheduling hcd_rh_portstatus_bh\n",__FUNCTION__);
++
++ PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
++ SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
++ return IRQ_HANDLED;
++}
++/* ********************************************************************************************** */
++#if !defined(OTG_C99)
++struct usbd_device_descriptor rh_device_descriptor;
++struct usbd_configuration_descriptor rh_configuration_descriptor;
++struct usbd_interface_descriptor rh_interface_descriptor;
++struct usbd_endpoint_descriptor rh_endpoint_descriptor;
++struct hub_descriptor rh_hub_descriptor;
++
++void rh_global_init(void)
++{
++ ZERO(rh_device_descriptor);
++ rh_device_descriptor.bLength = USB_DT_DEVICE_SIZE;
++ rh_device_descriptor.bDescriptorType = USB_DT_DEVICE;
++ rh_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
++ rh_device_descriptor.bDeviceClass = USB_CLASS_HUB;
++ rh_device_descriptor.bDeviceSubClass = 0;
++ rh_device_descriptor.bDeviceProtocol = 0;
++ rh_device_descriptor.bMaxPacketSize0 = 8;
++ rh_device_descriptor.iManufacturer = XHC_RH_STRING_MANUFACTURER;
++ rh_device_descriptor.iProduct = XHC_RH_STRING_PRODUCT;
++ rh_device_descriptor.iSerialNumber = XHC_RH_STRING_SERIAL;
++ rh_device_descriptor.bNumConfigurations = 1;
++
++ ZERO(rh_configuration_descriptor);
++ rh_configuration_descriptor.bLength = USB_DT_CONFIG_SIZE;
++ rh_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
++ rh_configuration_descriptor.wTotalLength = __constant_cpu_to_le16(USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE
++ + USB_DT_ENDPOINT_SIZE);
++ rh_configuration_descriptor.bNumInterfaces = 1;
++ rh_configuration_descriptor.bConfigurationValue = 1;
++ rh_configuration_descriptor.iConfiguration = XHC_RH_STRING_CONFIGURATION;
++
++ ZERO(rh_interface_descriptor);
++ rh_interface_descriptor.bLength = USB_DT_INTERFACE_SIZE;
++ rh_interface_descriptor.bDescriptorType = USB_DT_INTERFACE;
++ rh_interface_descriptor.bInterfaceNumber = 0;
++ rh_interface_descriptor.bAlternateSetting = 0;
++ rh_interface_descriptor.bNumEndpoints = 1;
++ rh_interface_descriptor.bInterfaceClass = USB_CLASS_HUB;
++ rh_interface_descriptor.bInterfaceSubClass = 0;
++ rh_interface_descriptor.bInterfaceProtocol = 0;
++ rh_interface_descriptor.iInterface = XHC_RH_STRING_INTERFACE;
++
++ ZERO(rh_endpoint_descriptor);
++ rh_endpoint_descriptor.bLength = USB_DT_ENDPOINT_SIZE;
++ rh_endpoint_descriptor.bDescriptorType = USB_DT_ENDPOINT;
++ rh_endpoint_descriptor.bEndpointAddress = USB_DIR_IN | 1; // Fixed EP 1
++ rh_endpoint_descriptor.bmAttributes = INTERRUPT;
++ rh_endpoint_descriptor.wMaxPacketSize = __constant_cpu_to_le16(4);
++ rh_endpoint_descriptor.bInterval = 0xFF;
++
++ ZERO(rh_hub_descriptor);
++ rh_hub_descriptor.bDescLength = USB_DT_HUB_NONVAR_SIZE+2;
++ rh_hub_descriptor.bDescriptorType = USB_DT_HUB;
++};
++
++#else /* !defined(OTG_C99) */
++struct usbd_device_descriptor rh_device_descriptor = {
++ .bLength = USB_DT_DEVICE_SIZE,
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
++ .bDeviceClass = USB_CLASS_HUB,
++ .bDeviceSubClass = 0,
++ .bDeviceProtocol = 0,
++ .bMaxPacketSize0 = 8,
++ .iManufacturer = XHC_RH_STRING_MANUFACTURER,
++ .iProduct = XHC_RH_STRING_PRODUCT,
++ .iSerialNumber = XHC_RH_STRING_SERIAL,
++ .bNumConfigurations = 1,
++};
++
++struct usbd_configuration_descriptor rh_configuration_descriptor = {
++ .bLength = USB_DT_CONFIG_SIZE,
++ .bDescriptorType = USB_DT_CONFIGURATION,
++ .wTotalLength = __constant_cpu_to_le16(USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE),
++ .bNumInterfaces = 1,
++ .bConfigurationValue = 1,
++ .iConfiguration = XHC_RH_STRING_CONFIGURATION,
++};
++
++struct usbd_interface_descriptor rh_interface_descriptor = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0,
++ .bAlternateSetting = 0,
++ .bNumEndpoints = 1,
++ .bInterfaceClass = USB_CLASS_HUB,
++ .bInterfaceSubClass = 0,
++ .bInterfaceProtocol = 0,
++ .iInterface = XHC_RH_STRING_INTERFACE,
++};
++
++struct usbd_endpoint_descriptor rh_endpoint_descriptor = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN | 1, // Fixed EP 1
++ .bmAttributes = INTERRUPT,
++ .wMaxPacketSize = __constant_cpu_to_le16(4),
++ .bInterval = 0xFF,
++};
++
++/* This assumes 1-8 ports.
++ * If ports > 8, then DeviceRemovable and PortPwrCtrlMask need to be sized accordingly.
++ */
++struct hub_descriptor rh_hub_descriptor = {
++ .bDescLength = USB_DT_HUB_NONVAR_SIZE+2,
++ .bDescriptorType = USB_DT_HUB,
++};
++#endif /* !defined(OTG_C99) */
++
++/* ********************************************************************************************** */
++/*
++ * Copy static descriptors to buffer to allow modification for actual
++ * configuration and provide full configuration descriptor.
++ */
++STATIC void build_descriptors(struct bus_hcpriv *bus_hcpriv)
++{
++ struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
++ void *bp = rh_hcpriv->descriptors;
++
++
++ rh_hcpriv->dd = (struct usbd_device_descriptor *) bp;
++ memcpy(bp, &rh_device_descriptor, sizeof(rh_device_descriptor));
++ rh_hcpriv->cd = (struct usbd_configuration_descriptor *) bp = bp + USB_DT_DEVICE_SIZE;
++ memcpy(bp, &rh_configuration_descriptor, sizeof(rh_configuration_descriptor));
++ rh_hcpriv->id = (struct usbd_interface_descriptor *) bp = bp + USB_DT_CONFIG_SIZE;
++ memcpy(bp, &rh_interface_descriptor, sizeof(rh_interface_descriptor));
++ rh_hcpriv->ed = (struct usbd_endpoint_descriptor *) bp = bp + USB_DT_INTERFACE_SIZE;
++ memcpy(bp, &rh_endpoint_descriptor, sizeof(rh_endpoint_descriptor));
++ rh_hcpriv->hd = (struct hub_descriptor *) bp = bp + USB_DT_ENDPOINT_SIZE;
++ memcpy(bp, &rh_hub_descriptor, sizeof(rh_hub_descriptor));
++
++ rh_hcpriv->dd->idVendor = cpu_to_le16(bus_hcpriv->rh_vendorid);
++ rh_hcpriv->dd->idProduct = cpu_to_le16(bus_hcpriv->rh_productid);
++ rh_hcpriv->dd->bcdDevice = cpu_to_le16(bus_hcpriv->rh_bcddevice);
++ rh_hcpriv->cd->bmAttributes = bus_hcpriv->rh_bmAttributes;
++ rh_hcpriv->cd->bMaxPower = bus_hcpriv->rh_bMaxPower;
++ rh_hcpriv->hd->bNbrPorts = bus_hcpriv->num_ports,
++ rh_hcpriv->hd->wHubCharacteristics = cpu_to_le16(hcd_hw_rh_hub_attributes(bus_hcpriv));
++ rh_hcpriv->hd->bPwrOn2PwrGood = hcd_hw_rh_power_delay(bus_hcpriv);
++ rh_hcpriv->hd->bHubContrCurrent = hcd_hw_rh_hub_contr_current(bus_hcpriv);
++ rh_hcpriv->hd->DeviceRemovable = hcd_hw_rh_DeviceRemovable(bus_hcpriv);
++ rh_hcpriv->hd->PortPwrCtrlMask = hcd_hw_rh_PortPwrCtrlMask(bus_hcpriv);
++}
++
++/* ********************************************************************************************** */
++
++#define PORT_SYNC_MASK ( (1 << PORT_POWER) | (1 << PORT_SUSPEND) | (1 << PORT_RESET) )
++
++/* puts OTG capable port into a_host or b_host state - attempt to use port */
++void rh_loc_sof_func(struct otg_instance *otg, u8 on)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
++ int i;
++ unsigned long flags;
++
++ RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv && bus_hcpriv->rh_hcpriv->port_change_status);
++
++ local_irq_save(flags);
++ switch (on) {
++ case SET:
++ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ TRACE_MSG0(HCD, "RH LOC_SOF SET");
++
++ // Stop treating otg capable port as a device
++ bus_hcpriv->rh_hcpriv->otg_device_mask &= ~(0x1 << (bus_hcpriv->otg_port));
++
++ /* Sync the state of the HW to the shadow values, because
++ * the root hub was registered with usbcore a while back, and
++ * at the very least it probably tried to turn on the power,
++ * and until now, the otg_device_mask was preventing that.
++ */
++ for (i = 0; i < 16; i++) {
++
++ if (PORT_SYNC_MASK & (0x1 << i) & bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]) {
++ hcd_hw_rh_port_feature(bus_hcpriv, i, bus_hcpriv->otg_port, TRUE);
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "OTG EN");
++ }
++ }
++
++ /* "Connect" on OTG port and simulate a port status change interrupt
++ */
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00010001;
++ TRACE_MSG2(HCD, "OUTPUT: RH LOC_SOF_SET port_change_status[%d]: %08x",
++ bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF SET");
++ break;
++
++ case RESET:
++ //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
++ TRACE_MSG0(HCD, "RH LOC_SOF RESET");
++
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - BEFORE");
++
++ // "Disconnect" on OTG port and simulate a port status change interrupt
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] &= ~0x00000001;
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00010000;
++ TRACE_MSG2(HCD, "OUTPUT: RH LOC_SOF_RESET port_change_status[%d]: %08x",
++ bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
++
++
++ // Turn off port power.
++ hcd_hw_rh_port_feature(bus_hcpriv, PORT_POWER, bus_hcpriv->otg_port, FALSE);
++ //hcd_hw_rh_port_feature(bus_hcpriv, PORT_ENABLE, bus_hcpriv->otg_port, FALSE);
++
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - AFTER");
++
++ // Start treating otg capable port as a device
++ bus_hcpriv->rh_hcpriv->otg_device_mask |= (0x1 << (bus_hcpriv->otg_port));
++ break;
++ }
++
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << bus_hcpriv->otg_port);
++ TRACE_MSG0(HCD, "Schedule hcd_rh_portstatus_bh");
++ PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
++ SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
++ local_irq_restore(flags);
++}
++
++/* puts OTG capable port into a_host or b_host state - attempt to use port */
++void rh_loc_suspend_func(struct otg_instance *otg, u8 on)
++{
++ struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
++ struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
++ int i;
++ unsigned long flags;
++
++ //printk(KERN_INFO"%s: \n", __FUNCTION__);
++ RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv && bus_hcpriv->rh_hcpriv->port_change_status);
++
++ local_irq_save(flags);
++ switch (on) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: RH LOC_SUSPEND SET");
++
++ rh_hcpriv->suspended = 1;
++
++ // suspend
++ hcd_hw_rh_port_feature(bus_hcpriv, PORT_SUSPEND, bus_hcpriv->otg_port, TRUE);
++
++ // "Connect" on OTG port and simulate a port status change interrupt
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00040004;
++ TRACE_MSG2(HCD, "OUTPUT: RH LOC_SUSPNED_SET port_change_status[%d]: %08x",
++ bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "LOC_SUSPEND SET");
++ break;
++
++ case RESET:
++
++ TRACE_MSG0(HCD, "OUTPUT: RH LOC_SUSPEND RESET");
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "LOC_SUSPEND RESET - BEFORE");
++
++ // "Disconnect" on OTG port and simulate a port status change interrupt
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] &= ~0x00000004;
++ bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00040000;
++ TRACE_MSG2(HCD, "OUTPUT: RH LOC_SUSPEND port_change_status[%d]: %08x",
++ bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
++
++
++ // suspend
++ hcd_hw_rh_port_feature(bus_hcpriv, PORT_SUSPEND, bus_hcpriv->otg_port, FALSE);
++ check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - AFTER");
++
++ rh_hcpriv->suspended = 0;
++
++ break;
++ }
++
++ bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << bus_hcpriv->otg_port);
++ TRACE_MSG0(HCD, "Schedule hcd_rh_portstatus_bh");
++ PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
++ SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
++ local_irq_restore(flags);
++}
++
++void rh_suspend_func(struct otg_instance *otg, u8 flag)
++{
++ /* suspends the OTG capable port */
++ //TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
++ TRACE_MSG0(HCD, "OUTPUT: RH SUSPEND_SET");
++ break;
++ case RESET:
++ //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
++ TRACE_MSG0(HCD, "OUTPUT: RH SUSPEND_RESET");
++ break;
++ }
++}
++
++/* ********************************************************************************************* */
++
++int hcd_rh_init(struct bus_hcpriv *bus_hcpriv)
++{
++ struct rh_hcpriv *rh_hcpriv;
++ int wIndex;
++ int port_mask;
++
++ #if !defined(OTG_C99)
++ rh_global_init();
++ #endif /* !defined(OTG_C99) */
++
++ //printk(KERN_INFO"%s: \n", __FUNCTION__);
++ RETURN_ZERO_UNLESS (bus_hcpriv);
++ RETURN_ENOMEM_UNLESS ((rh_hcpriv = bus_hcpriv->rh_hcpriv =
++ (struct rh_hcpriv *) kmalloc(sizeof(struct rh_hcpriv),GFP_KERNEL)));
++ memset(rh_hcpriv, 0, sizeof(struct rh_hcpriv));
++
++ //printk(KERN_INFO "%s: rh_hcpriv: %08x\n",__FUNCTION__,(u32)(void*)rh_hcpriv);
++ //init_timer(&rh_hcpriv->poll_timer);
++ // Get the number of ports, and which port is OTG capable.
++
++ //rh_hcpriv->num_ports = hcd_hw_rh_num_ports(bus_hcpriv);
++
++ // Allocate the shadow port_change_status array.
++ UNLESS ((rh_hcpriv->port_change_status = (u32 *) kmalloc((bus_hcpriv->num_ports*sizeof(u32)),GFP_KERNEL))) {
++ //printk(KERN_ERR "%s: allocation of root hub shadow port data fails\n",__FUNCTION__);
++ kfree(rh_hcpriv);
++ bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
++ return -ENOMEM;
++ }
++ memset(rh_hcpriv->port_change_status,0,(bus_hcpriv->num_ports*sizeof(u32)));
++ UNLESS ((rh_hcpriv->dev = usb_alloc_dev(NULL, bus_hcpriv->usb_bus, 0))) {
++ //printk(KERN_ERR "%s: allocation of root hub dev fails\n",__FUNCTION__);
++ kfree(rh_hcpriv->port_change_status);
++ rh_hcpriv->port_change_status = NULL;
++ kfree(rh_hcpriv);
++ bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
++ return -ENOMEM;
++ }
++ rh_hcpriv->dev->speed = USB_SPEED_FULL; // QQSV --- this belongs in the HW dependent portion...
++
++ // Build up USB descriptors
++ build_descriptors(bus_hcpriv);
++
++ // Leave OTG capable port as disabled as possible until OTG core enables it.
++ rh_hcpriv->otg_device_mask = bus_hcpriv->otg_capable_mask;
++
++ for (wIndex = 1; wIndex <= bus_hcpriv->num_ports; wIndex++) {
++ port_mask = (1 << (wIndex - 1));
++ if (port_mask & bus_hcpriv->otg_capable_mask)
++ TRACE_MSG1(HCD,"OTG capable port %d", wIndex);
++ else
++ TRACE_MSG1(HCD,"Standard port %d", wIndex);
++ }
++ return 0;
++}
++
++void hcd_rh_exit(struct bus_hcpriv *bus_hcpriv)
++{
++ struct rh_hcpriv *rh_hcpriv;
++ RETURN_UNLESS(bus_hcpriv && (rh_hcpriv = bus_hcpriv->rh_hcpriv));
++
++ (void *) hcd_rh_unlink_urb(bus_hcpriv,rh_hcpriv->int_urb);
++
++ if (rh_hcpriv->dev) {
++ usb_put_dev(rh_hcpriv->dev);
++ rh_hcpriv->dev = NULL;
++ }
++ if (rh_hcpriv->port_change_status) {
++ kfree(rh_hcpriv->port_change_status);
++ rh_hcpriv->port_change_status = NULL;
++ }
++ kfree(rh_hcpriv);
++ bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
++}
++
+diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd.c linux/drivers/otg/ocd/otg-hcd/hcd.c
+--- linux/drivers/no-otg/ocd/otg-hcd/hcd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-hcd/hcd.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,139 @@
++/*
++ * otg/ocd/otg-hcd/hcd.c - OTG Host Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ * Notes
++ *
++ * 1. The usbd-bi layer has be re-implemented to re-factor the UDC layer in a way to
++ * simplify implementation of UDC drivers. As much of the complexity of dealing with the middle
++ * layers and buffer (urb) handling is provided for in the common bi layer.
++ *
++ * 2. TODO The udc interface will be further modified to allow the UDC to export a block of
++ * function pointers for the common bi layer to use. This will allow the common layer to
++ * implement default operations where the UDC does not provide an function. For example many UDC
++ * drivers do not provide full support for cable detection and usb pullup control. If these
++ * routines are not provided the common layer will supply defaults. This eliminates a reasonably
++ * larger amount of effectively unused code from many of the udc drivers.
++ *
++ */
++/*!
++ * @file otg/ocd/otg-hcd/hcd.c
++ * @brief Root Hub for Generic Host Controller Driver
++ *
++ *
++ * This file initializes the low level hardware drivers.
++ *
++ * This is the linux 2.4 version.
++ *
++ * @ingroup OTGHCD
++ */
++
++#include <otg/otg-compat.h>
++
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++
++/* ************************************************************************************* */
++
++void hcd_en_func (struct otg_instance *otg, u8 flag)
++{
++ //struct hcd_instance *hcd = otg->hcd;
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_EN_SET");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_EN_RESET");
++ break;
++ }
++}
++
++void hcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ struct hcd_instance *hcd = otg->hcd;
++
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_INIT_SET");
++ otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_INIT_RESET");
++ otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
++ break;
++ }
++}
++
++/* ************************************************************************************* */
++
++void hcd_loc_sof_func (struct otg_instance *otg, u8 flag)
++{
++ //struct hcd_instance *hcd = otg->hcd;
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_LOC_SOF_SET");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_LOC_SOF_RESET");
++ break;
++ }
++}
++
++void hcd_suspend_func (struct otg_instance *otg, u8 flag)
++{
++ //struct hcd_instance *hcd = otg->hcd;
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_SUSPEND_EN_SET");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_SUSPEND_EN_RESET");
++ break;
++ }
++}
++
++void hcd_remote_wakeup_en_func (struct otg_instance *otg, u8 flag)
++{
++ //struct hcd_instance *hcd = otg->hcd;
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_REMOTE_WAKEUP_EN_SET");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_REMOTE_WAKEUP_EN_RESET");
++ break;
++ }
++}
++
++void hcd_hnp_en_func (struct otg_instance *otg, u8 flag)
++{
++ //struct hcd_instance *hcd = otg->hcd;
++ TRACE_MSG0(HCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_HNP_EN_SET");
++ break;
++ case RESET:
++ TRACE_MSG0(HCD, "OUTPUT: HCD_HNP_EN_RESET");
++ break;
++ }
++}
++
++
+diff -uNr linux/drivers/no-otg/ocd/otg-i2c/i2c-l26.c linux/drivers/otg/ocd/otg-i2c/i2c-l26.c
+--- linux/drivers/no-otg/ocd/otg-i2c/i2c-l26.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-i2c/i2c-l26.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,160 @@
++/*
++ * otg/ocd/otg-i2c/i2c-l26.c -- Linux 2.6 I2C access
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-i2c/i2c-l26.c
++ * @brief Linux I2C I/O via generic i2c device.
++ *
++ * @ingroup ISP1301TCD
++ */
++
++#include <otg/otg-compat.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <linux/i2c.h>
++
++#include <otg/pcd-include.h>
++#include <linux/pci.h>
++#include <otghw/isp1301-hardware.h>
++#include "isp1301.h"
++
++/* ********************************************************************************************* */
++
++/*
++ * N.B. i2c functions must not be called from interrupt handlers
++ */
++
++static struct file *i2c_file;
++static struct i2c_client *omap_i2c_client;
++static int initstate_i2c;
++static int initstate_region;
++#define MAX_I2C 16
++
++#ifdef CONFIG_OMAP_H2
++#define ADAPTOR_NAME "OMAP I2C"
++#endif /* CONFIG_OMAP_H2 */
++#ifdef CONFIG_ARCH_MAINSTONE
++#define ADAPTOR_NAME "PXA-I2C-Adapter"
++#endif /* CONFIG_ARCH_MAINSTONE */
++
++/*! i2c_configure
++ * Attempt to find and open generic i2c device
++ * @return - non-zero for failure
++ */
++int i2c_configure(char *name, int addr)
++{
++ char filename[20];
++ int tmp;
++
++ RETURN_ZERO_IF(initstate_i2c);
++
++ /*find the I2C driver we need
++ */
++ for (tmp = 0; tmp < MAX_I2C; tmp++) {
++
++ sprintf(filename, "/dev/i2c/%d", tmp);
++
++ printk(KERN_INFO"%s: %s\n", __FUNCTION__, filename);
++
++ UNLESS (IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {
++
++ //printk(KERN_INFO"%s: %s found\n", __FUNCTION__, filename);
++
++ /*found some driver */
++ omap_i2c_client = (struct i2c_client *)i2c_file->private_data;
++
++ printk(KERN_INFO"%s: found %s\n", __FUNCTION__, omap_i2c_client->adapter->name);
++ if (strlen(omap_i2c_client->adapter->name) >= 8) {
++ if (!strncmp(omap_i2c_client->adapter->name, name, strlen(name)))
++ break; /*we found our driver! */
++ }
++ omap_i2c_client = NULL;
++ filp_close(i2c_file, NULL);
++ }
++ printk(KERN_INFO"%s: %s %d\n", __FUNCTION__, filename, i2c_file);
++ }
++ if (tmp == MAX_I2C) { // Nothing found
++ printk(KERN_ERR"%s: cannot find I2C driver", __FUNCTION__);
++ return -ENODEV;
++ }
++ omap_i2c_client->addr = addr;
++ initstate_i2c = 1;
++ return 0;
++}
++
++/*! i2c_close
++ * Close i2c device fd.
++ */
++void i2c_close(void)
++{
++ if (initstate_i2c)
++ filp_close(i2c_file, NULL);
++ initstate_i2c = 0;
++}
++
++/*! i2c_readb
++ * Read byte from i2c device
++ * @param subaddr
++ */
++u8 i2c_readb(u8 subaddr)
++{
++ u8 buf = 0;
++ i2c_master_send(omap_i2c_client, &subaddr, 1);
++ i2c_master_recv(omap_i2c_client, &buf, 1);
++ TRACE_MSG2(TCD, "addr: %02x buf: %02x", subaddr, buf);
++ return buf;
++}
++
++/*! i2c_readw
++ * Read word from i2c device
++ * @param subaddr
++ */
++u16 i2c_readw(u8 subaddr)
++{
++ u16 buf = 0;
++ i2c_master_send(omap_i2c_client, &subaddr, 1);
++ i2c_master_recv(omap_i2c_client, (u8 *)&buf, 2);
++ TRACE_MSG2(TCD, "addr: %02x buf: %04x", subaddr, buf);
++ return buf;
++}
++
++/*! i2c_readl
++ * Read long from i2c device
++ * @param subaddr
++ */
++u32 i2c_readl(u8 subaddr)
++{
++ u32 buf = 0;
++ i2c_master_send(omap_i2c_client, &subaddr, 1);
++ i2c_master_recv(omap_i2c_client, (u8 *)&buf, 4);
++ TRACE_MSG2(TCD, "addr: %02x buf: %08x", subaddr, buf);
++ return buf;
++}
++
++
++/*! i2c_writeb
++ * Writw byte to i2c device
++ * @param subaddr
++ * @param buf
++ */
++int i2c_writeb(u8 subaddr, u8 buf)
++{
++ char tmpbuf[2];
++
++ tmpbuf[0] = subaddr; /*register number */
++ tmpbuf[1] = buf; /*register data */
++ i2c_master_send(omap_i2c_client, &tmpbuf[0], 2);
++
++ return 0;
++}
++
+diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd-init-l24.c linux/drivers/otg/ocd/otg-pcd/pcd-init-l24.c
+--- linux/drivers/no-otg/ocd/otg-pcd/pcd-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-pcd/pcd-init-l24.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,119 @@
++/*
++ * otg/ocd/otg-pcd/pcd-init-l24.c - OTG Peripheral Controller Driver Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-pcd/pcd-init-l24.c
++ * @brief PCD only driver init.
++ *
++ *
++ * PCD Initialization
++ *
++ * This file initializes all of the low level hardware drivers for a PCD.
++ *
++ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
++ * USBD stack to send and receive data from the USB actings as a USB
++ * peripheral.
++ *
++ * Notes
++ *
++ * 1. This is the linux 2.4 version.
++ *
++ * TODO
++ *
++ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
++ *
++ *
++ * @ingroup OTGPCD
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-module.h>
++#include <otg/usbp-bus.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
++MODULE_LICENSE ("GPL");
++#endif
++MODULE_PARM (serial_number_str, "s");
++MODULE_PARM_DESC (serial_number_str, "Serial Number");
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_DESCRIPTION ("USB On-The-Go PCD");
++#endif
++char *serial_number_str;
++
++otg_tag_t PCD;
++struct pcd_instance *pcd_instance;
++
++/* ************************************************************************************* */
++
++/* pcd_modexit - module exit or init failure cleanup
++ *
++ * Specifically for each driver:
++ *
++ * call ops.mod_exit
++ * reset instance address and ops table address in state machine to NULL
++ * invalidate tag
++ */
++static void pcd_modexit (void)
++{
++ struct otg_instance *otg = ocd_instance->otg;
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++ if (otg)
++ otg_exit(otg);
++ if (pcd_ops.mod_exit) pcd_ops.mod_exit();
++ pcd_instance = otg_set_pcd_ops(NULL);
++ PCD = otg_trace_invalidate_tag(PCD);
++}
++
++/* pcd_modinit - linux module initialization
++ *
++ * This needs to initialize the ocd, pcd and tcd drivers.
++ *
++ * Specifically for each driver:
++ *
++ * obtain tag
++ * pass ops table address to state machine and get instance address
++ * call ops.mod_init
++ *
++ * Note that we automatically provide a default tcd_init if
++ * none is set.
++ */
++static int pcd_modinit (void)
++{
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ #if !defined(OTG_C99)
++ pcd_global_init();
++ #endif /* !defined(OTG_C99) */
++
++ PCD = otg_trace_obtain_tag();
++
++ UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
++ THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
++ THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
++
++ CATCH(error) {
++ pcd_modexit();
++ return -EINVAL;
++ }
++ return 0;
++}
++MOD_EXIT(pcd_modexit);
++MOD_INIT(pcd_modinit);
+diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd-ocd-init-l24.c linux/drivers/otg/ocd/otg-pcd/pcd-ocd-init-l24.c
+--- linux/drivers/no-otg/ocd/otg-pcd/pcd-ocd-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-pcd/pcd-ocd-init-l24.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,141 @@
++/*
++ * otg/pcd/pcd-ocd-init-l24.c - OTG Peripheral and OTG Controller Drivers Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-pcd/pcd-ocd-init-l24.c
++ * @brief PCD only driver init.
++ *
++ *
++ * PCD/OCD Initialization
++ *
++ * This file initializes all of the low level hardware drivers for a combined
++ * PCD/OCD module. It does not initialize the TCD module.
++ *
++ * USB Periphirals using this must implement the following:
++ *
++ * ocd_ops operations from ocd driver
++ * pcd_ops operations from pcd driver
++ *
++ * The OTG Controller driver (ocd) implements any required OTG timers and if
++ * necessary mediates access to and initializes the OTG and/or USB hardware.
++ *
++ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
++ * USBD stack to send and receive data from the USB actings as a USB
++ * peripheral.
++ *
++ * Notes
++ *
++ * 1. This is the linux 2.4 version.
++ *
++ * TODO
++ *
++ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
++ *
++ * @ingroup OTGPCD
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
++MODULE_LICENSE ("GPL");
++#endif
++MODULE_PARM (serial_number_str, "s");
++MODULE_PARM_DESC (serial_number_str, "Serial Number");
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_DESCRIPTION ("USB On-The-Go PCD");
++#endif
++char *serial_number_str;
++
++otg_tag_t PCD;
++struct pcd_instance *pcd_instance;
++otg_tag_t OCD;
++struct ocd_instance *ocd_instance;
++
++
++/* ************************************************************************************* */
++
++/* pcd_ocd_modexit - module exit or init failure cleanup
++ *
++ * Specifically for each driver:
++ *
++ * call ops.mod_exit
++ * reset instance address and ops table address in state machine to NULL
++ * invalidate tag
++ */
++static void pcd_ocd_modexit (void)
++{
++ struct otg_instance *otg = ocd_instance->otg;
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++ if (otg)
++ otg_exit(otg);
++
++ if (pcd_ops.mod_exit) pcd_ops.mod_exit();
++ pcd_instance = otg_set_pcd_ops(NULL);
++ PCD = otg_trace_invalidate_tag(PCD);
++
++ if (ocd_ops.mod_exit) ocd_ops.mod_exit();
++ ocd_instance = otg_set_ocd_ops(NULL);
++ OCD = otg_trace_invalidate_tag(OCD);
++}
++
++/* pcd_ocd_modinit - linux module initialization
++ *
++ * This needs to initialize the ocd, pcd and tcd drivers.
++ *
++ * Specifically for each driver:
++ *
++ * obtain tag
++ * pass ops table address to state machine and get instance address
++ * call ops.mod_init
++ *
++ * Note that we automatically provide a default tcd_init if
++ * none is set.
++ */
++static int pcd_ocd_modinit (void)
++{
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ #if !defined(OTG_C99)
++ pcd_global_init();
++ #endif /* !defined(OTG_C99) */
++
++ UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
++ PCD = otg_trace_obtain_tag();
++ THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
++ THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
++
++ OCD = otg_trace_obtain_tag();
++ THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
++ THROW_IF((ocd_ops.mod_init) ? ocd_ops.mod_init() : 0, error);
++
++ CATCH(error) {
++ pcd_ocd_modexit();
++ return -EINVAL;
++ }
++ return 0;
++}
++
++MOD_EXIT (pcd_ocd_modexit);
++MOD_INIT (pcd_ocd_modinit);
++
++
+diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd.c linux/drivers/otg/ocd/otg-pcd/pcd.c
+--- linux/drivers/no-otg/ocd/otg-pcd/pcd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-pcd/pcd.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,845 @@
++/*
++ * otg/ocd/otg-pcd/pcd.c - OTG Peripheral Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-pcd/pcd.c
++ * @brief PCD only driver init.
++ * Notes
++ *
++ * 1. The pcd file abstracts much of the UDC complexity as possible and
++ * provides a common implementation that is shared to various extents by the
++ * various pcd drivers.
++ *
++ * @ingroup OTGPCD
++ */
++
++#include <otg/pcd-include.h>
++#include <asm/au1000.h>
++
++
++extern char *serial_number_str;
++
++/* ******************************************************************************************* */
++/*! bus_request_endpoints
++ */
++int bus_request_endpoints(struct usbd_bus_instance *bus, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested,
++ struct usbd_endpoint_request *requestedEndpoints)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ int i;
++ TRACE_MSG0(PCD, "BUS_REQUEST ENDPOINTS:");
++ if (usbd_pcd_ops.request_endpoints(pcd, endpoint_map_array, endpointsRequested, requestedEndpoints)) {
++ printk(KERN_INFO"%s: failed\n", __FUNCTION__);
++ return -EINVAL;
++ }
++ for (i = 0; i < endpointsRequested; i++) {
++ struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
++ TRACE_MSG4(PCD, "address: %02x physical: %02x request: %02x size: %04x",
++ endpoint_map->bEndpointAddress[0], endpoint_map->physicalEndpoint[0],
++ endpoint_map->bmAttributes[0], endpoint_map->wMaxPacketSize[0]);
++ }
++ return 0;
++}
++
++/*! bus_set_endpoints
++ */
++int bus_set_endpoints(struct usbd_bus_instance *bus, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ TRACE_MSG0(PCD, "SET ENDPOINTS");
++ return usbd_pcd_ops.set_endpoints ? usbd_pcd_ops.set_endpoints(pcd, endpointsRequested, endpoint_map_array) : 0;
++}
++
++/*! bus_set_address
++ */
++int bus_set_address(struct usbd_bus_instance *bus, int address)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ if (usbd_pcd_ops.set_address) usbd_pcd_ops.set_address (pcd, address);
++ return 0;
++}
++
++/* ******************************************************************************************* */
++
++/*! pcd_search_endpoint_index - find endpoint map index given endpoint address
++ */
++int pcd_search_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress)
++{
++ int i;
++ for (i = 0; i < bus->endpoints; i++)
++ BREAK_IF (bus->endpoint_array[i].bEndpointAddress == bEndpointAddress);
++ return i;
++}
++
++/*! pcd_search_endpoint - find endpoint given endpoint address
++ */
++struct usbd_endpoint_instance * pcd_search_endpoint(struct usbd_bus_instance *bus, int bEndpointAddress)
++{
++ int i = pcd_search_endpoint_index(bus, bEndpointAddress);
++ TRACE_MSG2(PCD, "BUS_SEARCH ENDPOINT: addr: %02x index: %d", bEndpointAddress, i);
++ RETURN_NULL_UNLESS(i < bus->endpoints);
++ return &(bus->endpoint_array[i]);
++}
++
++/*! bus_endpoint_halted - check if endpoint halted
++ * Used by the USB Device Core to check endpoint halt status.
++ *
++ * Return actual halted status if available or'd with endpoint->feature_setting set value.
++ * Assume not halted if udc driver does not provide an endpoint halted function.
++ */
++int bus_endpoint_halted (struct usbd_bus_instance *bus, int bEndpointAddress)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ int endpoint_index = pcd_search_endpoint_index(bus, bEndpointAddress);
++ struct usbd_endpoint_instance *endpoint = pcd_search_endpoint(bus, bEndpointAddress);
++ int halted;
++
++ TRACE_MSG1(PCD, "BUS_ENDPOINT HALTED: endpoint: %p", (int) endpoint);
++ RETURN_EINVAL_UNLESS(endpoint);
++
++ //halted = usbd_pcd_ops.endpoint_halted ? usbd_pcd_ops.endpoint_halted(pcd, endpoint_index) : 0;
++ halted = usbd_pcd_ops.endpoint_halted ? usbd_pcd_ops.endpoint_halted(pcd, endpoint) : 0;
++ TRACE_MSG1(PCD, "BUS_ENDPOINT HALTED: %08x", bus->endpoint_array[endpoint_index].feature_setting);
++
++ return halted || (endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)? 1 : 0);
++}
++
++/*! bus_halt_endpoint - handle set/clear feature requests
++ * Used by the USB Device Core to set/clear endpoint halt status.
++ *
++ * We assume that if the udc driver does not implement anything then
++ * we should just return zero for ok.
++ */
++int bus_halt_endpoint (struct usbd_bus_instance *bus, int bEndpointAddress, int flag)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ int endpoint_index = pcd_search_endpoint_index(bus, bEndpointAddress);
++ struct usbd_endpoint_instance *endpoint = pcd_search_endpoint(bus, bEndpointAddress);
++
++ TRACE_MSG1(PCD, "BUS_ENDPOINT HALT: endpoint: %p", (int) endpoint);
++ RETURN_EINVAL_UNLESS(endpoint);
++ endpoint->feature_setting = flag;
++ return usbd_pcd_ops.halt_endpoint ? usbd_pcd_ops.halt_endpoint(pcd, endpoint, flag) : 0;
++}
++
++/*! pcd_disable_endpoints - disable udc and all endpoints
++ */
++static void pcd_disable_endpoints (struct usbd_bus_instance *bus)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ int i;
++ RETURN_IF (!bus || !bus->endpoint_array);
++ for (i = 1; i < usbd_pcd_ops.max_endpoints; i++) {
++ struct usbd_endpoint_instance *endpoint = (bus->endpoint_array + i);
++ CONTINUE_IF (!endpoint);
++ usbd_flush_endpoint (endpoint);
++ }
++}
++
++
++/*! bus_event_handler - handle generic bus event
++ * Called by usb core layer to inform bus of an event.
++ */
++int bus_event_handler (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ int epn;
++ //struct usbd_endpoint_map *endpoint_map_array = bus->function_instance->endpoint_map_array;
++
++ //TRACE_MSG1(PCD, "BUS_EVENT %x", event);
++ switch (event) {
++ case DEVICE_UNKNOWN:
++ break;
++
++ case DEVICE_INIT:
++ TRACE_MSG0(PCD, "EVENT INIT");
++ break;
++
++ case DEVICE_CREATE:
++ TRACE_MSG0(PCD, "EVENT CREATE");
++ pcd_disable_endpoints (bus);
++ if (usbd_pcd_ops.start) usbd_pcd_ops.start (pcd);
++ break;
++
++ case DEVICE_HUB_CONFIGURED:
++ TRACE_MSG0(PCD, "EVENT HUB_CONFIGURED");
++ //bi_connect (bus, NULL);
++ break;
++
++ case DEVICE_RESET:
++ TRACE_MSG0(PCD, "EVENT RESET");
++
++ if (usbd_pcd_ops.set_address) usbd_pcd_ops.set_address (pcd, 0);
++
++ if (usbd_pcd_ops.reset_ep) usbd_pcd_ops.reset_ep (pcd, 0);
++
++ pcd_disable_endpoints (bus);
++ otg_event_irq(pcd->otg, BUS_RESET | BUS_SUSPENDED_, PCD, "DEVICE_RESET");
++
++ break;
++
++ case DEVICE_ADDRESS_ASSIGNED:
++ TRACE_MSG1(PCD, "EVENT ADDRESSED: %d", data);
++
++ otg_event_irq(pcd->otg, ADDRESSED, PCD, "ADDRESSED");
++
++ break;
++
++ case DEVICE_CONFIGURED:
++ TRACE_MSG0(PCD, "EVENT CONFIGURED");
++ otg_event_irq(pcd->otg, CONFIGURED, PCD, "CONFIGURED");
++ // iterate across the physical endpoint instance array to enable the endpoints
++ if (usbd_pcd_ops.setup_ep)
++ for (epn = 1; epn < bus->endpoints; epn++)
++ usbd_pcd_ops.setup_ep (pcd, epn, bus->endpoint_array + epn);
++ break;
++
++ case DEVICE_DE_CONFIGURED:
++ TRACE_MSG0(PCD, "EVENT DE-CONFIGURED");
++ break;
++
++ case DEVICE_SET_INTERFACE:
++ TRACE_MSG0(PCD, "EVENT SET INTERFACE");
++ break;
++
++ case DEVICE_SET_FEATURE:
++ TRACE_MSG0(PCD, "EVENT SET FEATURE");
++ break;
++
++ case DEVICE_CLEAR_FEATURE:
++ TRACE_MSG0(PCD, "EVENT CLEAR FEATURE");
++ break;
++
++ case DEVICE_BUS_INACTIVE:
++ TRACE_MSG0(PCD, "EVENT INACTIVE");
++ TRACE_MSG1(PCD, "EVENT INACTIVE: state: %x", bus->device_state);
++ otg_event_irq(pcd->otg, BUS_SUSPENDED, PCD, "DEVICE_BUS_INACTIVE");
++ break;
++
++ case DEVICE_BUS_ACTIVITY:
++ TRACE_MSG0(PCD, "EVENT ACTIVITY");
++ otg_event_irq(pcd->otg, BUS_SUSPENDED_, PCD, "DEVICE_BUS_ACTIVITY");
++ break;
++
++ case DEVICE_POWER_INTERRUPTION:
++ TRACE_MSG0(PCD, "POWER INTERRUPTION");
++ break;
++
++ case DEVICE_HUB_RESET:
++ TRACE_MSG0(PCD, "HUB RESET");
++ break;
++
++ case DEVICE_DESTROY:
++ TRACE_MSG0(PCD, "DEVICE DESTROY");
++ //bi_disconnect (bus, NULL);
++ pcd_disable_endpoints (bus);
++ if (usbd_pcd_ops.stop) usbd_pcd_ops.stop (pcd);
++ break;
++
++ case DEVICE_CLOSE:
++ TRACE_MSG0(PCD, "DEVICE CLOSE");
++ break;
++ default:
++ TRACE_MSG1(PCD, "DEVICE UNKNOWN: %d", event);
++ break;
++ }
++ TRACE_MSG2(PCD, "EVENT bNumInterfaces: %x alternates: %x", bus->bNumInterfaces, bus->alternates);
++ return 0;
++}
++
++
++/*! bus_start_endpoint_in
++ */
++int bus_start_endpoint_in (struct usbd_bus_instance *bus, struct usbd_endpoint_instance *endpoint)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ unsigned long flags;
++
++ RETURN_ZERO_IF (!endpoint);
++ ocd_ops.interrupts++;
++
++ local_irq_save (flags);
++
++ // call pcd_start_endpoint_in IFF we didn't previously have a tx urb
++ if (!endpoint->tx_urb && pcd_tx_next_irq (endpoint)) {
++ usbd_pcd_ops.start_endpoint_in (pcd, endpoint);
++ }
++ local_irq_restore (flags);
++ return 0;
++}
++
++/*! bus_start_endpoint_out
++ */
++int bus_start_endpoint_out (struct usbd_bus_instance *bus, struct usbd_endpoint_instance *endpoint)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ unsigned long flags;
++
++ RETURN_ZERO_IF (!endpoint);
++ ocd_ops.interrupts++;
++ local_irq_save (flags);
++ // call pcd_start_endpoint_OUT IFF we didn't previously have a rcv urb
++ if (!endpoint->rcv_urb && pcd_rcv_next_irq (endpoint)) {
++ usbd_pcd_ops.start_endpoint_out (pcd, endpoint);
++ }
++ local_irq_restore (flags);
++ return 0;
++}
++
++
++/*! bus_cancel_urb_irq - cancel sending an urb
++ * Used by the USB Device Core to cancel an urb.
++ */
++int bus_cancel_urb_irq (struct usbd_urb *urb)
++{
++ struct usbd_bus_instance *bus = urb->bus;
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ RETURN_EINVAL_IF (!urb);
++ TRACE_MSG1(PCD, "BUS_CANCEL URB: %x", (int)urb);
++ switch (urb->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
++ case USB_DIR_IN:
++ // is this the active urb?
++ if (urb->endpoint->tx_urb == urb) {
++ urb->endpoint->tx_urb = NULL;
++ TRACE_MSG1(PCD, "CANCEL IN URB: %02x", urb->endpoint->bEndpointAddress);
++ if (usbd_pcd_ops.cancel_in_irq) usbd_pcd_ops.cancel_in_irq (pcd, urb);
++ }
++ usbd_urb_finished_irq (urb, SEND_CANCELLED);
++ break;
++
++ case USB_DIR_OUT:
++ // is this the active urb?
++ if (urb->endpoint->rcv_urb == urb) {
++ urb->endpoint->rcv_urb = NULL;
++ TRACE_MSG1(PCD, "CANCEL OUT URB: %02x", urb->endpoint->bEndpointAddress);
++ if (usbd_pcd_ops.cancel_out_irq) usbd_pcd_ops.cancel_out_irq (pcd, urb);
++ }
++ TRACE_MSG0(PCD, "CANCEL RECV URB");
++ usbd_urb_finished_irq (urb, RECV_CANCELLED);
++ break;
++ }
++ urb->endpoint->last = urb->endpoint->sent = 0;
++ return 0;
++}
++
++/*! pcd_rcv_finished_irq
++ */
++struct usbd_urb * pcd_rcv_finished_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
++{
++ struct usbd_urb *rcv_urb;
++
++ // if we had an urb then update actual_length, dispatch if neccessary
++ if (likely ( (int) (rcv_urb = endpoint->rcv_urb))) {
++ struct usbd_bus_instance *bus = rcv_urb->bus;
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++
++ //TRACE_MSG5(PCD, "BUS_RCV COMPLETE: finished buffer: %x actual: %d len: %d bad: %d: status: %d",
++ // rcv_urb->buffer, rcv_urb->actual_length, len, urb_bad, rcv_urb->status);
++
++ if (!urb_bad && !endpoint->rcv_error && (rcv_urb->bus->status == USBD_OK)) {
++
++#if 0
++ int i;
++ u8 *cp = rcv_urb->buffer;
++ for (i = 0; i < rcv_urb->actual_length + len; i+= 8) {
++
++ TRACE_MSG8(PCD, "RECV %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++ }
++#endif
++ // increment the received data size
++ rcv_urb->actual_length += len;
++
++ endpoint->rcv_urb = NULL;
++ rcv_urb->jiffies = jiffies;
++ rcv_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
++ //TRACE_MSG1(PCD, "BUS_RCV COMPLETE: framenum: %x", (int) rcv_urb->framenum);
++ usbd_urb_finished_irq (rcv_urb, RECV_OK);
++ rcv_urb = NULL;
++ }
++ else {
++ rcv_urb->actual_length = 0;
++ //endpoint->rcv_error = 1;
++ }
++ }
++
++ // if we don't have an urb see if we can get one
++ return pcd_rcv_next_irq (endpoint);
++}
++
++/*! pcd_rcv_complete_irq
++ */
++struct usbd_urb * pcd_rcv_complete_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
++{
++ struct usbd_urb *rcv_urb;
++
++ // if we had an urb then update actual_length, dispatch if neccessary
++ if (likely ( (int) (rcv_urb = endpoint->rcv_urb))) {
++ struct usbd_bus_instance *bus = rcv_urb->bus;
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++
++ TRACE_MSG4(PCD, "BUS_RCV COMPLETE: actual: %d len: %d bad: %d: status: %d",
++ rcv_urb->actual_length, len, urb_bad, rcv_urb->status);
++
++ //TRACE_MSG4(PCD, "BUS_RCV COMPLETE: request: %d buffer: %d packet: %d transfer: %d",
++ // rcv_urb->request_length, rcv_urb->buffer_length,
++ // endpoint->wMaxPacketSize, endpoint->rcv_transferSize);
++
++ // check the urb is ok, are we adding data less than the packetsize
++ if (!urb_bad && !endpoint->rcv_error && (rcv_urb->bus->status == USBD_OK) && (len <= endpoint->wMaxPacketSize)) {
++
++ // increment the received data size
++ rcv_urb->actual_length += len;
++
++ // if the current received data is short (less than full packetsize) which
++ // indicates the end of the bulk transfer, we have received the maximum
++ // transfersize, or if we do not have enough room to receive another packet
++ // then pass this data up to the function driver
++
++ // XXX this needs to be fixed, for example the MSC driver
++ // has varying maximum sizes
++
++
++ if (
++ ( (len < endpoint->wMaxPacketSize) ||
++ (rcv_urb->actual_length >= endpoint->rcv_transferSize) ||
++ (rcv_urb->actual_length >= rcv_urb->request_length) ||
++ (rcv_urb->actual_length + endpoint->wMaxPacketSize > rcv_urb->buffer_length)))
++ {
++#if 0
++ int i;
++ u8 *cp = rcv_urb->buffer;
++ for (i = 0; i < rcv_urb->actual_length; i+= 8)
++ TRACE_MSG8(PCD, "RECV %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++#endif
++ endpoint->rcv_urb = NULL;
++ rcv_urb->jiffies = jiffies;
++ rcv_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
++ TRACE_MSG2(PCD, "BUS_RCV COMPLETE: finished length: %d framenum: %x",
++ rcv_urb->actual_length, (int) rcv_urb->framenum);
++ usbd_urb_finished_irq (rcv_urb, RECV_OK);
++ rcv_urb = NULL;
++ }
++ }
++ else {
++ rcv_urb->actual_length = 0;
++ //endpoint->rcv_error = 1;
++ }
++ }
++
++ // if we don't have an urb see if we can get one
++ return pcd_rcv_next_irq (endpoint);
++}
++
++/*! pcd_tx_complete_irq
++ */
++struct usbd_urb * pcd_tx_complete_irq (struct usbd_endpoint_instance *endpoint, int restart)
++{
++ struct usbd_urb *tx_urb;
++
++ TRACE_MSG2(PCD, "tx_urb: %x restart: %d", endpoint->tx_urb, restart);
++
++ // if we have a tx_urb advance or reset, finish if complete
++ if ( (tx_urb = endpoint->tx_urb)) {
++
++ struct usbd_bus_instance *bus = tx_urb->bus;
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++
++ TRACE_MSG5(PCD, "BUS_TX CURRENT TX_URB: %p actual: %d sent: %d last: %d: flags: %d",
++ (int)endpoint->tx_urb, tx_urb->actual_length, endpoint->sent,
++ endpoint->last, tx_urb->flags);
++
++ if (likely (!restart)) {
++ int sent = endpoint->last;
++ endpoint->sent += sent;
++ endpoint->last -= sent;
++ }
++ else {
++ TRACE_MSG0(PCD, "RESTARTING");
++ endpoint->last = 0;
++ }
++
++ //if ( ( (tx_urb->actual_length - endpoint->sent) <= 0) && ! (tx_urb->flags & USBD_URB_SENDZLP) ) {
++
++ if ( (endpoint->sent >= tx_urb->actual_length) && ! (tx_urb->flags & USBD_URB_SENDZLP) ) {
++ tx_urb->jiffies = jiffies;
++ tx_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
++ TRACE_MSG2(PCD, "BUS_TX COMPLETE: finished tx_urb: %p framenum: %x",
++ (int)tx_urb, (int)tx_urb->framenum);
++ usbd_urb_finished_irq (tx_urb, SEND_FINISHED_OK);
++ endpoint->tx_urb = NULL;
++ endpoint->last = endpoint->sent = 0;
++ }
++ }
++ return pcd_tx_next_irq (endpoint);
++}
++
++/* ******************************************************************************************* */
++
++/*! pcd_disable - Stop using the USB Device Controller
++ * Stop using the USB Device Controller.
++ * Shutdown and free dma channels, de-register the interrupt handler.
++ */
++void pcd_disable (struct usbd_bus_instance *bus)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ TRACE_MSG0(PCD, "BUS_UDC DISABLE");
++ if (usbd_pcd_ops.disable_ep) usbd_pcd_ops.disable_ep (pcd, 0);
++ pcd_disable_endpoints (bus);
++
++ if (usbd_pcd_ops.disable) usbd_pcd_ops.disable (pcd);
++}
++
++/* ************************************************************************************* */
++/*! bus_framenum
++ */
++int bus_framenum (void)
++{
++ return (pcd_ops.framenum) ? pcd_ops.framenum () : 0;
++}
++
++/*! bus_interrupts
++ */
++u64 bus_interrupts (void)
++{
++ return ocd_ops.interrupts;
++}
++
++/*! bus_ticks
++ */
++u64 bus_ticks (void)
++{
++ return (ocd_ops.ticks) ? ocd_ops.ticks () : 0;
++}
++
++/*! bus_elapsed
++ */
++u64 bus_elapsed (u64 *t1, u64 *t2)
++{
++ return (ocd_ops.elapsed) ? (ocd_ops.elapsed (t1, t2)) : 0;
++}
++
++/*! pcd_recv_setup_emulate_irq - emulate a device request
++ */
++int pcd_recv_setup_emulate_irq(struct usbd_bus_instance *bus, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ struct usbd_device_request request;
++
++ TRACE_MSG4(PCD, "bmRequestType: %02x bRequest: %02x wValue: %04x wIndex: %04x", bmRequestType, bRequest, wValue, wIndex);
++ request.bmRequestType = bmRequestType;
++ request.bRequest = bRequest;
++ request.wValue = cpu_to_le16(wValue);
++ request.wIndex = cpu_to_le16(wIndex);
++ request.wLength = cpu_to_le16(wLength);
++ return pcd_recv_setup_irq(pcd, &request);
++}
++
++/*! pcd_check_device_feature - verify that feature is set or clear
++ * Check current feature setting and emulate SETUP Request to set or clear
++ * if required.
++ */
++void pcd_check_device_feature(struct usbd_bus_instance *bus, int feature, int flag)
++{
++ int status = bus->device_feature_settings & (1 << feature);
++ TRACE_MSG2(PCD, "BUS_CHECK FEATURE: feature: %x flag: %x", feature, flag);
++ if (!status && flag)
++ pcd_recv_setup_emulate_irq(bus, USB_REQ_HOST2DEVICE, USB_REQ_SET_FEATURE, feature, 0, 0);
++ else if (status && !flag)
++ pcd_recv_setup_emulate_irq(bus, USB_REQ_HOST2DEVICE, USB_REQ_CLEAR_FEATURE, feature, 0, 0);
++ TRACE_MSG1(PCD, "BUS_CHECK FEATURE: features; %08x", bus->device_feature_settings);
++}
++
++/* ******************************************************************************************* */
++#if !defined(OTG_C99)
++struct usbd_bus_operations bus_ops;
++
++void pcd_global_init(void)
++{
++ ZERO(bus_ops);
++ bus_ops.start_endpoint_in = bus_start_endpoint_in;
++ bus_ops.start_endpoint_out = bus_start_endpoint_out;
++ bus_ops.cancel_urb_irq = bus_cancel_urb_irq;
++ bus_ops.endpoint_halted = bus_endpoint_halted;
++ bus_ops.halt_endpoint = bus_halt_endpoint;
++ bus_ops.set_address = bus_set_address;
++ bus_ops.event_handler = bus_event_handler;
++ bus_ops.request_endpoints = bus_request_endpoints;
++ bus_ops.set_endpoints = bus_set_endpoints;
++ bus_ops.framenum = bus_framenum;
++ bus_ops.ticks = bus_ticks;
++ bus_ops.elapsed = bus_elapsed;
++ bus_ops.interrupts = bus_interrupts;
++ //bus_ops.device_feature = bus_device_feature;
++}
++
++#else /* !defined(OTG_C99) */
++struct usbd_bus_operations bus_ops = {
++ .start_endpoint_in = bus_start_endpoint_in,
++ .start_endpoint_out = bus_start_endpoint_out,
++ .cancel_urb_irq = bus_cancel_urb_irq,
++ .endpoint_halted = bus_endpoint_halted,
++ .halt_endpoint = bus_halt_endpoint,
++ .set_address = bus_set_address,
++ .event_handler = bus_event_handler,
++ .request_endpoints = bus_request_endpoints,
++ .set_endpoints = bus_set_endpoints,
++ .framenum = bus_framenum,
++ .ticks = bus_ticks,
++ .elapsed = bus_elapsed,
++ .interrupts = bus_interrupts,
++ //.device_feature = bus_device_feature,
++};
++#endif /* !defined(OTG_C99) */
++
++
++struct usbd_bus_driver bus_driver = {
++ bops: &bus_ops,
++};
++
++
++
++/* ******************************************************************************************* */
++/* Prevent overlapp of bi administrative functions mainly:
++ * bus_register_bh
++ * bus_deregister_bh
++ */
++//DECLARE_MUTEX (usbd_bi_sem);
++struct usbd_bus_instance *usbd_bus;
++
++/*! pcd_startup_events
++ */
++void pcd_startup_events(struct usbd_bus_instance *bus)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ //TRACE_MSG0(PCD, "BI_STARTUP");
++ if (usbd_pcd_ops.startup_events) {
++ TRACE_MSG0(PCD, "BI_STARTUP_EVENTS - udc");
++ usbd_pcd_ops.startup_events(pcd);
++ }
++ else {
++ TRACE_MSG0(PCD, "BI_STARTUP_EVENTS - default");
++ usbd_bus_event_handler_irq (bus, DEVICE_INIT, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_CREATE, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_HUB_CONFIGURED, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
++ }
++ //TRACE_MSG0(PCD, "BI_STARTUP: FINISHED");
++}
++
++/*! bus_register_bh
++ */
++void bus_register_bh(void *arg)
++{
++ struct pcd_instance *pcd = arg;
++ struct otg_instance *otg = pcd->otg;
++ struct usbd_bus_instance *bus;
++ struct usbd_endpoint_instance *endpoint;
++ unsigned long flags;
++
++ TRACE_MSG1(PCD, "BUS_REGISTER_BH: pcd: %p", (int)arg);
++ RETURN_UNLESS(pcd);
++
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH");
++
++ bus_driver.name = usbd_pcd_ops.name;
++ bus_driver.max_endpoints = usbd_pcd_ops.max_endpoints;
++ bus_driver.maxpacketsize = usbd_pcd_ops.ep0_packetsize;
++ bus_driver.capabilities = usbd_pcd_ops.capabilities;
++ bus_driver.bMaxPower = usbd_pcd_ops.bMaxPower;
++ bus_driver.ports = usbd_pcd_ops.ports;
++ // XXX bus_driver.otg_bmAttributes = tcd_ops.bmAttributes;
++ bus_driver.otg_bmAttributes = usbd_pcd_ops.bmAttributes;
++
++ TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC Capabilities: %x", bus_driver.capabilities);
++ // XXX TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC OTG Attributes: %x\n", tcd_ops.bmAttributes);
++ TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC OTG Attributes: %x\n", usbd_pcd_ops.bmAttributes);
++
++ // register this bus interface driver and create the device driver instance
++ if (! (bus = usbd_register_bus (&bus_driver, usbd_pcd_ops.ep0_packetsize))) {
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH: register failed");
++ printk (KERN_INFO "%s: failed\n", __FUNCTION__);
++ pcd_disable (NULL);
++ otg_event(pcd->otg, enable_otg_ | PCD_OK, PCD, "BUS_REGISTER_BH");
++ return;
++ }
++
++ bus->privdata = (void *) pcd;
++ pcd->bus = bus;
++
++ //if (usbd_pcd_ops.serial_init ? usbd_pcd_ops.serial_init (pcd) : -EINVAL) {
++ //
++ //}
++
++ if (serial_number_str && strlen(serial_number_str)) {
++ char *sp, *dp;
++ int i;
++ printk(KERN_INFO"%s:\n", __FUNCTION__);
++ printk(KERN_INFO"%s: serial_number_str: %s\n", __FUNCTION__, serial_number_str);
++ TRACE_MSG1(PCD, "prm serial_number_str: %s", serial_number_str);
++ for (sp = serial_number_str, dp = otg->serial_number, i = 0;
++ *sp && (i < (sizeof(otg->serial_number) - 1)); i++, sp++)
++ if (isxdigit(*sp)) *dp++ = toupper(*sp);
++ }
++
++
++ TRACE_MSG1(PCD, "otg serial_number_str: %s", pcd->otg->serial_number);
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH: usbd_enable_function_irq");
++
++ if (usbd_enable_function_irq (bus, pcd->otg->function_name, pcd->otg->serial_number)) {
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH: enable function failed");
++ printk (KERN_INFO "%s: failed\n", __FUNCTION__);
++ pcd_disable (NULL);
++ otg_event(pcd->otg, enable_otg_ | PCD_OK, PCD, "BUS_REGISTER_BH");
++ return;
++ }
++
++ // setup endpoint zero
++ endpoint = bus->endpoint_array + 0;
++ endpoint->bEndpointAddress = 0;
++
++ //endpoint->tx_attributes = 0;
++ //
++
++ endpoint->wMaxPacketSize = usbd_pcd_ops.ep0_packetsize;
++ endpoint->rcv_transferSize = 4096; // XXX should this be higher
++ endpoint->wMaxPacketSize = usbd_pcd_ops.ep0_packetsize;
++ if (usbd_pcd_ops.setup_ep) usbd_pcd_ops.setup_ep (pcd, 0, endpoint);
++
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH: startup");
++
++ // hopefully device enumeration will finish this process
++ // XXX should this move to pcd_en?
++ pcd_startup_events (bus);
++ TRACE_MSG0(PCD, "BUS_REGISTER_BH: FINISHED - sending PCD_OK");
++ //MOD_INC_USE_COUNT;
++ otg_event(pcd->otg, PCD_OK, PCD, "BUS_REGISTER_BH PCD_OK");
++}
++
++/*! bus_deregister_bh
++ */
++void bus_deregister_bh(void *arg)
++{
++ struct pcd_instance *pcd = arg;
++ struct usbd_bus_instance *bus;
++ struct bus_data *data;
++ unsigned long flags;
++
++ //TRACE_MSG1(PCD, "BUS_DEREGISTER_BH: pcd: %x", pcd);
++ if (pcd && (bus = pcd->bus) && (usbd_bus_state_enabled == bus->bus_state)) {
++
++ if (usbd_pcd_ops.disable) usbd_pcd_ops.disable (pcd);
++
++ if (bus->device_state != STATE_ATTACHED) {
++ usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_POWER_INTERRUPTION, 0);
++ usbd_bus_event_handler_irq (bus, DEVICE_HUB_RESET, 0);
++ }
++ usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
++ pcd_disable_endpoints (bus);
++ pcd_disable (bus);
++
++ usbd_disable_function (bus);
++ bus->bus_state = usbd_bus_state_disabled;
++
++ //TRACE_MSG1(PCD, "%s: BI_SEM UP", (int)__FUNCTION__);
++ //otg_event(pcd->otg, exit_ok, "BUS_DISABLE EXIT_OK");
++
++ //if (bus->serial_number_str)
++ // lkfree (pcd->bus->serial_number_str);
++
++ usbd_deregister_bus (bus);
++ pcd->bus = NULL;
++
++ TRACE_MSG0(PCD, "BUS_DEREGISTER_BH: FINISHED - sending PCD_OK");
++ //MOD_DEC_USE_COUNT;
++ }
++ otg_event(pcd->otg, PCD_OK, PCD, "BUS_DEREGISTER_BH PCD_OK");
++}
++
++/* ************************************************************************************* */
++
++
++/*! pcd_en_func - enable
++ *
++ * This is called to enable / disable the PCD and USBD stack.
++ */
++void pcd_en_func (struct otg_instance *otg, u8 flag)
++{
++ struct pcd_instance *pcd = otg->pcd;
++ struct usbd_bus_instance *bus = pcd->bus;
++
++ //TRACE_MSG0(PCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(PCD, "PCD_EN: SET");
++#ifdef CONFIG_OTG_DB1550_J15
++ int ret = au_readl(SYS_PINFUNC);
++ au_writel((ret | 0x8000),SYS_PINFUNC);
++ ret = au_readl(SYS_PINFUNC);
++ TRACE_MSG1(PCD, "Set the OTG for device mode (sys_pfunc = %04x)", ret);
++#endif
++ // check if we can see the UDC and register, then enable the function
++ if (usbd_pcd_ops.enable) usbd_pcd_ops.enable (pcd);
++ //BREAK_IF (pcd_enable_irq (bus));
++ //BREAK_IF (usbd_enable_function_irq (bus, otg->function_name));
++
++ // XXX should this move to here
++ // pcd_startup_events (bus);
++ break;
++
++ case RESET:
++ TRACE_MSG0(PCD, "PCD_EN: RESET");
++ usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
++ TRACE_MSG0(PCD, "PCD_EN: DESTROY");
++ usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
++ TRACE_MSG0(PCD, "PCD_EN: FINISHED");
++ // XXX need to set a flag here
++ break;
++ }
++}
++
++/*! pcd_init_func - per peripheral controller common initialization
++ *
++ * This is called to initialize / de-initialize the PCD and USBD stack.
++ *
++ * We start work items to do this.
++ *
++ */
++void pcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ struct pcd_instance *pcd = otg->pcd;
++ struct usbd_bus_instance *bus = pcd->bus;
++ //struct bus_data *data = NULL;
++
++ //printk(KERN_INFO"%s:\n", __FUNCTION__);
++
++ //TRACE_MSG0(PCD, "--");
++ switch (flag) {
++ case SET:
++ TRACE_MSG0(PCD, "PCD_INIT: SET");
++ PREPARE_WORK_ITEM(pcd->bh, bus_register_bh, pcd);
++ SCHEDULE_WORK(pcd->bh);
++ TRACE_MSG0(PCD, "BUS_REGISTER_SCHEDULE: finished");
++ break;
++
++ case RESET:
++ TRACE_MSG0(PCD, "PCD_INIT: RESET");
++ PREPARE_WORK_ITEM(pcd->bh, bus_deregister_bh, pcd);
++ SCHEDULE_WORK(pcd->bh);
++ }
++}
++
+diff -uNr linux/drivers/no-otg/ocd/otg-pcd/tr-init-l24.c linux/drivers/otg/ocd/otg-pcd/tr-init-l24.c
+--- linux/drivers/no-otg/ocd/otg-pcd/tr-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-pcd/tr-init-l24.c 2006-09-01 21:41:32.000000000 +0200
+@@ -0,0 +1,234 @@
++/*
++ * otg/ocd/otg-pcd/tr-init-l24.c - Traditional Device Peripheral and OTG Controller Drivers Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-pcd/tr-init-l24.c
++ * @brief Traditional device driver init.
++ *
++ * TR OTG PCD/OCD/TCD Initialization
++ *
++ * This file initializes all of the low level hardware drivers for a traditional device.
++ *
++ * Traditional USB Devices must implement the following:
++ *
++ * ocd_ops operations from ocd driver
++ * pcd_ops operations from pcd driver
++ * tcd_ops operations from tcd driver
++ *
++ * The OTG Controller driver (ocd) implements any required OTG timers and if
++ * necessary mediates access to and initializes the OTG and/or USB hardware.
++ *
++ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
++ * USBD stack to send and receive data from the USB actings as a USB
++ * peripheral.
++ *
++ * The Transceiver Controller Driver (tcd) implements control of the OTG or
++ * USB transceiver. At a minimum for a traditional device this should
++ * implement VBUS sensing (sometimes known as cable detect) and where
++ * possible control over the DP+ pullup resistor.
++ *
++ *
++ * Notes
++ *
++ * 1. This is the linux 2.4 version.
++ *
++ * 2. This will optionally do an auto start with TR_INIT if the OCD_CAPBILITIES_AUTO
++ * flag is set.
++ *
++ * TODO
++ *
++ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
++ *
++ * @ingroup OTGPCD
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++EMBED_LICENSE();
++
++MOD_PARM (serial_number_str, "s");
++MOD_PARM_DESC (serial_number_str, "Serial Number");
++MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MOD_DESCRIPTION ("Traditional USB Device");
++
++char *serial_number_str;
++
++otg_tag_t OCD;
++struct ocd_instance *ocd_instance;
++
++otg_tag_t PCD;
++struct pcd_instance *pcd_instance;
++
++otg_tag_t TCD;
++struct tcd_instance *tcd_instance;
++
++
++/* ************************************************************************************* */
++
++/* tr_ocd_start_timer
++ * Fake - Set or reset timer to interrupt in number of uS (micro-seconds).
++ * This is only suitable for MN or TR firmware.
++ */
++int tr_ocd_start_timer(struct otg_instance *otg, int usec)
++{
++ otg_event(otg, TMOUT, OCD, "FAKE TMOUT");
++ return 0;
++}
++
++/* ************************************************************************** */
++/* tr_tcd_en_func - used to enable or disable transciever
++ *
++ */
++void tr_tcd_en_func(struct otg_instance *otg, u8 flag)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *) otg->pcd;
++ struct usbd_bus_instance *bus = pcd->bus;
++
++ //printk(KERN_INFO"%s: start\n", __FUNCTION__);
++ TRACE_MSG0(TCD, "--");
++ TRACE_MSG2(TCD, "pcd: %x bus: %x", pcd, pcd->bus);
++
++ switch (flag) {
++ case PULSE:
++ case SET:
++ TRACE_MSG0(TCD, "TR_TCD_EN SET");
++ /* enable clock interrupt */
++ otg_event_set_irq(tcd_instance->otg, 1, 1, B_SESS_VLD, TCD, "B_SESS_VLD");
++ break;
++ case RESET:
++ TRACE_MSG0(TCD, "TR_TCD_EN RESET");
++ /* disable clock interrupt */
++ break;
++ }
++// TRACE_MSG2(TCD, "ep0 endpoint: %x bEndpointAddress: %02x BBB", bus->ep0->endpoint_map_array->endpoint,
++ // bus->ep0->endpoint_map_array->endpoint->bEndpointAddress);
++}
++
++
++/* ************************************************************************** */
++
++/* tr_modexit - This is used as module exit, and as cleanup if modinit fails.
++ *
++ * Specifically for each driver:
++ *
++ * call ops.mod_exit
++ * reset instance address and ops table address in state machine to NULL
++ * invalidate tag
++ */
++static void tr_modexit (void)
++{
++ struct otg_instance *otg = ocd_instance->otg;
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ TRACE_MSG1(TCD, "otg: %x", otg);
++ if (otg) {
++ TRACE_MSG0(TCD, "Calling otg_exit()");
++ otg_exit(otg);
++ TRACE_MSG0(TCD, "back from otg_exit()");
++ }
++ else
++ TRACE_MSG0(TCD, "did not call otg_exit()");
++
++#if 0
++ if ((ocd_ops.capabilities & OCD_CAPABILITIES_TR) && (ocd_ops.capabilities & OCD_CAPABILITIES_AUTO)) {
++ printk(KERN_INFO"%s calling otg_admin\n",__FUNCTION__);
++ otg_admin("exit_all", "Traditional Device Auto TR_INIT");
++ }
++#endif
++
++ if (tcd_ops.mod_exit) tcd_ops.mod_exit();
++ if (ocd_ops.mod_exit) ocd_ops.mod_exit();
++ if (pcd_ops.mod_exit) pcd_ops.mod_exit();
++
++ tcd_instance = otg_set_tcd_ops(NULL);
++ ocd_instance = otg_set_ocd_ops(NULL);
++ pcd_instance = otg_set_pcd_ops(NULL);
++
++ TCD = otg_trace_invalidate_tag(TCD);
++ OCD = otg_trace_invalidate_tag(OCD);
++ PCD = otg_trace_invalidate_tag(PCD);
++ printk(KERN_INFO"%s finished\n", __FUNCTION__);
++}
++
++
++/* tr_modinit - linux module initialization
++ *
++ * This needs to initialize the ocd, pcd and tcd drivers.
++ *
++ * Specifically for each driver:
++ *
++ * obtain tag
++ * pass ops table address to state machine and get instance address
++ * call ops.mod_init
++ *
++ */
++static int tr_modinit (void)
++{
++ struct otg_instance *otg;
++ printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ #if !defined(OTG_C99)
++ pcd_global_init();
++ #endif /* !defined(OTG_C99) */
++
++ /* For each of ocd, pcd and tcd do:
++ *
++ * get tag
++ * update ops table with default functions where possible
++ * do otg_set_xxx_ops() as appropriate
++ * call xxx_ops.mod_init as appropriate
++ */
++
++ OCD = otg_trace_obtain_tag();
++ PCD = otg_trace_obtain_tag();
++ TCD = otg_trace_obtain_tag();
++
++ UNLESS(ocd_ops.start_timer) ocd_ops.start_timer = tr_ocd_start_timer;
++ UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
++ UNLESS(pcd_ops.pcd_en_func) pcd_ops.pcd_en_func = pcd_en_func;
++ UNLESS(tcd_ops.tcd_en_func) tcd_ops.tcd_en_func = tr_tcd_en_func;
++
++ THROW_IF((ocd_ops.mod_init) ? ocd_ops.mod_init() : 0, error);
++ THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
++ THROW_IF((tcd_ops.mod_init) ? tcd_ops.mod_init() : 0, error);
++
++ THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
++ THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
++ THROW_UNLESS(tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
++
++ THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
++
++ CATCH(error) {
++ tr_modexit();
++ return -EINVAL;
++ }
++ /* Success!
++ */
++ otg_init(otg);
++#if 0
++ otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_TR);
++#endif
++ return 0;
++}
++
++module_init(tr_modinit);
++MOD_EXIT (tr_modexit);
++
+diff -uNr linux/drivers/no-otg/ocd/otg-tcd/tcd-init-l24.c linux/drivers/otg/ocd/otg-tcd/tcd-init-l24.c
+--- linux/drivers/no-otg/ocd/otg-tcd/tcd-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-tcd/tcd-init-l24.c 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,95 @@
++/*
++ * otg/ocd/otg-tcd/tcd-init-l24.c - OTG Transceiver Controller Driver Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-tcd/tcd-init-l24.c
++ * @brief PCD only driver init.
++ *
++ * OTG TCD Initialization
++ *
++ * This file initializes the low level hardware drivers.
++ *
++ * This is the linux 2.4 version.
++ *
++ * @ingroup OTGTCD
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
++MODULE_LICENSE ("GPL");
++#endif
++MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MODULE_DESCRIPTION ("USB On-The-Go TCD");
++#endif
++
++otg_tag_t TCD;
++
++extern struct tcd_ops tcd_ops;
++struct tcd_instance *tcd_instance;
++
++//extern void db1550_tcd_global_init(void);
++
++/* ************************************************************************************* */
++
++/* tcd_modexit - This is *only* used for drivers compiled and used as a module.
++ */
++static void tcd_modexit (void)
++{
++ struct otg_instance *otg = tcd_instance->otg;
++ //printk(KERN_INFO"%s\n", __FUNCTION__);
++
++ if (otg)
++ otg_exit(otg);
++
++ if (tcd_ops.mod_exit) tcd_ops.mod_exit();
++ tcd_instance = otg_set_tcd_ops(NULL);
++ otg_trace_invalidate_tag(TCD);
++}
++
++/* otg_modinit - linux module initialization
++ *
++ * This needs to initialize the hcd, pcd and tcd drivers. This includes tcd and possibly hcd
++ * for some architectures.
++ *
++ */
++static int tcd_modinit (void)
++{
++ printk(KERN_INFO"Initilize the tcd structure\n");
++// db1550_tcd_global_init();
++ TCD = otg_trace_obtain_tag();
++ THROW_UNLESS(tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
++ THROW_IF((tcd_ops.mod_init) ? tcd_ops.mod_init() : 0, error);
++ //printk(KERN_INFO"%s finish\n", __FUNCTION__);
++
++ TRACE_MSG0(TCD, "--");
++
++ CATCH(error) {
++ tcd_modexit();
++ return -EINVAL;
++ }
++ return 0;
++}
++
++module_init (tcd_modinit);
++module_exit (tcd_modexit);
++
+diff -uNr linux/drivers/no-otg/ocd/otg-tcd/tcd.c linux/drivers/otg/ocd/otg-tcd/tcd.c
+--- linux/drivers/no-otg/ocd/otg-tcd/tcd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/ocd/otg-tcd/tcd.c 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ * otg/ocd/otg-tcd/tcd.c - OTG Transceiver Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/ocd/otg-tcd/tcd.c
++ * @brief TCD Support
++ * Notes
++ *
++ * @ingroup OTGTCD
++ */
++
++#include <otg/otg-compat.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++
++extern struct tcd_ops tcd_ops;
++
++/* ************************************************************************************* */
++void tcd_cable_event_irq (struct otg_instance *otg)
++{
++ TRACE_MSG1(TCD, "TCD_CABLE_EVENT: vbus: %d", tcd_vbus(otg));
++ otg_event(otg, VBUS_VLD, TCD, "CABLE");
++ //otg_b_sess_vld(otg, 1, tcd_vbus (otg), "Cable Event");
++}
++
++void tcd_cable_event (struct otg_instance *otg)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ tcd_cable_event_irq (otg);
++ local_irq_restore (flags);
++}
++
++/* ************************************************************************************* */
++int tcd_vbus (struct otg_instance *otg)
++{
++ TRACE_MSG0(TCD, "OCD VBUS");
++ return tcd_ops.vbus ? tcd_ops.vbus (otg) : 1;
++}
++
++
+diff -uNr linux/drivers/no-otg/otg/hcd-hw.h linux/drivers/otg/otg/hcd-hw.h
+--- linux/drivers/no-otg/otg/hcd-hw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/hcd-hw.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,101 @@
++/*
++ * otg/hcd/hc_xfer_hw.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Tom Rushworth <tbr@belcara.com>,
++ * Stuart Lynne <sl@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/otg/hcd-hw.h
++ * @brief Implements Generic Host Controller Driver
++ *
++ * @ingroup OTGHCD
++ */
++#ifndef HC_XFER_HW_H
++#define HC_XFER_HW_H 1
++
++/*===========================================================================*
++ * Functions provided by the hardware specific component (whatever HW it is).
++ * Each HW specific component provides these functions.
++ *===========================================================================*/
++
++/*===========================================================================*
++ * For the generic transfer aware framework.
++ *===========================================================================*/
++
++/*
++ * hcd_hw_max_active_transfers()
++ * Returns: the (constant) maximum number of concurrently active transfers the HW will handle.
++ */
++extern int hcd_hw_max_active_transfers(struct bus_hcpriv *bus_hcpriv);
++
++/*
++ * hcd_hw_start_transfer()
++ * Returns: tid >= 0 when the transfer starts - this is an index in [0..hcd_hw_max_active_transfers]
++ * -1 when the transfer is invalid,
++ * -2 when there are no resources for the transfer currently available.
++ */
++extern int hcd_hw_start_transfer(struct bus_hcpriv *bus_hcpriv,
++ int len, // length of data region
++ void *data, // virtual address of data region
++ int toggle, // toggle value to start the xfer with
++ int maxps, // max packet size of endpoint
++ int slow, // 1 ==> slow speed, 0 ==> full speed QQSV verify: (((urb->pipe) >> 26) & 1)
++ int endpoint, // endpoint number
++ int address, // USB device address
++ int pid, // {PID_OUT, PID_IN, PID_SETUP}
++ int format, // PIPE_{CONTROL,BULK,INTERRUPT,ISOCHRONOUS}
++ u32 other); // Values depending on format
++
++/*
++ * hcd_hw_unlink_urb()
++ * Called in irq_lock, calls back to xhc_transfer_complete().
++ * Returns: 0 when transfer is unlinked, non-zero otherwise.
++ */
++extern int hcd_hw_unlink_urb(struct bus_hcpriv *bus_hcpriv, int tid); // tid is value returned by hcd_hw_start_transfer()
++
++extern u32 hcd_hw_frame_number(struct bus_hcpriv *bus_hcpriv);
++
++extern void hcd_hw_enable_interrupts(struct bus_hcpriv *bus_hcpriv);
++extern void hcd_hw_disable_interrupts(struct bus_hcpriv *bus_hcpriv);
++
++extern void hcd_hw_get_ops(struct bus_hcpriv *bus_hcpriv);
++
++extern int hcd_hw_init(struct bus_hcpriv *bus_hcpriv);
++
++extern void hcd_hw_exit(struct bus_hcpriv *bus_hcpriv);
++
++/*===========================================================================*
++ * For the virtual root hub.
++ *===========================================================================*/
++
++extern int hcd_hw_rh_num_ports(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_otg_capable_mask(struct bus_hcpriv *bus_hcpriv);
++
++extern char *hcd_hw_rh_string(struct bus_hcpriv *bus_hcpriv, int strno);
++extern u16 hcd_hw_rh_idVendor(struct bus_hcpriv *bus_hcpriv);
++extern u16 hcd_hw_rh_idProduct(struct bus_hcpriv *bus_hcpriv);
++extern u16 hcd_hw_rh_bcdDevice(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_cfg_bmAttributes(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_cfg_MaxPower(struct bus_hcpriv *bus_hcpriv);
++extern u16 hcd_hw_rh_hub_attributes(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_power_delay(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_hub_contr_current(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_DeviceRemovable(struct bus_hcpriv *bus_hcpriv);
++extern u8 hcd_hw_rh_PortPwrCtrlMask(struct bus_hcpriv *bus_hcpriv);
++extern u32 hcd_hw_rh_get_hub_change_status(struct bus_hcpriv *bus_hcpriv);
++extern void hcd_hw_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, int feat_selector, int set_flag);
++extern void hcd_hw_hcd_en_func(struct otg_instance *oi, u8 on);
++/*
++ * Note: in the following functions, portnum is 0-origin.
++ * (I.e., valid range is [0..(hcd_hw_rh_num_ports-1)].)
++ */
++extern u32 hcd_hw_rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, int portnum);
++extern void hcd_hw_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag);
++
++
++#endif
+diff -uNr linux/drivers/no-otg/otg/hcd-l26.h linux/drivers/otg/otg/hcd-l26.h
+--- linux/drivers/no-otg/otg/hcd-l26.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/hcd-l26.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,119 @@
++/*
++ * otg/hcd/hc_xfer.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/otg/hcd-l26.h
++ * @brief Implements Linux version of Generic Host Controller driver
++ *
++ * @ingroup OTGHCD
++ */
++#ifndef HC_XFER_H
++#define HC_XFER_H 1
++
++/*===========================================================================*
++ * Data structures and functions provided by the generic transfer aware
++ * host controller framework.
++ *
++ * The generic framework must be linked with a hardware specific component,
++ * whose functions are specified in hc_xfer_hw.h, and a generic root hub
++ * component, whose functions are specified in hc_xfer_rh.h.
++ *
++ * The resulting module provides a table of operations to the usb core layer,
++ * passed to the core layer by a call to usb_alloc_bus().
++ *===========================================================================*/
++
++#define XHC_RH_DESCRIPTORS_SIZE (USB_DT_DEVICE_SIZE+USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE+USB_DT_HUB_NONVAR_SIZE+2)
++
++typedef struct rh_hcpriv {
++ struct urb *int_urb;
++ struct usbd_device_descriptor *dd;
++ struct usbd_configuration_descriptor *cd;
++ struct usbd_interface_descriptor *id;
++ struct usbd_endpoint_descriptor *ed;
++ struct hub_descriptor *hd;
++ struct timer_list poll_timer;
++ //int poll_jiffies;
++ struct usb_device *dev;
++ int dev_registered;
++ u32 hub_change_status; // For shadowing the HW
++ u32 *port_change_status; // An array of [num_ports] values for shadowing the HW
++ u32 hub_port_change_status;
++ struct WORK_STRUCT psc_bh;
++ u8 curr_cfg;
++ u8 curr_itf;
++ //u8 num_ports;
++ u8 otg_device_mask; // (1 << port_num) bit set iff port_num is acting as a device, not host, and so not usable
++ u8 descriptors[XHC_RH_DESCRIPTORS_SIZE];
++ int suspended;
++} rh_hcpriv_t;
++
++typedef struct bus_hcpriv { // XFER level Host Controller Info
++ struct usb_bus *usb_bus;
++ void *hw_hci; // HW specific information for this HC
++ int root_hub_addr; // Initially 0, set by the virtual root hub when addressed.
++ struct rh_hcpriv *rh_hcpriv; // Generic root hub info (see hc_xfer_rh.[hc])
++ int terminating; // Boolean, TRUE if shutting down.
++ //struct hcd_instance *hcd; // OTG Controller Info
++ int max_active_urbs;
++ struct urb **active_urbs;
++ int device_registered; // bus_device status
++ struct device bus_device; // Linux Driver Model info.
++ //struct hcd_ops otg_ops; // operations for OTG component.
++ struct usb_driver *usb_driver;
++
++ u8 num_ports;
++ u8 otg_port;
++ u8 otg_capable_mask;
++ u16 rh_vendorid;
++ u16 rh_productid;
++ u16 rh_bcddevice;
++ char *rh_serial;
++ char *rh_product;
++ char *rh_manufacturer;
++ u8 rh_bmAttributes;
++ u8 rh_bMaxPower;
++
++ struct usb_device *roothub_dev;
++ struct usb_device *first_dev;
++
++ int max_active_transfers;
++
++} bus_hcpriv_t;
++
++typedef struct dev_hcpriv { // XFER level HCI per attached device info
++ struct usb_device *dev;
++ struct list_head queued_urbs_both[2][16];
++ u32 num_urbs_both[2][16];
++ u8 epq_state_both[2][16];
++} dev_hcpriv_t;
++
++#define EPQ_EMPTY 0
++#define EPQ_RUNNING 1
++#define EPQ_WAITING 2
++
++/*===========================================================================*
++ * For the hardware specific component.
++ *===========================================================================*/
++
++extern void hcd_transfer_complete(struct bus_hcpriv *bus_hcpriv, int transfer_id, int format,
++ int cc, u32 remaining, int next_toggle);
++
++/*===========================================================================*
++ * For the virtual root hub.
++ *===========================================================================*/
++
++extern void hcd_rh_urb_complete(struct bus_hcpriv *bus_hcpriv, struct urb *urb);
++
++#include "../otg/otg-trace.h"
++extern otg_tag_t xfer_hci_trace_tag;
++
++
++#endif
+diff -uNr linux/drivers/no-otg/otg/hcd-rh.h linux/drivers/otg/otg/hcd-rh.h
+--- linux/drivers/no-otg/otg/hcd-rh.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/hcd-rh.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ * otg/hcd/hc_xfer_rh.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
++ *
++ * Copyright (c) 2004 Belcarra Technologies
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ */
++/*!
++ * @file otg/otg/hcd-rh.h
++ * @brief Implements Generic Root Hub function for Generic Host Controller Driver.
++ *
++ * @ingroup OTGHCD
++ */
++#ifndef HC_XFER_RH_H
++#define HC_XFER_RH_H 1
++
++#define XHC_RH_STRING_CONFIGURATION 1
++#define XHC_RH_STRING_INTERFACE 2
++#define XHC_RH_STRING_SERIAL 3
++#define XHC_RH_STRING_PRODUCT 4
++#define XHC_RH_STRING_MANUFACTURER 5
++
++/*===========================================================================*
++ * Functions provided by the generic virtual root hub.
++ *===========================================================================*/
++
++/*===========================================================================*
++ * For the generic transfer aware framework.
++ *===========================================================================*/
++
++/*
++ * hcd_rh_submit_urb()
++ * Returns: values as for the generic submit_urb() function.
++ */
++extern int hcd_rh_submit_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int mem_flags);
++
++extern int hcd_rh_unlink_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb);
++
++extern void hcd_rh_get_ops(struct bus_hcpriv *bus_hcpriv);
++
++extern int hcd_rh_init(struct bus_hcpriv *bus_hcpriv);
++
++extern void hcd_rh_exit(struct bus_hcpriv *bus_hcpriv);
++
++/*===========================================================================*
++ * For the hardware specific root hub component.
++ *===========================================================================*/
++
++extern irqreturn_t hcd_rh_int_hndlr(int irq, void *dev_id, struct pt_regs *regs);
++
++#endif
+diff -uNr linux/drivers/no-otg/otg/otg-api.h linux/drivers/otg/otg/otg-api.h
+--- linux/drivers/no-otg/otg/otg-api.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-api.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,233 @@
++/*
++ * otg/otg-api.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*
++ * Doxygen group definitions - N.B. These much each be in
++ * their own separate comment...
++ */
++/*!
++ * @defgroup onthegogroup On-The-Go
++ */
++/*!
++ * @defgroup functiongroup Function Drivers
++ */
++/*!
++ * @defgroup tcdgroup Transceiver Controller Drivers
++ */
++/*!
++ * @defgroup pcdgroup Peripheral Controller Drivers
++ */
++/*!
++ * @defgroup libgroup Architecture Libraries
++ */
++/*!
++ * @defgroup platformgroup Platform Drivers
++ */
++
++
++/*!
++ * @defgroup OTGCore Core
++ * @ingroup onthegogroup
++ */
++
++/*!
++ * @file otg/otg/otg-api.h
++ * @brief Core Defines for USB OTG Core Layaer
++ *
++ * @ingroup OTGCore
++ */
++
++/*!
++ * @name OTGCORE OTG API Definitions
++ * This contains the OTG API structures and definitions.
++ * @{
++ */
++
++#include <otg/otg-fw.h>
++
++#ifdef CONFIG_OTG_FW_MN
++#include <otg/otg-fw-mn.h>
++#else /* CONFIG_OTG_FW_MN */
++#include <otg/otg-fw-df.h>
++#endif /* CONFIG_OTG_FW_MN */
++
++
++struct otg_instance;
++typedef void (*otg_output_proc_t) (struct otg_instance *, u8);
++
++extern struct otg_firmware *otg_firmware_loaded;
++extern struct otg_firmware *otg_firmware_orig;
++extern struct otg_firmware *otg_firmware_loading;
++
++
++char * otg_get_state_name(int state);
++
++/*!
++ * @struct otg_instance
++ *
++ * This tracks the current OTG configuration and state
++ */
++struct otg_instance {
++
++ u16 state; /*!< current state */
++ int previous; /*!< previous state */
++
++ int active; /*!< used as semaphore */
++
++ u32 current_inputs; /*!< input settings */
++ u64 outputs; /*!< output settings */
++
++ u64 tickcount; /*!< when we transitioned to current state */
++ u64 bconn; /*!< when b_conn was set */
++
++ struct otg_state *current_outputs; /*!< output table entry for current state */
++ struct otg_state *previous_outputs; /*!< output table entry for current state */
++
++ otg_output_proc_t otg_output_ops[MAX_OUTPUTS]; /*!< array of functions mapped to output numbers */
++
++ int (*start_timer) (struct otg_instance *, int); /*!< OCD function to start timer */
++ u64 (*ticks) (void); /*!< OCD function to return ticks */
++ u64 (*elapsed) ( u64 *, u64 *); /*!< OCD function to return elapsed ticks */
++
++ void * hcd; /*!< pointer to hcd instance */
++ void * ocd; /*!< pointer to ocd instance */
++ void * pcd; /*!< pointer to pcd instance */
++ void * tcd; /*!< pointer to tcd instance */
++
++ char function_name[OTGADMIN_MAXSTR]; /*!< current function */
++ char serial_number[OTGADMIN_MAXSTR]; /*!< current serial number */
++};
++
++typedef int (*otg_event_t) (struct otg_instance *, int, char *);
++
++struct otg_event_info {
++ char *name;
++ otg_event_t event;
++};
++
++
++/* 1 - used by external functions to pass in administrative commands as simple strings
++ */
++extern int otg_status(int, u32, u32, char *, int);
++extern void otg_message(char *);
++
++/* 2 - used internally by any OTG stack component to single event from interrupt context
++ */
++extern int otg_event_irq(struct otg_instance *, u64, otg_tag_t, char *);
++
++/* 3 - used internally by any OTG stack component to single event from non-interrupt context,
++ */
++extern int otg_event(struct otg_instance *, u64, otg_tag_t, char *);
++
++/* 5 - used by PCD/TCD drivers to signal various OTG Transceiver events
++ */
++int otg_event_set_irq(struct otg_instance *, int, int, u32, otg_tag_t, char *);
++
++
++extern void otg_init (struct otg_instance *otg);
++extern void otg_exit (struct otg_instance *otg);
++
++/* message
++ */
++#if defined(OTG_LINUX)
++extern int otg_message_init_l24(struct otg_instance *);
++extern void otg_message_exit_l24(void);
++#endif /* defined(OTG_LINUX) */
++
++#if defined(OTG_WINCE)
++extern int otg_message_init_w42(struct otg_instance *);
++extern void otg_message_exit_w42(void);
++#endif /* defined(OTG_WINCE) */
++
++extern int otg_message_init(struct otg_instance *);
++extern void otg_message_exit(void);
++
++extern int otg_write_message_irq(char *buf, int size);
++extern int otg_write_message(char *buf, int size);
++extern int otg_read_message(char *buf, int size);
++extern int otg_data_queued(void);
++extern unsigned int otg_message_block(void);
++extern unsigned int otg_message_poll(struct file *, struct poll_table_struct *);
++
++
++/* trace
++ */
++extern int otg_trace_init (void);
++extern void otg_trace_exit (void);
++#if defined(OTG_LINUX)
++extern int otg_trace_init_l24(void);
++extern void otg_trace_exit_l24(void);
++#endif /* defined(OTG_LINUX) */
++
++#if defined(OTG_WINCE)
++extern int otg_trace_init_w42(void);
++extern void otg_trace_exit_w42(void);
++#endif /* defined(OTG_WINCE) */
++
++extern int otgtrace_init (void);
++extern void otgtrace_exit (void);
++extern int otg_trace_proc_read (char *page, int count, int * pos);
++extern int otg_trace_proc_write (const char *buf, int count, int * pos);
++
++/* usbp
++ */
++extern int usbd_device_init (void);
++extern void usbd_device_exit (void);
++
++
++/*
++ * otgcore/otg-mesg.c
++ */
++
++extern void otg_message(char *buf);
++extern void otg_mesg_get_status_update(struct otg_status_update *status_update);
++extern void otg_mesg_get_firmware_info(struct otg_firmware_info *firmware_info);
++extern int otg_mesg_set_firmware_info(struct otg_firmware_info *firmware_info);
++extern struct otg_instance * mesg_otg_instance;
++
++
++
++/*
++ * otgcore/otg.c
++ */
++extern char * otg_get_state_names(int i);
++
++/*
++ * ops
++ */
++
++extern struct hcd_ops *otg_hcd_ops;
++extern struct ocd_ops *otg_ocd_ops;
++extern struct pcd_ops *otg_pcd_ops;
++extern struct tcd_ops *otg_tcd_ops;
++extern struct usbd_ops *otg_usbd_ops;
++
++#define CORE core_trace_tag
++extern otg_tag_t CORE;
++
++extern struct hcd_instance * otg_set_hcd_ops(struct hcd_ops *);
++extern struct ocd_instance * otg_set_ocd_ops(struct ocd_ops *);
++extern struct pcd_instance * otg_set_pcd_ops(struct pcd_ops *);
++extern struct tcd_instance * otg_set_tcd_ops(struct tcd_ops *);
++extern int otg_set_usbd_ops(struct usbd_ops *);
++
++extern void otg_get_trace_info(otg_trace_t *p);
++extern int otg_tmr_id_gnd(void);
++extern u64 otg_tmr_ticks(void);
++extern u64 otg_tmr_elapsed(u64 *t1, u64 *t2);
++extern u16 otg_tmr_framenum(void);
++extern u32 otg_tmr_interrupts(void);
++
++extern void otg_write_info_message(char *msg);
++
++/* @} */
++
++
+diff -uNr linux/drivers/no-otg/otg/otg-compat.h linux/drivers/otg/otg/otg-compat.h
+--- linux/drivers/no-otg/otg/otg-compat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-compat.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,73 @@
++/*
++ * otg/otgcore/otg-compat.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++/*!
++ * @file otg/otg/otg-compat.h
++ * @brief Common include file to determine and include appropriate OS compatibility file.
++ *
++ *
++ * @ingroup OTGCore
++ */
++#ifndef _OTG_COMPAT_H
++#define _OTG_COMPAT_H 1
++
++#if defined(_WIN32_WCE)
++#define OTG_WINCE _WIN32_WCE
++#endif /* defined(_WIN32_WCE) */
++
++ /* What operating system are we running under? */
++
++ /* Recursively include enough information to determine which release */
++
++ #if (__GNUC__ >=3)
++ #define GCC3
++ #else
++ #define GCC2
++ #endif
++ #include <linux/config.h>
++ #include <linux/kernel.h>
++ #include <linux/version.h>
++
++#if defined(__GNUC__)
++ #define OTG_LINUX
++ #ifndef CONFIG_OTG_NOC99
++ #define OTG_C99
++ #else
++ #endif
++
++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
++ #define LINUX26
++ #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5)
++ #define LINUX24
++ #else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5) */
++ #define LINUX24
++ #define LINUX_OLD
++ #warning "Early unsupported release of Linux kernel"
++ #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5) */
++
++ /* We are running under a supported version of Linux */
++ #include <otg/otg-linux.h>
++
++#elif defined(OTG_WINCE)
++
++ /* We are running under a supported version of WinCE */
++ #include <otg/otg-wince.h>
++ #include <otg/otg-wince-ex.h>
++
++#else /* defined(OTG_WINCE) */
++
++ #error "Operating system not recognized"
++
++#endif /* defined(OTG_WINCE) */
++
++#include <otg/otg-utils.h>
++
++#if !defined(OTG_C99)
++#else /* !defined(OTG_C99) */
++#endif /* !defined(OTG_C99) */
++
++
++#endif /* _OTG_COMPAT_H */
+diff -uNr linux/drivers/no-otg/otg/otg-fw-df.h linux/drivers/otg/otg/otg-fw-df.h
+--- linux/drivers/no-otg/otg/otg-fw-df.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-fw-df.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,53 @@
++
++/* Generated by otg-states-h.awk
++ *
++ * Do not Edit thie file
++ */
++
++/*!
++* @file otg/otg/otg-fw-df.h
++* @brief OTG Firmware - Firmware for df
++*
++* This file defines the OTG State Machine tests.
++*
++* @ingroup OTGFW
++*/
++
++
++/*!
++* @page OTGFW
++* @section OTGFW - otg-fw-df.h
++* This contains the input, output and timout definitions for the OTG state machine firmware
++*/
++extern char otg_fw_name_df[];
++extern int otg_test_max_df;
++extern struct otg_test otg_tests_df[];
++extern struct otg_output otg_outputs_df[];
++
++ /*
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++ /*!
++ * This is the default Firmware. It is included in the
++ * compiled modules and supports the auto Traditional USB
++ * mode. No user inputs are implemented.
++ */
++
++#define invalid_state 0 /* State machine has been initialized. */
++
++#define otg_disabled 1 /* State machine has been initialized. */
++
++#define terminator_state 2 /* terminator */
++ /*
++ * This is not an OTG State. It is used internally to mark the end of the
++ * list of states and inputs.
++ */
++
++#define OTG_STATES_DF 3
++
++extern struct otg_state otg_states_df[OTG_STATES_DF + 1];
++
++extern char *otg_get_state_name_df(int);
++
++extern struct otg_firmware otg_firmware_df;
+diff -uNr linux/drivers/no-otg/otg/otg-fw-mn.h linux/drivers/otg/otg/otg-fw-mn.h
+--- linux/drivers/no-otg/otg/otg-fw-mn.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-fw-mn.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,201 @@
++
++/* Generated by otg-states-h.awk
++ *
++ * Do not Edit thie file
++ */
++
++/*!
++* @file otg/otg/otg-fw-mn.h
++* @brief OTG Firmware - Firmware for mn
++*
++* This file defines the OTG State Machine tests.
++*
++* @ingroup OTGFW
++*/
++
++
++/*!
++* @page OTGFW
++* @section OTGFW - otg-fw-mn.h
++* This contains the input, output and timout definitions for the OTG state machine firmware
++*/
++extern char otg_fw_name_mn[];
++extern int otg_test_max_mn;
++extern struct otg_test otg_tests_mn[];
++extern struct otg_output otg_outputs_mn[];
++
++ /*
++ * Copyright (c) 2004 Belcarra
++ */
++ /*!
++ * This is the initialization set for pcd and tcd.
++ */
++
++#define invalid_state 0 /* Un-initialized state. */
++ /*
++ * This the initial state of the software when first loaded.
++ * It is not possible to return to this state.
++ */
++
++#define otg_disabled 1 /* State Machine ready but disabled. */
++ /*
++ * The USBOTG State Machine has been initialized but is inactive.
++ * This state may have arrived at from either the invalid_state or
++ * from the otg_disable state.
++ */
++
++#define otg_disable_tcd 2 /* State Machine waiting for driver de-initialization. */
++ /*
++ * The State Machine stops the device drivers and waits for them
++ * to signal that they have finished de-initializing.
++ *
++ * This state disables the TCD driver and waits for TCD ok.
++ */
++
++#define otg_disable_pcd 3 /* State Machine waiting for driver de-initialization. */
++ /*
++ * The State Machine stops the device drivers and waits for them
++ * to signal that they have finished de-initializing.
++ *
++ * This state disables the PCD driver and waits for PCD ok.
++ */
++
++#define otg_enable_pcd 4 /* State Machine waiting for driver initialization. */
++ /*
++ * The State Machine starts the device drivers and waits for them
++ * to signal that they have finished initializing.
++ *
++ * This state enables the PCD driver and waits for PCD ok.
++ */
++
++#define otg_enable_tcd 5 /* State Machine waiting for driver initialization. */
++ /*
++ * The State Machine starts the device drivers and waits for them
++ * to signal that they have finished initializing.
++ *
++ * This state enables the PCD driver and waits for PCD ok.
++ */
++ /*
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++ /*!
++ * This is the minimal firmware. It can be included in the
++ * compiled modules and supports the auto Traditional USB
++ * mode. No user inputs are required for normal operation.
++ *
++ * The b_bus_drop input can be optionally used to disconnect and re-connect.
++ *
++ * The enable_otg input can be optionally used to disable and re-enable.
++ * Note that disable/enable will reset b_bus_drop.
++ *
++ */
++ /*!
++ * @name Meta State - otg_init
++ * @{
++ */
++
++#define otg_enabled 6 /* State machine has been initialized. */
++ /*!
++ * The State Machine has successfully started the device drivers and
++ * is waiting for an input event. Typically it will move from here to
++ * an idle state specific to the current conditions (a_idle, b_idle, mn_idle etc.)
++ * based on user request b_bus_drop.
++ *
++ */
++ /* @} */
++ /*!
++ * @name Meta State - b_idle
++ * @{
++ */
++
++#define mn_idle 7 /* In idle mode with bus_drop reset. */
++ /*!
++ * The State Machine is in the idle state for a Traditional USB Device.
++ * It is waiting for Vbus to indicate that it has been plugged into a USB Host.
++ *
++ */
++
++#define mn_bus_drop 8 /* In idle mode with bus_drop set. */
++ /*!
++ * The State Machine is in the idle state for a Traditional USB Device.
++ * The B-Device applications has requested that the bus connection be dropped.
++ * Wait for either enable_otg reset or b_bus_drop reset.
++ */
++ /* @} */
++ /*!
++ * @name Meta State - b_peripheral
++ * @{
++ */
++
++#define mn_peripheral 9 /* Signal a connection and wait for packet traffic. */
++ /*!
++ * The State Machine in the peripheral state for a Traditional USB Device.
++ * The D+ pullup is enabled and we are waiting for a BUS_RESET to
++ * indicate that the USB Host has recognized that a USB Device is attached.
++ */
++
++#define mn_bus_reset 10 /* The bus has been reset. */
++ /*!
++ * The State Machine in the bus_reset state for a Traditional USB Device.
++ * It is waiting to be enumerated and configured by the USB Host.
++ */
++
++#define mn_addressed 11 /* The device has been addressed. */
++ /*!
++ * The State Machine in the configured state for a Traditional USB Device.
++ * This means that there is an active session, there is packet traffic
++ * with this device.
++ */
++
++#define mn_configured 12 /* The device has been configured. */
++ /*!
++ * The State Machine in the configured state for a Traditional USB Device.
++ * This means that there is an active session, there is packet traffic
++ * with this device.
++ */
++
++#define mn_discharge 13 /* Discharging Vbus */
++ /*!
++ * The State Machine in the discharge state for a Traditional USB Device.
++ * The device has been unplugged. The Vbus discharge resistor will be enabled
++ * for the TLDISC_DSCHRG time period.
++ */
++ /* @} */
++ /*!
++ * @name Meta State - b_suspended
++ * @{
++ */
++
++#define mn_suspended 14 /* The bus has been suspended */
++ /*!
++ * The State Machine in the suspend state for a Traditional USB Device.
++ */
++
++#define mn_wakeup_enabled 15 /* Suspended with REMOTE WAKEUP enabled. */
++ /*!
++ * The State Machine in the suspend state for a Traditional USB Device,
++ * prior to suspended the USB Host enabled Remote Wakeup by sending a
++ * set REMOTE WAKUP request.
++ */
++
++#define mn_wakeup 16 /* Perform REMOTE WAKEUP procedure. */
++ /*!
++ * The State Machine in the wakeup state for a Traditional USB Device,
++ * The REMOTE WAKEUP procedure will be performed.
++ */
++ /* @} */
++
++#define terminator_state 17 /* terminator */
++ /*!
++ * This is not an OTG State. It is used internally to mark the end of the
++ * list of states and inputs.
++ */
++
++#define OTG_STATES_MN 18
++
++extern struct otg_state otg_states_mn[OTG_STATES_MN + 1];
++
++extern char *otg_get_state_name_mn(int);
++
++extern struct otg_firmware otg_firmware_mn;
+diff -uNr linux/drivers/no-otg/otg/otg-fw.h linux/drivers/otg/otg/otg-fw.h
+--- linux/drivers/no-otg/otg/otg-fw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-fw.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,1309 @@
++
++/* Generated by otg-h.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++
++/*!
++* @defgroup OTGFW Firmware
++* @ingroup onthegogroup
++*/
++
++/*!
++* @file otg/otg/otg-fw.h
++* @brief OTG Firmware - Input, Output and Timeout definitions
++* This file defines the OTG State Machine input, output and timeout constants.
++*
++*
++* @ingroup OTGFW
++*/
++
++/*!
++* @name OTGFW
++* @section OTGFW - otg-fw.h
++*/
++
++/*!
++* @name OTGVERSION OTG Version
++* Version information
++* @{
++*/
++
++#define OTG_VERSION_FW 200502152159L
++
++/*! @} */
++
++/*!
++* @name BASIC
++* These are the provided for application layer compatibility.
++* @{
++*/
++#ifdef OTG_APPLICATION
++typedef unsigned char u8;
++typedef unsigned short u16;
++typedef unsigned long u32;
++typedef unsigned long long u64;
++#include <stdio.h>
++#include <sys/ioctl.h>
++#endif /* OTG_APPLICATION/ */
++
++/*! @} */
++
++/*!
++* @name OTGSTRUCT OTG Structures
++* Basic OTG Structures
++*/
++#define OTGADMIN_MAXSTR 48
++
++/*!
++ * @struct otg_test
++ *
++ * This defines the tests that allow the state machine to move
++ * from state to state based on input events.
++ *
++ * Goto target: if (
++ * (!test1 || (test1 & inputs)) &&
++ * (!test2 || (test2 & inputs)) &&
++ *
++ */
++typedef struct otg_test {
++ u16 test; /*!< Test number */
++ u16 state; /*!< State Machine State */
++ u32 target; /*!< Goto this target if */
++ u64 test1; /*!< (!test1 || (test1 & inputs)) && */
++ u64 test2; /*!< (!test2 || (test2 & inputs)) && */
++ u64 test3; /*!< (!test3 || (test3 & inputs)) && */
++ /* N.B. An empty test is ignored. */
++} otg_test_t; /*!< */
++
++
++/*!
++ * @struct otg_input_name
++ * This structure simply allows for a table of input names that can
++ * searched for by input mask
++ */
++typedef struct otg_input_name {
++ u32 value; /*!< Bit value */
++ char name[OTGADMIN_MAXSTR]; /*!< Name of state. */
++} otg_input_name_t;
++
++
++/*!
++ * @struct otg_state
++ * This defines an OTG State. Each state has a name, meta state,
++ * timeout, reset and outputs
++ *
++ * On entry to the state the reset mask is or'd into the current
++ * input mask, the settings defined in the output mask are used to.
++ * call the required output functions and then if present the timer
++ * is started with the timeout value (in uSec).
++ *
++ */
++typedef struct otg_state {
++ u16 state; /*!< State Machine State */
++ u16 meta; /*!< Meta Machine State */
++ char name[OTGADMIN_MAXSTR]; /*!< Name of state. */
++ u32 tmout; /*!< Start timeout if non-zero */
++ u64 reset; /*!< Or these inputs on entry to state */
++ u64 outputs; /*!< Or these outputs on entry to state */
++} otg_state_t;
++
++
++/*!
++ * @struct otg_ioctl_name
++ * This structure allows a table for a table of IOCTL event names that can be
++ * searched for by the ioctl command value. It also stores the actual
++ * input mask to set or reset when according to the ioctl arguement.
++ */
++typedef struct otg_ioctl_name {
++ u32 cmd; /*!< Ioctl cmd */
++ u32 set; /*!< Signal to set/reset */
++ char *name; /*!< Name of ioctl. */
++} otg_ioctl_name_t;
++
++
++/*!
++ * @struct otg_admin_command
++ * This allows for a table of IOCTL admin commands.
++ */
++typedef struct otg_admin_command {
++ int n; /*!< Ioctl cmd */
++ char string[OTGADMIN_MAXSTR]; /*!< Signal to set/reset */
++} otg_admin_command_t;
++
++
++/*!
++ * @struct otg_status_update
++ * This is used by the OTG administrative programs to pass data to and received
++ * data from the OTG State Machine driver.
++ */
++typedef struct otg_status_update {
++ u16 state; /*!< current state */
++ u16 meta; /*!< current meta state */
++ u32 inputs; /*!< current inputs */
++ u64 outputs; /*!< current outputs */
++ u32 capabilities; /*!< */
++ char fw_name[OTGADMIN_MAXSTR]; /*!< name of firmware */
++ char state_name[OTGADMIN_MAXSTR]; /*!< name of current state */
++ char meta_name[OTGADMIN_MAXSTR]; /*!< name of current meta-state */
++ char function_name[OTGADMIN_MAXSTR]; /*!< currently selected function */
++} otg_status_update_t;
++
++
++/*!
++ * @struct otg_firmware_info
++ * This is used by the OTG Administrative program to pass firmware information
++ * to the OTG State Machine./
++ */
++typedef struct otg_firmware_info {
++ int number_of_states; /*!< number of states */
++ int number_of_tests; /*!< number of tests */
++ char fw_name[OTGADMIN_MAXSTR]; /*!< name of firmware */
++} otg_firmware_info_t;
++
++
++/*!
++ * @struct otg_firmware
++ * This is used by the OTG Administrative program to pass firmware
++ * to the OTG State Machine./
++ */
++typedef struct otg_firmware {
++ int number_of_states; /*!< number of states */
++ int number_of_tests; /*!< number of tests */
++ char fw_name[OTGADMIN_MAXSTR]; /*!< name of firmware */
++ struct otg_state *otg_states; /*!< output information */
++ struct otg_test *otg_tests; /*!< test information */
++} otg_firmware_t;
++
++/*! @} */
++
++/*!
++* @name OTGTIME Time Macros
++* Basic OTG Time Macros
++*/
++
++#define US(n) (n) /*!< micro-seconds */
++
++#define MS(n) (1000 * US(n)) /*!< milli-seconds */
++
++#define SEC(n) (1000 * MS(n)) /*!< seconds */
++
++/*! @} */
++
++/*!
++* @name OTGOUTPUTM Output Macros
++* OTG Output Macros
++*/
++
++/* OTG State Outputs
++ *
++ * Each state that we transition to defines new settings for each of the defined
++ * outputs. Each output setting can have four settings:
++ *
++ *
++ *
++ *
++ *
++ */
++#define NC ((u64)0x0) /*!< NC no change */
++#define SET ((u64)0x1) /*!< SET the output should be set (i.e. enabled) */
++#define RESET ((u64)0x2) /*!< RESET the output should be reset (i.e. disabled) */
++#define PULSE ((u64)0x3) /*!< OTHER special setting, for example used for pulse vbus */
++#define POWER ((u64)0x3) /*!< POWER */
++
++#define _MASK(n) (((u64) 1) << n) /*!< Set nth bit in 64 bit mask */
++#define _NOT(n) (((u64) n) << 32) /*!< Set nth+32 bit in 64 bit mask */
++#define _ncmask(n) (NC) /*!< No output change mask */
++#define _setmask(n) (SET << (n*2)) /*!< Output set mask */
++#define _resetmask(n) (RESET << (n*2)) /*!< Output reset mask */
++#define _pulsemask(n) (PULSE << (n*2)) /*!< Output pulse mask */
++#define _powermask(n) (POWER << (n*2)) /*!< Output poser mask */
++
++/*! @} */
++
++/*!
++* @name OTGNAMES OTG Names
++* Basic OTG Name Tables
++*/
++
++extern struct otg_input_name otg_input_names[];
++extern struct otg_ioctl_name otg_ioctl_names[];
++extern struct otg_timeouts otg_timeouts[];
++extern struct otg_firmware *otg_firmware_loaded;
++extern char *otg_output_names[];
++
++
++/*! @} */
++
++/* Generated by otg-inputs-h.awk
++ *
++ * Do not Edit this file.
++ */
++
++
++ /*!
++ * N.B. The OTG State Machine Documentation uses the syntax A and A/
++ * to indicate an event being true or not true. Because a trailing
++ * slash is not legal in C we use A and A_ to indicate true and not true.
++ */
++
++ /*!
++ * @name OTG Transceiver Inputs
++ * These inputs reflect changes seen in the OTG Transceiver. These
++ * what are available in most common OTG transceivers, for example
++ * the ISP1301 or MAX3353.
++ *
++ * The following are typical Vbus comparators.
++ *
++ * ISP1301 MAX3353E
++ * B-Session end threshold 0.2V-0.8V 0.5V
++ * Session Valid Comparator 0.8V-2.0V 1.4V
++ * B-Session Valid 2.0V-4.0V N/A
++ * A-Device Vbus Valid Comparator 4.4V 4.6V
++ *
++ * @{
++ */
++#define ID_GND _MASK( 0) /*!< otg_ok - ID is grounded */
++#define ID_GND_ _NOT(ID_GND)
++#define ID_FLOAT _MASK( 1) /*!< otg_ok - ID is floating */
++#define ID_FLOAT_ _NOT(ID_FLOAT)
++#define DP_HIGH _MASK( 2) /*!< otg_ok - DP is pulled high */
++#define DP_HIGH_ _NOT(DP_HIGH)
++#define DM_HIGH _MASK( 3) /*!< otg_ok - DM pullup is pulled high */
++#define DM_HIGH_ _NOT(DM_HIGH)
++#define B_SESS_END _MASK( 4) /*!< otg_ok - Vbus less than B-Session end thresshold */
++#define B_SESS_END_ _NOT(B_SESS_END)
++#define A_SESS_VLD _MASK( 5) /*!< otg_ok - Vbus greater than Session valid threshold */
++#define A_SESS_VLD_ _NOT(A_SESS_VLD)
++#define B_SESS_VLD _MASK( 6) /*!< otg_ok - Vbus greater than B-Session Valid threshold */
++#define B_SESS_VLD_ _NOT(B_SESS_VLD)
++#define VBUS_VLD _MASK( 7) /*!< otg_ok - Vbus greater than A-Device Vbus Valid threshold */
++#define VBUS_VLD_ _NOT(VBUS_VLD)
++#define SRP_DET _MASK( 8) /*!< a_idle - SRP Detected (Vbus pulsed) */
++#define SRP_DET_ _NOT(SRP_DET)
++#define SE0_DET _MASK( 9) /*!< b_idle - SE0 Detected (Single Ended Zeros, DM and DP both low) */
++#define SE0_DET_ _NOT(SE0_DET)
++#define SE1_DET _MASK(10) /*!< b_idle - SE1 Detected (Single Ended Ones, DM and DP both high) */
++#define SE1_DET_ _NOT(SE1_DET)
++#define BDIS_ACON _MASK(10) /*!< a_hnp_wait - Auto DP pullup high after B-disconnect */
++#define BDIS_ACON_ _NOT(BDIS_ACON)
++#define CR_INT_DET _MASK(10) /*!< ph_audio - 0.4V < DP < 0.6V */
++#define CR_INT_DET_ _NOT(CR_INT_DET)
++ /* @} */
++ /*!
++ * @name Peripheral and Host driver signals.
++ *
++ *
++ * @{
++ */
++#define HUB_PORT_CONNECT _MASK(12) /*!< otg_both - Port Connection */
++#define HUB_PORT_CONNECT_ _NOT(HUB_PORT_CONNECT)
++#define BUS_RESET _MASK(13) /*!< otg_both - Bus has reset. */
++#define BUS_RESET_ _NOT(BUS_RESET)
++#define ADDRESSED _MASK(14) /*!< otg_both - Device has been addressed (received SET ADDRESS request.) */
++#define ADDRESSED_ _NOT(ADDRESSED)
++#define CONFIGURED _MASK(15) /*!< otg_both - Device has been configured (received SET CONFIG request.) */
++#define CONFIGURED_ _NOT(CONFIGURED)
++#define NOT_SUPPORTED _MASK(16) /*!< otg_both - Peripheral not supported (no class driver.) */
++#define NOT_SUPPORTED_ _NOT(NOT_SUPPORTED)
++#define BUS_SUSPENDED _MASK(17) /*!< otg_both - Bus has been suspended. */
++#define BUS_SUSPENDED_ _NOT(BUS_SUSPENDED)
++ /* @} */
++
++ /*!
++ * @name Administrative Policy Inputs
++ * These are only valid in the state indicated and
++ * can be enabled or disabled.
++ *
++ * @{
++ */
++#define a_bcon_no_tmout_req _MASK(18) /*!< otg_host - Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode). */
++#define a_bcon_no_tmout_req_ _NOT(a_bcon_no_tmout_req)
++#define a_hpwr_req _MASK(19) /*!< otg_host - Application on A-host wants external charge pump enabled. */
++#define a_hpwr_req_ _NOT(a_hpwr_req)
++#define bus_drop _MASK(20) /*!< otg_ok - Application on Device needs to power down bus. */
++#define bus_drop_ _NOT(bus_drop)
++#define a_bus_drop _MASK(20) /*!< otg_ok - Application on A-Device needs to power down bus. */
++#define a_bus_drop_ _NOT(a_bus_drop)
++#define b_bus_drop _MASK(20) /*!< otg_ok - Application on B-Device needs to disconnect from bus. */
++#define b_bus_drop_ _NOT(b_bus_drop)
++#define bus_req _MASK(21) /*!< otg_ok - Application on Device wants to use the bus. */
++#define bus_req_ _NOT(bus_req)
++#define a_bus_req _MASK(21) /*!< otg_ok - Application on A-Device wants to act as host */
++#define a_bus_req_ _NOT(a_bus_req)
++#define b_bus_req _MASK(21) /*!< otg_ok - Application on B-Device wants to act as host */
++#define b_bus_req_ _NOT(b_bus_req)
++#define b_sess_req _MASK(21) /*!< otg_ok - Application on B-Device to perform SRP (alias for b_srp_req.) */
++#define b_sess_req_ _NOT(b_sess_req)
++#define suspend_req _MASK(22) /*!< otg_host - Application on Device requests bus be suspended (alias for a_bus_req/.) */
++#define suspend_req_ _NOT(suspend_req)
++#define a_suspend_req _MASK(22) /*!< otg_host - Application on A-host requests bus be suspended (alias for a_bus_req/.) */
++#define a_suspend_req_ _NOT(a_suspend_req)
++#define b_suspend_req _MASK(22) /*!< otg_host - Application on B-host requests bus be suspended (alias for b_bus_req/.) */
++#define b_suspend_req_ _NOT(b_suspend_req)
++ /* @} */
++
++ /*!
++ * @name Administrative Action Inputs
++ * These are only valid in state indicated. The
++ * state machine tests must reset in states
++ * prior and after use.
++ * @{
++ */
++#define set_remote_wakeup_cmd _MASK(24) /*!< a_host - A-Device will send Remote Wakeup Enable Request */
++#define set_remote_wakeup_cmd_ _NOT(set_remote_wakeup_cmd)
++#define remote_wakeup_cmd _MASK(24) /*!< tr_configured - B-Device will perform Remote Wakeup. */
++#define remote_wakeup_cmd_ _NOT(remote_wakeup_cmd)
++#define reset_remote_wakeup_cmd _MASK(25) /*!< a_host - A-Device will send Remote Wakeup Disable Request */
++#define reset_remote_wakeup_cmd_ _NOT(reset_remote_wakeup_cmd)
++#define clr_err_cmd _MASK(25) /*!< a_vbus_err - A-Device ill clears Vbus overcurrent error. */
++#define clr_err_cmd_ _NOT(clr_err_cmd)
++#define b_hnp_cmd _MASK(25) /*!< b_configured - B-Device will attempt HNP */
++#define b_hnp_cmd_ _NOT(b_hnp_cmd)
++#define ph_int_cmd _MASK(25) /*!< ph_audio - B-Device will request Carkit interrupt */
++#define ph_int_cmd_ _NOT(ph_int_cmd)
++#define ph_audio_cmd _MASK(25) /*!< ph_uart - Application on B-Device connected to Carkit requests audio mode. */
++#define ph_audio_cmd_ _NOT(ph_audio_cmd)
++#define cr_int_cmd _MASK(25) /*!< cr_aud - Application on A-Device wants to emulate Carkit */
++#define cr_int_cmd_ _NOT(cr_int_cmd)
++#define led_on_cmd _MASK(26) /*!< ph_uart - B-Device will enable Carkit LED */
++#define led_on_cmd_ _NOT(led_on_cmd)
++#define led_off_cmd _MASK(27) /*!< ph_uart - B-Device will disable Carkit LED */
++#define led_off_cmd_ _NOT(led_off_cmd)
++ /* @} */
++
++ /*!
++ * @name Internal State
++ * Used to track status changes.
++ * @{
++ */
++#define HNP_ENABLED _MASK(27) /*!< b_configured - B-HNP Enable Request sent (a-host) or received (b-peripheral). */
++#define HNP_ENABLED_ _NOT(HNP_ENABLED)
++#define HNP_CAPABLE _MASK(28) /*!< otg_both - B-host Peripheral may do HNP */
++#define HNP_CAPABLE_ _NOT(HNP_CAPABLE)
++#define HNP_SUPPORTED _MASK(28) /*!< otg_both - B-host can do HNP (A-Host Received HNP Supported SET FEATURE) */
++#define HNP_SUPPORTED_ _NOT(HNP_SUPPORTED)
++#define REMOTE_WAKEUP_ENABLED _MASK(29) /*!< otg_configured - Remote Wakeup Enable Request received. */
++#define REMOTE_WAKEUP_ENABLED_ _NOT(REMOTE_WAKEUP_ENABLED)
++#define REMOTE_CAPABLE _MASK(29) /*!< otg_both - Peripheral can do remote wakeup */
++#define REMOTE_CAPABLE_ _NOT(REMOTE_CAPABLE)
++ /* @} */
++
++ /*!
++ * @name Global Administration
++ * @{
++ */
++ /* @} */
++
++ /*!
++ * @name Driver Initialization Finished signals
++ * @{
++ */
++#define PCD_OK _MASK(30) /*!< otg_driver - PCD Driver Initialization Finished. */
++#define PCD_OK_ _NOT(PCD_OK)
++#define TCD_OK _MASK(30) /*!< otg_driver - TCD Driver Initialization Finished. */
++#define TCD_OK_ _NOT(TCD_OK)
++#define HCD_OK _MASK(30) /*!< otg_driver - HCD Driver Initialization Finished. */
++#define HCD_OK_ _NOT(HCD_OK)
++#define OCD_OK _MASK(30) /*!< otg_driver - OCD Driver Initialization Finished. */
++#define OCD_OK_ _NOT(OCD_OK)
++ /* @} */
++
++ /*!
++ * @name Timeout and enable
++ * @{
++ */
++#define TMOUT _MASK(30) /*!< otg_all - Generic Timeout */
++#define TMOUT_ _NOT(TMOUT)
++#define enable_otg _MASK(31) /*!< otg_all - Move State Machine otg_disabled state. */
++#define enable_otg_ _NOT(enable_otg)
++#define AUTO _MASK(31) /*!< otg_all - Auto Return (enable_otg only true when active) */
++#define AUTO_ _NOT(AUTO)
++ /* @} */
++
++ /*! @name Timeouts C.f. OTG Table 5-2 A-Device Timing
++ * @{
++ */
++#define Ta_wait_vrise _MASK(30) /*!< a_wait_vrise - Wait for Vbus Rise */
++#define Ta_wait_vrise_ _NOT(Ta_wait_vrise)
++#define TA_WAIT_VRISE MS(100)
++#define Ta_wait_vrise_200 _MASK(30) /*!< a_wait_vrise - Wait for Vbus Rise */
++#define Ta_wait_vrise_200_ _NOT(Ta_wait_vrise_200)
++#define TA_WAIT_VRISE_200 MS(200)
++#define Ta_wait_vrise_400 _MASK(30) /*!< a_wait_vrise - Wait for Vbus Rise */
++#define Ta_wait_vrise_400_ _NOT(Ta_wait_vrise_400)
++#define TA_WAIT_VRISE_400 MS(400)
++#define Ta_wait_vrise_500 _MASK(30) /*!< a_wait_vrise - Wait for Vbus Rise */
++#define Ta_wait_vrise_500_ _NOT(Ta_wait_vrise_500)
++#define TA_WAIT_VRISE_500 MS(500)
++#define Ta_wait_vrise_800 _MASK(30) /*!< a_wait_vrise - Wait for Vbus Rise */
++#define Ta_wait_vrise_800_ _NOT(Ta_wait_vrise_800)
++#define TA_WAIT_VRISE_800 MS(800)
++#define Ta_bcon_ldb _MASK(30) /*!< a_bcon_ldb - B-Connect Long Debounce */
++#define Ta_bcon_ldb_ _NOT(Ta_bcon_ldb)
++#define TA_BCON_LDB MS(100)
++#define Ta_wait_bcon _MASK(30) /*!< a_wait_bcon - Wait for 1 second for B-Connect */
++#define Ta_wait_bcon_ _NOT(Ta_wait_bcon)
++#define TA_WAIT_BCON SEC(1)
++#define Ta_wait_bcon_5 _MASK(30) /*!< a_wait_bcon - Wait for 5 second for B-Connect */
++#define Ta_wait_bcon_5_ _NOT(Ta_wait_bcon_5)
++#define TA_WAIT_BCON_5 SEC(5)
++#define Ta_wait_bcon_10 _MASK(30) /*!< a_wait_bcon - Wait for 10 second for B-Connect */
++#define Ta_wait_bcon_10_ _NOT(Ta_wait_bcon_10)
++#define TA_WAIT_BCON_10 SEC(10)
++#define Ta_aidl_bdis _MASK(30) /*!< a_hnp_wait - A-Idle to B-Disconnect */
++#define Ta_aidl_bdis_ _NOT(Ta_aidl_bdis)
++#define TA_AIDL_BDIS MS(200)
++#define Ta_bdis_acon _MASK(30) /*!< a_suspend - B-disconnect to A-Connect */
++#define Ta_bdis_acon_ _NOT(Ta_bdis_acon)
++#define TA_BDIS_ACON MS(3)
++#define Ta_bidl_adis_min _MASK(30) /*!< a_peripheral - B-Idle to A-Disconnect minimum (TODO) */
++#define Ta_bidl_adis_min_ _NOT(Ta_bidl_adis_min)
++#define TA_BIDL_ADIS_MIN MS(3)
++#define Ta_bcon_sdb _MASK(30) /*!< a_bcon_sdb - B-Connect Short Debounce */
++#define Ta_bcon_sdb_ _NOT(Ta_bcon_sdb)
++#define TA_BCON_SDB US(2)
++#define Ta_bcon_sdb_win _MASK(30) /*!< a_bcon_win - B-Connect Short Debounce Window */
++#define Ta_bcon_sdb_win_ _NOT(Ta_bcon_sdb_win)
++#define TA_BCON_SDB_WIN MS(100)
++ /* @} */
++
++ /*! @name Timeouts C.f. OTG Table 5-3 B-Device Timing
++ * @{
++ */
++#define Tb_se0_srp _MASK(30) /*!< b_srp_se0 - SE0 Time Before SRP */
++#define Tb_se0_srp_ _NOT(Tb_se0_srp)
++#define TB_SE0_SRP MS(2)
++#define Tb_data_pls _MASK(30) /*!< b_srp_init - Data-Line Pulse Time */
++#define Tb_data_pls_ _NOT(Tb_data_pls)
++#define TB_DATA_PLS MS(7)
++#define Tb_data_pls_min _MASK(30) /*!< a_srp_min - Data-Line Pulse minimum time */
++#define Tb_data_pls_min_ _NOT(Tb_data_pls_min)
++#define TB_DATA_PLS_MIN MS(5)
++#define Tb_data_pls_max _MASK(30) /*!< a_srp_wait - Data-Line Pulse maximum time */
++#define Tb_data_pls_max_ _NOT(Tb_data_pls_max)
++#define TB_DATA_PLS_MAX MS(10)
++#define Tb_srp_init _MASK(30) /*!< b_srp_init - SRP Initiate Time (TODO multi-state? Not-needed?) */
++#define Tb_srp_init_ _NOT(Tb_srp_init)
++#define TB_SRP_INIT MS(100)
++#define Tb_srp_fail_min _MASK(30) /*!< b_srp_wait - SRP Fail Time minimum (TODO) */
++#define Tb_srp_fail_min_ _NOT(Tb_srp_fail_min)
++#define TB_SRP_FAIL_MIN SEC(5)
++#define Tb_aidl_bdis_min _MASK(30) /*!< b_peripheral - A-idle to B-Disconnect minimum (TODO) */
++#define Tb_aidl_bdis_min_ _NOT(Tb_aidl_bdis_min)
++#define TB_AIDL_BDIS_MIN MS(5)
++#define Tb_aidl_bdis_max _MASK(30) /*!< b_peripheral - A-idle to B-Disconnect maximum (TODO) */
++#define Tb_aidl_bdis_max_ _NOT(Tb_aidl_bdis_max)
++#define TB_AIDL_BDIS_MAX MS(150)
++#define Tldisc_dschrg _MASK(30) /*!< b_dischrg - Local Disconnect to Data Line Discharge (TODO) */
++#define Tldisc_dschrg_ _NOT(Tldisc_dschrg)
++#define TLDISC_DSCHRG US(25)
++#define Tb_ase0_brst_min _MASK(30) /*!< b_wait_acon - A-SE0 to B-Reset minimum */
++#define Tb_ase0_brst_min_ _NOT(Tb_ase0_brst_min)
++#define TB_ASE0_BRST_MIN US(3125)
++#define Tb_acon_dbnc _MASK(30) /*!< b_acon_dbnc - A-Connect Debounce */
++#define Tb_acon_dbnc_ _NOT(Tb_acon_dbnc)
++#define TB_ACON_DBNC US(2)
++#define Tb_acon_bse0 _MASK(30) /*!< b_host_se0 - A-Connect to B-SE0 */
++#define Tb_acon_bse0_ _NOT(Tb_acon_bse0)
++#define TB_ACON_BSE0 MS(1)
++#define Tid_ldb _MASK(30) /*!< otg_enable - ID changes debounce */
++#define Tid_ldb_ _NOT(Tid_ldb)
++#define TID_LDB MS(100)
++ /* @} */
++
++ /*! @name Timeouts for Carkit
++ * @{
++ */
++#define Tph_bcon_ldb _MASK(30) /*!< ph_init - B-Connect Long Debounce */
++#define Tph_bcon_ldb_ _NOT(Tph_bcon_ldb)
++#define TPH_BCON_LDB MS(100)
++#define Tph_init_pls _MASK(30) /*!< ph_int - Timeout for Carkit interrupt. */
++#define Tph_init_pls_ _NOT(Tph_init_pls)
++#define TPH_INIT_PLS US(500)
++#define Tcr_uart_rsp _MASK(30) /*!< ph_int - Timeout for Carkit UART */
++#define Tcr_uart_rsp_ _NOT(Tcr_uart_rsp)
++#define TCR_UART_RSP MS(30)
++#define Tcr_aud_det _MASK(30) /*!< ph_audio_wait - Timeout waiting for Carkit Audio ack */
++#define Tcr_aud_det_ _NOT(Tcr_aud_det)
++#define TCR_AUD_DET US(1000)
++#define Tph_led_off _MASK(30) /*!< ph_uart - Timeout for LED off pulse */
++#define Tph_led_off_ _NOT(Tph_led_off)
++#define TPH_LED_OFF US(10)
++#define Tph_led_on _MASK(30) /*!< ph_uart - Timeout for LED on pulse */
++#define Tph_led_on_ _NOT(Tph_led_on)
++#define TPH_LED_ON MS(4)
++#define Tcr_led_off _MASK(30) /*!< ph_uart - Timeout for LED off pulse */
++#define Tcr_led_off_ _NOT(Tcr_led_off)
++#define TCR_LED_OFF MS(4)
++#define Tcr_led_on _MASK(30) /*!< ph_uart - Timeout for LED on pulse */
++#define Tcr_led_on_ _NOT(Tcr_led_on)
++#define TCR_LED_ON MS(8)
++#define Tcr_dm_disc _MASK(30) /*!< cr_aud - Timeout for DM disconnect */
++#define Tcr_dm_disc_ _NOT(Tcr_dm_disc)
++#define TCR_DM_DISC MS(50)
++#define Tph_mono_ack _MASK(30) /*!< cr_wait - Timeout for CR INT */
++#define Tph_mono_ack_ _NOT(Tph_mono_ack)
++#define TPH_MONO_ACK MS(1)
++#define Tph_aud_det _MASK(30) /*!< cr_ack - Timeout for CR ACK */
++#define Tph_aud_det_ _NOT(Tph_aud_det)
++#define TPH_AUD_DET MS(100)
++ /* @} */
++
++ /*! @name Timeouts for timer test
++ * @{
++ */
++#define Tzero _MASK(30) /*!< otg_enabled - Startup */
++#define Tzero_ _NOT(Tzero)
++#define TZERO MS(2)
++#define Tst_one_ms _MASK(30) /*!< tm_start - Timer test */
++#define Tst_one_ms_ _NOT(Tst_one_ms)
++#define TST_ONE_MS MS(1)
++#define Tst_ten_ms _MASK(30) /*!< tm_start - Timer test */
++#define Tst_ten_ms_ _NOT(Tst_ten_ms)
++#define TST_TEN_MS MS(10)
++#define Tst_one_second _MASK(30) /*!< tm_start - Timer test */
++#define Tst_one_second_ _NOT(Tst_one_second)
++#define TST_ONE_SECOND SEC(1)
++#define Tst_two_second _MASK(30) /*!< tm_start - Timer test */
++#define Tst_two_second_ _NOT(Tst_two_second)
++#define TST_TWO_SECOND SEC(2)
++#define Tst_four_second _MASK(30) /*!< tm_start - Timer test */
++#define Tst_four_second_ _NOT(Tst_four_second)
++#define TST_FOUR_SECOND SEC(4)
++#define Tst_eight_second _MASK(30) /*!< tm_start - Timer test */
++#define Tst_eight_second_ _NOT(Tst_eight_second)
++#define TST_EIGHT_SECOND SEC(8)
++#define Tst_ten_second _MASK(30) /*!< tm_start - Timer test */
++#define Tst_ten_second_ _NOT(Tst_ten_second)
++#define TST_TEN_SECOND SEC(10)
++ /* @} */
++
++/* Generated by otg-outputs-h.awk
++ *
++ * Do not Edit this file.
++ */
++
++
++
++ /* State Machine Outputs
++ */
++
++ /*! @name Driver Initialization Outputs
++ * N.B. tcd_en is used for older devices, to check if Vbus
++ * already enabled.
++ * @{
++ */
++
++#define TCD_INIT_OUT 0 /*!< Initiate Transceiver Controller Driver Initialization (or De-initialization.) */
++#define tcd_init_out _setmask(TCD_INIT_OUT)
++#define tcd_init_out_ _resetmask(TCD_INIT_OUT)
++#define tcd_init_out_set _setmask(TCD_INIT_OUT)
++#define tcd_init_out_reset _resetmask(TCD_INIT_OUT)
++#define tcd_init_out_power _powermask(TCD_INIT_OUT)
++
++#define PCD_INIT_OUT 1 /*!< Initiate Peripheral Controller Driver Initialization (or De-initialization.) */
++#define pcd_init_out _setmask(PCD_INIT_OUT)
++#define pcd_init_out_ _resetmask(PCD_INIT_OUT)
++#define pcd_init_out_set _setmask(PCD_INIT_OUT)
++#define pcd_init_out_reset _resetmask(PCD_INIT_OUT)
++#define pcd_init_out_power _powermask(PCD_INIT_OUT)
++
++#define HCD_INIT_OUT 2 /*!< Initiate Host Controller Driver Initialization (or De-initialization). */
++#define hcd_init_out _setmask(HCD_INIT_OUT)
++#define hcd_init_out_ _resetmask(HCD_INIT_OUT)
++#define hcd_init_out_set _setmask(HCD_INIT_OUT)
++#define hcd_init_out_reset _resetmask(HCD_INIT_OUT)
++#define hcd_init_out_power _powermask(HCD_INIT_OUT)
++
++#define OCD_INIT_OUT 3 /*!< Initiate OTG Controller Driver Initialization (or De-initialization). */
++#define ocd_init_out _setmask(OCD_INIT_OUT)
++#define ocd_init_out_ _resetmask(OCD_INIT_OUT)
++#define ocd_init_out_set _setmask(OCD_INIT_OUT)
++#define ocd_init_out_reset _resetmask(OCD_INIT_OUT)
++#define ocd_init_out_power _powermask(OCD_INIT_OUT)
++
++#define TCD_EN_OUT 4 /*!< Enable Transceiver Controller Driver */
++#define tcd_en_out _setmask(TCD_EN_OUT)
++#define tcd_en_out_ _resetmask(TCD_EN_OUT)
++#define tcd_en_out_set _setmask(TCD_EN_OUT)
++#define tcd_en_out_reset _resetmask(TCD_EN_OUT)
++#define tcd_en_out_power _powermask(TCD_EN_OUT)
++
++#define PCD_EN_OUT 5 /*!< Enable Peripheral Controller Driver */
++#define pcd_en_out _setmask(PCD_EN_OUT)
++#define pcd_en_out_ _resetmask(PCD_EN_OUT)
++#define pcd_en_out_set _setmask(PCD_EN_OUT)
++#define pcd_en_out_reset _resetmask(PCD_EN_OUT)
++#define pcd_en_out_power _powermask(PCD_EN_OUT)
++
++#define HCD_EN_OUT 6 /*!< Enable Host Controller Driver */
++#define hcd_en_out _setmask(HCD_EN_OUT)
++#define hcd_en_out_ _resetmask(HCD_EN_OUT)
++#define hcd_en_out_set _setmask(HCD_EN_OUT)
++#define hcd_en_out_reset _resetmask(HCD_EN_OUT)
++#define hcd_en_out_power _powermask(HCD_EN_OUT)
++ /* @) */
++
++ /*! @name Transceiver Controller Driver Outputs
++ * @{
++ */
++
++#define DRV_VBUS_OUT 7 /*!< A-Device will Drive Vbus to 5V through charge pump. */
++#define drv_vbus_out _setmask(DRV_VBUS_OUT)
++#define drv_vbus_out_ _resetmask(DRV_VBUS_OUT)
++#define drv_vbus_out_set _setmask(DRV_VBUS_OUT)
++#define drv_vbus_out_reset _resetmask(DRV_VBUS_OUT)
++#define drv_vbus_out_power _powermask(DRV_VBUS_OUT)
++
++#define CHRG_VBUS_OUT 8 /*!< B-Device will charge Vbus to 3.3V through resistor (SRP.) */
++#define chrg_vbus_out _setmask(CHRG_VBUS_OUT)
++#define chrg_vbus_out_ _resetmask(CHRG_VBUS_OUT)
++#define chrg_vbus_out_set _setmask(CHRG_VBUS_OUT)
++#define chrg_vbus_out_reset _resetmask(CHRG_VBUS_OUT)
++#define chrg_vbus_out_power _powermask(CHRG_VBUS_OUT)
++
++#define DISCHRG_VBUS_OUT 9 /*!< B-Device will discharge Vbus (enable dischage resistor.) */
++#define dischrg_vbus_out _setmask(DISCHRG_VBUS_OUT)
++#define dischrg_vbus_out_ _resetmask(DISCHRG_VBUS_OUT)
++#define dischrg_vbus_out_set _setmask(DISCHRG_VBUS_OUT)
++#define dischrg_vbus_out_reset _resetmask(DISCHRG_VBUS_OUT)
++#define dischrg_vbus_out_power _powermask(DISCHRG_VBUS_OUT)
++
++#define DM_PULLUP_OUT 10 /*!< DM pullup control - aka loc_carkit */
++#define dm_pullup_out _setmask(DM_PULLUP_OUT)
++#define dm_pullup_out_ _resetmask(DM_PULLUP_OUT)
++#define dm_pullup_out_set _setmask(DM_PULLUP_OUT)
++#define dm_pullup_out_reset _resetmask(DM_PULLUP_OUT)
++#define dm_pullup_out_power _powermask(DM_PULLUP_OUT)
++
++#define DM_PULLDOWN_OUT 11 /*!< DM pulldown control */
++#define dm_pulldown_out _setmask(DM_PULLDOWN_OUT)
++#define dm_pulldown_out_ _resetmask(DM_PULLDOWN_OUT)
++#define dm_pulldown_out_set _setmask(DM_PULLDOWN_OUT)
++#define dm_pulldown_out_reset _resetmask(DM_PULLDOWN_OUT)
++#define dm_pulldown_out_power _powermask(DM_PULLDOWN_OUT)
++
++#define DP_PULLUP_OUT 12 /*!< DP pullup control - aka loc_conn */
++#define dp_pullup_out _setmask(DP_PULLUP_OUT)
++#define dp_pullup_out_ _resetmask(DP_PULLUP_OUT)
++#define dp_pullup_out_set _setmask(DP_PULLUP_OUT)
++#define dp_pullup_out_reset _resetmask(DP_PULLUP_OUT)
++#define dp_pullup_out_power _powermask(DP_PULLUP_OUT)
++
++#define DP_PULLDOWN_OUT 13 /*!< DP pulldown control */
++#define dp_pulldown_out _setmask(DP_PULLDOWN_OUT)
++#define dp_pulldown_out_ _resetmask(DP_PULLDOWN_OUT)
++#define dp_pulldown_out_set _setmask(DP_PULLDOWN_OUT)
++#define dp_pulldown_out_reset _resetmask(DP_PULLDOWN_OUT)
++#define dp_pulldown_out_power _powermask(DP_PULLDOWN_OUT)
++
++#define CLR_OVERCURRENT_OUT 14 /*!< Clear overcurrent indication */
++#define clr_overcurrent_out _setmask(CLR_OVERCURRENT_OUT)
++#define clr_overcurrent_out_ _resetmask(CLR_OVERCURRENT_OUT)
++#define clr_overcurrent_out_set _setmask(CLR_OVERCURRENT_OUT)
++#define clr_overcurrent_out_reset _resetmask(CLR_OVERCURRENT_OUT)
++#define clr_overcurrent_out_power _powermask(CLR_OVERCURRENT_OUT)
++
++#define DM_DET_OUT 15 /*!< Enable B-Device D- High detect */
++#define dm_det_out _setmask(DM_DET_OUT)
++#define dm_det_out_ _resetmask(DM_DET_OUT)
++#define dm_det_out_set _setmask(DM_DET_OUT)
++#define dm_det_out_reset _resetmask(DM_DET_OUT)
++#define dm_det_out_power _powermask(DM_DET_OUT)
++
++#define DP_DET_OUT 16 /*!< Enable B-Device D+ High detect */
++#define dp_det_out _setmask(DP_DET_OUT)
++#define dp_det_out_ _resetmask(DP_DET_OUT)
++#define dp_det_out_set _setmask(DP_DET_OUT)
++#define dp_det_out_reset _resetmask(DP_DET_OUT)
++#define dp_det_out_power _powermask(DP_DET_OUT)
++
++#define CR_DET_OUT 17 /*!< Enable D+ CR detect */
++#define cr_det_out _setmask(CR_DET_OUT)
++#define cr_det_out_ _resetmask(CR_DET_OUT)
++#define cr_det_out_set _setmask(CR_DET_OUT)
++#define cr_det_out_reset _resetmask(CR_DET_OUT)
++#define cr_det_out_power _powermask(CR_DET_OUT)
++
++#define CHARGE_PUMP_OUT 18 /*!< Enable external charge pump. */
++#define charge_pump_out _setmask(CHARGE_PUMP_OUT)
++#define charge_pump_out_ _resetmask(CHARGE_PUMP_OUT)
++#define charge_pump_out_set _setmask(CHARGE_PUMP_OUT)
++#define charge_pump_out_reset _resetmask(CHARGE_PUMP_OUT)
++#define charge_pump_out_power _powermask(CHARGE_PUMP_OUT)
++
++#define BDIS_ACON_OUT 19 /*!< Enable auto A-connect after B-disconnect. */
++#define bdis_acon_out _setmask(BDIS_ACON_OUT)
++#define bdis_acon_out_ _resetmask(BDIS_ACON_OUT)
++#define bdis_acon_out_set _setmask(BDIS_ACON_OUT)
++#define bdis_acon_out_reset _resetmask(BDIS_ACON_OUT)
++#define bdis_acon_out_power _powermask(BDIS_ACON_OUT)
++
++#define MX21_VBUS_DRAIN 20 /*!< MX21 hack */
++#define mx21_vbus_drain _setmask(MX21_VBUS_DRAIN)
++#define mx21_vbus_drain_ _resetmask(MX21_VBUS_DRAIN)
++#define mx21_vbus_drain_set _setmask(MX21_VBUS_DRAIN)
++#define mx21_vbus_drain_reset _resetmask(MX21_VBUS_DRAIN)
++#define mx21_vbus_drain_power _powermask(MX21_VBUS_DRAIN)
++
++#define ID_PULLDOWN_OUT 21 /*!< Enable the ID to ground pulldown ( (CEA-936 - 5 wire carkit.) */
++#define id_pulldown_out _setmask(ID_PULLDOWN_OUT)
++#define id_pulldown_out_ _resetmask(ID_PULLDOWN_OUT)
++#define id_pulldown_out_set _setmask(ID_PULLDOWN_OUT)
++#define id_pulldown_out_reset _resetmask(ID_PULLDOWN_OUT)
++#define id_pulldown_out_power _powermask(ID_PULLDOWN_OUT)
++
++#define UART_OUT 22 /*!< Enable Transparent UART mode (CEA-936.) */
++#define uart_out _setmask(UART_OUT)
++#define uart_out_ _resetmask(UART_OUT)
++#define uart_out_set _setmask(UART_OUT)
++#define uart_out_reset _resetmask(UART_OUT)
++#define uart_out_power _powermask(UART_OUT)
++
++#define AUDIO_OUT 23 /*!< Enable Audio mode (CEA-936 CarKit interrupt detector.) */
++#define audio_out _setmask(AUDIO_OUT)
++#define audio_out_ _resetmask(AUDIO_OUT)
++#define audio_out_set _setmask(AUDIO_OUT)
++#define audio_out_reset _resetmask(AUDIO_OUT)
++#define audio_out_power _powermask(AUDIO_OUT)
++
++#define MONO_OUT 24 /*!< Enable Mono-Audio mode (CEA-936.) */
++#define mono_out _setmask(MONO_OUT)
++#define mono_out_ _resetmask(MONO_OUT)
++#define mono_out_set _setmask(MONO_OUT)
++#define mono_out_reset _resetmask(MONO_OUT)
++#define mono_out_power _powermask(MONO_OUT)
++ /* @) */
++
++ /*! @name Peripheral Controller Driver Outputs
++ * @{
++ */
++
++#define REMOTE_WAKEUP_OUT 25 /*!< Peripheral will perform remote wakeup. */
++#define remote_wakeup_out _setmask(REMOTE_WAKEUP_OUT)
++#define remote_wakeup_out_ _resetmask(REMOTE_WAKEUP_OUT)
++#define remote_wakeup_out_set _setmask(REMOTE_WAKEUP_OUT)
++#define remote_wakeup_out_reset _resetmask(REMOTE_WAKEUP_OUT)
++#define remote_wakeup_out_power _powermask(REMOTE_WAKEUP_OUT)
++ /* @) */
++
++ /*! @name Host Controller Driver Outputs
++ * @{
++ */
++
++#define LOC_SOF_OUT 26 /*!< Host will enable packet traffic. */
++#define loc_sof_out _setmask(LOC_SOF_OUT)
++#define loc_sof_out_ _resetmask(LOC_SOF_OUT)
++#define loc_sof_out_set _setmask(LOC_SOF_OUT)
++#define loc_sof_out_reset _resetmask(LOC_SOF_OUT)
++#define loc_sof_out_power _powermask(LOC_SOF_OUT)
++
++#define LOC_SUSPEND_OUT 27 /*!< Host will suspend bus. */
++#define loc_suspend_out _setmask(LOC_SUSPEND_OUT)
++#define loc_suspend_out_ _resetmask(LOC_SUSPEND_OUT)
++#define loc_suspend_out_set _setmask(LOC_SUSPEND_OUT)
++#define loc_suspend_out_reset _resetmask(LOC_SUSPEND_OUT)
++#define loc_suspend_out_power _powermask(LOC_SUSPEND_OUT)
++
++#define REMOTE_WAKEUP_EN_OUT 28 /*!< Host will send remote wakeup enable or disable request. */
++#define remote_wakeup_en_out _setmask(REMOTE_WAKEUP_EN_OUT)
++#define remote_wakeup_en_out_ _resetmask(REMOTE_WAKEUP_EN_OUT)
++#define remote_wakeup_en_out_set _setmask(REMOTE_WAKEUP_EN_OUT)
++#define remote_wakeup_en_out_reset _resetmask(REMOTE_WAKEUP_EN_OUT)
++#define remote_wakeup_en_out_power _powermask(REMOTE_WAKEUP_EN_OUT)
++
++#define HNP_EN_OUT 29 /*!< Host will send HNP enable request. */
++#define hnp_en_out _setmask(HNP_EN_OUT)
++#define hnp_en_out_ _resetmask(HNP_EN_OUT)
++#define hnp_en_out_set _setmask(HNP_EN_OUT)
++#define hnp_en_out_reset _resetmask(HNP_EN_OUT)
++#define hnp_en_out_power _powermask(HNP_EN_OUT)
++
++#define HPWR_OUT 30 /*!< Host will enable high power (external charge pump.) */
++#define hpwr_out _setmask(HPWR_OUT)
++#define hpwr_out_ _resetmask(HPWR_OUT)
++#define hpwr_out_set _setmask(HPWR_OUT)
++#define hpwr_out_reset _resetmask(HPWR_OUT)
++#define hpwr_out_power _powermask(HPWR_OUT)
++ /* @) */
++#define MAX_OUTPUTS 31
++
++/* Generated by otg-ioctls-h.awk
++ *
++ * Do not Edit this file,
++ */
++
++
++#if defined(OTG_LINUX)
++
++#define OTGADMIN_MAGIC 'O'
++#define OTGADMIN_VERSION _IOR(OTGADMIN_MAGIC, 1, u64)
++#define OTGADMIN_STATUS _IOR(OTGADMIN_MAGIC, 3, struct otg_status_update)
++#define OTGADMIN_SET_FUNCTION _IOW(OTGADMIN_MAGIC, 4, struct otg_admin_command)
++#define OTGADMIN_GET_FUNCTION _IOR(OTGADMIN_MAGIC, 4, struct otg_admin_command)
++#define OTGADMIN_SET_INFO _IOW(OTGADMIN_MAGIC, 5, struct otg_firmware_info)
++#define OTGADMIN_GET_INFO _IOR(OTGADMIN_MAGIC, 5, struct otg_firmware_info)
++#define OTGADMIN_SET_STATE _IOW(OTGADMIN_MAGIC, 6, struct otg_state)
++#define OTGADMIN_GET_STATE _IOR(OTGADMIN_MAGIC, 6, struct otg_state)
++#define OTGADMIN_SET_TEST _IOW(OTGADMIN_MAGIC, 7, struct otg_test)
++#define OTGADMIN_GET_TEST _IOR(OTGADMIN_MAGIC, 7, struct otg_test)
++#define OTGADMIN_SET_SERIAL _IOW(OTGADMIN_MAGIC, 8, struct otg_admin_command)
++#define OTGADMIN_GET_SERIAL _IOR(OTGADMIN_MAGIC, 8, struct otg_admin_command)
++
++
++
++ /*!
++ * Signal Sent: a_bcon_no_tmout_req
++ * State Valid: otg_host
++ * Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode).
++ */
++#define OTGADMIN_A_BCON_NO_TMOUT_REQ _IOW(OTGADMIN_MAGIC, 10, int)
++
++ /*!
++ * Signal Sent: a_hpwr_req
++ * State Valid: otg_host
++ * Application on A-host wants external charge pump enabled.
++ */
++#define OTGADMIN_A_HPWR_REQ _IOW(OTGADMIN_MAGIC, 11, int)
++
++ /*!
++ * Signal Sent: bus_drop
++ * State Valid: otg_ok
++ * Application on Device needs to power down bus.
++ */
++#define OTGADMIN_BUS_DROP _IOW(OTGADMIN_MAGIC, 12, int)
++
++ /*!
++ * Signal Sent: a_bus_drop
++ * State Valid: otg_ok
++ * Application on A-Device needs to power down bus.
++ */
++#define OTGADMIN_A_BUS_DROP _IOW(OTGADMIN_MAGIC, 13, int)
++
++ /*!
++ * Signal Sent: b_bus_drop
++ * State Valid: otg_ok
++ * Application on B-Device needs to disconnect from bus.
++ */
++#define OTGADMIN_B_BUS_DROP _IOW(OTGADMIN_MAGIC, 14, int)
++
++ /*!
++ * Signal Sent: bus_req
++ * State Valid: otg_ok
++ * Application on Device wants to use the bus.
++ */
++#define OTGADMIN_BUS_REQ _IOW(OTGADMIN_MAGIC, 15, int)
++
++ /*!
++ * Signal Sent: a_bus_req
++ * State Valid: otg_ok
++ * Application on A-Device wants to act as host
++ */
++#define OTGADMIN_A_BUS_REQ _IOW(OTGADMIN_MAGIC, 16, int)
++
++ /*!
++ * Signal Sent: b_bus_req
++ * State Valid: otg_ok
++ * Application on B-Device wants to act as host
++ */
++#define OTGADMIN_B_BUS_REQ _IOW(OTGADMIN_MAGIC, 17, int)
++
++ /*!
++ * Signal Sent: b_sess_req
++ * State Valid: otg_ok
++ * Application on B-Device to perform SRP (alias for b_srp_req.)
++ */
++#define OTGADMIN_B_SESS_REQ _IOW(OTGADMIN_MAGIC, 18, int)
++
++ /*!
++ * Signal Sent: suspend_req
++ * State Valid: otg_host
++ * Application on Device requests bus be suspended (alias for a_bus_req/.)
++ */
++#define OTGADMIN_SUSPEND_REQ _IOW(OTGADMIN_MAGIC, 19, int)
++
++ /*!
++ * Signal Sent: a_suspend_req
++ * State Valid: otg_host
++ * Application on A-host requests bus be suspended (alias for a_bus_req/.)
++ */
++#define OTGADMIN_A_SUSPEND_REQ _IOW(OTGADMIN_MAGIC, 20, int)
++
++ /*!
++ * Signal Sent: b_suspend_req
++ * State Valid: otg_host
++ * Application on B-host requests bus be suspended (alias for b_bus_req/.)
++ */
++#define OTGADMIN_B_SUSPEND_REQ _IOW(OTGADMIN_MAGIC, 21, int)
++
++ /*!
++ * Signal Sent: set_remote_wakeup_cmd
++ * State Valid: a_host
++ * A-Device will send Remote Wakeup Enable Request
++ */
++#define OTGADMIN_SET_REMOTE_WAKEUP_CMD _IOW(OTGADMIN_MAGIC, 22, int)
++
++ /*!
++ * Signal Sent: remote_wakeup_cmd
++ * State Valid: tr_configured
++ * B-Device will perform Remote Wakeup.
++ */
++#define OTGADMIN_REMOTE_WAKEUP_CMD _IOW(OTGADMIN_MAGIC, 23, int)
++
++ /*!
++ * Signal Sent: reset_remote_wakeup_cmd
++ * State Valid: a_host
++ * A-Device will send Remote Wakeup Disable Request
++ */
++#define OTGADMIN_RESET_REMOTE_WAKEUP_CMD _IOW(OTGADMIN_MAGIC, 24, int)
++
++ /*!
++ * Signal Sent: clr_err_cmd
++ * State Valid: a_vbus_err
++ * A-Device ill clears Vbus overcurrent error.
++ */
++#define OTGADMIN_CLR_ERR_CMD _IOW(OTGADMIN_MAGIC, 25, int)
++
++ /*!
++ * Signal Sent: b_hnp_cmd
++ * State Valid: b_configured
++ * B-Device will attempt HNP
++ */
++#define OTGADMIN_B_HNP_CMD _IOW(OTGADMIN_MAGIC, 26, int)
++
++ /*!
++ * Signal Sent: ph_int_cmd
++ * State Valid: ph_audio
++ * B-Device will request Carkit interrupt
++ */
++#define OTGADMIN_PH_INT_CMD _IOW(OTGADMIN_MAGIC, 27, int)
++
++ /*!
++ * Signal Sent: ph_audio_cmd
++ * State Valid: ph_uart
++ * Application on B-Device connected to Carkit requests audio mode.
++ */
++#define OTGADMIN_PH_AUDIO_CMD _IOW(OTGADMIN_MAGIC, 28, int)
++
++ /*!
++ * Signal Sent: cr_int_cmd
++ * State Valid: cr_aud
++ * Application on A-Device wants to emulate Carkit
++ */
++#define OTGADMIN_CR_INT_CMD _IOW(OTGADMIN_MAGIC, 29, int)
++
++ /*!
++ * Signal Sent: led_on_cmd
++ * State Valid: ph_uart
++ * B-Device will enable Carkit LED
++ */
++#define OTGADMIN_LED_ON_CMD _IOW(OTGADMIN_MAGIC, 30, int)
++
++ /*!
++ * Signal Sent: led_off_cmd
++ * State Valid: ph_uart
++ * B-Device will disable Carkit LED
++ */
++#define OTGADMIN_LED_OFF_CMD _IOW(OTGADMIN_MAGIC, 31, int)
++
++ /*!
++ * Signal Sent: enable_otg
++ * State Valid: otg_all
++ * Move State Machine otg_disabled state.
++ */
++#define OTGADMIN_ENABLE_OTG _IOW(OTGADMIN_MAGIC, 32, int)
++
++#define OTGADMIN_MAXNR 33
++
++
++#endif /* defined(OTG_LINUX) */
++
++/* Generated by otg-iocontrol-h.awk
++ *
++ * Do not Edit this file,
++ */
++
++
++#if defined(OTG_WINCE)
++
++#define OTGADMIN_BASE$ 0x401
++#define _USBLAN_CTL_CODE(_Function, _Method, _Access) \
++ CTL_CODE(OTGADMIN_BASE, _Function, _Method, _Access)
++
++#define OTGADMIN_VERSION OTGADMIN_CTL_CODE(0x401, METHOD_BUFFERRED, FILE_READ_ACCESS)
++#define OTGADMIN_STATUS OTGADMIN_CTL_CODE(0x403, METHOD_BUFFERRED, FILE_READ_ACCESS)
++#define OTGADMIN_SET_FUNCTION OTGADMIN_CTL_CODE(0x404, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
++#define OTGADMIN_GET_FUNCTION OTGADMIN_CTL_CODE(0x404, METHOD_BUFFERRED, FILE_READ_ACCESS)
++#define OTGADMIN_SET_INFO OTGADMIN_CTL_CODE(0x405, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
++#define OTGADMIN_GET_INFO OTGADMIN_CTL_CODE(0x405, METHOD_BUFFERRED, FILE_READ_ACCESS)
++#define OTGADMIN_SET_STATE OTGADMIN_CTL_CODE(0x406, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
++#define OTGADMIN_GET_STATE OTGADMIN_CTL_CODE(0x406, METHOD_BUFFERRED, FILE_READ_ACCESS)
++#define OTGADMIN_SET_TEST OTGADMIN_CTL_CODE(0x407, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
++#define OTGADMIN_GET_TEST OTGADMIN_CTL_CODE(0x407, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++
++
++ /*!
++ * Signal Sent: a_bcon_no_tmout_req
++ * State Valid: otg_host
++ * Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode).
++ */
++#define OTGADMIN_A_BCON_NO_TMOUT_REQ OTGADMIN_CTL_CODE(, 0x40a, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: a_hpwr_req
++ * State Valid: otg_host
++ * Application on A-host wants external charge pump enabled.
++ */
++#define OTGADMIN_A_HPWR_REQ OTGADMIN_CTL_CODE(, 0x40b, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: bus_drop
++ * State Valid: otg_ok
++ * Application on Device needs to power down bus.
++ */
++#define OTGADMIN_BUS_DROP OTGADMIN_CTL_CODE(, 0x40c, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: a_bus_drop
++ * State Valid: otg_ok
++ * Application on A-Device needs to power down bus.
++ */
++#define OTGADMIN_A_BUS_DROP OTGADMIN_CTL_CODE(, 0x40d, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: b_bus_drop
++ * State Valid: otg_ok
++ * Application on B-Device needs to disconnect from bus.
++ */
++#define OTGADMIN_B_BUS_DROP OTGADMIN_CTL_CODE(, 0x40e, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: bus_req
++ * State Valid: otg_ok
++ * Application on Device wants to use the bus.
++ */
++#define OTGADMIN_BUS_REQ OTGADMIN_CTL_CODE(, 0x40f, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: a_bus_req
++ * State Valid: otg_ok
++ * Application on A-Device wants to act as host
++ */
++#define OTGADMIN_A_BUS_REQ OTGADMIN_CTL_CODE(, 0x410, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: b_bus_req
++ * State Valid: otg_ok
++ * Application on B-Device wants to act as host
++ */
++#define OTGADMIN_B_BUS_REQ OTGADMIN_CTL_CODE(, 0x411, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: b_sess_req
++ * State Valid: otg_ok
++ * Application on B-Device to perform SRP (alias for b_srp_req.)
++ */
++#define OTGADMIN_B_SESS_REQ OTGADMIN_CTL_CODE(, 0x412, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: suspend_req
++ * State Valid: otg_host
++ * Application on Device requests bus be suspended (alias for a_bus_req/.)
++ */
++#define OTGADMIN_SUSPEND_REQ OTGADMIN_CTL_CODE(, 0x413, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: a_suspend_req
++ * State Valid: otg_host
++ * Application on A-host requests bus be suspended (alias for a_bus_req/.)
++ */
++#define OTGADMIN_A_SUSPEND_REQ OTGADMIN_CTL_CODE(, 0x414, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: b_suspend_req
++ * State Valid: otg_host
++ * Application on B-host requests bus be suspended (alias for b_bus_req/.)
++ */
++#define OTGADMIN_B_SUSPEND_REQ OTGADMIN_CTL_CODE(, 0x415, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: set_remote_wakeup_cmd
++ * State Valid: a_host
++ * A-Device will send Remote Wakeup Enable Request
++ */
++#define OTGADMIN_SET_REMOTE_WAKEUP_CMD OTGADMIN_CTL_CODE(, 0x416, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: remote_wakeup_cmd
++ * State Valid: tr_configured
++ * B-Device will perform Remote Wakeup.
++ */
++#define OTGADMIN_REMOTE_WAKEUP_CMD OTGADMIN_CTL_CODE(, 0x417, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: reset_remote_wakeup_cmd
++ * State Valid: a_host
++ * A-Device will send Remote Wakeup Disable Request
++ */
++#define OTGADMIN_RESET_REMOTE_WAKEUP_CMD OTGADMIN_CTL_CODE(, 0x418, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: clr_err_cmd
++ * State Valid: a_vbus_err
++ * A-Device ill clears Vbus overcurrent error.
++ */
++#define OTGADMIN_CLR_ERR_CMD OTGADMIN_CTL_CODE(, 0x419, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: b_hnp_cmd
++ * State Valid: b_configured
++ * B-Device will attempt HNP
++ */
++#define OTGADMIN_B_HNP_CMD OTGADMIN_CTL_CODE(, 0x41a, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: ph_int_cmd
++ * State Valid: ph_audio
++ * B-Device will request Carkit interrupt
++ */
++#define OTGADMIN_PH_INT_CMD OTGADMIN_CTL_CODE(, 0x41b, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: ph_audio_cmd
++ * State Valid: ph_uart
++ * Application on B-Device connected to Carkit requests audio mode.
++ */
++#define OTGADMIN_PH_AUDIO_CMD OTGADMIN_CTL_CODE(, 0x41c, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: cr_int_cmd
++ * State Valid: cr_aud
++ * Application on A-Device wants to emulate Carkit
++ */
++#define OTGADMIN_CR_INT_CMD OTGADMIN_CTL_CODE(, 0x41d, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: led_on_cmd
++ * State Valid: ph_uart
++ * B-Device will enable Carkit LED
++ */
++#define OTGADMIN_LED_ON_CMD OTGADMIN_CTL_CODE(, 0x41e, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: led_off_cmd
++ * State Valid: ph_uart
++ * B-Device will disable Carkit LED
++ */
++#define OTGADMIN_LED_OFF_CMD OTGADMIN_CTL_CODE(, 0x41f, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++ /*!
++ * Signal Sent: enable_otg
++ * State Valid: otg_all
++ * Move State Machine otg_disabled state.
++ */
++#define OTGADMIN_ENABLE_OTG OTGADMIN_CTL_CODE(, 0x420, METHOD_BUFFERRED, FILE_READ_ACCESS)
++
++#define OTGADMIN_MAXNR 33
++
++
++#endif /* defined(OTG_WINCE) */
++
++/* Generated by otg-metas-h.awk
++ *
++ * Do not Edit thie file
++ */
++
++
++ /*! @name OTG Figure 6-2 Meta States
++ *
++ * These are the Meta States defined in the 2.0 OTG Specification
++ * Figure 6.2 - Dual-Role A-Device.
++ * @{
++ */
++
++#define m_a_idle 0 /* */
++
++#define m_a_wait_vrise 1 /* */
++
++#define m_a_wait_bcon 2 /* */
++
++#define m_a_host 3 /* */
++
++#define m_a_suspend 4 /* */
++
++#define m_a_peripheral 5 /* */
++
++#define m_a_wait_vfall 6 /* */
++
++#define m_a_vbus_err 7 /* */
++ /* @} */
++ /*! @name OTG Figure 6-3 Meta States
++ *
++ * These are the Meta States defined in the 2.0 OTG Specification
++ * Figure 6.3 - Dual-Role B-Device.
++ * @{
++ */
++
++#define m_b_idle 8 /* */
++
++#define m_b_srp_init 9 /* */
++
++#define m_b_peripheral 10 /* */
++
++#define m_b_suspend 11 /* */
++
++#define m_b_wait_acon 12 /* */
++
++#define m_b_host 13 /* */
++
++#define m_b_suspended 14 /* */
++ /* @} */
++ /*! @name Carkit Meta States Figure 7-7
++ *
++ * @{
++ */
++
++#define m_ph_disc 15 /* Equivalent to b_peripheral */
++
++#define m_ph_init 16 /* */
++
++#define m_ph_uart 17 /* */
++
++#define m_ph_aud 18 /* */
++
++#define m_ph_wait 19 /* */
++
++#define m_ph_exit 20 /* */
++
++#define m_cr_init 21 /* */
++
++#define m_cr_uart 22 /* */
++
++#define m_cr_aud 23 /* */
++
++#define m_cr_ack 24 /* */
++
++#define m_cr_wait 25 /* */
++
++#define m_cr_disc 26 /* */
++ /* @} */
++ /*! @name Additional states used locally.
++ *
++ * @{
++ */
++
++#define m_otg_init 27 /* */
++
++#define m_usb_accessory 28 /* */
++
++#define m_usb_factory 29 /* */
++
++#define m_unknown 30 /* */
++ /* @} */
++
++#define OTG_METAS_FW 31
++
++extern char *otg_meta_names[];
+diff -uNr linux/drivers/no-otg/otg/otg-hcd.h linux/drivers/otg/otg/otg-hcd.h
+--- linux/drivers/no-otg/otg/otg-hcd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-hcd.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * otg/otg-hcd.h - OTG Host Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @defgroup OTGHCD Host Controller Driver Support
++ * @ingroup onthegogroup
++ */
++/*!
++ * @file otg/otg/otg-hcd.h
++ * @brief Defines common to On-The-Go Host Controller Support
++ *
++ * This file defines the hcd_ops and hcd_instance structures.
++ *
++ * The hcd_ops structure contains all of the output functions that will
++ * be called as required by the OTG event handler when changing states.
++ *
++ * The hcd_instance structure is used to maintain the global data
++ * required by the host controller drivers.
++ *
++ * @ingroup OTGHCD
++ */
++
++/*!
++ * @name HCD Host Controller Driver
++ * @{
++ */
++struct hcd_instance;
++
++/*!
++ * @struct hcd_ops
++ * The pcd_ops structure contains pointers to all of the functions implemented for the
++ * linked in driver. Having them in this structure allows us to easily determine what
++ * functions are available without resorting to ugly compile time macros or ifdefs
++ *
++ * There is only one instance of this, defined in the device specific lower layer.
++ */
++struct hcd_ops {
++
++ /* mandatory */
++ int max_ports; /*!< maximum number of ports available */
++ u32 capabilities; /*!< UDC Capabilities - see usbd-bus.h for details */
++ char *name; /*!< name of controller */
++
++ /* Driver Initialization - by degrees
++ */
++ int (*mod_init) (void); /*!< HCD Module Initialization */
++ void (*mod_exit) (void); /*!< HCD Module Exit */
++
++
++ otg_output_proc_t hcd_init_func; /*!< OTG calls to initialize or de-initialize the HCD */
++ otg_output_proc_t hcd_en_func; /*!< OTG calls to enable or disable the HCD */
++ otg_output_proc_t loc_sof_func; /*!< OTG calls to into a_host or b_host state - attempt to use port */
++ otg_output_proc_t loc_suspend_func; /*!< OTG calls to suspend bus */
++ otg_output_proc_t remote_wakeup_en_func; /*!< OTG calls to issue SET FEATURE REMOTE WAKEUP */
++ otg_output_proc_t hnp_en_func; /*!< OTG calls to issues SET FEATURE B_HNP_ENABLE */
++};
++
++/*!
++ * @struct hcd_instance
++ */
++struct hcd_instance {
++ struct otg_instance *otg; /*!< pointer to OTG Instance */
++ void * privdata; /*!< pointer to private data for PCD */
++ struct WORK_STRUCT bh; /*!< work structure for bottom half handler */
++};
++
++#define HCD hcd_trace_tag
++extern otg_tag_t HCD;
++extern struct hcd_ops hcd_ops;
++extern struct hcd_instance *hcd_instance;
++
++extern void hcd_init_func(struct otg_instance *, u8 );
++extern void hcd_en_func(struct otg_instance *, u8 );
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/otg/otg-linux.h linux/drivers/otg/otg/otg-linux.h
+--- linux/drivers/no-otg/otg/otg-linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-linux.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,284 @@
++/*
++ * otg/otg/otg-linux.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++
++/*!
++ * @file otg/otg/otg-linux.h
++ * @brief Linux OS Compatibility defines
++ *
++ * @ingroup OTGCore
++ */
++#ifndef _OTG_LINUX_H
++#define _OTG_LINUX_H 1
++
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/ctype.h>
++#include <linux/slab.h>
++#include <asm/types.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/atomic.h>
++#include <linux/proc_fs.h>
++#include <linux/interrupt.h>
++#include <linux/random.h>
++#include <linux/sched.h>
++
++/*! @name Compilation Related
++ */
++
++/*! @{ */
++#undef PRAGMAPACK
++#define PACKED __attribute__((packed))
++#define INLINE __inline__
++
++/*! @} */
++
++/*! @name Memory Allocation Primitives
++ *
++ * CKMALLOC()
++ * LSTRDUP()
++ * LKFREE()
++ * LIST_ENTRY()
++ * LIST_FOR_EACH()
++ */
++
++ /*! @{ */
++
++#if defined(LINUX26)
++ #include <linux/gfp.h>
++#define GET_KERNEL_PAGE() __get_free_page(GFP_KERNEL)
++
++#else /* LINUX26 */
++
++ #include <linux/mm.h>
++ #define GET_KERNEL_PAGE() get_free_page(GFP_KERNEL)
++#endif /* LINUX26 */
++
++
++
++// Common to all supported versions of Linux ??
++
++#define CKMALLOC(n,f) _ckmalloc(__FUNCTION__, __LINE__, n, f)
++#define LSTRDUP(str) _lstrdup(__FUNCTION__, __LINE__, str)
++#define LKFREE(p) _lkfree(__FUNCTION__, __LINE__, p)
++
++#define ckmalloc(n,f) _ckmalloc(__FUNCTION__, __LINE__, n, f)
++#define lstrdup(str) _lstrdup(__FUNCTION__, __LINE__, str)
++#define lkfree(p) _lkfree(__FUNCTION__, __LINE__, p)
++
++#define OTG_MALLOC_TEST
++#undef OTG_MALLOC_DEBUG
++
++#ifdef OTG_MALLOC_TEST
++ extern int otg_mallocs;
++#endif
++
++
++static INLINE void *_ckmalloc (const char *func, int line, int n, int f)
++{
++ void *p;
++ if ((p = kmalloc (n, f)) == NULL) {
++ return NULL;
++ }
++ memset (p, 0, n);
++ #ifdef OTG_MALLOC_TEST
++ ++otg_mallocs;
++ #endif
++ #ifdef OTG_MALLOC_DEBUG
++ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, otg_mallocs);
++ #endif
++ return p;
++}
++
++static INLINE char *_lstrdup (const char *func, int line, char *str)
++{
++ int n;
++ char *s;
++ if (str && (n = strlen (str) + 1) && (s = kmalloc (n, GFP_ATOMIC))) {
++#ifdef OTG_MALLOC_TEST
++ ++otg_mallocs;
++#endif
++#ifdef OTG_MALLOC_DEBUG
++ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, s, func, line, otg_mallocs);
++#endif
++ return strcpy (s, str);
++ }
++ return NULL;
++}
++
++static INLINE void _lkfree (const char *func, int line, void *p)
++{
++ if (p) {
++#ifdef OTG_MALLOC_TEST
++ --otg_mallocs;
++#endif
++#ifdef OTG_MALLOC_DEBUG
++ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, otg_mallocs);
++#endif
++ kfree (p);
++#ifdef MALLOC_TEST
++ if (otg_mallocs < 0) {
++ printk(KERN_INFO"%s: %p %s %d %d otg_mallocs less zero!\n", __FUNCTION__, p, func, line, otg_mallocs);
++ }
++#endif
++#ifdef OTG_MALLOC_DEBUG
++ else {
++ printk(KERN_INFO"%s: %s %d NULL\n", __FUNCTION__, func, line);
++ }
++#endif
++ }
++}
++
++#if 1
++#include <linux/list.h>
++#define LIST_NODE struct list_head
++#define LIST_NODE_INIT(name) struct list_head name = {&name, &name}
++#define LIST_ENTRY(pointer, type, member) list_entry(pointer, type, member)
++#define LIST_FOR_EACH(cursor, head) list_for_each(cursor, head)
++#define LIST_ADD_TAIL(n,h) list_add_tail(n,h)
++#define LIST_DEL(h) list_del(&(h))
++#else
++#include <otg/otg-list.h>
++#endif
++
++/*! @} */
++
++
++/*! @name Atomic Operations
++ *
++ * atomic_post_inc()
++ * atomic_pre_dec()
++ */
++/*! @{ */
++static __inline__ int atomic_post_inc(volatile atomic_t *v)
++{
++ unsigned long flags;
++ int result;
++ local_irq_save(flags);
++ result = (v->counter)++;
++ local_irq_restore(flags);
++ return(result);
++}
++
++static __inline__ int atomic_pre_dec(volatile atomic_t *v)
++{
++ unsigned long flags;
++ int result;
++ local_irq_save(flags);
++ result = --(v->counter);
++ local_irq_restore(flags);
++ return(result);
++}
++/*! @} */
++
++
++
++/*!@name Scheduling Primitives
++ *
++ * WORK_STRUCT
++ * WORK_ITEM
++ *
++ * SCHEDULE_TIMEOUT()\n
++ * SET_WORK_ARG()\n
++ * SCHEDULE_WORK()\n
++ * SCHEDULE_IMMEDIATE_WORK()\n
++ * NO_WORK_DATA()\n
++ * MOD_DEC_USE_COUNT\n
++ * MOD_INC_USE_COUNT\n
++ */
++
++/*! @{ */
++
++static void inline SCHEDULE_TIMEOUT(int seconds){
++ schedule_timeout( seconds * HZ );
++}
++
++
++/* Separate Linux 2.4 and 2.6 versions of scheduling primitives */
++#if defined(LINUX26)
++ #include <linux/workqueue.h>
++
++ #define WORK_STRUCT work_struct
++ #define WORK_ITEM work_struct
++ typedef struct WORK_ITEM WORK_ITEM;
++ #if 0
++ #define PREPARE_WORK_ITEM(__item,__routine,__data) INIT_WORK((__item),(__routine),(__data))
++ #else
++ #include <linux/interrupt.h>
++ #define PREPARE_WORK_ITEM(__item,__routine,__data) __prepare_work(&(__item),(__routine),(__data))
++ static inline void __prepare_work(struct work_struct *_work,
++ void (*_routine),
++ void * _data){
++ INIT_LIST_HEAD(&_work->entry);
++ _work->pending = 0;
++ _work->func = _routine;
++ _work->data = _data;
++ init_timer(&_work->timer);
++ }
++ #endif
++ #undef PREPARE_WORK
++ typedef void (* WORK_PROC)(void *);
++
++ #define SET_WORK_ARG(__item, __data) (__item).data = __data
++
++ #define SCHEDULE_WORK(item) schedule_work(&item)
++ #define SCHEDULE_IMMEDIATE_WORK(item) SCHEDULE_WORK((item))
++ #define PENDING_WORK_ITEM(item) (item.pending != 0)
++ #define NO_WORK_DATA(item) (!item.data)
++ #define _MOD_DEC_USE_COUNT //Not used in 2.6
++ #define _MOD_INC_USE_COUNT //Not used in 2.6
++
++#else /* LINUX26 */
++
++ #define WORK_STRUCT tq_struct
++ #define WORK_ITEM tq_struct
++ typedef struct WORK_ITEM WORK_ITEM;
++ #define PREPARE_WORK_ITEM(item,work_routine,work_data) { item.routine = work_routine; item.data = work_data; }
++ #define SET_WORK_ARG(__item, __data) (__item).data = __data
++ #define NO_WORK_DATA(item) (!(item).data)
++ #define SCHEDULE_WORK(item) schedule_task(&item)
++ #define PENDING_WORK_ITEM(item) (item.sync != 0)
++ #define _MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
++ #define _MOD_INC_USE_COUNT MOD_INC_USE_COUNT
++
++ typedef void (* WORK_PROC)(void *);
++
++ #if !defined(IRQ_HANDLED)
++ // Irq's
++ typedef void irqreturn_t;
++ #define IRQ_NONE
++ #define IRQ_HANDLED
++ #define IRQ_RETVAL(x)
++ #endif
++#endif /* LINUX26 */
++
++/*! @} */
++
++/*!@name Semaphores
++ *
++ * up()
++ * down()
++ */
++/*! @{ */
++#define UP(s) up(s)
++#define DOWN(s) down(s)
++/*! @} */
++
++/*! @name Printk
++ *
++ * PRINTK()
++ */
++/*! @{ */
++#define PRINTK(s) printk(s)
++/*! @} */
++
++
++#endif /* _OTG_LINUX_H */
+diff -uNr linux/drivers/no-otg/otg/otg-list.h linux/drivers/otg/otg/otg-list.h
+--- linux/drivers/no-otg/otg/otg-list.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-list.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,69 @@
++#ifndef _OTG_LIST_H
++#define _OTG_LIST_H 1
++
++/*
++ This file defines doubly linked list capabilities
++ needed. Many operating systems have built in capabilities
++ which match and may possibly be borrowed.
++
++
++ Here is a typical implementation
++*/
++
++struct otg_list_node {
++ struct otg_list_node *previous, *next;
++};
++typedef struct otg_list_node otg_list_node_t, *otg_list_node_ptr;
++
++//A macro to define an list node within a structure
++#define OTG_LIST_HEAD struct otg_list_node
++#define OTG_LIST_HEAD_INIT(name) struct otg_list_node name = {&name, &name};
++//Assume that an OTG_LIST_HEAD pointer is embedded as structure
++// Recover numerical offset of member "member" within a pointer to a "type"
++#define __OTG_PTR_OFFSET(type, member) (u32) ( &(((type *) 0)->member) )
++//Recover typed pointer from pointer to interior of type at the given offset
++#define __OTG_PTR_CONTAINER(ptr, type, member) (type *) ((char *) ptr - __OTG_PTR_OFFSET(type,member))
++// member "member" of type "type". Recover a pointer to the beginning of the structure
++
++#define OTG_LIST_ENTRY(pointer, type, member) __OTG_PTR_CONTAINER(pointer, type, member)
++
++//Recover list header embedded in structure which is a member of a list
++#define OTG_LIST_MEMBER(pointer, member) &(ptr->member)
++//Add an entry at the logical end of the list
++
++//#define INLINE inline
++#define OTG_LIST_ADD_TAIL(new_entry, list_head) __otg_list_add_tail(new_entry, list_head)
++static INLINE void __otg_list_add_tail(struct otg_list_node *new_entry, struct otg_list_node *list_head)
++{
++ struct otg_list_node *old_previous = list_head->previous;
++ old_previous->next = new_entry;
++ new_entry->next = list_head;
++ new_entry->previous = old_previous;
++ list_head -> previous = new_entry;
++
++}
++
++//Delete an entry from the surrounding list
++#define OTG_LIST_DEL_ENTRY(del_entry) __otg_list_del_entry(&(del_entry))
++
++static void INLINE __otg_list_del_entry(struct otg_list_node *del_entry){
++ //Remove from list
++ del_entry->previous->next = del_entry->next;
++ del_entry->next->previous = del_entry->previous;
++ //Invalidate the entry
++ del_entry->previous = NULL;
++ del_entry->next = NULL;
++}
++
++#define OTG_LIST_FOR_EACH(cursor, list) for(cursor=(list)->next; cursor != (list); cursor=cursor->next)
++
++#undef LIST_HEAD
++#define LIST_HEAD OTG_LIST_HEAD
++#undef LIST_HEAD_INIT
++#define LIST_HEAD_INIT(name) OTG_LIST_HEAD_INIT(name)
++#define LIST_ENTRY(pointer,type,member) OTG_LIST_ENTRY(pointer,type,member)
++#define LIST_ADD_TAIL(new_entry, list_head) OTG_LIST_ADD_TAIL(new_entry, list_head)
++#define LIST_DEL_ENTRY(del_entry) OTG_LIST_DEL_ENTRY(del_entry)
++#define LIST_FOR_EACH(cursor, list) OTG_LIST_FOR_EACH(cursor, list)
++
++#endif /*_OTG_LIST_H */
+diff -uNr linux/drivers/no-otg/otg/otg-module.h linux/drivers/otg/otg/otg-module.h
+--- linux/drivers/no-otg/otg/otg-module.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-module.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,71 @@
++/*
++ * otg/otg/otg-module.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++/*!
++ * @file otg/otg/otg-module.h
++ * @brief Linux Module OS Compatibility defines
++ *
++ *
++ * @ingroup OTGCore
++ */
++#ifndef _OTG_MODULE_H
++#define _OTG_MODULE_H 1
++
++#if defined(OTG_LINUX)
++ #if !defined(_LINUX_MODULE_H)
++ #include <linux/module.h>
++ #endif /* _LINUX_MODULE_H */
++
++ #if defined(MODULE)
++
++ #define MOD_EXIT(exit_routine) module_exit(exit_routine)
++ #define MOD_INIT(init_routine) module_init(init_routine)
++ #define MOD_PROC(proc) (proc)
++ #define MOD_AUTHOR(string) MODULE_AUTHOR(string)
++ #define MOD_PARM(param, type) MODULE_PARM(param, type)
++ #define MOD_PARM_DESC(param,desc) MODULE_PARM_DESC(param, desc)
++ #define MOD_DESCRIPTION(description) MODULE_DESCRIPTION(description)
++ #define OTG_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol)
++ #define OTG_EPILOGUE 1 /* EPILOGUE ROUTINE NEEDED */
++
++ #else /* defined(MODULE) */
++
++ #define MOD_EXIT(exit_routine)
++ #define MOD_INIT(init_routine) module_init(init_routine)
++ #define MOD_PROC(proc) NULL
++ #define MOD_AUTHOR(string)
++ #define MOD_PARM(param, type)
++ #define MOD_PARM_DESC(param,desc)
++ #define MOD_DESCRIPTION(description)
++ #define OTG_EXPORT_SYMBOL(symbol) //EXPORT_SYMBOL(symbol)
++ #undef EXPORT_SYMBOL
++ #define OTG_EPILOGUE 0 /* EPILOGUE ROUTINE NOT NEEDED */
++
++ #endif /* defined(MODULE) */
++
++ //#undef MODULE_AUTHOR
++ //#undef MODULE_DESCRIPTION
++ //#undef MODULE_PARM_DESC
++ //#undef MODULE_PARM
++ #if defined(LINUX24) || defined(LINUX26)
++ #include <linux/version.h>
++ #if defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17))
++ //"GPL License applies under certain cirumstances; consult your vendor for details"
++ #define EMBED_LICENSE() MODULE_LICENSE ("GPL")
++ #else
++ #define EMBED_LICENSE() //Operation not supported for earlier Linux kernels
++ #endif
++
++ #else /* defined(LINUX24) || defined(LINUX26) */
++ #error "Need to define EMBED_LICENSE for the current operating system"
++ #endif /* defined(LINUX24) || defined(LINUX26) */
++ #define EMBED_MODULE_INFO(section,moduleinfo) static char __##section##_module_info[] = moduleinfo "balden@belcarra.com"
++ #define EMBED_USBD_INFO(moduleinfo) EMBED_MODULE_INFO(usbd,moduleinfo)
++ #define GET_MODULE_INFO(section) __##section##_module_info
++#endif /* defined(OTG_LINUX) */
++
++
++#endif
+diff -uNr linux/drivers/no-otg/otg/otg-ocd.h linux/drivers/otg/otg/otg-ocd.h
+--- linux/drivers/no-otg/otg/otg-ocd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-ocd.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,94 @@
++/*
++ * otg/otg-ocd.h - OTG Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++/*!
++ * @defgroup OTGOCD OTG Controller Driver Support
++ * @ingroup onthegogroup
++ */
++/*!
++ * @file otg/otg/otg-ocd.h
++ * @brief Defines common to On-The-Go OTG Controller Support
++ *
++ * This file defines the ocd_ops and ocd_instance structures.
++ *
++ * The ocd_ops structure contains all of the output functions that will
++ * be called as required by the OTG event handler when changing states.
++ *
++ * The ocd_instance structure is used to maintain the global data
++ * required by the OTG controller drivers.
++ *
++ * @ingroup OTGOCD
++ */
++
++/*!
++ * @name OCD OTG Controller Driver
++ * @{
++ */
++//struct ocd_instance;
++
++struct ocd_instance {
++ struct otg_instance *otg;
++ void * privdata;
++};
++
++
++typedef int (*otg_timer_callback_proc_t) (void *);
++
++#define OCD_CAPABILITIES_DR 1 << 0
++#define OCD_CAPABILITIES_PO 1 << 1
++#define OCD_CAPABILITIES_TR 1 << 2
++#define OCD_CAPABILITIES_HOST 1 << 3
++
++#define OCD_CAPABILITIES_AUTO 1 << 4
++
++
++/*!
++ * @struct ocd_ops
++ * The ocd_ops structure contains pointers to all of the functions implemented for the
++ * linked in driver. Having them in this structure allows us to easily determine what
++ * functions are available without resorting to ugly compile time macros or ifdefs
++ *
++ * There is only one instance of this, defined in the device specific lower layer.
++ */
++struct ocd_ops {
++
++ u32 capabilities; /* OCD Capabilities */
++
++ /* Driver Initialization - by degrees
++ */
++ int (*mod_init) (void); /*!< OCD Module Initialization */
++ void (*mod_exit) (void); /*!< OCD Module Exit */
++
++ otg_output_proc_t ocd_init_func; /*!< OTG calls to initialize or de-initialize the OCD */
++
++ int (*start_timer) (struct otg_instance *, int);/*!< called by OTG to start timer */
++ u64 (*ticks) (void); /*!< called by OTG to fetch current ticks, typically micro-seconds when available */
++ u64 (*elapsed) ( u64 *, u64 *); /*!< called by OTG to get micro-seconds elapsed between two ticks */
++ u32 interrupts; /*!< called by OTG to get number of interrupts */
++};
++
++
++#if 0
++struct ocd_instance {
++ struct otg_instance *otg;
++ void * privdata;
++};
++#endif
++
++#ifndef OTG_APPLICATION
++
++//#define OCD ocd_trace_tag
++extern otg_tag_t OCD;
++extern struct ocd_ops ocd_ops;
++extern struct ocd_instance *ocd_instance;
++#endif
++/* @} */
+diff -uNr linux/drivers/no-otg/otg/otg-p2k.h linux/drivers/otg/otg/otg-p2k.h
+--- linux/drivers/no-otg/otg/otg-p2k.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-p2k.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * otg/otg/otg-p2k.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++/*!
++ * @file otg/otg/otg-p2k.h
++ * @brief Linux OS Compatibility defines
++ *
++ * @ingroup OTGCore
++ */
++
++#ifndef _OTG_P2K_H 1
++#define _OTG_P2K_H 1
++
++/*!@name Common Platform 2000 includes
++ */
++/*! * @{ */
++
++/* UNKNOWN SO FAR */
++/*! @} */
++
++/*!@name Compilation Related
++ */
++
++/*! @{ */
++#define PRAGMAPACK
++#define PACKED
++#define INLINE __inline
++
++/*! @} */
++
++/*!@name OTG int typedefs
++ */
++/*! * @{ */
++typedef unsigned short u16;
++typedef unsigned char u8;
++typedef unsigned long int u32;
++typedef __int64 u64;
++typedef unsigned char __u8;
++typedef unsigned short __u16;
++typedef unsigned long int __u32;
++typedef __int64 __u64;
++
++/*! @} */
++
++/*!@name Memory Allocation Primitives
++ *
++ * CKMALLOC()
++ * LSTRDUP()
++ * LKFREE()
++ * LIST_ENTRY()
++ */
++/*! @{ */
++
++#define GFP_KERNEL 0
++#define GFP_ATOMIC 0
++
++#define CKMALLOC(n,f) _ckmalloc(__FILE__, __LINE__, n, f)
++#define LSTRDUP(str) _lstrdup(__FILE__, __LINE__, str)
++#define LKFREE(p) _lkfree(__FILE__, __LINE__, p)
++
++#define OTG_MALLOC_TEST
++#undef OTG_MALLOC_DEBUG
++
++#ifdef OTG_MALLOC_TEST
++ extern int otg_mallocs;
++#endif
++
++static INLINE void *_ckmalloc (const char *func, int line, int n, int f)
++{
++
++ return 0;
++}
++static INLINE char *_lstrdup (const char *func, int line, char *str)
++{
++
++ return 0;
++}
++static INLINE void _lkfree (const char *func, int line, void *p)
++{
++}
++
++// XXX
++#define LIST_ENTRY(p, t, m) \
++ ((t *)((char *)(p)-(unsigned long)(&((t *)0)->m)))
++
++// XXX
++#define LIST_FOR_EACH(p, h) \
++ for (p = (h)->next, (p->next); p != (h); \
++ p = p->next, (p->next))
++
++#define LIST_ADD_TAIL(n,h) (0)
++#define LIST_ADD_TAIL(n,h) (0)
++#define LIST_DEL(h) (0)
++
++
++/*! @} */
++
++
++/*! @name Atomic Operations
++ *
++ * atomic_post_inc()
++ * atomic_pre_dec()
++ */
++/*! @{ */
++
++/* @} */
++
++
++
++/*! @name Scheduling Primitives
++ *
++ * WORK_STRUCT
++ * WORK_ITEM
++ *
++ * SCHEDULE_TIMEOUT()
++ * SET_WORK_ARG()
++ * SCHEDULE_WORK()
++ * SCHEDULE_IMMEDIATE_WORK()
++ * NO_WORK_DATA()
++ * MOD_DEC_USE_COUNT
++ * MOD_INC_USE_COUNT
++ */
++/*! @{ */
++#define HZ 60
++#define SCHEDULE_TIMEOUT(seconds)
++
++ #define SCHEDULE_WORK(item) (0)
++#define PENDING_WORK_ITEM(item) (0)
++#define PREPARE_WORK_ITEM(__item,__routine,__data) (0)
++
++/*! @} */
++
++
++/*! @name Semaphores
++ *
++ * up()
++ * down()
++ */
++/*! @{ */
++#define UP(s)
++#define DOWN(s)
++/*! @} */
++
++
++/*!@name Printk
++ *
++ * PRINTK()
++ */
++/*! @{ */
++//#define PRINTK(s) printk(s)
++// DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s"), _T(msg)));
++
++/*! @} */
++
++/*! @name Little Endian Macros
++ * /
++ *! @{
++ */
++
++__inline u16 cpu_to_le16 ( u16 x )
++{
++ return (x<<8) | (x>>8);
++}
++
++__inline u16 le16_to_cpu ( u16 val )
++{
++ return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
++}
++
++__inline u32 le32_to_cpu (u32 val)
++{
++ return (((val) & 0xff000000) >> 24) | (((val) & 0x00ff0000) >> 8) |
++ (((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24);
++}
++/*! @} */
++
++/*! @name little endian macros
++ */
++/*! @{ */
++#define local_irq_save(f) f = 0; __asm cli
++#define local_irq_restore(f) __asm sti
++
++/*! @} */
++
++/*! @name Ioctl
++ */
++/*! @{ */
++#define _IOR(m,n,s) ((m)|(n))
++#define _IOW(m,n,s) ((m)|(n))
++#define _IOCSIZE(a) (sizeof(a))
++#define copy_from_user(d,s,n) memcpy(d,s,n)
++#define copy_to_user(d,s,n) memcpy(d,s,n)
++
++/*! @} */
++
++/*! @name ERRNO
++ */
++/*! @{ */
++#define EINVAL WSAEINVAL
++
++/*! @} */
++
++
++
++#endif /* _OTG_P2K_H */
+diff -uNr linux/drivers/no-otg/otg/otg-pcd.h linux/drivers/otg/otg/otg-pcd.h
+--- linux/drivers/no-otg/otg/otg-pcd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-pcd.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,84 @@
++/*
++ * otg/otg-pcd.h - OTG Peripheral Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup OTGPCD Peripheral Controller Driver Support
++ * @ingroup onthegogroup
++ */
++/*!
++ * @file otg/otg/otg-pcd.h
++ * @brief Defines common to On-The-Go Peripheral Controller Support
++ *
++ * This file defines the pcd_ops and pcd_instance structures.
++ *
++ * The pcd_ops structure contains all of the output functions that will
++ * be called as required by the OTG event handler when changing states.
++ *
++ * The pcd_instance structure is used to maintain the global data
++ * required by the peripheral controller drivers.
++ *
++ * @ingroup OTGPCD
++ */
++
++/*!
++ * @name PCD Peripheral Controller Driver
++ * @{
++ */
++typedef u16 (*framenum_t)(void);
++
++/*!
++ * @struct pcd_ops
++ *
++ * The pcd_ops structure contains pointers to all of the functions implemented for the
++ * linked in driver. Having them in this structure allows us to easily determine what
++ * functions are available without resorting to ugly compile time macros or ifdefs
++ *
++ * There is only one instance of this, defined in the device specific lower layer.
++ */
++struct pcd_ops {
++
++ int (*mod_init) (void); /*!< PCD Module Initialization */
++ void (*mod_exit) (void); /*!< PCD Module Exit */
++
++ otg_output_proc_t pcd_init_func; /*!< OTG calls to initialize or de-initialize the PCD */
++ otg_output_proc_t pcd_en_func; /*!< OTG calls to enable or disable the PCD */
++ otg_output_proc_t remote_wakeup_func; /*!< OTG calls to have PCD perform remote wakeup */
++
++ framenum_t framenum; /*!< OTG calls to get current USB Frame number */
++};
++
++#define PCD pcd_trace_tag
++extern otg_tag_t PCD;
++extern struct pcd_ops pcd_ops;
++extern struct pcd_instance *pcd_instance;
++
++/*!
++ * @struct pcd_instance
++ */
++struct pcd_instance {
++ struct otg_instance *otg; /*!< pointer to OTG Instance */
++ struct usbd_bus_instance *bus; /*!< pointer to usb bus instance */
++ void * privdata; /*!< pointer to private data for PCD */
++ int pcd_exiting; /*!< non-zero if OTG is unloading */
++ struct WORK_STRUCT bh; /*!< work structure for bottom half handler */
++
++};
++
++
++#if !defined(OTG_C99)
++extern void pcd_global_init(void);
++#endif /* !defined(OTG_C99) */
++extern void pcd_init_func(struct otg_instance *, u8 );
++extern void pcd_en_func(struct otg_instance *, u8 );
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/otg/otg-tcd.h linux/drivers/otg/otg/otg-tcd.h
+--- linux/drivers/no-otg/otg/otg-tcd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-tcd.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * otg/otg-tcd.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup OTGTCD Transceiver Controller Driver Support
++ * @ingroup onthegogroup
++ */
++/*!
++ * @file otg/otg/otg-tcd.h
++ * @brief Defines common to On-The-Go Transceiver Controller Support
++ *
++ * This file defines the tcd_ops and tcd_instance structures.
++ *
++ * The tcd_ops structure contains all of the output functions that will
++ * be called as required by the OTG event handler when changing states.
++ *
++ * The tcd_instance structure is used to maintain the global data
++ * required by the transceiver controller drivers.
++ *
++ * @ingroup OTGTCD
++ */
++
++/*!
++ * @name TCD Transceiver Controller Driver
++ * @{
++ */
++
++
++/*!
++ * @struct tcd_ops
++ * The pcd_ops structure contains pointers to all of the functions implemented for the
++ * linked in driver. Having them in this structure allows us to easily determine what
++ * functions are available without resorting to ugly compile time macros or ifdefs
++ *
++ * There is only one instance of this, defined in the device specific lower layer.
++ */
++struct tcd_ops {
++ u64 initial_state;
++
++ void * privdata;
++
++ /* Driver Initialization - by degrees
++ */
++ int (*mod_init) (void); /*!< TCD Module Initialization */
++ void (*mod_exit) (void); /*!< TCD Module Exit */
++
++
++ /* 3. called for usbd_vbus() if defined */
++ int (*vbus) (struct otg_instance *); /* return non-zero if the Vbus valid */
++ int (*id) (struct otg_instance *); /* return non-zero if the ID valid */
++
++ /* 4. called by otg event to control outputs
++ */
++
++ otg_output_proc_t tcd_init_func; /*!< OTG calls to initialize or de-initialize the HCD */
++ otg_output_proc_t tcd_en_func; /*!< OTG calls to enable or disable the TCD */
++ otg_output_proc_t chrg_vbus_func; /*!< OTG calls to enable or disable charging Vbus */
++ otg_output_proc_t drv_vbus_func; /*!< OTG calls to enable or disable Vbus */
++ otg_output_proc_t dischrg_vbus_func; /*!< OTG calls to enable or disable discharging Vbus */
++ otg_output_proc_t dp_pullup_func; /*!< OTG calls to enable or disable D+ pullup (aka loc_conn) */
++ otg_output_proc_t dm_pullup_func; /*!< OTG calls to enable or disable D- pullup (aka loc_carkit) */
++ otg_output_proc_t dp_pulldown_func; /*!< OTG calls to enable or disable D+ pulldown (aka loc_conn) */
++ otg_output_proc_t dm_pulldown_func; /*!< OTG calls to enable or disable D- pulldown (aka loc_carkit) */
++ otg_output_proc_t peripheral_host_func; /*!< OTG calls to enable or disable D- pulldown (aka loc_carkit) */
++ otg_output_proc_t overcurrent_func; /*!< OTG calls to clear overcurrent indication */
++ otg_output_proc_t dm_det_func; /*!< OTG calls to enable or disable D+ pullup detection */
++ otg_output_proc_t dp_det_func; /*!< OTG calls to enable or disable D- pullup detection */
++ otg_output_proc_t cr_det_func; /*!< OTG calls to enable or disable D+ CRINT detection */
++ otg_output_proc_t charge_pump_func; /*!< OTG calls to enable or disable external charge pump */
++ otg_output_proc_t bdis_acon_func; /*!< OTG calls to enable or disable the BDIS ACON feature */
++ otg_output_proc_t mx21_vbus_drain_func; /*!< OTG calls to enable or disable the mx21 vbus drain feature */
++ otg_output_proc_t id_pulldown_func; /*!< OTG calls to enable or disable ID pulldown to ground */
++ otg_output_proc_t audio_func; /*!< OTG calls to enable or disable audio function */
++ otg_output_proc_t uart_func; /*!< OTG calls to enable or disable uart function */
++ otg_output_proc_t mono_func; /*!< OTG calls to enable or disable mono function */
++};
++
++/*!
++ * @struct hcd_instance
++ */
++struct tcd_instance {
++ struct otg_instance *otg; /*!< pointer to OTG Instance */
++ struct WORK_STRUCT bh; /*!< work structure for bottom half handler */
++};
++
++
++extern struct trace_ops trace_ops;
++extern struct tcd_ops tcd_ops;
++
++
++extern struct tcd_instance *tcd_instance;
++extern int tcd_vbus (struct otg_instance *otg);
++
++/* pcd_cable_event[_irq] - these can be called in a traditional PCD implementation
++ * to set b_sess_vld appropriately when vbus is sensed (pcd must implement ocd_ops.vbus)
++ */
++extern void tcd_cable_event_irq (struct otg_instance *);
++extern void tcd_cable_event (struct otg_instance *);
++
++//extern void tcd_init(struct otg_instance *, u8 );
++
++#define TCD tcd_trace_tag
++extern otg_tag_t TCD;
++
++/* @} */
+diff -uNr linux/drivers/no-otg/otg/otg-trace.h linux/drivers/otg/otg/otg-trace.h
+--- linux/drivers/no-otg/otg/otg-trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-trace.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,404 @@
++/*
++ * otg/otgcore/otg-trace.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++/*!
++ * @file otg/otg/otg-trace.h
++ * @brief Core Defines for USB OTG Core Layaer
++ *
++ * Fast Trace Utility
++ * This set of definitions and code is meant to provide a _fast_ debugging facility
++ * (much faster than printk) so that time critical code can be debugged by looking
++ * at a trace of events provided by reading a file in the procfs without affecting
++ * the timing of events in the critical code.
++ *
++ * The mechanism used it to allocate a (large) ring buffer of relatively small structures
++ * that include location and high-res timestamp info, and up to 8 bytes of optional
++ * data. Values are stored and timestamps are taken as the critical code runs, but
++ * data formatting and display are done during the procfs read, when more time is
++ * available :).
++ *
++ * Note that there is usually some machine dependent code involved in getting the
++ * high-res timestamp, and there may be other bits used just to keep the overall
++ * time impact as low as possible.
++ *
++ * Varargs up to 9 arguments are now supported, but you have to supply the number
++ * of args, since examining the format string for the number at trace event time
++ * was deemed too expensive time-wise.
++ *
++ *
++ * @ingroup OTGCore
++ */
++
++#ifndef OTG_TRACE_H
++#define OTG_TRACE_H 1
++
++//#include <linux/interrupt.h>
++
++
++
++typedef u8 otg_tag_t; // 1-origin tags (0 ==> invalid/unused trace entry. Max is 32.
++
++#ifdef PRAGMAPACK
++#pragma pack(push,1)
++#endif /* PRAGMAPACK */
++typedef enum otg_trace_types {
++ otg_trace_msg_invalid_n,
++ otg_trace_msg_va_start_n,
++ otg_trace_msg_va_list_n,
++ otg_trace_setup_n,
++ otg_trace_msg_n,
++ otg_trace_msg32_n,
++ otg_trace_msg16_n,
++ otg_trace_msg8_n
++} PACKED otg_trace_types_t;
++#ifdef PRAGMAPACK
++#pragma pack(pop)
++#endif /* PRAGMAPACK */
++
++typedef struct otg_trace_msg {
++ char *msg;
++} otg_trace_msg_t;
++
++typedef struct otg_trace_msg32 {
++ char *msg;
++ u32 val;
++} otg_trace_msg32_t;
++
++typedef struct otg_trace_msg16 {
++ char *msg;
++ u16 val0;
++ u16 val1;
++} otg_trace_msg16_t;
++
++typedef struct otg_trace_msg8 {
++ char *msg;
++ u8 val0;
++ u8 val1;
++ u8 val2;
++ u8 val3;
++} otg_trace_msg8_t;
++
++#define OTG_TRACE_MAX_IN_VA 7
++typedef struct otg_trace_msg_va_list {
++ u32 val[OTG_TRACE_MAX_IN_VA];
++} otg_trace_msg_va_list_t;
++
++typedef struct otg_trace_msg_va_start {
++ const char *function;
++ u32 interrupts;
++ u64 ticks;
++ u16 framenum;
++ u16 dummy;
++
++ union {
++ otg_trace_msg_t msg;
++ otg_trace_msg8_t msg8;
++ otg_trace_msg16_t msg16;
++ otg_trace_msg32_t msg32;
++
++#if !defined(BELCARRA_DEBUG)
++ struct usbd_device_request setup;
++#else
++ unsigned char setup[8];
++#endif /* !defined(BELCARRA_DEBUG) */
++
++ } trace;
++} PACKED otg_trace_msg_va_start_t;
++
++typedef struct trace {
++ otg_trace_types_t otg_trace_type;
++ otg_tag_t tag;
++ u8 va_num_args;
++ u8 in_interrupt:1;
++ u8 id_gnd:1;
++ union {
++ otg_trace_msg_va_start_t s;
++ otg_trace_msg_va_list_t l;
++ } va;
++} PACKED otg_trace_t;
++
++#define TRACE_MAX_IS_2N 1
++#define TRACE_MAX 0x00008000
++#define TRACE_MASK 0x00007FFF
++//#define TRACE_MAX 0x000080
++//#define TRACE_MASK 0x00007F
++
++
++#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
++
++#if !defined(OLD_TRACE_API)
++
++// The new API hides otg_trace_get_next(), and adds otg_trace_setup() as part of the core.
++
++#if !defined(BELCARRA_DEBUG)
++extern void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup);
++#define TRACE_SETUP(tag,setup) otg_trace_setup(tag,__FUNCTION__,setup)
++#endif
++#define TRACE_MSG0(tag, msg) otg_trace_msg(tag, __FUNCTION__, 0, msg, 0)
++#define TRACE_FMSG0(tag, f, msg) otg_trace_msg(tag, f, 0, msg, 0)
++
++#else
++
++extern int otg_trace_first;
++extern int otg_trace_last_read;
++extern int otg_trace_next;
++
++#if 0
++
++extern otg_trace_t *otg_traces;
++
++
++otg_trace_t *otg_trace_get_next(otg_tag_t tag, const char *fn, otg_trace_types_t otg_trace_type, int n);
++
++#if !defined(BELCARRA_DEBUG)
++/*
++ * Trace a setup packet.
++ * The BELCARRA_DEBUG guard is so the rest of these functions can be used
++ * outside of a USB context, such as debugging TTY flow control.
++ */
++static __inline__ void otg_trace_setup(otg_tag_t tag, const char *fn, struct usbd_device_request *setup)
++{
++ if (otg_traces) {
++ otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_setup_n,1);
++ memcpy(&p->va.s.trace.setup, setup, sizeof(struct usbd_device_request));
++ }
++}
++#define TRACE_SETUP(tag,setup) otg_trace_setup(tag,__FUNCTION__,setup)
++#endif /* !defined(BELCARRA_DEBUG) */
++
++/*
++ * Trace a single non-parameterized message.
++ */
++static __inline__ void otg_trace_msg_0(otg_tag_t tag, const char *fn, char *msg)
++{
++ if (otg_traces) {
++ otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg_n,1);
++ p->va.s.trace.msg.msg = msg;
++ }
++}
++#define TRACE_MSG0(tag, msg) otg_trace_msg_0(tag, __FUNCTION__, msg)
++#define TRACE_FMSG0(tag, f, msg) otg_trace_msg_0(tag, f, msg)
++
++/*
++ * Trace a message with a single 32-bit value.
++ */
++static __inline__ void otg_trace_msg_1xU32(otg_tag_t tag, const char *fn, char *fmt, u32 val)
++{
++ if (otg_traces) {
++ otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg32_n,1);
++ p->va.s.trace.msg32.val = val;
++ p->va.s.trace.msg32.msg = fmt;
++ }
++}
++#define OTRACE_MSG1(tag,fmt,val) otg_trace_msg_1xU32(tag,__FUNCTION__,fmt,(u32)val)
++
++/*
++ * Trace a message with two 16-bit values.
++ */
++static __inline__ void otg_trace_msg_2xU16(otg_tag_t tag, const char *fn, char *fmt, u16 val0, u16 val1)
++{
++ if (otg_traces) {
++ otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg16_n,1);
++ p->va.s.trace.msg16.val0 = val0;
++ p->va.s.trace.msg16.val1 = val1;
++ p->va.s.trace.msg16.msg = fmt;
++ }
++}
++#define OTRACE_MSG2(tag,fmt,val0,val1) otg_trace_msg_2xU16(tag,__FUNCTION__,fmt,(u16)val0,(u16)val1)
++
++/*
++ * Trace a message with four 8-bit values.
++ */
++static __inline__ void otg_trace_msg_4xU8(otg_tag_t tag, const char *fn, char *fmt, u8 val0, u8 val1, u8 val2, u8 val3)
++{
++ if (otg_traces) {
++ otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg8_n,1);
++ p->va.s.trace.msg8.val0 = val0;
++ p->va.s.trace.msg8.val1 = val1;
++ p->va.s.trace.msg8.val2 = val2;
++ p->va.s.trace.msg8.val3 = val3;
++ p->va.s.trace.msg8.msg = fmt;
++ }
++}
++#define OTRACE_MSG4(tag,fmt,val0,val1,val2,val3) otg_trace_msg_4xU8(tag,__FUNCTION__,fmt,(u8)val0,(u8)val1,(u8)val2,(u8)val3)
++#endif
++
++#endif
++
++extern void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...);
++
++#define eprintf(format, args...) printk (KERN_INFO format , ## args)
++
++#define TRACE_MSG(tag, nargs, fmt, args...) otg_trace_msg(tag, __FUNCTION__, nargs, fmt, ## args)
++
++#define TRACE_MSG1(tag, fmt, a1) \
++ otg_trace_msg(tag, __FUNCTION__, 1, fmt, a1)
++#define TRACE_MSG2(tag, fmt, a1, a2) \
++ otg_trace_msg(tag, __FUNCTION__, 2, fmt, a1, a2)
++#define TRACE_MSG3(tag, fmt, a1, a2, a3) \
++ otg_trace_msg(tag, __FUNCTION__, 3, fmt, a1, a2, a3)
++#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4) \
++ otg_trace_msg(tag, __FUNCTION__, 4, fmt, a1, a2, a3, a4)
++#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5) \
++ otg_trace_msg(tag, __FUNCTION__, 5, fmt, a1, a2, a3, a4, a5)
++#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6) \
++ otg_trace_msg(tag, __FUNCTION__, 6, fmt, a1, a2, a3, a4, a5, a6)
++#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7) \
++ otg_trace_msg(tag, __FUNCTION__, 7, fmt, a1, a2, a3, a4, a5, a6, a7)
++#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
++ otg_trace_msg(tag, __FUNCTION__, 8, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
++#if 0
++#define TRACE_MSG9(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
++ otg_trace_msg(tag, __FUNCTION__, 9, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
++#endif
++#define TRACE_FMSG1(tag, f, fmt, a1) \
++ otg_trace_msg(tag, f, 1, fmt, a1)
++#define TRACE_FMSG2(tag, f, fmt, a1, a2) \
++ otg_trace_msg(tag, f, 2, fmt, a1, a2)
++#define TRACE_FMSG3(tag, f, fmt, a1, a2, a3) \
++ otg_trace_msg(tag, f, 3, fmt, a1, a2, a3)
++#define TRACE_FMSG4(tag, f, fmt, a1, a2, a3, a4) \
++ otg_trace_msg(tag, f, 4, fmt, a1, a2, a3, a4)
++#define TRACE_FMSG5(tag, f, fmt, a1, a2, a3, a4, a5) \
++ otg_trace_msg(tag, f, 5, fmt, a1, a2, a3, a4, a5)
++#define TRACE_FMSG6(tag, f, fmt, a1, a2, a3, a4, a5, a6) \
++ otg_trace_msg(tag, f, 6, fmt, a1, a2, a3, a4, a5, a6)
++#define TRACE_FMSG7(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7) \
++ otg_trace_msg(tag, f, 7, fmt, a1, a2, a3, a4, a5, a6, a7)
++#define TRACE_FMSG8(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
++ otg_trace_msg(tag, f, 8, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
++#if 0
++#define TRACE_FMSG9(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
++ otg_trace_msg(tag, f, 9, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
++#endif
++extern otg_tag_t otg_trace_obtain_tag(void);
++extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
++
++#elif defined(OTG_WINCE)
++
++#define TRACE_MSG0(tag, msg) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s"), _T(msg)))
++
++#define TRACE_MSG1(tag, fmt, a1) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d"), _T(fmt), a1))
++
++#define TRACE_MSG2(tag, fmt, a1, a2) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d"), _T(fmt), a1, a2))
++
++#define TRACE_MSG3(tag, fmt, a1, a2, a3) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d"), _T(fmt), a1, a2, a3));
++
++#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d"), _T(fmt), a1, a2, a3, a4));
++
++#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5));
++
++#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6));
++
++#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6, a7));
++
++#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6, a7, a8));
++
++extern otg_tag_t otg_trace_obtain_tag(void);
++extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
++
++/*
++#define TRACE_OTG_CURRENT(o) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CURRENT - %s (%s) RESET: %08x SET: %08x"),\
++ otg_state_names[o->state], \
++ otg_state_names[o->previous], \
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs))\
++ );
++
++#define TRACE_OTG_CHANGE(o) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CHANGE - %s (%s) RESET: %08x SET: %08x"),\
++ otg_state_names[o->state], \
++ otg_state_names[o->previous], \
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs))\
++ );
++
++#define TRACE_OTG_NEW(o) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - NEW - %s (%s) RESET: %08x SET: %08x"),\
++ otg_state_names[o->state], \
++ otg_state_names[o->previous], \
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs))\
++ );
++
++#define TRACE_OTG_INPUTS(u) \
++ DEBUGMSG(ZONE_INIT,(_T("OTGCORE - INPUTS - RESET: %08x SET: %08x"),\
++ (u32)(u >> 32), \
++ (u32)(u & 0xffffffff))\
++ );
++*/
++
++extern otg_tag_t otg_trace_obtain_tag(void);
++extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
++
++#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++
++#define TRACE_SETUP(tag,setup)
++
++//#define TRACE_MSG(tag,nargs,fmt,...)
++//#define TRACE_FMSG(tag, nargs,fmt,...)
++
++#define TRACE_MSG0(tag, fmt)
++#define TRACE_MSG1(tag, fmt, a1)
++#define TRACE_MSG2(tag, fmt, a1, a2)
++#define TRACE_MSG3(tag, fmt, a1, a2, a3)
++#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4)
++#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5)
++#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6)
++#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7)
++#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
++//#define TRACE_MSG9(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
++
++#define TRACE_FMSG0(tag, f, fmt)
++#define TRACE_FMSG1(tag, f, fmt, a1)
++#define TRACE_FMSG2(tag, f, fmt, a1, a2)
++#define TRACE_FMSG3(tag, f, fmt, a1, a2, a3)
++#define TRACE_FMSG4(tag, f, fmt, a1, a2, a3, a4)
++#define TRACE_FMSG5(tag, f, fmt, a1, a2, a3, a4, a5)
++#define TRACE_FMSG6(tag, f, fmt, a1, a2, a3, a4, a5, a6)
++#define TRACE_FMSG7(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7)
++#define TRACE_FMSG8(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
++//#define TRACE_FMSG9(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
++
++//static inline otg_tag_t otg_trace_obtain_tag(void)
++//{
++// return 0;
++//}
++
++//static inline otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag)
++//{
++// return 0;
++//}
++
++extern otg_tag_t otg_trace_obtain_tag(void);
++extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
++
++#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++
++#define USBD usbd_trace_tag
++extern otg_tag_t USBD;
++
++//#define ACM acm_trace_tag
++//extern otg_tag_t ACM;
++
++//#define NETWORK network_trace_tag
++//extern otg_tag_t NETWORK;
++
++#endif /* OTG_TRACE_H */
+diff -uNr linux/drivers/no-otg/otg/otg-utils.h linux/drivers/otg/otg/otg-utils.h
+--- linux/drivers/no-otg/otg/otg-utils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/otg-utils.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,151 @@
++/*
++ * otg/otg/otg-utils.h
++ *
++ * Basic utilities for OTG package
++ * Copyright (c) 2004 Belcarra
++ */
++/*!
++ * @file otg/otg/otg-utils.h
++ * @brief Useful macros.
++ *
++ *
++ * @ingroup OTGCore
++ */
++
++
++#if !defined(_OTG_UTILS_H)
++#define _OTG_UTILS_H 1
++
++/*! @name Min, Max and zero
++ * @{
++ */
++#ifndef MIN
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++#endif
++#ifndef MAX
++#define MAX(a,b) ((a) > (b) ? (a) : (b))
++#endif
++
++#define ZERO(a) memset(&a, 0, sizeof(a))
++
++/* @} */
++
++/*! @name TRUE and FALSE
++ *
++ * @{
++ */
++#if !defined(TRUE)
++#define TRUE 1
++#endif
++
++#if !defined(FALSE)
++#define FALSE 0
++#endif
++/* @} */
++
++
++/*! @name CATCH and THROW
++ *
++ * These macros implement a conceptually clean way to use
++ * C's goto to implement a standard error handler. The typical forms are:
++ *
++ * THROW(error); // continue execution in CATCH statement
++ * THROW_IF(test, error); // continue execution in CATCH statement if test true
++ * THROW_UNLESS(test, error); // continue execution in CATCH statement if test false
++ *
++ * // program execution will continue after the CATCH statement;
++ * CATCH(error) {
++ * // handle error here
++ * }
++ *
++ * @{
++ */
++#define CATCH(x) while(0) x:
++#define THROW(x) goto x
++#define THROW_IF(e, x) if (e) goto x;
++#define THROW_UNLESS(e, x) UNLESS (e) goto x;
++/* @} */
++
++
++/*! @name UNLESS
++ *
++ * This implements a simple equivalent to negated if (expression).
++ *
++ * Unless expression then statement else statement.
++ *
++ * @{
++ */
++#define unless(x) if(!(x))
++#define UNLESS(x) if(!(x))
++/* @} */
++
++/*! @name BREAK_ and CONTINUE_
++ *
++ * These implement a conditional break and continue statement.
++ *
++ * @{
++ */
++#define BREAK_UNLESS(x) UNLESS (x) break;
++#define BREAK_IF(x) if (x) break;
++#define CONTINUE_IF(x) if (x) continue;
++#define CONTINUE_UNLESS(x) UNLESS (x) continue;
++
++/* @} */
++
++
++/*! @name RETURN_
++ *
++ * These implement conditional return statement.
++ * @{
++ */
++#define RETURN_IF(x) if (x) return;
++#define RETURN_ZERO_IF(x) if (x) return 0;
++#define RETURN_NULL_IF(x) if (x) return NULL;
++#define RETURN_EBUSY_IF(x) if (x) return -EBUSY;
++#define RETURN_EFAULT_IF(x) if (x) return -EFAULT;
++#define RETURN_EINVAL_IF(x) if (x) return -EINVAL;
++#define RETURN_ENOMEM_IF(x) if (x) return -ENOMEM;
++#define RETURN_EAGAIN_IF(x) if (x) return -EAGAIN;
++#define RETURN_ETIMEDOUT_IF(x) if (x) return -ETIMEDOUT;
++#define RETURN_EPIPE_IF(x) if (x) return -EPIPE;
++#define RETURN_IRQ_HANDLED_IF(x) if (x) return IRQ_HANDLED;
++#define RETURN_TRUE_IF(x) if (x) return TRUE;
++#define RETURN_FALSE_IF(x) if (x) return FALSE;
++
++#define RETURN_UNLESS(x) UNLESS (x) return;
++#define RETURN_NULL_UNLESS(x) UNLESS (x) return NULL;
++#define RETURN_ZERO_UNLESS(x) UNLESS (x) return 0;
++#define RETURN_EBUSY_UNLESS(x) UNLESS (x) return -EBUSY;
++#define RETURN_EFAULT_UNLESS(x) UNLESS (x) return -EFAULT;
++#define RETURN_EINVAL_UNLESS(x) UNLESS (x) return -EINVAL;
++#define RETURN_ENOMEM_UNLESS(x) UNLESS (x) return -ENOMEM;
++#define RETURN_EAGAIN_UNLESS(x) UNLESS (x) return -EAGAIN;
++#define RETURN_ETIMEDOUT_UNLESS(x) UNLESS (x) return -ETIMEDOUT;
++#define RETURN_EPIPE_UNLESS(x) UNLESS (x) return -EPIPE;
++#define RETURN_IRQ_HANDLED_UNLESS(x) UNLESS (x) return IRQ_HANDLED;
++#define RETURN_TRUE_UNLESS(x) UNLESS (x) return TRUE;
++#define RETURN_FALSE_UNLESS(x) UNLESS (x) return FALSE;
++
++/* @} */
++
++
++/*! @name likely and unlikely
++ *
++ * Under linux these can be used to provide a hint to GCC that
++ * the expression being evaluated is probably going to evaluate
++ * to true (likely) or false (unlikely). The intention is that
++ * GCC can then provide optimal code for that.
++ * @{
++ */
++#ifndef likely
++#define likely(x) x
++#endif
++
++#ifndef unlikely
++#define unlikely(x) x
++#endif
++/* @} */
++
++
++#endif /* _OTG_UTILS_H */
++
+diff -uNr linux/drivers/no-otg/otg/pcd-include.h linux/drivers/otg/otg/pcd-include.h
+--- linux/drivers/no-otg/otg/pcd-include.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/pcd-include.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,36 @@
++/*
++ * otg/udc.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otg/pcd-include.h
++ * @brief Linux OS Precompiled Headers
++ *
++ * @ingroup OTGCore
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/io.h>
++
++#include <otg/usbp-chap9.h>
++//#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++#include <otg/usbp-pcd.h>
++
+diff -uNr linux/drivers/no-otg/otg/usbp-bus.h linux/drivers/otg/otg/usbp-bus.h
+--- linux/drivers/no-otg/otg/usbp-bus.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/usbp-bus.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,354 @@
++/*
++ * otg/otg/usbp-bus.h - USB Device Bus Interface Driver Interface
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @file otg/otg/usbp-bus.h
++ * @brief Bus interface Defines for USB Device Core Layaer
++ *
++ * This file contains the USB Peripheral Driver definitions.
++ *
++ * The
++ *
++ * This is the interface between the bottom of the USB Core and the top of
++ * the Bus Interace Drivers and is comprised of:
++ *
++ * o public functions exported by the USB Core layer
++ *
++ * o structures and functions passed by the Function Driver to the USB
++ * Core layer
++ *
++ * USB Peripheral Controller Drivers are structured such that the upper edge
++ * implements interfaces to the USB Peripheral Core layer to provide low
++ * level USB services and the lower edge interfaces to the actual USB
++ * Hardware (typically called the USB Device Controller or UDC.)
++ *
++ * The peripheral controller layer primarily deals with endpoints.
++ * There is one control endpoint and one or more data endpoints.
++ *
++ * The control endpoint is special, with received data processed with
++ * the built in EP0 function. Which in turn will pass requests to
++ * interface functions as appropriate.
++ *
++ * Data endpoints are controlled by interface driver and have a
++ * function callback specified by the interface driver to perform
++ * whatever needs to be done when data is sent or received.
++ *
++ *
++ *
++ * @ingroup USBP
++ */
++
++struct usbd_endpoint_map;
++struct usbd_endpoint_instance;
++struct usbd_bus_instance;
++struct usbd_urb;
++
++/*!
++ * USB Bus Interface Driver structures
++ *
++ * Driver description:
++ *
++ * struct usbd_bus_operations
++ * struct usbd_bus_driver
++ *
++ */
++
++extern int usbd_maxstrings;
++
++
++/*!
++ * exported to otg
++ */
++struct usbd_ops {
++ int (*admin) (char *);
++ char * (*function_name) (int);
++};
++
++
++
++/*! Operations that the slave layer or function driver can use to interact
++ * with the bus interface driver.
++ *
++ * The send_urb() function is used by the usb-device endpoint 0 driver and
++ * function drivers to submit data to be sent.
++ *
++ * The cancel_urb() function is used by the usb-device endpoint 0 driver and
++ * function drivers to remove previously queued data to be sent.
++ *
++ * The endpoint_halted() function is used by the ep0 control function to
++ * check if an endpoint is halted.
++ *
++ * The endpoint_feature() function is used by the ep0 control function to
++ * set/reset device features on an endpoint.
++ *
++ * The device_event() function is used by the usb device core to tell the
++ * bus interface driver about various events.
++ */
++struct usbd_bus_operations {
++ //int (*xbus_serial_number) (struct usbd_bus_instance *, char *);
++
++ int (*start_endpoint_in) (struct usbd_bus_instance *, struct usbd_endpoint_instance *);
++ int (*start_endpoint_out) (struct usbd_bus_instance *, struct usbd_endpoint_instance *);
++ int (*cancel_urb_irq) (struct usbd_urb *);
++ //int (*device_feature) (struct usbd_bus_instance *, int, int);
++ int (*endpoint_halted) (struct usbd_bus_instance *, int, int);
++ int (*halt_endpoint) (struct usbd_bus_instance *, int, int, int);
++ int (*set_address) (struct usbd_bus_instance *, int);
++ int (*event_handler) (struct usbd_bus_instance *, usbd_device_event_t, int);
++ int (*request_endpoints) (struct usbd_bus_instance *, struct usbd_endpoint_map *,
++ int, struct usbd_endpoint_request *);
++ int (*set_endpoints) (struct usbd_bus_instance *, int , struct usbd_endpoint_map *);
++ int (*framenum) (void);
++ u64 (*ticks) (void);
++ u64 (*elapsed) (u64 *, u64 *);
++ u64 (*interrupts) (void);
++};
++
++/*! Endpoint Map
++ *
++ * An array of these structures is created by the bus interface driver to
++ * show what endpoints have been configured for the function driver.
++ *
++ * This is the logical array of endpoints that are indexed into by the
++ * function layer using the logical endpoint numbers defined by the function
++ * drivers. It maps these numbers into a real physical endpoint.
++ *
++ * Fields that can be different for Full speed versus High speed are
++ * represented with an array both values are available.
++ *
++ * For interfaces with multiple alternate settings, each separate
++ * combinantion of interface_num/altsetting/endpoint must be specified.
++ * It is up to the lower layers to determine if / when overlapped
++ * endpoints can be re-used.
++ *
++ */
++struct usbd_endpoint_map {
++ u8 configuration;
++ u8 interface_num;
++ u8 alternate;
++ u8 bEndpointAddress[2]; // logical endpoint address
++ u16 wMaxPacketSize[2]; // packetsSize for requested endpoint
++ u8 bmAttributes[2]; // requested endpoint type
++ u16 transferSize[2]; // transferSize for bulk transfers
++ u8 physicalEndpoint[2]; // physical endpoint number
++ struct usbd_endpoint_instance *endpoint;
++};
++
++
++/*! Endpoint configuration
++ *
++ * Per endpoint configuration data. Used to track which actual physical
++ * endpoints.
++ *
++ * The bus layer maintains an array of these to represent all physical
++ * endpoints.
++ *
++ */
++struct usbd_endpoint_instance {
++ int bEndpointAddress; // logical endpoint address
++ int physical_endpoint; // physical endpoint address - bus interface specific
++ int bmAttributes; // endpoint type
++ u16 wMaxPacketSize; // packet size for requested endpoint
++ u32 feature_setting; // save set feature information
++
++ // control
++ int state; // available for use by bus interface driver
++
++ // receive side
++ struct urb_link rdy; // empty urbs ready to receive
++ struct usbd_urb *rcv_urb; // active urb
++ u32 rcv_transferSize; // maximum transfer size from function driver
++ int rcv_error; // current bulk-in has an error
++
++ // transmit side
++ struct urb_link tx; // urbs ready to transmit
++ struct usbd_urb *tx_urb; // active urb
++ u32 tx_transferSize; // maximum transfer size from function driver
++
++ u32 sent; // data already sent
++ u32 last; // data sent in last packet XXX do we need this
++
++ void *privdata;
++
++};
++
++/*! @name endpoint zero states
++ * @{
++ */
++#define WAIT_FOR_SETUP 0
++#define DATA_STATE_XMIT 1
++#define DATA_STATE_NEED_ZLP 2
++#define WAIT_FOR_OUT_STATUS 3
++#define DATA_STATE_RECV 4
++#define DATA_STATE_PENDING_XMIT 5
++#define WAIT_FOR_IN_STATUS 6
++/*! @} */
++
++/*! Bus Interface data structure
++ *
++ * Keep track of specific bus interface.
++ *
++ * This is passed to the usb-device layer when registering. It contains all
++ * required information about each real bus interface found such that the
++ * usb-device layer can create and maintain a usb-device structure.
++ *
++ * Note that bus interface registration is incumbent on finding specific
++ * actual real bus interfaces. There will be a registration for each such
++ * device found.
++ *
++ * The max_tx_endpoints and max_rx_endpoints are the maximum number of
++ * possible endpoints that this bus interface can support. The default
++ * endpoint 0 is not included in these counts.
++ *
++ */
++struct usbd_bus_driver {
++ char *name;
++ u8 max_endpoints; // maximimum number of rx enpoints
++ u8 otg_bmAttributes;
++ u8 maxpacketsize;
++ u8 HighSpeedCapable;
++ struct usbd_device_description *device_description;
++ struct usbd_bus_operations *bops;
++ void *privdata;
++ u32 capabilities;
++ u8 bMaxPower;
++ u8 ports;
++};
++
++/*!
++ * Bus state
++ *
++ * enabled or disabled
++ */
++typedef enum usbd_bus_state {
++ usbd_bus_state_unknown,
++ usbd_bus_state_disabled,
++ usbd_bus_state_enabled
++} usbd_bus_state_t;
++
++
++/*!
++ * @name UDC Capabilities
++ * @{
++ */
++#define HAVE_CABLE_IRQ 0x0001
++#define REMOTE_WAKEUP_SUPPORTED 0x0002
++#define ROOT_HUB 0x0004
++/*! @} */
++
++/*! Bus Interface configuration structure
++ *
++ * This is allocated for each configured instance of a bus interface driver.
++ *
++ * It contains a pointer to the appropriate bus interface driver.
++ *
++ * The privdata pointer may be used by the bus interface driver to store private
++ * per instance state information.
++ */
++struct usbd_bus_instance {
++
++ struct usbd_bus_driver *driver;
++
++ int endpoints;
++ struct usbd_endpoint_instance *endpoint_array; // array of available configured endpoints
++
++ struct urb_link finished; // processed urbs
++
++ //char *serial_number_str;
++
++ usbd_device_status_t status; // device status
++ usbd_bus_state_t bus_state;
++ usbd_device_state_t device_state; // current USB Device state
++ usbd_device_state_t suspended_state; // previous USB Device state
++
++ struct usbd_function_instance *ep0; // ep0 configuration
++ struct usbd_function_instance *function_instance;
++
++
++ u8 HighSpeedFlag;
++
++ u8 ConfigurationValue; // current set configuration (zero is default)
++ u8 bNumInterfaces; // number of interfaces in the current configuration
++ u8 *alternates; // array[0..interfaces-1] of alternate settings
++ // for each interface
++
++ u32 device_feature_settings;// save set feature information
++ u8 otg_bmAttributes;
++
++ struct WORK_STRUCT device_bh; // runs as bottom half, equivalent to interrupt time
++
++ void *privdata; // private data for the bus interface
++ char *arg;
++};
++
++
++
++
++/*! bus driver registration
++ *
++ * Called by bus interface drivers to register themselves when loaded
++ * or de-register when unloading.
++ */
++struct usbd_bus_instance *usbd_register_bus (struct usbd_bus_driver *, int);
++void usbd_deregister_bus (struct usbd_bus_instance *);
++
++
++/*! Enable/Disable Function
++ *
++ * Called by a bus interface driver to select and enable a specific function
++ * driver.
++ */
++int usbd_enable_function_irq (struct usbd_bus_instance *, char *, char *);
++void usbd_disable_function (struct usbd_bus_instance *);
++
++
++/*!
++ * usbd_configure_device is used by function drivers (usually the control endpoint)
++ * to change the device configuration.
++ *
++ * usbd_device_event is used by bus interface drivers to tell the higher layers that
++ * certain events have taken place.
++ */
++void usbd_bus_event_handler (struct usbd_bus_instance *, usbd_device_event_t, int);
++void usbd_bus_event_handler_irq (struct usbd_bus_instance *, usbd_device_event_t, int);
++
++
++/*!
++ * usbd_device_request - process a received urb
++ * @urb: pointer to an urb structure
++ *
++ * Used by a USB Bus interface driver to pass received data in a URB to the
++ * appropriate USB Function driver.
++ *
++ * This function must return 0 for success and -EINVAL if the request
++ * is to be stalled.
++ *
++ * Not that if the SETUP is Host to Device with a non-zero wLength then there
++ * *MUST* be a valid receive urb queued OR the request must be stalled.
++ */
++int usbd_device_request (struct usbd_bus_instance*, struct usbd_device_request *);
++
++/*!
++ * Device I/O
++ */
++void usbd_urb_finished (struct usbd_urb *, int );
++void usbd_urb_finished_irq (struct usbd_urb *, int );
++struct usbd_urb *usbd_first_urb_detached_irq (urb_link * hd);
++
++/*! flush endpoint
++ */
++void usbd_flush_endpoint_irq (struct usbd_endpoint_instance *);
++void usbd_flush_endpoint (struct usbd_endpoint_instance *);
++int usbd_find_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress);
++
++
++
+diff -uNr linux/drivers/no-otg/otg/usbp-chap9.h linux/drivers/otg/otg/usbp-chap9.h
+--- linux/drivers/no-otg/otg/usbp-chap9.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/usbp-chap9.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,1577 @@
++/*
++ * otg/otg/usbp-chap9.h
++ *
++ * Copyright (c) 2004 Belcarra
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup USBP USB Peripheral Support
++ * @ingroup onthegogroup
++ */
++
++
++/*!
++ * @file otg/otg/usbp-chap9.h
++ * @brief Chapter 9 and other class descriptor structure definitions.
++ *
++ * USB Descriptors are used to build a configuration database for each USB
++ * Function driver.
++ *
++ * @ingroup USBP
++ */
++
++/*!
++ * @name Device and/or Interface Class Codes
++ */
++
++ /*! @{ */
++
++
++#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
++#define USB_CLASS_AUDIO 1
++#define USB_CLASS_COMM 2
++#define USB_CLASS_HID 3
++#define USB_CLASS_PHYSICAL 5
++#define USB_CLASS_PRINTER 7
++#define USB_CLASS_MASS_STORAGE 8
++#define USB_CLASS_HUB 9
++#define USB_CLASS_DATA 10
++#define USB_CLASS_APP_SPEC 0xfe
++#define USB_CLASS_VENDOR_SPEC 0xff
++/*! @} */
++
++
++/*! @name USB Device Request Types (bmRequestType)
++ *C.f. USB 2.0 Table 9-2
++*/
++
++/*! @{ */
++
++#define USB_TYPE_STANDARD (0x00 << 5)
++#define USB_TYPE_CLASS (0x01 << 5)
++#define USB_TYPE_VENDOR (0x02 << 5)
++#define USB_TYPE_RESERVED (0x03 << 5)
++
++#define USB_RECIP_DEVICE 0x00
++#define USB_RECIP_INTERFACE 0x01
++#define USB_RECIP_ENDPOINT 0x02
++#define USB_RECIP_OTHER 0x03
++
++#define USB_RECIP_HUB 0x00
++#define USB_RECIP_PORT 0x03
++
++#define USB_DIR_OUT 0
++#define USB_DIR_IN 0x80
++#define USB_ENDPOINT_OPT 0x40
++/*! @} */
++
++/*! @name Descriptor types
++ * C.f. USB Table 9-5
++ */
++
++/*! @{ */
++
++#define USB_DT_DEVICE 0x01
++#define USB_DT_CONFIGURATION 0x02
++#define USB_DT_STRING 0x03
++#define USB_DT_INTERFACE 0x04
++#define USB_DT_ENDPOINT 0x05
++#define USB_DT_DEVICE_QUALIFIER 0x06
++#define USB_DT_OTHER_SPEED_CONFIGURATION 0x07
++#define USB_DT_INTERFACE_POWER 0x08
++#define USB_DT_OTG 0x09
++
++
++#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
++#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
++#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
++#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
++/*! @} */
++
++/*! @name Descriptor sizes per descriptor type
++ */
++ /*! @{ */
++
++#define USB_DT_DEVICE_SIZE 18
++#define USB_DT_CONFIG_SIZE 9
++#define USB_DT_INTERFACE_SIZE 9
++#define USB_DT_ENDPOINT_SIZE 7
++#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
++#define USB_DT_HUB_NONVAR_SIZE 7
++#define USB_DT_HID_SIZE 9
++/*! @} */
++
++/*! @name Endpoints
++ */
++/*! @{ */
++#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
++#define USB_ENDPOINT_DIR_MASK 0x80
++
++#define USB_ENDPOINT_MASK 0x03 /* in bmAttributes */
++#define USB_ENDPOINT_CONTROL 0x00
++#define USB_ENDPOINT_ISOCHRONOUS 0x01
++#define USB_ENDPOINT_BULK 0x02
++#define USB_ENDPOINT_INTERRUPT 0x03
++/*! @} */
++
++/*!
++ * @name USB Packet IDs (PIDs)
++ */
++/*! @{ */
++#define USB_PID_UNDEF_0 0xf0
++#define USB_PID_OUT 0xe1
++#define USB_PID_ACK 0xd2
++#define USB_PID_DATA0 0xc3
++#define USB_PID_PING 0xb4 /* USB 2.0 */
++#define USB_PID_SOF 0xa5
++#define USB_PID_NYET 0x96 /* USB 2.0 */
++#define USB_PID_DATA2 0x87 /* USB 2.0 */
++#define USB_PID_SPLIT 0x78 /* USB 2.0 */
++#define USB_PID_IN 0x69
++#define USB_PID_NAK 0x5a
++#define USB_PID_DATA1 0x4b
++#define USB_PID_PREAMBLE 0x3c /* Token mode */
++#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
++#define USB_PID_SETUP 0x2d
++#define USB_PID_STALL 0x1e
++#define USB_PID_MDATA 0x0f /* USB 2.0 */
++/*! @} */
++
++/*! * @name Standard requests
++ */
++
++ /*! @{ */
++
++#define USB_REQ_GET_STATUS 0x00
++#define USB_REQ_CLEAR_FEATURE 0x01
++#define USB_REQ_SET_FEATURE 0x03
++#define USB_REQ_SET_ADDRESS 0x05
++#define USB_REQ_GET_DESCRIPTOR 0x06
++#define USB_REQ_SET_DESCRIPTOR 0x07
++#define USB_REQ_GET_CONFIGURATION 0x08
++#define USB_REQ_SET_CONFIGURATION 0x09
++#define USB_REQ_GET_INTERFACE 0x0A
++#define USB_REQ_SET_INTERFACE 0x0B
++#define USB_REQ_SYNCH_FRAME 0x0C
++/*! @} */
++
++/*!
++ * @name Hub requests
++ */
++ /*! @{ */
++#define USB_REQ_CLEAR_TT_BUFFER 0x08
++#define USB_REQ_RESET_TT 0x09
++#define USB_REQ_GET_TT_STATE 0x0A
++#define USB_REQ_STOP_TT 0x0B
++/*! @} */
++
++/*!
++ * @name HID requests
++ */
++ /*! @{ */
++#define USB_REQ_GET_REPORT 0x01
++#define USB_REQ_GET_IDLE 0x02
++#define USB_REQ_GET_PROTOCOL 0x03
++#define USB_REQ_SET_REPORT 0x09
++#define USB_REQ_SET_IDLE 0x0A
++#define USB_REQ_SET_PROTOCOL 0x0B
++/*! @} */
++
++
++/*!
++ * @name USB Spec Release number
++ */
++ /*! @{ */
++
++#define USB_BCD_VERSION 0x0200
++/*! @} */
++
++/*!
++ * @name Audio
++ */
++ /*! @{ */
++
++#define CS_AUDIO_UNDEFINED 0x20
++#define CS_AUDIO_DEVICE 0x21
++#define CS_AUDIO_CONFIGURATION 0x22
++#define CS_AUDIO_STRING 0x23
++#define CS_AUDIO_INTERFACE 0x24
++#define CS_AUDIO_ENDPOINT 0x25
++
++#define AUDIO_HEADER 0x01
++#define AUDIO_INPUT_TERMINAL 0x02
++#define AUDIO_OUTPUT_TERMINAL 0x03
++#define AUDIO_MIXER_UNIT 0x04
++#define AUDIO_SELECTOR_UNIT 0x05
++#define AUDIO_FEATURE_UNIT 0x06
++#define AUDIO_PROCESSING_UNIT 0x07
++#define AUDIO_EXTENSION_UNIT 0x08
++/*! @} */
++
++
++/*!
++ * @name Device Requests (c.f Table 9-2)
++ */
++ /*! @{ */
++
++#define USB_REQ_DIRECTION_MASK 0x80
++#define USB_REQ_TYPE_MASK 0x60
++#define USB_REQ_RECIPIENT_MASK 0x1f
++
++#define USB_REQ_DEVICE2HOST 0x80
++#define USB_REQ_HOST2DEVICE 0x00
++
++#define USB_REQ_TYPE_STANDARD 0x00
++#define USB_REQ_TYPE_CLASS 0x20
++#define USB_REQ_TYPE_VENDOR 0x40
++
++#define USB_REQ_RECIPIENT_DEVICE 0x00
++#define USB_REQ_RECIPIENT_INTERFACE 0x01
++#define USB_REQ_RECIPIENT_ENDPOINT 0x02
++#define USB_REQ_RECIPIENT_OTHER 0x03
++/*! @} */
++
++/*!
++ * @name Hub Recipients
++ */
++ /*! @{ */
++#define USB_REQ_RECIPIENT_HUB 0x00
++#define USB_REQ_RECIPIENT_PORT 0x03
++/*! @} */
++
++/*!
++ * @name get status bits
++ */
++ /*! @{ */
++
++#define USB_STATUS_SELFPOWERED 0x01
++#define USB_STATUS_REMOTEWAKEUP 0x02
++
++#define USB_STATUS_HALT 0x01
++/*! @} */
++
++/*!
++ * @name Convert Feature Selector to a Status Flag Setting
++ */
++ /*! @{ */
++#define FEATURE(f) (1 << f)
++/*! @} */
++
++/*!
++ * @name standard feature selectors
++ */
++ /*! @{ */
++#define USB_ENDPOINT_HALT 0x00
++#define USB_DEVICE_REMOTE_WAKEUP 0x01
++#define USB_TEST_MODE 0x02
++/*! @} */
++
++/*!
++ * @name Hub Feature Selectors C.f. Table 11-17
++ */
++ /*! @{ */
++#if !defined(C_HUB_LOCAL_POWER)
++#define C_HUB_LOCAL_POWER 0x0
++#endif
++#if !defined(C_HUB_OVER_CURRENT)
++#define C_HUB_OVER_CURRENT 0x1
++#endif
++
++#define PORT_CONNECTION 0
++#define PORT_ENABLE 1
++#define PORT_SUSPEND 2
++#define PORT_OVER_CURRENT 3
++#define PORT_RESET 4
++
++#define PORT_POWER 8
++#define PORT_LOW_SPEED 9
++#define PORT_HIGH_SPEED 10
++
++#define C_PORT_CONNECTION 16
++#define C_PORT_ENABLE 17
++#define C_PORT_SUSPEND 18
++#define C_PORT_OVER_CURRENT 19
++#define C_PORT_RESET 20
++
++#define PORT_TEST 21
++#define PORT_INDICATOR 22
++
++/*! @} */
++
++#ifdef PRAGMAPACK
++#pragma pack(push,1)
++#endif
++
++
++struct usbd_device_request {
++ u8 bmRequestType;
++ u8 bRequest;
++ u16 wValue;
++ u16 wIndex;
++ u16 wLength;
++} PACKED;
++
++
++
++struct usbd_otg_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bmAttributes;
++} PACKED;
++
++/*!
++ * @name OTG
++ */
++ /*! @{ */
++#define USB_OTG_HNP_SUPPORTED 0x02
++#define USB_OTG_SRP_SUPPORTED 0x01
++/*! @} */
++
++/*!
++ * @name OTG Feature selectors
++ */
++ /*! @{ */
++#define USB_OTG_B_HNP_ENABLE 0x03
++#define USB_OTG_A_HNP_SUPPORT 0x04
++#define USB_OTG_A_ALT_HNP_ENABLE 0x05
++/*! @} */
++
++/*!
++ * @name Class-Specific Request Codes
++ * C.f. CDC Table 46
++ */
++ /*! @{ */
++
++#define CDC_CLASS_REQUEST_SEND_ENCAPSULATED 0x00
++#define CDC_CLASS_REQUEST_GET_ENCAPSULATED 0x01
++
++#define CDC_CLASS_REQUEST_SET_COMM_FEATURE 0x02
++#define CDC_CLASS_REQUEST_GET_COMM_FEATURE 0x03
++#define CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE 0x04
++
++#define CDC_CLASS_REQUEST_SET_LINE_CODING 0x20
++#define CDC_CLASS_REQUEST_GET_LINE_CODING 0x21
++
++#define CDC_CLASS_REQUEST_SET_CONTROL_LINE_STATE 0x22
++#define CDC_CLASS_REQUEST_SEND_BREAK 0x23
++/*! @} */
++
++/*!
++ * @name Notification codes
++ * c.f. CDC Table 68
++ */
++ /*! @{ */
++
++#define CDC_NOTIFICATION_NETWORK_CONNECTION 0x00
++#define CDC_NOTIFICATION_RESPONSE_AVAILABLE 0x01
++#define CDC_NOTIFICATION_AUX_JACK_HOOK_STATE 0x08
++#define CDC_NOTIFICATION_RING_DETECT 0x09
++#define CDC_NOTIFICATION_SERIAL_STATE 0x20
++#define CDC_NOTIFICATION_CALL_STATE_CHANGE 0x28
++#define CDC_NOTIFICATION_LINE_STATE_CHANGE 0x29
++#define CDC_NOTIFICATION_CONNECTION_SPEED_CHANGE 0x2a
++/*! @} */
++
++struct hub_descriptor {
++ u8 bDescLength;
++ u8 bDescriptorType;
++ u8 bNbrPorts;
++ u16 wHubCharacteristics;
++ u8 bPwrOn2PwrGood;
++ u8 bHubContrCurrent;
++ u8 DeviceRemovable;
++ u8 PortPwrCtrlMask;
++} PACKED;
++
++/*!
++ * @name Hub Descriptor C.f. 11.23.2.1 Table 11-13
++ * N.B. This assumes 1-8 ports, DeviceRemovable and PortPwrCtrlMask
++ * must be sized for the number of if ports > 8.
++ */
++ /*! @{ */
++
++
++#define HUB_GANGED_POWER 0x00
++#define HUB_INDIVIDUAL_POWER 0x01
++#define HUB_COMPOUND_DEVICE 0x04
++#define HUB_GLOBAL_OVERCURRENT 0x00
++#define HUB_INDIVIDUAL_OVERCURRENT 0x08
++#define HUB_NO_OVERCURRENT 0x10
++#define HUB_TT_8 0x00
++#define HUB_TT_16 0x20
++#define HUB_TT_24 0x40
++#define HUB_TT_32 0x60
++#define HUB_INDICATORS_SUPPORTED 0x80
++/*! @} */
++
++/*!
++ * @name HID - Class Descriptors
++ * C.f. 7.1.1
++ */
++ /*! @{ */
++
++#define HID 0x21
++#define HID_REPORT 0x22
++#define HID_PHYSICAL 0x23
++/*! @} */
++
++/*!
++ * name HID Descriptor
++ * C.f. E.8
++ */
++ /*! @{ */
++
++
++struct hid_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u16 bcdHID;
++ u8 bCountryCode;
++ u8 bNumDescriptors;
++ u8 bReportType;
++ u16 wItemLength;
++} PACKED;
++
++/*! @} */
++
++/*!
++ * name ACM - Line Coding structure
++ * C.f. CDC Table 50
++ */
++ /*! @{ */
++
++
++struct cdc_acm_line_coding {
++ u32 dwDTERate;
++ u8 bCharFormat;
++ u8 bParityType;
++ u8 bDataBits;
++} PACKED;
++
++ /*!@} */
++
++/*!
++ * @name ACM - Line State
++ * C.f. CDC Table 51
++ */
++ /*! @{ */
++typedef u16 cdc_acm_bmLineState;
++#define CDC_LINESTATE_D1_RTS (1 << 1)
++#define CDC_LINESTATE_D0_DTR (1 << 0)
++/*! @} */
++
++/*!
++ * Serial State - C.f. 6.3.5
++ */
++struct acm_serial_state {
++ u16 uart_state_bitmap;
++};
++
++
++/*! @name ACM - UART State
++ * C.f. Table 69 - UART State Bitmap Values
++ */
++/*! @{ */
++typedef u16 cdc_acm_bmUARTState;
++#define CDC_UARTSTATE_BOVERRUN (1 << 6)
++#define CDC_UARTSTATE_BPARITY (1 << 5)
++#define CDC_UARTSTATE_BFRAMING (1 << 4)
++#define CDC_UARTSTATE_BRINGSIGNAL (1 << 3)
++#define CDC_UARTSTATE_BBREAK (1 << 2)
++#define CDC_UARTSTATE_BTXCARRIER_DSR (1 << 1)
++#define CDC_UARTSTATE_BRXCARRIER_DCD (1 << 0)
++/*! @} */
++
++/* !USB Notification
++ *
++ */
++
++struct cdc_notification_descriptor {
++ u8 bmRequestType;
++ u8 bNotification;
++ u16 wValue;
++ u16 wIndex;
++ u16 wLength;
++ u8 data[2];
++} PACKED;
++
++
++
++
++/*!
++ * @name Communications Class Types
++ *
++ * c.f. CDC USB Class Definitions for Communications Devices
++ * c.f. WMCD USB CDC Subclass Specification for Wireless Mobile Communications Devices
++ *
++ * @{
++ */
++
++#define CLASS_BCD_VERSION 0x0110
++/*! @} */
++
++/*! @name c.f. CDC 4.1 Table 14 */
++
++/*! @{ */
++
++#define AUDIO_CLASS 0x01
++#define COMMUNICATIONS_DEVICE_CLASS 0x02
++/*! @} */
++
++/*! @name c.f. CDC 4.2 Table 15
++ */
++ /*! @{ */
++#define COMMUNICATIONS_INTERFACE_CLASS 0x02
++/*! @} */
++
++/*! @name c.f. CDC 4.3 Table 16
++ */
++ /*! @{ */
++#define COMMUNICATIONS_NO_SUBCLASS 0x00
++#define COMMUNICATIONS_DLCM_SUBCLASS 0x01
++#define COMMUNICATIONS_ACM_SUBCLASS 0x02
++#define COMMUNICATIONS_TCM_SUBCLASS 0x03
++#define COMMUNICATIONS_MCCM_SUBCLASS 0x04
++#define COMMUNICATIONS_CCM_SUBCLASS 0x05
++#define COMMUNICATIONS_ENCM_SUBCLASS 0x06
++#define COMMUNICATIONS_ANCM_SUBCLASS 0x07
++
++#define AUDIO_CONTROL_SUBCLASS 0x01
++#define AUDIO_STREAMING_SUBCLASS 0x02
++/*! @} */
++
++/*! @name c.f. WMCD 5.1
++ */
++ /*! @{ */
++#define COMMUNICATIONS_WHCM_SUBCLASS 0x08
++#define COMMUNICATIONS_DMM_SUBCLASS 0x09
++#define COMMUNICATIONS_MDLM_SUBCLASS 0x0a
++#define COMMUNICATIONS_OBEX_SUBCLASS 0x0b
++/*! @} */
++
++/*! @name c.f. CDC 4.6 Table 18
++ */
++ /*! @{ */
++#define DATA_INTERFACE_CLASS 0x0a
++/*! @} */
++
++/*! @name c.f. CDC 4.7 Table 19
++ */
++ /*! @{ */
++#define COMMUNICATIONS_NO_PROTOCOL 0x00
++/*! @} */
++
++
++/*! @name c.f. CDC 5.2.3 Table 24
++ * c.f. Audio Appendix A.4
++ */
++ /*! @{ */
++#define CS_UNDEFINED 0x20
++#define CS_DEVICE 0x21
++#define CS_CONFIG 0x22
++#define CS_STRING 0x23
++#define CS_INTERFACE 0x24
++#define CS_ENDPOINT 0x25
++/*! @} */
++
++/*!
++ * @name Audio Interface Class - c.f Appendix A.1
++ */
++ /*! @{ */
++#define AUDIO_INTERFACE_CLASS 0x01
++/*! @} */
++
++/*! @name Audio Interface Subclass - c.f Appendix A.2
++ */
++ /*! @{ */
++#define AUDIO_SUBCLASS_UNDEFINED 0x00
++#define AUDIO_AUDIOCONTROL 0x01
++#define AUDIO_AUDIOSTREAMING 0x02
++#define AUDIO_MIDISTREAMING 0x03
++/*! @} */
++
++/*! @name Audio Interface Proctol - c.f. Appendix A.3
++ */
++ /*! @{ */
++#define AUDIO_PR_PROTOCOL_UNDEFINED 0x00
++/*! @} */
++
++/*! @name Audio Class-Specific AC Interface Descriptor Subtypes - c.f. A.5
++ */
++ /*! @{ */
++#define AUDIO_AC_DESCRIPTOR_UNDEFINED 0x00
++#define AUDIO_AC_HEADER 0x01
++#define AUDIO_AC_INPUT_TERMINAL 0x02
++#define AUDIO_AC_OUTPUT_TERMINAL 0x03
++#define AUDIO_AC_MIXER_UNIT 0x04
++#define AUDIO_AC_SELECTOR_UNIT 0x05
++#define AUDIO_AC_FEATURE_UNIT 0x06
++#define AUDIO_AC_PROCESSING_UNIT 0x07
++#define AUDIO_AC_EXTENSION_UNIT 0x08
++/*! @} */
++
++/*! @name Audio Class-Specific AS Interface Descriptor Subtypes - c.f. A.6
++ */
++ /*! @{ */
++#define AUDIO_AS_DESCRIPTOR_UNDEFINED 0x00
++#define AUDIO_AS_GENERAL 0x01
++#define AUDIO_AS_FORMAT_TYPE 0x02
++#define AUDIO_AS_FORMAT_UNSPECFIC 0x03
++/*! @} */
++
++/*! @name Audio Class Processing Unit Processing Types - c.f. A.7
++ */
++ /*! @{ */
++#define AUDIO_PROCESS_UNDEFINED 0x00
++#define AUDIO_UP_DOWN_MUIX_PROCESS 0x01
++#define AUDIO_DOLBY_PROLOGIC_PROCESS 0x02
++#define AUDIO_3D_STEREO_EXTENDER_PROCESS 0x03
++#define AUDIO_REVERBERATION_PROCESS 0x04
++#define AUDIO_CHORUS_PROCESS 0x05
++#define AUDIO_DYN_RANGE_COMP_PROCESS 0x06
++/*! @} */
++
++/*! @name Audio Class-Specific Endpoint Descriptor Subtypes - c.f. A.8
++ */
++ /*! @{ */
++#define AUDIO_DESCRIPTOR_UNDEFINED 0x00
++#define AUDIO_EP_GENERAL 0x01
++/*! @} */
++
++/*! @name Audio Class-Specific Request Codes - c.f. A.9
++ */
++ /*! @{ */
++#define AUDIO_REQUEST_CODE_UNDEFINED 0x00
++#define AUDIO_SET_CUR 0x01
++#define AUDIO_GET_CUR 0x81
++#define AUDIO_SET_MIN 0x02
++#define AUDIO_GET_MIN 0x82
++#define AUDIO_SET_MAX 0x03
++#define AUDIO_GET_MAX 0x83
++#define AUDIO_SET_RES 0x04
++#define AUDIO_GET_RES 0x84
++#define AUDIO_SET_MEM 0x05
++#define AUDIO_GET_MEM 0x85
++#define AUDIO_GET_STAT 0xff
++/*! @} */
++
++/*!
++ * @name bDescriptorSubtypes
++ *
++ * c.f. CDC 5.2.3 Table 25
++ * c.f. WMCD 5.3 Table 5.3
++ */
++ /*! @{ */
++
++#define USB_ST_HEADER 0x00
++#define USB_ST_CMF 0x01
++#define USB_ST_ACMF 0x02
++#define USB_ST_DLMF 0x03
++#define USB_ST_TRF 0x04
++#define USB_ST_TCLF 0x05
++#define USB_ST_UF 0x06
++#define USB_ST_CSF 0x07
++#define USB_ST_TOMF 0x08
++#define USB_ST_USBTF 0x09
++#define USB_ST_NCT 0x0a
++#define USB_ST_PUF 0x0b
++#define USB_ST_EUF 0x0c
++#define USB_ST_MCMF 0x0d
++#define USB_ST_CCMF 0x0e
++#define USB_ST_ENF 0x0f
++#define USB_ST_ATMNF 0x10
++
++#define USB_ST_WHCM 0x11
++#define USB_ST_MDLM 0x12
++#define USB_ST_MDLMD 0x13
++#define USB_ST_DMM 0x14
++#define USB_ST_OBEX 0x15
++#define USB_ST_CS 0x16
++#define USB_ST_CSD 0x17
++#define USB_ST_TCM 0x18
++/*! @} */
++
++/*!
++ * @name Class Descriptor Description Structures...
++ * c.f. CDC 5.1
++ * c.f. WCMC 6.7.2
++ *
++ * XXX add the other dozen class descriptor description structures....
++ *
++ */
++ /*! @{ */
++struct usbd_header_functional_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u16 bcdCDC;
++};
++
++struct usbd_call_management_functional_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bmCapabilities;
++ u8 bDataInterface;
++};
++
++struct usbd_abstract_control_functional_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bmCapabilities;
++};
++
++struct usbd_union_functional_functor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bMasterInterface;
++ u8 bSlaveInterface[1];
++ //u8 bSlaveInterface[0]; // XXX FIXME
++};
++
++struct usbd_ethernet_networking_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ char *iMACAddress;
++ u8 bmEthernetStatistics;
++ u16 wMaxSegmentSize;
++ u16 wNumberMCFilters;
++ u8 bNumberPowerFilters;
++};
++
++struct usbd_mobile_direct_line_model_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u16 bcdVersion;
++ u8 bGUID[16];
++};
++
++struct usbd_mobile_direct_line_model_detail_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bGuidDescriptorType;
++ u8 bDetailData[2];
++ //u8 bDetailData[0]; // XXX FIXME
++};
++#if 0
++struct usbd_header_description {
++ u8 bDescriptorSubtype;
++ u16 bcdCDC;
++};
++
++struct usbd_call_management_description {
++ u8 bmCapabilities;
++ u8 bDataInterface;
++};
++
++struct usbd_abstract_control_description {
++ u8 bmCapabilities;
++};
++
++struct usbd_union_function_description {
++ u8 bMasterInterface;
++ u8 bSlaveInterface[1];
++ //u8 bSlaveInterface[0]; // XXX FIXME
++};
++
++struct usbd_ethernet_networking_description {
++ char *iMACAddress;
++ u8 bmEthernetStatistics;
++ u16 wMaxSegmentSize;
++ u16 wNumberMCFilters;
++ u8 bNumberPowerFilters;
++};
++
++struct usbd_mobile_direct_line_model_description {
++ u16 bcdVersion;
++ u8 bGUID[16];
++};
++
++struct usbd_mobile_direct_line_model_detail_description {
++ u8 bGuidDescriptorType;
++ u8 bDetailData[2];
++ //u8 bDetailData[0]; // XXX FIXME
++};
++
++struct usbd_class_description {
++ u8 bDescriptorSubtype;
++ u8 elements;
++ union {
++ struct usbd_header_description header;
++ struct usbd_call_management_description call_management;
++ struct usbd_abstract_control_description abstract_control;
++ struct usbd_union_function_description union_function;
++ struct usbd_ethernet_networking_description ethernet_networking;
++ struct usbd_mobile_direct_line_model_description mobile_direct;
++ struct usbd_mobile_direct_line_model_detail_description mobile_direct_detail;
++ } description;
++};
++#endif
++/*! @} */
++
++/*!
++ * @name Endpoint Modifiers
++ * static struct usbd_endpoint_description function_default_A_1[] = {
++ *
++ * {this_endpoint: 0, attributes: CONTROL, max_size: 8, polling_interval: 0 },
++ * {this_endpoint: 1, attributes: BULK, max_size: 64, polling_interval: 0, direction: IN},
++ * {this_endpoint: 2, attributes: BULK, max_size: 64, polling_interval: 0, direction: OUT},
++ * {this_endpoint: 3, attributes: INTERRUPT, max_size: 8, polling_interval: 0},
++ *
++ *
++ */
++ /*! @{ */
++
++#define CONTROL 0x00
++#define ISOCHRONOUS 0x01
++#define BULK 0x02
++#define INTERRUPT 0x03
++/*! @} */
++
++
++/*! @name configuration modifiers
++ */
++
++/* @{ */
++#define BMATTRIBUTE_RESERVED 0x80
++#define BMATTRIBUTE_SELF_POWERED 0x40
++#define BMATTRIBUTE_REMOTE_WAKEUP 0x20
++
++#if 0
++/*
++ * The UUT tester specifically tests for MaxPower to be non-zero (> 0).
++ */
++#if !defined(CONFIG_OTG_MAXPOWER) || (CONFIG_OTG_MAXPOWER == 0)
++ #define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED
++ #define BMAXPOWER 1
++#else
++ #define BMATTRIBUTE BMATTRIBUTE_RESERVED
++ #define BMAXPOWER CONFIG_USBD_MAXPOWER
++#endif
++#endif
++/*! @} */
++
++
++
++/*!
++ * @name Standard Usb Descriptor Structures
++ */
++ /*! @{ */
++
++struct usbd_endpoint_descriptor {
++ u8 bLength;
++ u8 bDescriptorType; // 0x5
++ u8 bEndpointAddress;
++ u8 bmAttributes;
++ u16 wMaxPacketSize;
++ u8 bInterval;
++} PACKED;
++
++struct usbd_interface_descriptor {
++ u8 bLength;
++ u8 bDescriptorType; // 0x04
++ u8 bInterfaceNumber;
++ u8 bAlternateSetting;
++ u8 bNumEndpoints;
++ u8 bInterfaceClass;
++ u8 bInterfaceSubClass;
++ u8 bInterfaceProtocol;
++ u8 iInterface;
++} PACKED;
++
++struct usbd_configuration_descriptor {
++ u8 bLength;
++ u8 bDescriptorType; // 0x2
++ u16 wTotalLength;
++ u8 bNumInterfaces;
++ u8 bConfigurationValue;
++ u8 iConfiguration;
++ u8 bmAttributes;
++ u8 bMaxPower;
++} PACKED;
++
++struct usbd_device_descriptor {
++ u8 bLength;
++ u8 bDescriptorType; // 0x01
++ u16 bcdUSB;
++ u8 bDeviceClass;
++ u8 bDeviceSubClass;
++ u8 bDeviceProtocol;
++ u8 bMaxPacketSize0;
++ u16 idVendor;
++ u16 idProduct;
++ u16 bcdDevice;
++ u8 iManufacturer;
++ u8 iProduct;
++ u8 iSerialNumber;
++ u8 bNumConfigurations;
++} PACKED;
++
++struct usbd_string_descriptor {
++ u8 bLength;
++ u8 bDescriptorType; // 0x03
++ u16 wData[0];
++} PACKED;
++
++struct usbd_device_qualifier_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u16 bcdUSB;
++ u8 bDeviceClass;
++ u8 bDeviceSubClass;
++ u8 bDeviceProtocol;
++ u8 bMaxPacketSize0;
++ u8 bNumConfigurations;
++ u8 bReserved;
++} PACKED;
++
++struct usbd_generic_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++} PACKED;
++
++struct usbd_generic_class_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++} PACKED;
++/*! @} */
++
++/*!
++ * @name Communications Class Dscriptor Structures
++ * c.f. CDC 5.2 Table 25c
++ */
++
++/*! @{*/
++
++struct usbd_class_function_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++} PACKED;
++
++struct usbd_class_function_descriptor_generic {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bmCapabilities;
++} PACKED;
++
++struct usbd_class_header_function_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x00
++ u16 bcdCDC;
++} PACKED;
++
++struct usbd_class_call_management_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x01
++ u8 bmCapabilities;
++ u8 bDataInterface;
++} PACKED;
++
++struct usbd_class_abstract_control_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x02
++ u8 bmCapabilities;
++} PACKED;
++
++struct usbd_class_direct_line_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x03
++} PACKED;
++
++struct usbd_class_telephone_ringer_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x04
++ u8 bRingerVolSeps;
++ u8 bNumRingerPatterns;
++} PACKED;
++
++struct usbd_class_telephone_call_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x05
++ u8 bmCapabilities;
++} PACKED;
++
++struct usbd_class_union_function_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x06
++ u8 bMasterInterface;
++ u8 bSlaveInterface0[0];
++} PACKED;
++
++struct usbd_class_country_selection_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x07
++ u8 iCountryCodeRelDate;
++ u16 wCountryCode0[0];
++} PACKED;
++
++
++struct usbd_class_telephone_operational_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x08
++ u8 bmCapabilities;
++} PACKED;
++
++
++struct usbd_class_usbd_terminal_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x09
++ u8 bEntityId;
++ u8 bInterfaceNo;
++ u8 bOutInterfaceNo;
++ u8 bmOptions;
++ u8 bChild0[0];
++} PACKED;
++
++struct usbd_class_network_channel_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0a
++ u8 bEntityId;
++ u8 iName;
++ u8 bChannelIndex;
++ u8 bPhysicalInterface;
++} PACKED;
++
++struct usbd_class_protocol_unit_function_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0b
++ u8 bEntityId;
++ u8 bProtocol;
++ u8 bChild0[0];
++} PACKED;
++
++struct usbd_class_extension_unit_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0c
++ u8 bEntityId;
++ u8 bExtensionCode;
++ u8 iName;
++ u8 bChild0[0];
++} PACKED;
++
++struct usbd_class_multi_channel_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0d
++ u8 bmCapabilities;
++} PACKED;
++
++struct usbd_class_capi_control_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0e
++ u8 bmCapabilities;
++} PACKED;
++
++struct usbd_class_ethernet_networking_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x0f
++ u8 iMACAddress;
++ u32 bmEthernetStatistics;
++ u16 wMaxSegmentSize;
++ u16 wNumberMCFilters;
++ u8 bNumberPowerFilters;
++} PACKED;
++
++struct usbd_class_atm_networking_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x10
++ u8 iEndSystermIdentifier;
++ u8 bmDataCapabilities;
++ u8 bmATMDeviceStatistics;
++ u16 wType2MaxSegmentSize;
++ u16 wType3MaxSegmentSize;
++ u16 wMaxVC;
++} PACKED;
++
++
++struct usbd_class_mdlm_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x12
++ u16 bcdVersion;
++ u8 bGUID[16];
++} PACKED;
++
++/*
++struct usbd_class_mdlmd_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x13
++ u8 bGuidDescriptorType;
++ u8 bDetailData[0];
++} PACKED;
++*/
++
++struct usbd_class_blan_descriptor {
++ u8 bFunctionLength; // 0x7
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x13
++ u8 bGuidDescriptorType;
++ u8 bmNetworkCapabilities;
++ u8 bmDataCapabilities;
++ u8 bPad;
++} PACKED;
++
++struct usbd_class_safe_descriptor {
++ u8 bFunctionLength; // 0x6
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype; // 0x13
++ u8 bGuidDescriptorType;
++ u8 bmNetworkCapabilities;
++ u8 bmDataCapabilities;
++} PACKED;
++
++/*@}*/
++
++
++/*!
++ * @name Descriptor Union Structures
++ */
++ /*! @{ */
++
++struct usbd_descriptor {
++ union {
++ struct usbd_generic_descriptor generic_descriptor;
++ struct usbd_generic_class_descriptor generic_class_descriptor;
++ struct usbd_endpoint_descriptor endpoint_descriptor;
++ struct usbd_interface_descriptor interface_descriptor;
++ struct usbd_configuration_descriptor configuration_descriptor;
++ struct usbd_device_descriptor device_descriptor;
++ struct usbd_string_descriptor string_descriptor;
++ } descriptor;
++
++} PACKED;
++
++struct usbd_class_descriptor {
++ union {
++ struct usbd_class_function_descriptor function;
++ struct usbd_class_function_descriptor_generic generic;
++ struct usbd_class_header_function_descriptor header_function;
++ struct usbd_class_call_management_descriptor call_management;
++ struct usbd_class_abstract_control_descriptor abstract_control;
++ struct usbd_class_direct_line_descriptor direct_line;
++ struct usbd_class_telephone_ringer_descriptor telephone_ringer;
++ struct usbd_class_telephone_operational_descriptor telephone_operational;
++ struct usbd_class_telephone_call_descriptor telephone_call;
++ struct usbd_class_union_function_descriptor union_function;
++ struct usbd_class_country_selection_descriptor country_selection;
++ struct usbd_class_usbd_terminal_descriptor usb_terminal;
++ struct usbd_class_network_channel_descriptor network_channel;
++ struct usbd_class_extension_unit_descriptor extension_unit;
++ struct usbd_class_multi_channel_descriptor multi_channel;
++ struct usbd_class_capi_control_descriptor capi_control;
++ struct usbd_class_ethernet_networking_descriptor ethernet_networking;
++ struct usbd_class_atm_networking_descriptor atm_networking;
++ struct usbd_class_mdlm_descriptor mobile_direct;
++ //struct usbd_class_mdlmd_descriptor mobile_direct_detail;
++ struct usbd_class_blan_descriptor mobile_direct_blan_detail;
++ struct usbd_class_safe_descriptor mobile_direct_safe_detail;
++ } descriptor;
++
++} PACKED;
++/*! @} */
++
++/*!
++ * @name Audio Status Word Format - c.f. Table 3.1
++ */
++ /*! @{ */
++
++#define AUDIO_STATUS_INTERRUPT_PENDING 1<<7
++#define AUDIO_STATUS_MEMORY_CONTENT_CHANGED 1<<6
++#define AUDIO_STATUS_ORIGINATOR_AUDIO_CONTROL_INTERFACE 0
++#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_INTERFACE 1
++#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_ENDPOINT 2
++#define AUDIO_STATUS_ORIGINATOR_AUDIOCONTROL_INTERFACE 0
++
++struct usbd_audio_status_word {
++ u8 bStatusType;
++ u8 bOriginator;
++} PACKED;
++
++struct usbd_audio_ac_interface_header_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u16 bcdADC;
++ u16 wTotalLength;
++ u8 binCollection;
++ u8 bainterfaceNr[0];
++} PACKED;
++
++struct usbd_audio_input_terminal_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bTerminalID;
++ u16 wTerminalType;
++ u8 bAssocTerminal;
++ u8 bNrChannels;
++ u16 wChannelConfig;
++ u8 iChannelNames;
++ u8 iTerminal;
++} PACKED;
++
++struct usbd_audio_input_terminal_description {
++ struct usbd_audio_input_terminal_descriptor *audio_input_terminal_descriptor;
++ u16 wTerminalType;
++ u16 wChannelConfig;
++ char * iChannelNames;
++ char * iTerminal;
++};
++
++struct usbd_audio_output_terminal_descriptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bTerminalID;
++ u16 wTerminalType;
++ u8 bAssocTerminal;
++ u8 bSourceID;
++ u8 iTerminal;
++} PACKED;
++
++struct usbd_audio_output_terminal_description {
++ struct usbd_audio_output_terminal_descriptor *audio_output_terminal_descriptor;
++ u16 wTerminalType;
++ char * iTerminal;
++};
++
++struct usbd_audio_mixer_unit_descriptor_a {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bUniteID;
++ u8 bNrinPins;
++} PACKED;
++
++struct usbd_audio_mixer_unit_descriptor_b {
++ u8 baSourceID;
++ u8 bNrChannels;
++ u16 wChannelConfig;
++ u8 iChannelNames;
++ u8 bmControls;
++ u8 iMixer;
++} PACKED;
++
++struct usbd_audio_mixer_unit_description {
++ struct usbd_audio_mixer_unit_descriptor *audio_mixer_unit_descriptor;
++ u16 wChannelConfig;
++ char * iMixer;
++};
++
++
++struct usbd_audio_as_general_interface_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bTerminalLink;
++ u8 bDelay;
++ u16 wFormatTag;
++} PACKED;
++
++struct usbd_audio_as_general_interface_description {
++ struct usbd_audio_as_general_interface_descriptor *audio_as_general_interface_descriptor;
++ u16 wFormatTag;
++};
++
++struct usbd_audio_as_format_type_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bFormatType;
++ u8 bNrChannels;
++ u8 bSubFrameSize;
++ u8 bBitResolution;
++ u8 bSamFreqType;
++ u8 iSamFreq[3];
++} PACKED;
++
++struct usbd_audio_as_format_type_description {
++ struct usbd_audio_as_format_type_descriptor *audio_as_format_type_descriptor;
++ u16 wFormatTag;
++};
++
++
++
++
++struct usbd_audio_descriptor {
++ union {
++ struct usbd_audio_ac_interface_header_descriptor header;
++ struct usbd_audio_input_terminal_descriptor input;
++ struct usbd_audio_output_terminal_descriptor output;
++ } descriptor;
++} PACKED;
++
++
++
++struct usbd_ac_endpoint_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bEndpointAddress;
++ u8 bmAttributes;
++ u16 wMaxPacketSize;
++ u8 bInterval;
++ u8 bRefresh;
++ u8 bSynchAddress;
++} PACKED;
++
++
++struct usbd_as_iso_endpoint_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubtype;
++ u8 bmAttributes;
++ u8 bLockDelayUnits;
++ u16 wLockDelay;
++} PACKED;
++/*! @}*/
++
++
++/*!
++ * @name MCPC
++ */
++ /*! @{ */
++
++/*! struct usbd_interface_association
++ * Used in AB-1 or DL-1 interface bundles.
++ */
++struct usbd_interface_association_descriptor {
++ u8 bLength;
++ u8 bDescriptorType;
++ u8 bFirstInterface;
++ u8 bInterfaceCount;
++ u8 bFunctionClass;
++ u8 bFunctionSubClass;
++ u8 bFunctionProcotol;
++ u8 iFunction;
++} PACKED;
++
++struct usbd_mobile_abstract_control_model_specific_desciptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubType;
++ u8 bType;
++ u8 bMode_1;
++};
++
++struct usbd_mobile_direct_line_model_specific_desciptor {
++ u8 bFunctionLength;
++ u8 bDescriptorType;
++ u8 bDescriptorSubType;
++ u8 bType;
++ u8 bMode_N[2];
++};
++
++
++/*! @} */
++
++/*!
++ * Device Events
++ *
++ * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
++ *
++ * There are additional events defined to handle some extra actions we need to have handled.
++ *
++ */
++typedef enum usbd_device_event {
++
++ DEVICE_UNKNOWN, // bi - unknown event
++ DEVICE_INIT, // bi - initialize
++ DEVICE_CREATE, // bi -
++ DEVICE_HUB_CONFIGURED, // bi - bus has been plugged int
++ DEVICE_RESET, // bi - hub has powered our port
++
++ DEVICE_ADDRESS_ASSIGNED,// ep0 - set address setup received
++ DEVICE_CONFIGURED, // ep0 - set configure setup received
++ DEVICE_SET_INTERFACE, // ep0 - set interface setup received
++
++ DEVICE_SET_FEATURE, // ep0 - set feature setup received
++ DEVICE_CLEAR_FEATURE, // ep0 - clear feature setup received
++
++ DEVICE_DE_CONFIGURED, // ep0 - set configure setup received for ??
++
++ DEVICE_BUS_INACTIVE, // bi - bus in inactive (no SOF packets)
++ DEVICE_BUS_ACTIVITY, // bi - bus is active again
++
++ DEVICE_POWER_INTERRUPTION,// bi - hub has depowered our port
++ DEVICE_HUB_RESET, // bi - bus has been unplugged
++ DEVICE_DESTROY, // bi - device instance should be destroyed
++ DEVICE_CLOSE, // bi - device instance should be destroyed
++
++} usbd_device_event_t;
++
++/*! USB Request Block structure
++ *
++ * This is used for both sending and receiving data.
++ *
++ * The callback function is used to let the function driver know when
++ * transmitted data has been sent.
++ *
++ * The callback function is set by the alloc_recv function when an urb is
++ * allocated for receiving data for an endpoint and used to call the
++ * function driver to inform it that data has arrived.
++ *
++ * Note that for OUT urbs the buffer is always allocated to a multiple of
++ * the packetsize that is 1 larger than the requested size. This prevents
++ * overflow if the host unexpectedly sends a full sized packet when we are
++ * expecting a short one (the host is always right..)
++ *
++ * USBD_URB_SENDZLP - set this flag if a ZLP (zero length packet) should be
++ * sent after the data is sent. This is required if sending data that is a
++ * multiple of the packetsize but less than the maximum transfer size for
++ * the protocol in use. A ZLP is required to ensure that the host
++ * recognizes a short transfer.
++ *
++ */
++
++typedef struct urb_link {
++ struct urb_link *next;
++ struct urb_link *prev;
++} urb_link;
++
++
++/*! URB Status
++ *
++ * This defines the current status of a pending or finshed URB.
++ *
++ */
++typedef enum usbd_urb_status {
++ SEND_IN_QUEUE,
++ SEND_IN_PROGRESS,
++ SEND_FINISHED_OK,
++ SEND_FINISHED_ERROR,
++ SEND_CANCELLED,
++ SEND_STALLED,
++ SEND_DISABLED,
++ RECV_IN_QUEUE,
++ RECV_IN_PROGRESS,
++ RECV_OK,
++ RECV_ERROR,
++ RECV_CANCELLED,
++ RECV_STALLED,
++ RECV_DISABLED
++} usbd_urb_status_t;
++
++#define USBD_URB_SENDZLP 0x01
++
++struct usbd_urb {
++
++ struct usbd_bus_instance *bus;
++ struct usbd_function_instance *function_instance;
++ struct usbd_endpoint_instance *endpoint;
++
++ int (*callback) (struct usbd_urb *, int);
++
++ u8 *buffer; // data received (OUT) or being sent (IN)
++ u32 request_length; // maximum data expected for OUT
++ u32 buffer_length; // allocated size of buffer
++ u32 actual_length; // actual data received (OUT or being sent (IN)
++ u32 flags;
++
++ void *function_privdata;
++ void *bus_privdata;
++ void *pcimap;
++
++ struct urb_link link;
++ usbd_urb_status_t status; // what is the current status of the urb
++ time_t jiffies; // timestamp for when urb was started or finished
++ u16 framenum; // SOF framenum when urb was finished
++};
++
++/*! Endpoint Request
++ *
++ * An array of these structures is initialized by each function driver to specify the endpoints
++ * it requires.
++ *
++ * The bus interface driver will attempt to fulfill these requests with the actual endpoints it
++ * has available.
++ *
++ * Note that in most cases the bEndpointAddress should be left as zero except for specialized
++ * function drivers that both require a specific value and know ahead of time that the specified
++ * value is legal for the bus interface driver being used.
++ */
++struct usbd_endpoint_request {
++ u8 configuration; /* configuration endpoint will be in */
++ u8 interface_num; /* interface endpoint will be in */
++ u8 alternate; /* altsetting for this request */
++ u8 bmAttributes; /* endpoint type AND direction */
++ u16 fs_requestedTransferSize; /* max full speed transfer size for this endpoint */
++ u16 hs_requestedTransferSize; /* max high speed transfer size for this endpoint */
++ u8 bEndpointAddress; /* specific bEndpointAddress function driver requires */
++ u8 physical; /* physical endpoint used */
++};
++
++/*!
++ * Device status
++ *
++ * Overall state, we use this to show when we are suspended.
++ * This is required because when resumed we need to go back
++ * to previous state.
++ */
++typedef enum usbd_device_status {
++ USBD_OPENING, // we are currently opening
++ USBD_RESETING, // we are currently opening
++ USBD_OK, // ok to use
++ USBD_SUSPENDED, // we are currently suspended
++ USBD_CLOSING, // we are currently closing
++ USBD_CLOSED, // we are currently closing
++ USBD_UNKNOWN,
++} usbd_device_status_t;
++
++
++/*!
++ * Device State (c.f USB Spec 2.0 Figure 9-1)
++ *
++ * What state the usb device is in.
++ *
++ * Note the state does not change if the device is suspended, we simply set a
++ * flag to show that it is suspended.
++ *
++ */
++typedef enum usbd_device_state {
++ STATE_INIT, // just initialized
++ STATE_CREATED, // just created
++ STATE_ATTACHED, // we are attached
++ STATE_POWERED, // we have seen power indication (electrical bus signal)
++ STATE_DEFAULT, // we been reset
++ STATE_ADDRESSED, // we have been addressed (in default configuration)
++ STATE_CONFIGURED, // we have seen a set configuration device command
++ STATE_SUSPENDED, // device has been suspended
++ STATE_UNKNOWN, // destroyed
++} usbd_device_state_t;
++
++
++
++#ifdef PRAGMAPACK
++#pragma pack(pop)
++#endif
++
++
+diff -uNr linux/drivers/no-otg/otg/usbp-func.h linux/drivers/otg/otg/usbp-func.h
+--- linux/drivers/no-otg/otg/usbp-func.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/usbp-func.h 2006-09-01 21:41:33.000000000 +0200
+@@ -0,0 +1,428 @@
++/*
++ * otg/otg/usbp-func.h - USB Device Function Driver Interface
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ *
++ */
++
++/*!
++ * @file otg/otg/usbp-func.h
++ * @brief Function Driver related structures and definitions.
++ *
++ * This file contains the USB Function Driver and USB Interface Driver
++ * definitions.
++ *
++ * The USBOTG support allows for implementation of composite devices.
++ *
++ * From USB 2.0, C.f. 5.2.3:
++ *
++ * A Device that has multiple interfaces controlled independantly of
++ * each other is referred to as a composite device. A composite device
++ * has only a single device.
++ *
++ * In this implemenation the function portion of the device is split into
++ * two types of drivers:
++ *
++ * - USB Interface Driver
++ * - USB Function Driver
++ *
++ *
++ * USB Interface Driver
++ *
++ * An USB Interface Driver specifies the Interface related descriptors and
++ * implements the data handling processes for each of the data endpoints
++ * associated with the interface (or interfaces) required for the function.
++ * It typically will also implement the upper edge interface to the OS.
++ *
++ * The USB Interface Driver will also handle non-standard device requests
++ * and feature requests that are for the interface or an endpoint associated
++ * with one of the interfaces associated with the driver.
++ *
++ * Each interface implemented by an USB Interface Driver will have a
++ * interface instance that stores a pointer to the parent USB Function
++ * Driver and has an array of pointers to endpoint instances for the data
++ * endpoints associated with the interface.
++ *
++ *
++ * USB Function Driver
++ *
++ * A USB Function Driver specifies the device and configuration descriptors.
++ * A configuration descriptor is assembled from the interface descriptors
++ * from the USB Interface Driver (or drivers) that it is making available to
++ * the USB Host.
++ *
++ * The USB Function Driver handles non-standard device requests and feature
++ * requests for the device.
++ *
++ * Each function driver has a function instance that maintains an array
++ * of pointers to configuration instances and a pointer to the device
++ * descriptor.
++ *
++ * Each configuration instance maintains an array of pointers to the
++ * interface instances for that configuration and a pointer to the
++ * complete configuration descriptor.
++ *
++ * @ingroup USBP
++ */
++
++/*!
++ * This file contains the USB Device Core Common definitions. It also contains definitions for
++ * functions that are commonly used by both Function Drivers and Bus Interface Drivers.
++ *
++ * Specifically:
++ *
++ * o public functions exported by the USB Core layer
++ *
++ * o common structures and definitions
++ *
++ */
++
++
++
++struct usbd_bus_instance;
++struct usbd_endpoint_instance;
++struct usbd_function_instance;
++
++/*!
++ * USB Function Driver types
++ */
++typedef enum usbd_function_types {
++ function_simple,
++ function_interface,
++ function_composite
++} usbd_function_types_t;
++
++
++/*!
++ * USB Function Driver structures
++ *
++ * Descriptors:
++ * struct usbd_endpoint_description
++ * struct usbd_interface_description
++ * struct usbd_configuration_description
++ *
++ * Driver description:
++ * struct usbd_function_driver
++ * struct usbd_function_operations
++ *
++ */
++
++struct usbd_function_operations {
++
++ int (*function_enable) (struct usbd_function_instance *);
++ void (*function_disable) (struct usbd_function_instance *);
++
++ /*
++ * All of the following may be called from an interrupt context
++ */
++ void (*event_handler) (struct usbd_function_instance *, usbd_device_event_t, int);
++ int (*device_request) (struct usbd_function_instance *, struct usbd_device_request *);
++ int (*set_configuration) (struct usbd_function_instance *, int configuration);
++
++ int (*set_interface) (struct usbd_function_instance *, int interface, int altsetting);
++
++ void * (*get_descriptor)(struct usbd_function_instance *, int descriptor_type, int descriptor_index);
++ int * (*set_descriptor)(struct usbd_function_instance *, int descriptor_type, int descriptor_index, void *);
++
++ void (*endpoint_cleared)(struct usbd_function_instance*, int wIndex, int);
++
++};
++
++
++/*!
++ * function driver definitions
++ */
++struct usbd_alternate_instance {
++ struct usbd_interface_descriptor *interface_descriptor;
++ int classes;
++ struct usbd_generic_class_descriptor **class_list;
++ int endpoints;
++ struct usbd_endpoint_descriptor **endpoint_list;
++ u8 *endpoint_indexes;
++};
++
++
++/*!
++ * usb device description structures
++ */
++
++struct usbd_alternate_description {
++ struct usbd_interface_descriptor *interface_descriptor;
++ char *iInterface;
++
++ // list of CDC class descriptions for this alternate interface
++ u8 classes;
++ struct usbd_generic_class_descriptor **class_list;
++
++ // list of endpoint descriptions for this alternate interface
++ u8 endpoints;
++ struct usbd_endpoint_descriptor **endpoint_list;
++
++ // list of indexes into endpoint request map for each endpoint descriptor
++ u8 *endpoint_indexes;
++};
++
++typedef struct usbd_generic_class_descriptor usbd_class_descriptor_t;
++typedef struct usbd_endpoint_descriptor usbd_endpoint_descriptor_t;
++
++struct usbd_interface_description {
++ // list of alternate interface descriptions for this interface
++ u8 alternates;
++ struct usbd_alternate_description *alternate_list;
++};
++
++struct usbd_configuration_description {
++ struct usbd_configuration_descriptor *configuration_descriptor;
++ char *iConfiguration;
++ // list of interface descriptons for this configuration
++ //u8 bNumInterfaces;
++ //struct usbd_interface_description *interface_list;
++ int configuration_type;
++};
++
++struct usbd_device_description {
++ struct usbd_device_descriptor *device_descriptor;
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++ struct usbd_otg_descriptor *otg_descriptor;
++ u8 *iManufacturer;
++ u8 *iProduct;
++ u8 *iSerialNumber;
++ //u8 endpointsRequested;
++ //struct usbd_endpoint_request *requestedEndpoints;
++};
++
++
++struct usbd_interfaces_instance {
++ u8 alternates;
++ struct usbd_alternate_instance *alternates_instance_array;
++};
++
++struct usbd_configuration_instance {
++ int bNumInterfaces;
++ struct usbd_configuration_descriptor *configuration_descriptor;
++ struct usbd_interfaces_instance *interfaces_instance_array;
++ struct usbd_function_driver *function_driver;
++};
++
++
++/*! Function Driver data structure
++ *
++ * Function driver and its configuration descriptors.
++ *
++ * This is passed to the usb-device layer when registering. It contains all
++ * required information about the function driver for the usb-device layer
++ * to use the function drivers configuration data and to configure this
++ * function driver an active configuration.
++ *
++ * Note that each function driver registers itself on a speculative basis.
++ * Whether a function driver is actually configured will depend on the USB
++ * HOST selecting one of the function drivers configurations.
++ *
++ * This may be done multiple times WRT to either a single bus interface
++ * instance or WRT to multiple bus interface instances. In other words a
++ * multiple configurations may be selected for a specific bus interface. Or
++ * the same configuration may be selected for multiple bus interfaces.
++ *
++ */
++struct usbd_function_driver {
++ const char *name;
++ struct usbd_function_operations *fops; // functions
++
++ // device & configuration descriptions
++ struct usbd_device_description *device_description;
++ struct usbd_configuration_description *configuration_description;
++ int bNumConfigurations;
++
++ u16 idVendor;
++ u16 idProduct;
++ u16 bcdDevice;
++
++ u8 bNumInterfaces;
++ struct usbd_interface_description *interface_list;
++
++ u8 endpointsRequested;
++ struct usbd_endpoint_request *requestedEndpoints;
++
++ // constructed descriptors
++ struct usbd_device_descriptor *device_descriptor;
++#ifdef CONFIG_OTG_HIGH_SPEED
++ struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ struct usbd_otg_descriptor *otg_descriptor;
++ struct usbd_configuration_instance *configuration_instance_array;
++};
++
++/*! Function configuration structure
++ *
++ * This is allocated for each configured instance of a function driver.
++ *
++ * It stores pointers to the usbd_function_driver for the appropriate function,
++ * and pointers to the USB HOST requested usbd_configuration_description and
++ * usbd_interface_description.
++ *
++ * The privdata pointer may be used by the function driver to store private
++ * per instance state information.
++ *
++ * The endpoint map will contain a list of all endpoints for the configuration
++ * driver, and only related endpoints for an interface driver.
++ *
++ * The interface driver array will be NULL for an interface driver.
++ */
++struct usbd_function_instance {
++ char * name;
++ LIST_NODE instances; // linked list (was drivers in usbd_function_driver)
++ struct usbd_bus_instance *bus;
++ struct usbd_function_driver *function_driver;
++ void *privdata; // private data for the function
++
++ usbd_function_types_t function_type;
++
++ int configuration; // configuration driver only
++ int altsetting; // interface driver only
++
++ char **interfaces_list;
++
++ int interfaces;
++ struct usbd_function_instance **interfaces_array;
++
++ int endpoints;
++ struct usbd_endpoint_request *requestedEndpoints;
++ struct usbd_endpoint_map *endpoint_map_array;
++
++};
++
++
++struct usbd_function_instance;
++
++/*!
++ * @name Function Driver Registration
++ *
++ * Called by function drivers to register themselves when loaded
++ * or de-register when unloading.
++ * @{
++ */
++struct usbd_function_instance * usbd_register_function (struct usbd_function_driver *, char *, void *);
++struct usbd_function_instance * usbd_register_interface (struct usbd_function_driver *, char *, void *);
++struct usbd_function_instance * usbd_register_composite (struct usbd_function_driver *function_driver, char*, char **, void *);
++
++void usbd_deregister_function (struct usbd_function_instance *);
++struct usbd_function_instance *usbd_find_function (char *name);
++struct usbd_function_instance *usbd_find_interface(char *name);
++/*! @} */
++
++
++/*!
++ * @name String Descriptor database
++ *
++ * @{
++ */
++
++struct usbd_string_descriptor *usbd_get_string_descriptor (u8);
++u8 usbd_realloc_string (u8, char *);
++u8 usbd_alloc_string (char *);
++void usbd_free_string_descriptor(u8 );
++
++//extern struct usbd_string_descriptor **usb_strings;
++//void usbd_free_descriptor_strings (struct usbd_descriptor *);
++
++/*! @} */
++
++
++
++/*!
++ * @name Device Information
++ *
++ * @}
++ */
++int usbd_high_speed(struct usbd_function_instance *);
++int usbd_bmaxpower(struct usbd_function_instance *);
++int usbd_endpoint_wMaxPacketSize(struct usbd_function_instance *, int, int);
++int usbd_endpoint_zero_wMaxPacketSize(struct usbd_function_instance *, int);
++int usbd_endpoint_bEndpointAddress(struct usbd_function_instance *, int, int);
++int usbd_get_bMaxPower(struct usbd_function_instance *);
++/*! @} */
++
++
++/*!
++ * @name Device Control
++ *
++ * @}
++ */
++usbd_device_state_t usbd_get_device_state(struct usbd_function_instance *);
++usbd_device_status_t usbd_get_device_status(struct usbd_function_instance *);
++int usbd_framenum(struct usbd_function_instance *);
++u64 usbd_ticks(struct usbd_function_instance *);
++u64 usbd_elapsed(struct usbd_function_instance *, u64 *, u64 *);
++
++/*! @} */
++
++/*!
++ * @name Endpoint I/O
++ *
++ * @}
++ */
++
++struct usbd_urb *usbd_alloc_urb (struct usbd_function_instance *, int, int length, int (*callback) (struct usbd_urb *, int));
++struct usbd_urb *usbd_alloc_urb_ep0 (struct usbd_function_instance *, int length, int (*callback) (struct usbd_urb *, int));
++void usbd_free_urb (struct usbd_urb *urb);
++int usbd_start_in_urb (struct usbd_urb *urb);
++int usbd_start_out_urb (struct usbd_urb *);
++int usbd_cancel_urb(struct usbd_urb *);
++int usbd_halt_endpoint (struct usbd_function_instance *function, int endpoint_index);
++int usbd_endpoint_halted (struct usbd_function_instance *function, int endpoint);
++
++
++/*! @} */
++
++
++/*!
++ * @name endpoint information
++ *
++ * Used by function drivers to get specific endpoint information
++ * @{
++ */
++
++int usbd_endpoint_transferSize(struct usbd_function_instance *, int, int);
++int usbd_endpoint_interface(struct usbd_function_instance *, int);
++int usbd_interface_AltSetting(struct usbd_function_instance *, int);
++int usbd_ConfigurationValue(struct usbd_function_instance *);
++void usbd_endpoint_update(struct usbd_function_instance *, int , struct usbd_endpoint_descriptor *, int);
++/*! @} */
++
++//int usbd_remote_wakeup_enabled(struct usbd_function_instance *);
++
++/*!
++ * @name device information
++ *
++ * Used by function drivers to get device feature information
++ * @{
++ */
++int usbd_otg_bmattributes(struct usbd_function_instance *);
++/*! @} */
++
++/*!
++ * @name usbd_feature_enabled - return non-zero if specified feature has been enabled
++ * @{
++ */
++int usbd_feature_enabled(struct usbd_function_instance *function, int f);
++/*! @} */
++
++/* DEPRECATED */
++/*!
++ * @name Access to function privdata (DEPRECATED)
++ * @{
++ */
++void *usbd_function_get_privdata(struct usbd_function_instance *function);
++void usbd_function_set_privdata(struct usbd_function_instance *function, void *privdata);
++void usbd_flush_endpoint_index (struct usbd_function_instance *, int );
++int usbd_old_get_descriptor (struct usbd_function_instance *function, u8 *buffer, int max, int descriptor_type, int index);
++/*! @} */
++
+diff -uNr linux/drivers/no-otg/otg/usbp-pcd.h linux/drivers/otg/otg/usbp-pcd.h
+--- linux/drivers/no-otg/otg/usbp-pcd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otg/usbp-pcd.h 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,279 @@
++/*
++ * otg/otg/usbp-pcd.h - OTG Peripheral Controller Driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @file otg/otg/usbp-pcd.h
++ * @brief Peripheral Controller Driver Related Structures and Definitions.
++ *
++ * @ingroup USBP
++ */
++
++/*!
++ * The pcd_ops structure contains pointers to all of the functions implemented for the
++ * linked in driver. Having them in this structure allows us to easily determine what
++ * functions are available without resorting to ugly compile time macros or ifdefs
++ *
++ * There is only one instance of this, defined in the device specific lower layer.
++ */
++struct usbd_pcd_ops {
++
++ /* mandatory */
++ u8 bmAttributes;
++ int max_endpoints;
++ int ep0_packetsize;
++ u32 capabilities; /* UDC Capabilities - see usbd-bus.h for details */
++ u8 bMaxPower;
++ char *name;
++ u8 ports;
++
++
++ /* 3. called by ot_init() if defined */
++ int (* serial_init) (struct pcd_instance *); /* get device serial number if available */
++
++ /* 4. called from usbd_enable_function_irq() - REQUIRED */
++ int (*request_endpoints) /* process endpoint_request list and return endpoint_map */
++ (struct pcd_instance *,
++ struct usbd_endpoint_map *, /* showing allocated endpoints with attributes, addresses */
++ int, struct usbd_endpoint_request*); /* and other associated information */
++
++ /* 5. called from usbd_enable_function_irq() - REQUIRED */
++ int (*set_endpoints) /* setup required endpoints in hardware */
++ (struct pcd_instance *, int , struct usbd_endpoint_map *);
++
++ /* 6. called by xxx() if defined */
++ void (*enable) (struct pcd_instance *); /* enable the UDC */
++
++ /* 7. called by xxx() if defined */
++ void (*disable) (struct pcd_instance *); /* disable the UDC */
++
++ /* 8. called by xxx() if defined */
++ void (*start) (struct pcd_instance *); /* called for DEVICE_CREATE to start the UDC */
++ void (*stop) (struct pcd_instance *); /* called for DEVICE_DESTROY to stop the UDC */
++ void (*disable_ep)
++ (struct pcd_instance *,
++ unsigned int ep); /* called for DEVICE_DESTROTY to disable endpoint zero */
++
++ /* 9. called by xxx() if defined */
++ void (*set_address)
++ (struct pcd_instance *,
++ unsigned char address); /* called for DEVICE_RESET and DEVICE_ADDRESS_ASSIGNED to */
++
++
++ /* 10. called by xxx() if defined */
++ void (*setup_ep)
++ (struct pcd_instance *,
++ unsigned int ep, /* called for DEVICE_CONFIGURED to setup specified endpoint for use */
++ struct usbd_endpoint_instance *endpoint);
++
++ /* 11. called by xxx() if defined */
++ void (*reset_ep)
++ (struct pcd_instance *,
++ unsigned int ep); /* called for DEVICE_RESET to reset endpoint zero */
++
++
++ /* 12. called by usbd_send_urb() - REQUIRED */
++ void (*start_endpoint_in) /* start an IN urb */
++ (struct pcd_instance *,
++ struct usbd_endpoint_instance *);
++
++ /* 13. called by usbd_start_recv() - REQUIRED */
++ void (*start_endpoint_out) /* start an OUT urb */
++ (struct pcd_instance *,
++ struct usbd_endpoint_instance *);
++
++ /* 14. called by usbd_cancel_urb_irq() */
++ void (*cancel_in_irq)
++ (struct pcd_instance *,
++ struct usbd_urb *urb); /* cancel active urb for IN endpoint */
++ void (*cancel_out_irq)
++ (struct pcd_instance *,
++ struct usbd_urb *urb); /* cancel active urb for OUT endpoint */
++
++
++ /* 15. called from ep0_recv_setup() for GET_STATUS request */
++ int (*endpoint_halted)
++ (struct pcd_instance *,
++ struct usbd_endpoint_instance *); /* Return non-zero if requested endpoint is halted */
++ int (*halt_endpoint)
++ (struct pcd_instance *,
++ struct usbd_endpoint_instance *,
++ int); /* Return non-zero if requested endpoint clear fails */
++
++ /* 16 */
++ void (*startup_events) (struct pcd_instance *); /* perform UDC specific USB events */
++
++ /* 17. root hub operations
++ */
++ int (*hub_status) (struct pcd_instance *);
++ int (*port_status) (struct pcd_instance *, int);
++ int (*hub_feature) (struct pcd_instance *, int, int);
++ int (*port_feature) (struct pcd_instance *, int, int, int);
++ int (*get_ports_status) (struct pcd_instance *);
++ int (*wait_for_change) (struct pcd_instance *);
++};
++
++extern struct usbd_pcd_ops usbd_pcd_ops;
++
++
++/*! pcd_rcv_next_irq - get the current or next urb to receive into
++ * Called by UDC driver to get current receive urb or next available receive urb.
++ */
++static __inline__ struct usbd_urb * pcd_rcv_next_irq (struct usbd_endpoint_instance *endpoint)
++{
++ if (!endpoint->rcv_urb)
++ if ( (endpoint->rcv_urb = usbd_first_urb_detached_irq (&endpoint->rdy)))
++ endpoint->rcv_urb->status = RECV_IN_PROGRESS;
++
++ //TRACE_MSG1(PCD, "BUS_RCV_URB: %p", endpoint->rcv_urb);
++ return endpoint->rcv_urb;
++}
++
++
++/*! pcd_rcv_complete_irq - complete a receive operation
++ * Called by UDC driver to show completion of outstanding I/O, this will
++ * update the urb length and if necessary will finish the urb passing it to the
++ * bottom half which will in turn call the function driver callback.
++ */
++struct usbd_urb * pcd_rcv_complete_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad);
++struct usbd_urb * pcd_rcv_finished_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad);
++
++
++/*! pcd_rcv_cancelled_irq - cancel current receive urb
++ * Called by UDC driver to cancel the current receive urb.
++ */
++static __inline__ void pcd_rcv_cancelled_irq (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *rcv_urb;
++
++ TRACE_MSG1(PCD, "BUS_RCV CANCELLED: %p", (int) endpoint->rcv_urb);
++ RETURN_IF (! (rcv_urb = endpoint->rcv_urb));
++ //TRACE_MSG1(PCD, "rcv_urb: %p", (int)endpoint->rcv_urb);
++ usbd_urb_finished_irq (rcv_urb, RECV_CANCELLED);
++ endpoint->sent = endpoint->last = 0;
++ endpoint->rcv_urb = NULL;
++}
++
++
++/*! pcd_tx_next_irq - get the current or next urb to transmit
++ * Called by UDC driver to get current transmit urb or next available transmit urb.
++ */
++static __inline__ struct usbd_urb * pcd_tx_next_irq (struct usbd_endpoint_instance *endpoint)
++{
++ if (!endpoint->tx_urb)
++ if ( (endpoint->tx_urb = usbd_first_urb_detached_irq (&endpoint->tx))) {
++#if 0
++ int i;
++ u8 *cp = endpoint->tx_urb->buffer;
++
++ TRACE_MSG2(PCD, "NEXT TX: length: %d flags: %x",
++ endpoint->tx_urb->actual_length, endpoint->tx_urb->flags);
++
++ for (i = 0; i < endpoint->tx_urb->actual_length; i+= 8)
++
++ TRACE_MSG8(PCD, "SENT %02x %02x %02x %02x %02x %02x %02x %02x",
++ cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
++ cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
++ );
++#endif
++ endpoint->tx_urb->status = SEND_IN_PROGRESS;
++ }
++ //TRACE_MSG1(PCD, "BUS_TX NEXT TX_URB: %p", (int)endpoint->tx_urb);
++ return endpoint->tx_urb;
++}
++
++
++/*! pcd_tx_complete_irq - complete a transmit operation
++ * Called by UDC driver to show completion of an outstanding I/O, this will update the urb sent
++ * information and if necessary will finish the urb passing it to the bottom half which will in
++ * turn call the function driver callback.
++ */
++struct usbd_urb * pcd_tx_complete_irq (struct usbd_endpoint_instance *endpoint, int restart);
++
++
++/*! pcd_tx_cancelled_irq - finish pending tx_urb with SEND_CANCELLED
++ * Called by UDC driver to cancel the current transmit urb.
++ */
++static __inline__ void pcd_tx_cancelled_irq (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb;
++
++ TRACE_MSG1(PCD, "BUS_TX CANCELLED: %p", (int) endpoint->tx_urb);
++ RETURN_IF (! (tx_urb = endpoint->tx_urb));
++ usbd_urb_finished_irq (tx_urb, SEND_CANCELLED);
++ endpoint->sent = endpoint->last = 0;
++ endpoint->tx_urb = NULL;
++}
++
++
++/*! pcd_tx_sendzlp - test if we need to send a ZLP
++ * This has a side-effect of reseting the USBD_URB_SENDZLP flag.
++ */
++static __inline__ int pcd_tx_sendzlp (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *tx_urb = endpoint->tx_urb;
++ RETURN_FALSE_IF (!tx_urb || (tx_urb->actual_length < endpoint->sent) || ! (tx_urb->flags & USBD_URB_SENDZLP));
++ tx_urb->flags &= ~USBD_URB_SENDZLP;
++ return TRUE;
++}
++
++
++/*! pcd_rcv_complete_irq - complete a receive
++ * Called from rcv interrupt to complete.
++ */
++static __inline__ void pcd_rcv_fast_complete_irq (struct usbd_endpoint_instance *endpoint, struct usbd_urb *rcv_urb)
++{
++ //TRACE_MSG1(PCD, "BUS_RCV FAST COMPLETE: %d", rcv_urb->actual_length);
++ usbd_urb_finished_irq (rcv_urb, RECV_OK);
++}
++
++/*! pcd_recv_setup - process a device request
++ * Note that we verify if a receive urb has been queued for H2D with non-zero wLength
++ * and return -EINVAL to stall if the upper layers have not properly tested for and
++ * setup a receive urb in this case.
++ */
++static __inline__ int pcd_recv_setup_irq (struct pcd_instance *pcd, struct usbd_device_request *request)
++{
++ struct usbd_bus_instance *bus = pcd->bus;
++ struct usbd_endpoint_instance *endpoint = bus->endpoint_array + 0;
++ TRACE_SETUP (PCD, request);
++ RETURN_EINVAL_IF (usbd_device_request(bus, request)); // fail if already failed
++
++ //TRACE_MSG2(PCD, "BUS_RECV SETUP: RCV URB: %x TX_URB: %x", (int)endpoint->rcv_urb, (int)endpoint->tx_urb);
++ RETURN_ZERO_IF ( (request->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_DEVICE2HOST);
++ RETURN_ZERO_IF (!le16_to_cpu (request->wLength));
++ RETURN_EINVAL_IF (!endpoint->rcv_urb);
++ return 0;
++}
++
++/*! pcd_recv_setup_emulate_irq - emulate a device request
++ * Called by the UDC driver to inject a SETUP request. This is typically used
++ * by drivers for UDC's that do not pass all SETUP requests to us but instead give us
++ * a configuration change interrupt.
++ */
++int pcd_recv_setup_emulate_irq(struct usbd_bus_instance *, u8, u8, u16, u16, u16);
++
++/*! pcd_ep0_reset_irq - reset ep0 endpoint
++ */
++static void __inline__ pcd_ep0_reset_endpoint_irq (struct usbd_endpoint_instance *endpoint)
++{
++ TRACE_MSG0(PCD, "BUS_EP0 RESET");
++ pcd_tx_cancelled_irq (endpoint);
++ pcd_rcv_cancelled_irq (endpoint);
++ endpoint->sent = endpoint->last = 0;
++}
++
++/*! pcd_check_device_feature - verify that feature is set or clear
++ * Check current feature setting and emulate SETUP Request to set or clear
++ * if required.
++ */
++void pcd_check_device_feature(struct usbd_bus_instance *, int , int );
++
+diff -uNr linux/drivers/no-otg/otgcore/Makefile linux/drivers/otg/otgcore/Makefile
+--- linux/drivers/no-otg/otgcore/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/Makefile 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,107 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++TOPDIR ?= ../../../..
++
++subdir-y :=
++subdir-m :=
++subdir-n :=
++subdir- :=
++
++
++# The target object and module list name.
++
++O_TARGET := otgcore_target.o
++
++# Objects that export symbols.
++
++export-objs := core-init-l24.o otg.o otg-trace.o otg-mesg.o usbp-bops.o usbp-fops.o otg-mesg-l24.o
++
++# Multipart objects. (core layer)
++
++list-multi := otgtrace.o otgcore.o otgadmin.o
++
++otgcore-objs := core-init-l24.o otg.o \
++ otg-trace.o otg-trace-l24.o \
++ otg-mesg.o otg-mesg-l24.o \
++ otg-fw.o \
++ usbp-fops.o usbp-bops.o
++
++
++usbprocfs-objs := usbp-procfs.o
++
++
++ifeq ("$(CONFIG_OTG_FW_MN)", "y")
++otgcore-objs += otg-fw-mn.o
++else
++otgcore-objs += otg-fw-df.o
++endif
++
++
++# Optional parts of multipart objects.
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_OTG) += otgcore.o
++obj-$(CONFIG_OTG_PROCFSM) += usbprocfs.o
++
++
++# Object files in subdirectories
++
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++include $(TOPDIR)/Rules.make
++OTG=$(TOPDIR)/drivers/otg
++#USBDCORE_DIR=$(OTG)/usbdcore
++OTGCORE_DIR=$(OTG)/otgcore
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG)
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG)
++
++vpath %.c $(OTGCORE_DIR)
++
++# Link rules for multi-part drivers.
++
++otgadmin.o: $(otgadmin-objs)
++ $(LD) -r -o $@ $(otgadmin-objs)
++
++otgcore.o: $(otgcore-objs)
++ $(LD) -r -o $@ $(otgcore-objs)
++
++otgtrace.o: $(otgtrace-objs)
++ $(LD) -r -o $@ $(otgtrace-objs)
++
++usbprocfs.o: $(usbprocfs-objs)
++ $(LD) -r -o $@ $(usbprocfs-objs)
++
+diff -uNr linux/drivers/no-otg/otgcore/Makefile-l26 linux/drivers/otg/otgcore/Makefile-l26
+--- linux/drivers/no-otg/otgcore/Makefile-l26 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/Makefile-l26 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,24 @@
++#
++# Belcarra OTG - On-The-Go
++#
++# Copyright (c) 2004 Belcarra Technologies Corp
++
++OTG=$(TOPDIR)/drivers/otg
++EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG)
++EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG)
++
++#otgadmin-objs := admin-init-l24.o otg-admin.o otg-decode.o
++#obj-$(CONFIG_OTG) += otgadmin.o
++
++otgcore-objs := core-init-l24.o otg.o \
++ otg-trace.o otg-trace-l24.o \
++ otg-mesg.o otg-mesg-l24.o \
++ otg-fw.o \
++ usbp-bops.o \
++ usbp-fops.o \
++
++obj-$(CONFIG_OTG) += otgcore.o
++
++#otgtrace-objs := otg-trace.o
++#obj-$(CONFIG_OTG_TRACE) += otgtrace.o
++
+diff -uNr linux/drivers/no-otg/otgcore/TODO-USBP.txt linux/drivers/otg/otgcore/TODO-USBP.txt
+--- linux/drivers/no-otg/otgcore/TODO-USBP.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/TODO-USBP.txt 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,51 @@
++USBD Core Architecture ToDo Stuart Lynne
++Belcarra Fri Aug 13 14:37:13 PDT 2004
++
++
++The following need to be addressed to support ongoing development and support
++for the USB Device core and functions.
++
++
++Specifically:
++ - finish acm, make CDC compliant, support all possible operations
++ - enhance network, add NDIS support,
++ - wmc - implement wmc
++ - obex
++ - mass storage
++
++
++These require:
++
++ - enhancements to allow building composite functions
++ - common routines for handling CDC class requirements
++
++
++1. interface list
++
++ - currently we have an endpoint list that allows each endpoint to be
++ mapped to a function
++
++ - we need to do the same for interfaces, allow each interface to be
++ owned by a function, this will allow ep0 to multiplex per
++ interface standard requests to the proper function driver
++
++
++2. common functions
++
++ - a common send_interrupt_urb function
++
++ int usbd_send_interrupt(struct usbd_function_instance *,
++ int, void *, int, int (*callback) (struct usbd_urb *, int));
++
++
++ - this creates an interrupt urb on the required endpoint, copies the
++ data in, and starts it with the appropriate callback etc.
++
++
++ - notification
++
++ usbd_network_notfication
++ usbd_response_available
++ usbd_serial_state
++
++
+diff -uNr linux/drivers/no-otg/otgcore/core-init-l24.c linux/drivers/otg/otgcore/core-init-l24.c
+--- linux/drivers/no-otg/otgcore/core-init-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/core-init-l24.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,173 @@
++/*
++ * otg/otg/core-init-l24.c - OTG Peripheral Controller Driver Module Initialization
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcara.com>,
++ * Tom Rushworth <tbr@belcara.com>,
++ * Bruce Balden <balden@belcara.com>
++ *
++ * This is the linux 2.4 version.
++ *
++ */
++/*!
++ * @file otg/otgcore/core-init-l24.c
++ * @brief OTG Core Linux initialization.
++ *
++ * This file is the starting point for defining the Linux OTG Core
++ * driver. It references and starts all of the other components that
++ * must be "linked" into the OTGCORE mdoule.
++ *
++ * @ingroup OTGCore
++ */
++
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++EMBED_LICENSE(); // When supported by the OS, embed license information in the binary
++
++
++#ifdef OTG_MALLOC_TEST
++int otg_mallocs;
++#endif /* OTG_MALLOC_TEST */
++
++otg_tag_t CORE;
++
++#ifdef CONFIG_OTG_FW_MN
++struct otg_firmware *otg_firmware_loaded = &otg_firmware_mn;
++struct otg_firmware *otg_firmware_orig = &otg_firmware_mn;
++#else /* CONFIG_OTG_FW_MN */
++struct otg_firmware *otg_firmware_loaded = &otg_firmware_df;
++struct otg_firmware *otg_firmware_orig = &otg_firmware_df;
++#endif /* CONFIG_OTG_FW_MN */
++
++struct otg_firmware *otg_firmware_loading;
++
++
++struct otg_instance otg_instance_private;
++
++struct hcd_instance hcd_instance_private = { otg: &otg_instance_private, };
++struct ocd_instance ocd_instance_private = { otg: &otg_instance_private, };
++struct pcd_instance pcd_instance_private = { otg: &otg_instance_private, };
++struct tcd_instance tcd_instance_private = { otg: &otg_instance_private, };
++
++struct otg_instance otg_instance_private = {
++ hcd: &hcd_instance_private,
++ ocd: &ocd_instance_private,
++ pcd: &pcd_instance_private,
++ tcd: &tcd_instance_private,
++};
++
++struct otg_instance *otg_instance = &otg_instance_private;
++
++char * otg_get_state_name(int state)
++{
++ struct otg_state *otg_state;
++ if (!otg_firmware_loaded || (state >= otg_firmware_loaded->number_of_states))
++ return "UNKNOWN_STATE";
++
++ otg_state = otg_firmware_loaded->otg_states + state;
++ return otg_state->name;
++}
++
++
++/* ************************************************************************************* */
++
++
++/* otg_modinit - linux module initialization
++ */
++static int otg_modinit (void)
++{
++ int message_init = 0;
++ int message_init_l24 = 0;
++ int trace_init = 0;
++ int trace_init_l24 = 0;
++
++
++ printk(KERN_INFO"%s: \n", __FUNCTION__);
++
++ trace_init = otg_trace_init();
++ trace_init_l24 = otg_trace_init_l24();
++
++ CORE = otg_trace_obtain_tag();
++
++ TRACE_MSG0(CORE,"--");
++ otg_instance->current_outputs = otg_firmware_loaded->otg_states;
++ otg_instance->previous_outputs = otg_firmware_loaded->otg_states;
++
++ /* initialize otg-mesg and usbp
++ */
++ THROW_IF((message_init = otg_message_init(otg_instance)), error);
++ THROW_IF((message_init_l24 = otg_message_init_l24(otg_instance)), error);
++ THROW_IF(usbd_device_init(), error);
++
++ otg_set_ocd_ops(NULL);
++ otg_set_tcd_ops(NULL);
++ otg_set_hcd_ops(NULL);
++ otg_set_pcd_ops(NULL);
++
++ CATCH(error) {
++ CORE = otg_trace_invalidate_tag(CORE);
++ if (trace_init_l24 )otg_trace_exit_l24();
++ if (trace_init) otg_trace_exit();
++ if (message_init_l24 )otg_message_exit_l24();
++ if (message_init) otg_message_exit();
++ return -EINVAL;
++ }
++ return 0;
++}
++module_init (otg_modinit);
++
++
++#if OTG_EPILOGUE /* Set nonzero in <otg-module.h> when -DMODULE is in force */
++/* otg_modexit - This is *only* used for drivers compiled and used as a module.
++ */
++static void otg_modexit (void)
++{
++ printk(KERN_INFO"%s: \n", __FUNCTION__);
++
++ usbd_device_exit();
++ otg_message_exit_l24();
++
++ CORE = otg_trace_invalidate_tag(CORE);
++ otg_trace_exit();
++
++ if (otg_firmware_loading) {
++ lkfree(otg_firmware_loading->otg_states);
++ lkfree(otg_firmware_loading->otg_tests);
++ lkfree(otg_firmware_loading);
++ }
++ if (otg_firmware_loaded && (otg_firmware_loaded != otg_firmware_orig)) {
++ lkfree(otg_firmware_loaded->otg_states);
++ lkfree(otg_firmware_loaded->otg_tests);
++ lkfree(otg_firmware_loaded);
++ }
++}
++#endif
++
++#if defined (CONFIG_OTG_USBD_PM)
++int usbd_load(char * arg) { return 0; }
++int usbd_unload(char *arg) { return 0; }
++OTG_EXPORT_SYMBOL(usbd_load);
++OTG_EXPORT_SYMBOL(usbd_unload);
++#endif
++
++MOD_EXIT(otg_modexit);
++OTG_EXPORT_SYMBOL(otg_get_state_name);
++
++#ifdef OTG_MALLOC_TEST
++OTG_EXPORT_SYMBOL(otg_mallocs);
++#endif /* OTG_MALLOC_TEST */
++
+diff -uNr linux/drivers/no-otg/otgcore/hub.c linux/drivers/otg/otgcore/hub.c
+--- linux/drivers/no-otg/otgcore/hub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/hub.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,607 @@
++/*
++ * otg/otgcore/hub.c
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ * This is a root hub function.
++ *
++ */
++/*!
++ * @file otg/otgcore/hub.c
++ * @brief A simple hub function driver.
++ *
++ *
++ * @ingroup USBDCore
++ */
++#include <otg/otg-compat.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++#ifdef CONFIG_OTG_ROOT_HUB
++/*
++ * Root Hub Configuration
++ *
++ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
++ * Data Interface Alternate description(s)
++ * Interface description(s)
++ * Configuration description(s)
++ * Device Description
++ */
++
++#define BULK_INT 0x00
++#define ENDPOINTS 0x01
++
++#if 0
++
++Configuration descriptor [1 ] 09 02 19 00 01 01 02 00 00
++ 09 02 19 00 01 01 00 40 00
++
++Interface descriptor [1:1:0 ] 09 04 00 00 01 09 00 00 03
++Endpoint descriptor [1:1:0:1] 07 05 81 03 10 00 ff
++
++#endif
++
++#if defined(OTG_WINCE)
++
++static struct hub_descriptor rh_hub_descriptor;
++struct usbd_endpoint_descriptor rh_data;
++
++static struct usbd_endpoint_descriptor *rh_default[] = { &rh_data, };
++u8 rh_indexes[] = { BULK_INT, };
++
++static struct usbd_interface_descriptor rh_data_alternate_descriptor;
++static struct usbd_alternate_description rh_data_alternate_descriptions[1];
++};
++
++static struct usbd_interface_description rh_interfaces[1];
++
++struct usbd_configuration_descriptor rh_configuration_descriptor;
++
++struct usbd_configuration_description rh_description[1];
++
++static struct usbd_device_descriptor rh_device_descriptor;
++#ifdef CONFIG_OTG_HIGH_SPEED
++static struct usbd_device_qualifier_descriptor rh_device_qualifier_descriptor;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++static struct usbd_endpoint_request rh_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++static struct usbd_otg_descriptor rh_otg_descriptor;
++
++struct usbd_device_description rh_device_description;
++
++void hub_global_init(void)
++{
++ ZERO(rh_hub_descriptor);
++ rh_hub_descriptor.bDescLength = 0x09;
++ rh_hub_descriptor.bDescriptorType = USB_DT_HUB;
++ rh_hub_descriptor.bNbrPorts = 0x00;
++ rh_hub_descriptor.wHubCharacteristics = HUB_GANGED_POWER | HUB_GLOBAL_OVERCURRENT;
++ rh_hub_descriptor.bPwrOn2PwrGood = 0x01;
++ rh_hub_descriptor.bHubContrCurrent = 0x01;
++ rh_hub_descriptor.DeviceRemovable = 0x00;
++ rh_hub_descriptor.PortPwrCtrlMask = 0xff;
++
++ ZERO(rh_data);
++ rh_data.bLength: 0x07;
++ rh_data.bDescriptorType = USB_DT_ENDPOINT;
++ rh_data.bEndpointAddress = USB_DIR_IN;
++ rh_data.bmAttributes = INTERRUPT;
++ rh_data.wMaxPacketSize = __constant_cpu_to_le16(0x4);
++ rh_data.bInterval: 0xff;
++
++ ZERO(rh_data_alternate_desriptor);
++ rh_data_alternate_descriptor.bLength = 0x09;
++ rh_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
++ rh_data_alternate_descriptor.bNumEndpoints = 0x01;
++ rh_data_alternate_descriptor.bInterfaceClass = USB_CLASS_HUB;
++
++ ZERO(rh_data_alternate_descriptions);
++ rh_data_alternate_descriptors[0].iInterface =Root hub - Status";
++ rh_data_alternate_descriptors[0].interface_descriptor = &rh_data_alternate_descriptor;
++ rh_data_alternate_descriptors[0].endpoints = sizeof (rh_default) / sizeof(struct usbd_endpoint_descriptor *);
++ rh_data_alternate_descriptors[0].endpoint_list = rh_default;
++ rh_data_alternate_descriptors[0].endpoint_indexes = rh_indexes;
++
++ ZERO(rh_interfaces);
++
++ rh_interfaces[0].alternates = sizeof (rh_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
++ rh_interfaces[0].alternate_list = rh_data_alternate_descriptions;
++
++
++ ZERO(rh_configuration_descriptor);
++ rh_configuration_descriptor.bLength = 0x09;
++ rh_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
++ rh_configuration_descriptor.bNumInterfaces = sizeof (rh_interfaces) / sizeof (struct usbd_interface_description);
++ rh_configuration_descriptor.bConfigurationValue = 0x01;
++
++
++ ZERO(rh_description);
++ rh_description[0].configuration_descriptor = &rh_configuration_descriptor;
++ rh_description[0].iConfiguration = Root Hub";
++ rh_description[0].bNumInterfaces = sizeof (rh_interfaces) / sizeof (struct usbd_interface_description);
++ rh_description[0].interface_list = rh_interfaces;
++
++ ZERO(rh_device_descriptor);
++
++ rh_device_descriptor.bLength = sizeof(struct usbd_device_descriptor);
++ rh_device_descriptor.bDescriptorType = USB_DT_DEVICE;
++ rh_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
++ rh_device_descriptor.bDeviceClass = USB_CLASS_HUB;
++
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++ ZERO(rh_device_qualifier_descriptor);
++ rh_device_qualifier_descriptor.bLength = sizeof(struct usbd_device_qualifier_descriptor);
++ rh_device_qualifier_descriptor.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
++ rh_device_qualifier_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
++ rh_device_qualifier_descriptor.bDeviceClass = USB_CLASS_HUB;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++ ZERO(rh_otg_descriptor);
++ rh_otg_descriptor.bLength = sizeof(struct usbd_otg_descriptor);
++ rh_otg_descriptor.bDescriptorType = USB_DT_OTG;
++ rh_otg_descriptor.bmAttributes = 0;
++
++
++ ZERO(rh_device_description);
++ rh_device_description.device_descriptor = &rh_device_descriptor;
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ rh_device_description.device_qualifier_descriptor = &rh_device_qualifier_descriptor;
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++ rh_device_description.otg_descriptor = &rh_otg_descriptor;
++ rh_device_description.iManufacturer = "";
++ rh_device_description.iProduct = "root hub";
++ rh_device_description.endpointsRequested = ENDPOINTS;
++ rh_device_description.requestedEndpoints = rh_endpoint_requests;
++
++}
++#else /* defined(OTG_WINCE) */
++
++static struct hub_descriptor rh_hub_descriptor = {
++ bDescLength: 0x09,
++ bDescriptorType: USB_DT_HUB,
++ bNbrPorts: 0x00,
++ wHubCharacteristics: HUB_GANGED_POWER | HUB_GLOBAL_OVERCURRENT,
++ bPwrOn2PwrGood: 0x01,
++ bHubContrCurrent: 0x01,
++ DeviceRemovable: 0x00,
++ PortPwrCtrlMask: 0xff,
++};
++
++struct usbd_endpoint_descriptor rh_data = {
++ bLength: 0x07,
++ bDescriptorType: USB_DT_ENDPOINT,
++ bEndpointAddress: USB_DIR_IN,
++ bmAttributes: INTERRUPT,
++ wMaxPacketSize: __constant_cpu_to_le16(0x4),
++ bInterval: 0xff,
++};
++
++static struct usbd_endpoint_descriptor *rh_default[] = { &rh_data, };
++u8 rh_indexes[] = { BULK_INT, };
++
++static struct usbd_interface_descriptor rh_data_alternate_descriptor = {
++ bLength: 0x09,
++ bDescriptorType: USB_DT_INTERFACE,
++ bNumEndpoints: 0x01,
++ bInterfaceClass: USB_CLASS_HUB,
++};
++
++static struct usbd_alternate_description rh_data_alternate_descriptions[] = {
++ { iInterface:"Root hub - Status",
++ interface_descriptor: &rh_data_alternate_descriptor,
++ endpoints:sizeof (rh_default) / sizeof(struct usbd_endpoint_descriptor *),
++ endpoint_list: rh_default,
++ endpoint_indexes: rh_indexes,
++ },
++};
++
++static struct usbd_interface_description rh_interfaces[] = {
++ { alternates:sizeof (rh_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
++ alternate_list:rh_data_alternate_descriptions,},
++};
++
++
++struct usbd_configuration_descriptor rh_configuration_descriptor = {
++ bLength: 0x09,
++ bDescriptorType: USB_DT_CONFIGURATION,
++ bNumInterfaces: sizeof (rh_interfaces) / sizeof (struct usbd_interface_description),
++ bConfigurationValue: 0x01,
++};
++
++struct usbd_configuration_description rh_description[] = {
++ { configuration_descriptor: &rh_configuration_descriptor,
++ iConfiguration:"Root Hub",
++ bNumInterfaces:sizeof (rh_interfaces) / sizeof (struct usbd_interface_description),
++ interface_list:rh_interfaces,},
++};
++
++static struct usbd_device_descriptor rh_device_descriptor = {
++ bLength: sizeof(struct usbd_device_descriptor),
++ bDescriptorType: USB_DT_DEVICE,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: USB_CLASS_HUB,
++};
++
++#ifdef CONFIG_OTG_HIGH_SPEED
++static struct usbd_device_qualifier_descriptor rh_device_qualifier_descriptor = {
++ bLength: sizeof(struct usbd_device_qualifier_descriptor),
++ bDescriptorType: USB_DT_DEVICE_QUALIFIER,
++ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
++ bDeviceClass: USB_CLASS_HUB,
++};
++#endif /* CONFIG_OTG_HIGH_SPEED */
++
++static struct usbd_endpoint_request rh_endpoint_requests[ENDPOINTS+1] = {
++ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
++ { 0, },
++};
++
++static struct usbd_otg_descriptor rh_otg_descriptor = {
++ bLength : sizeof(struct usbd_otg_descriptor),
++ bDescriptorType: USB_DT_OTG,
++ bmAttributes: 0,
++};
++
++struct usbd_device_description rh_device_description = {
++ device_descriptor: &rh_device_descriptor,
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ device_qualifier_descriptor: &rh_device_qualifier_descriptor,
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++ otg_descriptor: &rh_otg_descriptor,
++ iManufacturer: "",
++ iProduct: "root hub",
++ endpointsRequested: ENDPOINTS,
++ requestedEndpoints: rh_endpoint_requests,
++};
++#endif /* defined(OTG_WINCE) */
++
++/* root hub Private variables ******************************************************************** */
++
++struct rh_private {
++ struct usbd_function_instance *function;
++ int usb_driver_registered; // non-zero if usb function registered
++ unsigned char connected; // non-zero if connected to host (configured)
++ u8 ports;
++ u8 hub_features;
++ u32 *port_features;
++ u32 ports_status;
++ struct WORK_STRUCT bh;
++};
++
++struct rh_private rh_private;
++
++/* Transmit Function *************************************************************************** */
++
++void rh_task(void *data)
++{
++
++ //struct rh_private *rh = (struct rh_private *)data;
++ //struct usbd_function_instance *function = rh->function;
++ //struct usbd_bus_instance *bus = function->bus;
++
++ printk(KERN_INFO"%s: start\n", __FUNCTION__);
++#if 0
++ wait_queue_head_t rh_wait_queue;
++ init_waitqueue_head(&rh_wait_queue);
++
++ while (rh->bh.data && rh->connected) {
++ u32 ports_status = cpu_to_le32(bus->driver->bops->get_ports_status(bus));
++
++ printk(KERN_INFO"%s: status: %08x\n", __FUNCTION__, ports_status);
++
++ if (rh->ports_status != ports_status) {
++ struct usbd_urb *urb = usbd_alloc_urb (function, BULK_INT, 4, NULL);
++ BREAK_UNLESS(urb);
++ memcpy(urb->buffer, &ports_status, 4);
++ urb->actual_length = 4;
++ if (usbd_send_urb(urb)) {
++ printk(KERN_INFO"%s: usbd_send_urb failed\n", __FUNCTION__);
++ usbd_dealloc_urb (urb);
++ }
++ }
++ rh->ports_status = ports_status;
++ interruptible_sleep_on_timeout(&rh_wait_queue, 10000);
++ }
++#endif
++ printk(KERN_INFO"%s: exiting\n", __FUNCTION__);
++}
++
++/* USB Device Functions ************************************************************************ */
++
++/* rh_event_irq - process a device event
++ */
++void rh_event_irq (struct usbd_function_instance *function, usbd_device_event_t event, int data)
++{
++ struct rh_private *rh = &rh_private;
++
++ switch (event) {
++ case DEVICE_CONFIGURED:
++ rh->connected = 1;
++
++ SET_WORK_ARG(rh->bh, &rh_private);
++// rh->bh.data = &rh_private;
++ SCHEDULE_WORK(rh_private.bh);
++// schedule_task(&rh_private.bh);
++ break;
++
++ case DEVICE_RESET:
++ case DEVICE_DE_CONFIGURED:
++ BREAK_UNLESS(rh->connected);
++ rh->connected = 0;
++ rh->bh.data = 0;
++ break;
++ default:
++ break;
++ }
++}
++
++/* copy_config
++ * @urb: pointer to urb
++ * @data: pointer to configuration data
++ * @length: length of data
++ *
++ * Copy configuration data to urb transfer buffer if there is room for it.
++ */
++static int copy_report (struct usbd_urb *urb, void *data, int size, int max_buf)
++{
++ int available;
++ int length = size;
++
++ //printk(KERN_INFO"%s: data: %p size: %d max: %d\n", __FUNCTION__, data, size, max_buf);
++ RETURN_EINVAL_UNLESS (urb);
++ RETURN_EINVAL_UNLESS (data);
++ RETURN_EINVAL_UNLESS (size);
++
++ RETURN_EINVAL_IF ((available = max_buf - urb->actual_length) <= 0);
++
++ //printk(KERN_INFO"%s: length: %d available: %d\n", __FUNCTION__, length, available);
++
++ length = (length < available) ? length : available;
++ memcpy (urb->buffer + urb->actual_length, data, length);
++ urb->actual_length += length;
++ return 0;
++}
++
++/* rh_recv_setup_irq - called to indicate urb has been received
++ */
++int rh_recv_setup_irq (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ u8 bRequest = request->bRequest;
++ u8 bmRequestType = request->bmRequestType;
++ u16 wValue = le16_to_cpu(request->wValue);
++ u16 wIndex = le16_to_cpu(request->wIndex);
++ u16 wLength = le16_to_cpu(request->wLength);
++
++ u8 direction = bmRequestType & USB_REQ_DIRECTION_MASK;
++ u8 recipient = bmRequestType & USB_REQ_RECIPIENT_MASK;
++
++ //printk(KERN_INFO"%s:\n", __FUNCTION__);
++ /* verify that this is a class request
++ */
++ RETURN_EINVAL_UNLESS((request->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS);
++
++ //printk(KERN_INFO"%s: valid direction: %x recipient: %x bRequest: %02x\n",
++ // __FUNCTION__, direction, recipient, bRequest);
++
++ if (USB_REQ_HOST2DEVICE == direction) {
++
++ //printk(KERN_INFO"%s: H2D\n", __FUNCTION__);
++
++ /* these do not require a reply
++ */
++ int setclear_flag = USB_REQ_SET_FEATURE == bRequest;
++ switch (recipient) {
++ case USB_RECIP_HUB:
++ switch (request->bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_FEATURE:
++ bus->driver->bops->hub_feature(bus, wValue, setclear_flag);
++ }
++ return 0;
++ case USB_RECIP_PORT:
++ switch (request->bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_FEATURE:
++ bus->driver->bops->port_feature(bus, wValue, wIndex, setclear_flag);
++#if 0
++ case USB_REQ_CLEAR_TT_BUFFER:
++ case USB_REQ_RESET_TT:
++ case USB_REQ_STOP_TT:
++#endif
++ }
++ return 0;
++ }
++ }
++ else {
++ //printk(KERN_INFO"%s: D2H\n", __FUNCTION__);
++
++ /* these do require a reply
++ */
++ struct usbd_urb *urb;
++ int rc = 0;
++ u32 status;
++
++ RETURN_EINVAL_UNLESS(wLength);
++ RETURN_EINVAL_UNLESS((urb = usbd_alloc_urb_ep0(function, wLength, NULL)));
++
++ switch (recipient) {
++ case USB_RECIP_HUB:
++ //printk(KERN_INFO"%s: HUB\n", __FUNCTION__);
++ switch (request->bRequest) {
++ case USB_REQ_GET_DESCRIPTOR:
++ BREAK_UNLESS (copy_report(urb, (void *)&rh_hub_descriptor, sizeof(rh_hub_descriptor), wLength));
++ rc = -EINVAL;
++ break;
++
++ case USB_REQ_GET_STATUS:
++ status = cpu_to_le16(bus->driver->bops->hub_status(bus));
++ urb->actual_length = 4;
++ memcpy(urb->buffer, &status, 4);
++ break;
++ }
++ break;
++ case USB_RECIP_PORT:
++ //printk(KERN_INFO"%s: PORT\n", __FUNCTION__);
++ switch (request->bRequest) {
++ case USB_REQ_GET_STATUS:
++ status = cpu_to_le16(bus->driver->bops->port_status(bus, wIndex));
++ urb->actual_length = 4;
++ memcpy(urb->buffer, &status, 4);
++ break;
++#if 0
++ case USB_REQ_GET_TT_STATE:
++#endif
++ }
++ break;
++ default:
++ rc = -EINVAL;
++ }
++ UNLESS (rc)
++ RETURN_ZERO_IF(!usbd_send_urb(urb));
++ /* error */
++ usbd_dealloc_urb(urb);
++ }
++ return -EINVAL;
++}
++
++
++static int rh_function_enable (struct usbd_function_instance *function)
++{
++ struct rh_private *rh = &rh_private;
++ struct usbd_bus_instance *bus = function->bus;
++ int ports;
++
++ printk (KERN_INFO "%s:\n", __FUNCTION__);
++
++ if (rh->port_features)
++ lkfree(rh->port_features);
++
++ rh->ports = ports = bus->driver->ports;
++ rh->port_features = ckmalloc(4 * ports, GFP_KERNEL);
++ rh_private.bh.data = &rh_private;
++
++ rh_hub_descriptor.bNbrPorts = ports;
++
++ printk (KERN_INFO "%s: ports: %d\n", __FUNCTION__, ports);
++
++ //schedule_task(&rh_private.bh);
++
++ printk (KERN_INFO "%s: finished\n", __FUNCTION__);
++
++ return 0;
++}
++
++static void rh_function_disable (struct usbd_function_instance *function)
++{
++ struct rh_private *rh = &rh_private;
++ printk (KERN_INFO "%s:\n", __FUNCTION__);
++ if (rh->port_features)
++ lkfree(rh->port_features);
++ printk (KERN_INFO "%s: finished\n", __FUNCTION__);
++}
++
++#if defined(OTG_WINCE)
++
++struct otg_instance otg_instance_private;
++
++void hub_ops_init(void)
++{
++ ZERO(otg_instance_private);
++ otg_instance_private.hcd = &hcd_instance_privatej
++}
++
++#else /* defined(OTG_WINCE) */
++
++static struct usbd_function_operations function_ops = {
++ event_irq: rh_event_irq,
++ recv_setup_irq: rh_recv_setup_irq,
++ function_enable: rh_function_enable,
++ function_disable: rh_function_disable,
++};
++
++static struct usbd_function_driver function_driver = {
++ name:"root hub",
++ fops:&function_ops,
++ device_description:&rh_device_description,
++ bNumConfigurations:sizeof (rh_description) / sizeof (struct usbd_configuration_description),
++ configuration_description:rh_description,
++ idVendor: __constant_cpu_to_le16(0x15ec),
++ idProduct: __constant_cpu_to_le16(0xf010),
++ bcdDevice: __constant_cpu_to_le16(0x000),
++};
++#endif /* defined(OTG_WINCE) */
++
++/* USB Module init/exit ************************************************************************ */
++#if defined(OTG_WINCE)
++
++
++#else /* defined(OTG_WINCE) */
++
++
++/*
++ * rh_modinit - module init
++ */
++int rh_init (void)
++{
++ printk (KERN_INFO "%s:\n", __FUNCTION__);
++
++ THROW_IF (usbd_register_function (&function_driver), error);
++
++ printk (KERN_INFO "%s: registered\n", __FUNCTION__);
++
++ rh_private.usb_driver_registered++;
++
++// rh_private.bh.sync = 0;
++// rh_private.bh.routine = rh_task;
++ PREPARE_WORK_ITEM(rh_private.bh,rh_task,NULL);
++
++ CATCH(error) {
++ if (rh_private.usb_driver_registered) {
++ usbd_deregister_function (&function_driver);
++ rh_private.usb_driver_registered = 0;
++ }
++ return -EINVAL;
++ }
++ printk (KERN_INFO "%s: finished\n", __FUNCTION__);
++ return 0;
++}
++
++/* rh_modexit - module cleanup
++ */
++void rh_exit (void)
++{
++ //while (rh_private.bh.sync)
++ while (PENDING_WORK_ITEM(rh_private.bh))
++ schedule_timeout(HZ);
++
++ //rh_private.bh.data = 0;
++ SET_WORK_ARG(rh_private.bh,0);
++ while (PENDING_WORK_ITEM(rh_private.bh))
++ schedule_timeout(HZ);
++
++ if (rh_private.usb_driver_registered)
++ usbd_deregister_function (&function_driver);
++}
++#endif /* defined(OTG_WINCE) */
++#endif /* CONFIG_OTG_ROOT_HUB */
++
+diff -uNr linux/drivers/no-otg/otgcore/otg-fw-df.c linux/drivers/otg/otgcore/otg-fw-df.c
+--- linux/drivers/no-otg/otgcore/otg-fw-df.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-fw-df.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,121 @@
++
++/* Generated by otg-tests-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++
++/*!
++* @file otg/otgcore/otg-fw-df.c
++* @brief OTG Firmware - Firmware for df
++*
++* This file defines the OTG State Machine tests.
++*
++*
++* @ingroup OTGFW
++*/
++
++/*!
++* @page OTGFW
++* @section OTGFW - otg-fw-df.c
++* This contains the input, output and timout definitions for the OTG state machine firmware
++*/
++
++
++#ifdef OTG_APPLICATION
++#define NULL 0
++#include "otg-fw.h"
++#include "otg-fw-df.h"
++#else /* OTG_APPLICATION/ */
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++//#include <otg/otg-api.h>
++#include <otg/otg-fw.h>
++#include <otg/otg-fw-df.h>
++#endif /* OTG_APPLICATION */
++
++char otg_fw_name_df[] = "otg_df";
++
++
++struct otg_test otg_tests_df[] = {
++ /*
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++ /*!
++ * This is the default Firmware. It is included in the
++ * compiled modules and supports the auto Traditional USB
++ * mode. No user inputs are implemented.
++ */
++ { /* */
++ 0, /* .test */
++ invalid_state, /* .state */
++ otg_disabled, /* .target */
++ enable_otg, /* .test1 */
++ },
++ /*
++ * This is not an OTG State. It is used internally to mark the end of the
++ * list of states and inputs.
++ */
++ { /* */
++ 1, /* .test */
++ terminator_state, /* .state */
++ invalid_state, /* .target */
++ 0, /* .test1 */
++ },
++ {2, invalid_state,},
++
++};
++
++#define OTG_TESTS_DF 2
++
++int otg_test_max_df = 2;
++
++ /* eof */
++
++/* Generated by otg-info-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++struct otg_state otg_states_df[OTG_STATES_DF + 1] = {
++ { /* 0 */
++ invalid_state, /* .state */
++ m_otg_init, /* .meta */
++ "invalid_state", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ },
++ { /* 1 */
++ otg_disabled, /* .state */
++ m_otg_init, /* .meta */
++ "otg_disabled", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ },
++ { /* 2 */
++ terminator_state, /* .state */
++ m_otg_init, /* .meta */
++ "terminator_state", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ /* .outputs */
++ 0,
++ },
++
++ {0, 0, "", 0, 0,},
++
++};
++
++struct otg_firmware otg_firmware_df = {
++ OTG_STATES_DF, /* number of states */
++ OTG_TESTS_DF, /* number of tests */
++ "otg-df", /* name of firmware */
++ otg_states_df, /* struct otg_state * */
++ otg_tests_df, /* struct otg_test * */
++};
++
++/* eof */
+diff -uNr linux/drivers/no-otg/otgcore/otg-fw-mn.c linux/drivers/otg/otgcore/otg-fw-mn.c
+--- linux/drivers/no-otg/otgcore/otg-fw-mn.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-fw-mn.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,511 @@
++
++/* Generated by otg-tests-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++
++/*!
++* @file otg/otgcore/otg-fw-mn.c
++* @brief OTG Firmware - Firmware for mn
++*
++* This file defines the OTG State Machine tests.
++*
++*
++* @ingroup OTGFW
++*/
++
++/*!
++* @page OTGFW
++* @section OTGFW - otg-fw-mn.c
++* This contains the input, output and timout definitions for the OTG state machine firmware
++*/
++
++
++#ifdef OTG_APPLICATION
++#define NULL 0
++#include "otg-fw.h"
++#include "otg-fw-mn.h"
++#else /* OTG_APPLICATION/ */
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++//#include <otg/otg-api.h>
++#include <otg/otg-fw.h>
++#include <otg/otg-fw-mn.h>
++#endif /* OTG_APPLICATION */
++
++char otg_fw_name_mn[] = "otg_mn";
++
++
++struct otg_test otg_tests_mn[] = {
++ /*
++ * Copyright (c) 2004 Belcarra
++ */
++ /*!
++ * This is the initialization set for pcd and tcd.
++ */
++ /*
++ * This the initial state of the software when first loaded.
++ * It is not possible to return to this state.
++ */
++ { /* Initialize by sending the otg_enable signal. */
++ 0, /* .test */
++ invalid_state, /* .state */
++ otg_disabled, /* .target */
++ enable_otg, /* .test1 */
++ },
++ /*
++ * The USBOTG State Machine has been initialized but is inactive.
++ * This state may have arrived at from either the invalid_state or
++ * from the otg_disable state.
++ */
++ { /* Initialize by sending the otg_enable signal. */
++ 1, /* .test */
++ otg_disabled, /* .state */
++ otg_enable_pcd, /* .target */
++ enable_otg, /* .test1 */
++ },
++ /*
++ * The State Machine stops the device drivers and waits for them
++ * to signal that they have finished de-initializing.
++ *
++ * This state disables the TCD driver and waits for TCD ok.
++ */
++ { /* Wait for ok from de-initializing drivers. */
++ 2, /* .test */
++ otg_disable_tcd, /* .state */
++ otg_disable_pcd, /* .target */
++ TCD_OK, /* .test1 */
++ },
++ /*
++ * The State Machine stops the device drivers and waits for them
++ * to signal that they have finished de-initializing.
++ *
++ * This state disables the PCD driver and waits for PCD ok.
++ */
++ { /* Wait for ok from de-initializing drivers. */
++ 3, /* .test */
++ otg_disable_pcd, /* .state */
++ otg_disabled, /* .target */
++ PCD_OK, /* .test1 */
++ },
++ /*
++ * The State Machine starts the device drivers and waits for them
++ * to signal that they have finished initializing.
++ *
++ * This state enables the PCD driver and waits for PCD ok.
++ */
++ { /* Wait for ok from initializing drivers. */
++ 4, /* .test */
++ otg_enable_pcd, /* .state */
++ otg_enable_tcd, /* .target */
++ PCD_OK, /* .test1 */
++ },
++ /*
++ * The State Machine starts the device drivers and waits for them
++ * to signal that they have finished initializing.
++ *
++ * This state enables the PCD driver and waits for PCD ok.
++ */
++ { /* Wait for ok from initializing drivers. */
++ 5, /* .test */
++ otg_enable_tcd, /* .state */
++ otg_enabled, /* .target */
++ TCD_OK, /* .test1 */
++ },
++ /*
++ * Copyright (c) 2004 Belcarra
++ *
++ */
++ /*!
++ * This is the minimal firmware. It can be included in the
++ * compiled modules and supports the auto Traditional USB
++ * mode. No user inputs are required for normal operation.
++ *
++ * The b_bus_drop input can be optionally used to disconnect and re-connect.
++ *
++ * The enable_otg input can be optionally used to disable and re-enable.
++ * Note that disable/enable will reset b_bus_drop.
++ *
++ */
++ /*!
++ * The State Machine has successfully started the device drivers and
++ * is waiting for an input event. Typically it will move from here to
++ * an idle state specific to the current conditions (a_idle, b_idle, mn_idle etc.)
++ * based on user request b_bus_drop.
++ *
++ */
++ { /* Check for disable. */
++ 6, /* .test */
++ otg_enabled, /* .state */
++ otg_disable_tcd, /* .target */
++ enable_otg_, /* .test1 */
++ },
++ { /* Move to idle. */
++ 7, /* .test */
++ otg_enabled, /* .state */
++ mn_idle, /* .target */
++ AUTO | AUTO_, /* .test1 */
++ },
++ /*!
++ * The State Machine is in the idle state for a Traditional USB Device.
++ * It is waiting for Vbus to indicate that it has been plugged into a USB Host.
++ *
++ */
++ { /* Check for disable (must be done for check for bus_drop.) */
++ 8, /* .test */
++ mn_idle, /* .state */
++ otg_disable_tcd, /* .target */
++ enable_otg_, /* .test1 */
++ },
++ { /* Check for b_bus_drop */
++ 9, /* .test */
++ mn_idle, /* .state */
++ mn_bus_drop, /* .target */
++ b_bus_drop, /* .test1 */
++ },
++ { /* move to peripheral mode when SESSION valid. */
++ 10, /* .test */
++ mn_idle, /* .state */
++ mn_peripheral, /* .target */
++ b_bus_drop_, /* .test1 */
++ B_SESS_VLD, /* .test2 */
++ },
++ /*!
++ * The State Machine is in the idle state for a Traditional USB Device.
++ * The B-Device applications has requested that the bus connection be dropped.
++ * Wait for either enable_otg reset or b_bus_drop reset.
++ */
++ { /* Wait for b_bus_drop/ or enable_otg/ */
++ 11, /* .test */
++ mn_bus_drop, /* .state */
++ mn_idle, /* .target */
++ b_bus_drop_ | enable_otg_, /* .test1 */
++ },
++ /*!
++ * The State Machine in the peripheral state for a Traditional USB Device.
++ * The D+ pullup is enabled and we are waiting for a BUS_RESET to
++ * indicate that the USB Host has recognized that a USB Device is attached.
++ */
++ { /* Move to idle if we loose any of these inputs. */
++ 12, /* .test */
++ mn_peripheral, /* .state */
++ mn_idle, /* .target */
++ enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
++ },
++ { /* Move to next state if bus reset is seen. */
++ 13, /* .test */
++ mn_peripheral, /* .state */
++ mn_bus_reset, /* .target */
++ BUS_RESET, /* .test1 */
++ },
++ /*!
++ * The State Machine in the bus_reset state for a Traditional USB Device.
++ * It is waiting to be enumerated and configured by the USB Host.
++ */
++ { /* Move to idle via discharge, if we loose any of these inputs. */
++ 14, /* .test */
++ mn_bus_reset, /* .state */
++ mn_discharge, /* .target */
++ enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
++ },
++ { /* Progress if we are addressed. */
++ 15, /* .test */
++ mn_bus_reset, /* .state */
++ mn_addressed, /* .target */
++ ADDRESSED, /* .test1 */
++ },
++ /*!
++ * The State Machine in the configured state for a Traditional USB Device.
++ * This means that there is an active session, there is packet traffic
++ * with this device.
++ */
++ { /* Move to idle via discharge, if we loose any of these inputs. */
++ 16, /* .test */
++ mn_addressed, /* .state */
++ mn_discharge, /* .target */
++ enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
++ },
++ { /* Progress if we are configured. */
++ 17, /* .test */
++ mn_addressed, /* .state */
++ mn_configured, /* .target */
++ CONFIGURED, /* .test1 */
++ },
++ /*!
++ * The State Machine in the configured state for a Traditional USB Device.
++ * This means that there is an active session, there is packet traffic
++ * with this device.
++ */
++ { /* */
++ 18, /* .test */
++ mn_configured, /* .state */
++ mn_suspended, /* .target */
++ BUS_SUSPENDED, /* .test1 */
++ },
++ { /* Move to idle via discharge, if we loose any of these inputs. */
++ 19, /* .test */
++ mn_configured, /* .state */
++ mn_discharge, /* .target */
++ enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
++ },
++ /*!
++ * The State Machine in the discharge state for a Traditional USB Device.
++ * The device has been unplugged. The Vbus discharge resistor will be enabled
++ * for the TLDISC_DSCHRG time period.
++ */
++ { /* Progress to idle on timeout. */
++ 20, /* .test */
++ mn_discharge, /* .state */
++ mn_idle, /* .target */
++ Tldisc_dschrg, /* .test1 */
++ },
++ /*!
++ * The State Machine in the suspend state for a Traditional USB Device.
++ */
++ { /* Move to idle via discharge, if we loose any of these inputs. */
++ 21, /* .test */
++ mn_suspended, /* .state */
++ mn_discharge, /* .target */
++ enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
++ },
++ { /* Check for a resumed bus. */
++ 22, /* .test */
++ mn_suspended, /* .state */
++ mn_configured, /* .target */
++ BUS_SUSPENDED_, /* .test1 */
++ },
++ { /* Is remote wakeup enabled? */
++ 23, /* .test */
++ mn_suspended, /* .state */
++ mn_wakeup_enabled, /* .target */
++ REMOTE_WAKEUP_ENABLED, /* .test1 */
++ },
++ /*!
++ * The State Machine in the suspend state for a Traditional USB Device,
++ * prior to suspended the USB Host enabled Remote Wakeup by sending a
++ * set REMOTE WAKUP request.
++ */
++ { /* Move to idle via discharge, if we loose any of these inputs. */
++ 24, /* .test */
++ mn_wakeup_enabled, /* .state */
++ mn_discharge, /* .target */
++ enable_otg_ | b_bus_req_ | B_SESS_VLD_, /* .test1 */
++ },
++ { /* Check for a resumed bus. */
++ 25, /* .test */
++ mn_wakeup_enabled, /* .state */
++ mn_suspended, /* .target */
++ BUS_SUSPENDED_, /* .test1 */
++ },
++ { /* Remote wakeup requested? */
++ 26, /* .test */
++ mn_wakeup_enabled, /* .state */
++ mn_wakeup, /* .target */
++ remote_wakeup_cmd, /* .test1 */
++ },
++ /*!
++ * The State Machine in the wakeup state for a Traditional USB Device,
++ * The REMOTE WAKEUP procedure will be performed.
++ */
++ { /* Automatic return. */
++ 27, /* .test */
++ mn_wakeup, /* .state */
++ mn_wakeup_enabled, /* .target */
++ AUTO | AUTO_, /* .test1 */
++ },
++ /*!
++ * This is not an OTG State. It is used internally to mark the end of the
++ * list of states and inputs.
++ */
++ { /* */
++ 28, /* .test */
++ terminator_state, /* .state */
++ invalid_state, /* .target */
++ 0, /* .test1 */
++ },
++ {29, invalid_state,},
++
++};
++
++#define OTG_TESTS_MN 29
++
++int otg_test_max_mn = 29;
++
++ /* eof */
++
++/* Generated by otg-info-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++struct otg_state otg_states_mn[OTG_STATES_MN + 1] = {
++ { /* 0 */
++ invalid_state, /* .state */
++ m_otg_init, /* .meta */
++ "invalid_state", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ },
++ { /* 1 */
++ otg_disabled, /* .state */
++ m_otg_init, /* .meta */
++ "otg_disabled", /* .name */
++ 0, /* .tmout */
++ enable_otg_, /* .reset */
++ /* .outputs */
++ chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_,
++ },
++ { /* 2 */
++ otg_disable_tcd, /* .state */
++ m_otg_init, /* .meta */
++ "otg_disable_tcd", /* .name */
++ 0, /* .tmout */
++ TCD_OK_, /* .reset */
++ /* .outputs */
++ tcd_init_out_,
++ },
++ { /* 3 */
++ otg_disable_pcd, /* .state */
++ m_otg_init, /* .meta */
++ "otg_disable_pcd", /* .name */
++ 0, /* .tmout */
++ PCD_OK_, /* .reset */
++ /* .outputs */
++ pcd_init_out_,
++ },
++ { /* 4 */
++ otg_enable_pcd, /* .state */
++ m_otg_init, /* .meta */
++ "otg_enable_pcd", /* .name */
++ 0, /* .tmout */
++ PCD_OK_, /* .reset */
++ /* .outputs */
++ chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_ | pcd_init_out,
++ },
++ { /* 5 */
++ otg_enable_tcd, /* .state */
++ m_otg_init, /* .meta */
++ "otg_enable_tcd", /* .name */
++ 0, /* .tmout */
++ TCD_OK_, /* .reset */
++ /* .outputs */
++ chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_ | tcd_init_out,
++ },
++ { /* 6 */
++ otg_enabled, /* .state */
++ m_otg_init, /* .meta */
++ "otg_enabled", /* .name */
++ 0, /* .tmout */
++ b_bus_drop_, /* .reset */
++ },
++ { /* 7 */
++ mn_idle, /* .state */
++ m_b_idle, /* .meta */
++ "mn_idle", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ /* .outputs */
++ dp_pullup_out_ | pcd_en_out_ | tcd_en_out_power | dischrg_vbus_out_,
++ },
++ { /* 8 */
++ mn_bus_drop, /* .state */
++ m_b_idle, /* .meta */
++ "mn_bus_drop", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ },
++ { /* 9 */
++ mn_peripheral, /* .state */
++ m_b_peripheral, /* .meta */
++ "mn_peripheral", /* .name */
++ 0, /* .tmout */
++ BUS_RESET_, /* .reset */
++ /* .outputs */
++ dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
++ },
++ { /* 10 */
++ mn_bus_reset, /* .state */
++ m_b_peripheral, /* .meta */
++ "mn_bus_reset", /* .name */
++ 0, /* .tmout */
++ BUS_RESET_ | ADDRESSED_, /* .reset */
++ },
++ { /* 11 */
++ mn_addressed, /* .state */
++ m_b_peripheral, /* .meta */
++ "mn_addressed", /* .name */
++ 0, /* .tmout */
++ ADDRESSED_ | CONFIGURED_, /* .reset */
++ /* .outputs */
++ dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
++ },
++ { /* 12 */
++ mn_configured, /* .state */
++ m_b_peripheral, /* .meta */
++ "mn_configured", /* .name */
++ 0, /* .tmout */
++ CONFIGURED_ | BUS_SUSPENDED_, /* .reset */
++ /* .outputs */
++ dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
++ },
++ { /* 13 */
++ mn_discharge, /* .state */
++ m_b_peripheral, /* .meta */
++ "mn_discharge", /* .name */
++ TLDISC_DSCHRG, /* .tmout */
++ 0, /* .reset */
++ /* .outputs */
++ dischrg_vbus_out | pcd_en_out_,
++ },
++ { /* 14 */
++ mn_suspended, /* .state */
++ m_b_suspended, /* .meta */
++ "mn_suspended", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ },
++ { /* 15 */
++ mn_wakeup_enabled, /* .state */
++ m_b_suspended, /* .meta */
++ "mn_wakeup_enabled", /* .name */
++ 0, /* .tmout */
++ remote_wakeup_cmd_, /* .reset */
++ /* .outputs */
++ remote_wakeup_out_,
++ },
++ { /* 16 */
++ mn_wakeup, /* .state */
++ m_b_suspended, /* .meta */
++ "mn_wakeup", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ /* .outputs */
++ remote_wakeup_out,
++ },
++ { /* 17 */
++ terminator_state, /* .state */
++ m_otg_init, /* .meta */
++ "terminator_state", /* .name */
++ 0, /* .tmout */
++ 0, /* .reset */
++ /* .outputs */
++ 0,
++ },
++
++ {0, 0, "", 0, 0,},
++
++};
++
++struct otg_firmware otg_firmware_mn = {
++ OTG_STATES_MN, /* number of states */
++ OTG_TESTS_MN, /* number of tests */
++ "otg-mn", /* name of firmware */
++ otg_states_mn, /* struct otg_state * */
++ otg_tests_mn, /* struct otg_test * */
++};
++
++/* eof */
+diff -uNr linux/drivers/no-otg/otgcore/otg-fw.c linux/drivers/otg/otgcore/otg-fw.c
+--- linux/drivers/no-otg/otgcore/otg-fw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-fw.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,251 @@
++
++/* Generated by otg-fw-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++/*!
++* @file otg/otgcore/otg-fw.c
++* @brief OTG Firmware - Input, Output and Timeout definitions
++*
++* This file defines the OTG State Machine input, output and timeout constants.
++*
++*
++* @ingroup OTGFW
++*/
++
++/*!
++* @page OTGFW
++* @section OTGFW - otg-fw.c
++* This contains the input, output and timout definitions for the OTG state machine firmware
++*/
++
++
++#ifdef OTG_APPLICATION
++#include "otg-fw.h"
++#else /* OTG_APPLICATION/ */
++#include <otg/otg-compat.h>
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#endif /* OTG_APPLICATION */
++
++#define OTG_VERSION_FWC 200502152159L
++
++
++#if OTG_VERSION_FWC != OTG_VERSION_FW
++#error OTG_VERSION_FWC != OTG_VERSION_FW
++#endif /* OTG_VERSION_FWC != OTG_VERSION_FW */
++
++/* Generated by otg-input-name-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++
++/* #include "otg-fw.h" */
++
++#define OTG_VERSION_INPUT_TABLE 200502152159L
++
++
++#if OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW
++#error OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW
++#endif /* OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW */
++
++
++struct otg_input_name otg_input_names[] = {
++ {ID_GND, "ID_GND",},
++ {ID_FLOAT, "ID_FLOAT",},
++ {DP_HIGH, "DP_HIGH",},
++ {DM_HIGH, "DM_HIGH",},
++ {B_SESS_END, "B_SESS_END",},
++ {A_SESS_VLD, "A_SESS_VLD",},
++ {B_SESS_VLD, "B_SESS_VLD",},
++ {VBUS_VLD, "VBUS_VLD",},
++ {SRP_DET, "SRP_DET",},
++ {SE0_DET, "SE0_DET",},
++ {SE1_DET, "SE1_DET",},
++ {BDIS_ACON, "BDIS_ACON",},
++ {CR_INT_DET, "CR_INT_DET",},
++ {HUB_PORT_CONNECT, "HUB_PORT_CONNECT",},
++ {BUS_RESET, "BUS_RESET",},
++ {ADDRESSED, "ADDRESSED",},
++ {CONFIGURED, "CONFIGURED",},
++ {NOT_SUPPORTED, "NOT_SUPPORTED",},
++ {BUS_SUSPENDED, "BUS_SUSPENDED",},
++ {a_bcon_no_tmout_req, "a_bcon_no_tmout_req",},
++ {a_hpwr_req, "a_hpwr_req",},
++ {bus_drop, "bus_drop",},
++ {a_bus_drop, "a_bus_drop",},
++ {b_bus_drop, "b_bus_drop",},
++ {bus_req, "bus_req",},
++ {a_bus_req, "a_bus_req",},
++ {b_bus_req, "b_bus_req",},
++ {b_sess_req, "b_sess_req",},
++ {suspend_req, "suspend_req",},
++ {a_suspend_req, "a_suspend_req",},
++ {b_suspend_req, "b_suspend_req",},
++ {set_remote_wakeup_cmd, "set_remote_wakeup_cmd",},
++ {remote_wakeup_cmd, "remote_wakeup_cmd",},
++ {reset_remote_wakeup_cmd, "reset_remote_wakeup_cmd",},
++ {clr_err_cmd, "clr_err_cmd",},
++ {b_hnp_cmd, "b_hnp_cmd",},
++ {ph_int_cmd, "ph_int_cmd",},
++ {ph_audio_cmd, "ph_audio_cmd",},
++ {cr_int_cmd, "cr_int_cmd",},
++ {led_on_cmd, "led_on_cmd",},
++ {led_off_cmd, "led_off_cmd",},
++ {HNP_ENABLED, "HNP_ENABLED",},
++ {HNP_CAPABLE, "HNP_CAPABLE",},
++ {HNP_SUPPORTED, "HNP_SUPPORTED",},
++ {REMOTE_WAKEUP_ENABLED, "REMOTE_WAKEUP_ENABLED",},
++ {REMOTE_CAPABLE, "REMOTE_CAPABLE",},
++ {PCD_OK, "PCD_OK",},
++ {TCD_OK, "TCD_OK",},
++ {HCD_OK, "HCD_OK",},
++ {OCD_OK, "OCD_OK",},
++ {TMOUT, "TMOUT",},
++ {enable_otg, "enable_otg",},
++ {AUTO, "AUTO",},
++ {0, "0",},
++
++};
++
++ /* eof */
++
++/* Generated by otg-ioctls-names-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++#if defined(OTG_LINUX) || defined(OTG_WINCE)
++
++
++/* #include "otg-fw.h" */
++
++#define OTG_VERSION_IOCTL_TABLE 200502152159L
++
++
++#if OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW
++#error OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW
++#endif /* OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW */
++
++struct otg_ioctl_name otg_ioctl_names[] = {
++ {OTGADMIN_A_BCON_NO_TMOUT_REQ, a_bcon_no_tmout_req, "OTGADMIN_A_BCON_NO_TMOUT_REQ",},
++ {OTGADMIN_A_HPWR_REQ, a_hpwr_req, "OTGADMIN_A_HPWR_REQ",},
++ {OTGADMIN_BUS_DROP, bus_drop, "OTGADMIN_BUS_DROP",},
++ {OTGADMIN_A_BUS_DROP, a_bus_drop, "OTGADMIN_A_BUS_DROP",},
++ {OTGADMIN_B_BUS_DROP, b_bus_drop, "OTGADMIN_B_BUS_DROP",},
++ {OTGADMIN_BUS_REQ, bus_req, "OTGADMIN_BUS_REQ",},
++ {OTGADMIN_A_BUS_REQ, a_bus_req, "OTGADMIN_A_BUS_REQ",},
++ {OTGADMIN_B_BUS_REQ, b_bus_req, "OTGADMIN_B_BUS_REQ",},
++ {OTGADMIN_B_SESS_REQ, b_sess_req, "OTGADMIN_B_SESS_REQ",},
++ {OTGADMIN_SUSPEND_REQ, suspend_req, "OTGADMIN_SUSPEND_REQ",},
++ {OTGADMIN_A_SUSPEND_REQ, a_suspend_req, "OTGADMIN_A_SUSPEND_REQ",},
++ {OTGADMIN_B_SUSPEND_REQ, b_suspend_req, "OTGADMIN_B_SUSPEND_REQ",},
++ {OTGADMIN_SET_REMOTE_WAKEUP_CMD, set_remote_wakeup_cmd, "OTGADMIN_SET_REMOTE_WAKEUP_CMD",},
++ {OTGADMIN_REMOTE_WAKEUP_CMD, remote_wakeup_cmd, "OTGADMIN_REMOTE_WAKEUP_CMD",},
++ {OTGADMIN_RESET_REMOTE_WAKEUP_CMD, reset_remote_wakeup_cmd, "OTGADMIN_RESET_REMOTE_WAKEUP_CMD",},
++ {OTGADMIN_CLR_ERR_CMD, clr_err_cmd, "OTGADMIN_CLR_ERR_CMD",},
++ {OTGADMIN_B_HNP_CMD, b_hnp_cmd, "OTGADMIN_B_HNP_CMD",},
++ {OTGADMIN_PH_INT_CMD, ph_int_cmd, "OTGADMIN_PH_INT_CMD",},
++ {OTGADMIN_PH_AUDIO_CMD, ph_audio_cmd, "OTGADMIN_PH_AUDIO_CMD",},
++ {OTGADMIN_CR_INT_CMD, cr_int_cmd, "OTGADMIN_CR_INT_CMD",},
++ {OTGADMIN_LED_ON_CMD, led_on_cmd, "OTGADMIN_LED_ON_CMD",},
++ {OTGADMIN_LED_OFF_CMD, led_off_cmd, "OTGADMIN_LED_OFF_CMD",},
++ {OTGADMIN_ENABLE_OTG, enable_otg, "OTGADMIN_ENABLE_OTG",},
++ {0, 0, "",},
++
++};
++
++ /* eof */
++#endif /* defined(OTG_LINUX) || defined(OTG_WINCE) */
++
++/* Generated by otg-output-names-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++char *otg_output_names[] = {
++ "tcd_init_out", /* 0 Initiate Transceiver Controller Driver Initialization (or De-initialization.) */
++ "pcd_init_out", /* 1 Initiate Peripheral Controller Driver Initialization (or De-initialization.) */
++ "hcd_init_out", /* 2 Initiate Host Controller Driver Initialization (or De-initialization). */
++ "ocd_init_out", /* 3 Initiate OTG Controller Driver Initialization (or De-initialization). */
++ "tcd_en_out", /* 4 Enable Transceiver Controller Driver */
++ "pcd_en_out", /* 5 Enable Peripheral Controller Driver */
++ "hcd_en_out", /* 6 Enable Host Controller Driver */
++ "drv_vbus_out", /* 7 A-Device will Drive Vbus to 5V through charge pump. */
++ "chrg_vbus_out", /* 8 B-Device will charge Vbus to 3.3V through resistor (SRP.) */
++ "dischrg_vbus_out", /* 9 B-Device will discharge Vbus (enable dischage resistor.) */
++ "dm_pullup_out", /* 10 DM pullup control - aka loc_carkit */
++ "dm_pulldown_out", /* 11 DM pulldown control */
++ "dp_pullup_out", /* 12 DP pullup control - aka loc_conn */
++ "dp_pulldown_out", /* 13 DP pulldown control */
++ "clr_overcurrent_out", /* 14 Clear overcurrent indication */
++ "dm_det_out", /* 15 Enable B-Device D- High detect */
++ "dp_det_out", /* 16 Enable B-Device D+ High detect */
++ "cr_det_out", /* 17 Enable D+ CR detect */
++ "charge_pump_out", /* 18 Enable external charge pump. */
++ "bdis_acon_out", /* 19 Enable auto A-connect after B-disconnect. */
++ "mx21_vbus_drain", /* 20 MX21 hack */
++ "id_pulldown_out", /* 21 Enable the ID to ground pulldown ( (CEA-936 - 5 wire carkit.) */
++ "uart_out", /* 22 Enable Transparent UART mode (CEA-936.) */
++ "audio_out", /* 23 Enable Audio mode (CEA-936 CarKit interrupt detector.) */
++ "mono_out", /* 24 Enable Mono-Audio mode (CEA-936.) */
++ "remote_wakeup_out", /* 25 Peripheral will perform remote wakeup. */
++ "loc_sof_out", /* 26 Host will enable packet traffic. */
++ "loc_suspend_out", /* 27 Host will suspend bus. */
++ "remote_wakeup_en_out", /* 28 Host will send remote wakeup enable or disable request. */
++ "hnp_en_out", /* 29 Host will send HNP enable request. */
++ "hpwr_out", /* 30 Host will enable high power (external charge pump.) */
++ NULL,
++
++};
++
++ /* eof */
++
++/* Generated by otg-meta-names-c.awk
++ *
++ * Do not Edit, see otg-state.awk
++ */
++
++
++
++char *otg_meta_names[] = {
++ "a_idle", /* 0 - */
++ "a_wait_vrise", /* 1 - */
++ "a_wait_bcon", /* 2 - */
++ "a_host", /* 3 - */
++ "a_suspend", /* 4 - */
++ "a_peripheral", /* 5 - */
++ "a_wait_vfall", /* 6 - */
++ "a_vbus_err", /* 7 - */
++ "b_idle", /* 8 - */
++ "b_srp_init", /* 9 - */
++ "b_peripheral", /* 10 - */
++ "b_suspend", /* 11 - */
++ "b_wait_acon", /* 12 - */
++ "b_host", /* 13 - */
++ "b_suspended", /* 14 - */
++ "ph_disc", /* 15 - Equivalent to b_peripheral */
++ "ph_init", /* 16 - */
++ "ph_uart", /* 17 - */
++ "ph_aud", /* 18 - */
++ "ph_wait", /* 19 - */
++ "ph_exit", /* 20 - */
++ "cr_init", /* 21 - */
++ "cr_uart", /* 22 - */
++ "cr_aud", /* 23 - */
++ "cr_ack", /* 24 - */
++ "cr_wait", /* 25 - */
++ "cr_disc", /* 26 - */
++ "otg_init", /* 27 - */
++ "usb_accessory", /* 28 - */
++ "usb_factory", /* 29 - */
++ "unknown", /* 30 - */
++
++ "",
++};
++
++/* eof */
+diff -uNr linux/drivers/no-otg/otgcore/otg-mesg-l24.c linux/drivers/otg/otgcore/otg-mesg-l24.c
+--- linux/drivers/no-otg/otgcore/otg-mesg-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-mesg-l24.c 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,399 @@
++/*
++ * otg/otgcore/otg-mesg-l24.c - OTG state machine Administration
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/otg-mesg-l24.c
++ * @brief OTG Core Linux Message Interface.
++ *
++ * Implement linux char device via /proc/otg-mesg.
++ *
++ * @ingroup OTGCore
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++#include <linux/poll.h>
++#include <linux/sched.h>
++
++
++wait_queue_head_t otg_message_queue;
++
++/*!
++ * otg_message() - queue message data
++ * @param buf message to send.
++ */
++void otg_message (char *buf)
++{
++ char time_buf[64];
++ static u64 save_ticks;
++ u64 new_ticks;
++ u64 ticks;
++
++ new_ticks = otg_tmr_ticks();
++
++ otg_write_message(buf, strlen(buf));
++
++ ticks = otg_tmr_elapsed(&new_ticks, &save_ticks);
++ save_ticks = new_ticks;
++
++ if (ticks < 10000)
++ sprintf(time_buf, " %d uS\n", ticks);
++ else if (ticks < 10000000)
++ //sprintf(time_buf, " %d mS\n", ticks / 1000);
++ sprintf(time_buf, " %d mS\n", ticks >> 10);
++ else
++ //sprintf(time_buf, " %d S\n", ticks / 1000000);
++ sprintf(time_buf, " %d S\n", ticks >> 20);
++
++ otg_write_message(time_buf, strlen(time_buf));
++
++
++ //TRACE_MSG0(CORE, "wakeup ");
++ //printk(KERN_INFO"%s: wakeup\n", __FUNCTION__);
++ wake_up_interruptible(&otg_message_queue);
++}
++
++/*!
++ * otg_message_block() - implement block
++ */
++unsigned int otg_message_block(void)
++{
++ int count = otg_data_queued();
++ if (count) return count;
++ //TRACE_MSG0(CORE, "sleeping ");
++ //printk(KERN_INFO"%s: sleeping\n", __FUNCTION__);
++ interruptible_sleep_on(&otg_message_queue);
++ return otg_data_queued();
++}
++
++/*!
++ * otg_message_poll() - implement poll
++ * @param filp file pointer
++ * @param wait poll table structure
++ */
++unsigned int otg_message_poll(struct file *filp, struct poll_table_struct *wait)
++{
++ //TRACE_MSG0(CORE, "polling ");
++ poll_wait(filp, &otg_message_queue, wait);
++ return otg_data_queued() ? POLLIN | POLLRDNORM : 0;
++}
++
++/*!
++ * otg_message_ioctl_internal() - ioctl call
++ * @param cmd ioctl command.
++ * @param arg ioctl arguement.
++ * @return non-zero for error.
++ */
++int otg_message_ioctl_internal(unsigned int cmd, unsigned long arg)
++{
++ int i;
++ int len;
++ int flag;
++ struct otg_admin_command admin_command;
++ struct otg_status_update status_update;
++ struct otg_firmware_info firmware_info;
++ struct otg_state otg_state;
++ struct otg_test otg_test;
++ struct otg_ioctl_name *otg_ioctl_name;
++ static char func_buf[32];
++ char *sp, *dp;
++ char *name;
++
++ switch (cmd) {
++
++ case OTGADMIN_GET_FUNCTION:
++ //TRACE_MSG0(CORE, "OTGADMIN_GET_FUNCTION");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
++ name = otg_usbd_ops->function_name(admin_command.n);
++ admin_command.string[0] = '\0';
++ if (name)
++ strncat(admin_command.string, name, sizeof(admin_command.string));
++
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &admin_command, _IOC_SIZE(cmd)));
++ return 0;
++
++ case OTGADMIN_SET_FUNCTION:
++ //TRACE_MSG0(CORE, "OTGADMIN_SET_FUNCTION");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ memset(&admin_command, 0x41, sizeof(struct otg_admin_command));
++ RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
++ len = sizeof(mesg_otg_instance->function_name);
++ admin_command.string[len] = '\0';
++ //TRACE_MSG1(CORE, "Setting function: \"%s\"", mesg_otg_instance->function_name);
++ strncpy(mesg_otg_instance->function_name, admin_command.string, len);
++ mesg_otg_instance->function_name[len-1] = '\0';
++ return 0;
++
++ case OTGADMIN_GET_SERIAL:
++ //TRACE_MSG0(CORE, "OTGADMIN_GET_SERIAL");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ strncpy(admin_command.string, mesg_otg_instance->serial_number, sizeof(admin_command.string));
++ admin_command.string[sizeof(admin_command.string) - 1] = '\0';
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &admin_command, _IOC_SIZE(cmd)));
++ return 0;
++
++ case OTGADMIN_SET_SERIAL:
++ //TRACE_MSG0(CORE, "OTGADMIN_SET_SERIAL");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
++ admin_command.string[sizeof(admin_command.string) - 1] = '\0';
++ printk(KERN_INFO"%s: string: %s\n", __FUNCTION__, admin_command.string);
++ for (sp = admin_command.string, dp = mesg_otg_instance->serial_number, i = 0;
++ *sp && (i < (sizeof(admin_command.string) - 1)); i++, sp++)
++ if (isxdigit(*sp)) *dp++ = toupper(*sp);
++
++ *sp = '\0';
++ //TRACE_MSG1(CORE, "serial_number: %s", mesg_otg_instance->serial_number);
++ printk(KERN_INFO"%s: serial: %s\n", __FUNCTION__, mesg_otg_instance->serial_number);
++ return 0;
++
++ case OTGADMIN_STATUS:
++ //TRACE_MSG0(CORE, "OTGADMIN_STATUS");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ memset(&status_update, 0, sizeof(struct otg_status_update));
++
++ otg_mesg_get_status_update(&status_update);
++
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &status_update, _IOC_SIZE(cmd)));
++ return 0;
++
++ case OTGADMIN_GET_INFO:
++ //TRACE_MSG0(CORE, "OTGADMIN_GET_INFO");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++
++ otg_mesg_get_firmware_info(&firmware_info);
++
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &firmware_info, _IOC_SIZE(cmd)));
++ //TRACE_MSG0(CORE, "OTGADMIN_GET_INFO: finished");
++ return 0;
++
++ case OTGADMIN_SET_INFO:
++ //TRACE_MSG0(CORE, "OTGADMIN_SET_INFO");
++ memset(&firmware_info, 0x41, sizeof(firmware_info));
++ RETURN_EINVAL_IF(copy_from_user(&firmware_info, (void *)arg, _IOC_SIZE(cmd)));
++
++
++ return otg_mesg_set_firmware_info(&firmware_info);
++ return 0;
++
++ case OTGADMIN_GET_STATE:
++ case OTGADMIN_SET_STATE:
++ //TRACE_MSG0(CORE, "OTGADMIN_XXX_STATE");
++ RETURN_EINVAL_IF(copy_from_user(&otg_state, (void *)arg, _IOC_SIZE(cmd)));
++
++ switch (cmd) {
++ case OTGADMIN_GET_STATE:
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ //TRACE_MSG0(CORE, "OTGADMIN_GET_STATE");
++ RETURN_EINVAL_UNLESS (otg_state.state < otg_firmware_loaded->number_of_states);
++ memcpy(&otg_state, otg_firmware_loaded->otg_states + otg_state.state, sizeof(otg_state));
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &otg_state, _IOC_SIZE(cmd)));
++ break;
++ case OTGADMIN_SET_STATE:
++ RETURN_EINVAL_UNLESS(otg_firmware_loading);
++ //TRACE_MSG0(CORE, "OTGADMIN_SET_STATE");
++ RETURN_EINVAL_UNLESS (otg_state.state < otg_firmware_loading->number_of_states);
++ memcpy(otg_firmware_loading->otg_states + otg_state.state, &otg_state, sizeof(otg_state));
++ break;
++ }
++ return 0;
++
++
++ case OTGADMIN_GET_TEST:
++ case OTGADMIN_SET_TEST:
++ RETURN_EINVAL_IF(copy_from_user(&otg_test, (void *)arg, _IOC_SIZE(cmd)));
++
++ switch (cmd) {
++ case OTGADMIN_GET_TEST:
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ //TRACE_MSG1(CORE, "OTGADMIN_GET_TEST: %d", otg_test.test);
++ RETURN_EINVAL_UNLESS (otg_test.test < otg_firmware_loaded->number_of_tests);
++ memcpy(&otg_test, otg_firmware_loaded->otg_tests + otg_test.test, sizeof(otg_test));
++ RETURN_EINVAL_IF(copy_to_user((void *)arg, &otg_test, _IOC_SIZE(cmd)));
++ break;
++ case OTGADMIN_SET_TEST:
++ RETURN_EINVAL_UNLESS(otg_firmware_loading);
++ //TRACE_MSG1(CORE, "OTGADMIN_SET_TEST : %d", otg_test.test);
++ RETURN_EINVAL_UNLESS (otg_test.test < otg_firmware_loading->number_of_tests);
++ memcpy(otg_firmware_loading->otg_tests + otg_test.test, &otg_test, sizeof(otg_test));
++ break;
++ }
++ return 0;
++
++ default:
++ //TRACE_MSG0(CORE, "OTGADMIN_");
++ RETURN_EINVAL_UNLESS(otg_firmware_loaded);
++ for (otg_ioctl_name = otg_ioctl_names; otg_ioctl_name && otg_ioctl_name->cmd; otg_ioctl_name++) {
++ //TRACE_MSG4(CORE, "lookup: %04x %04x %08x %08x",
++ // _IOC_NR(cmd), _IOC_NR(otg_ioctl_name->cmd), cmd, otg_ioctl_name->cmd);
++ BREAK_IF(_IOC_NR(otg_ioctl_name->cmd) == _IOC_NR(cmd));
++ }
++ //TRACE_MSG3(CORE, "checking %d %08x %08x", _IOC_NR(cmd), otg_ioctl_name->cmd, cmd);
++ RETURN_EINVAL_UNLESS(otg_ioctl_name->cmd);
++ __get_user(flag, (int *)arg);
++ //TRACE_MSG3(CORE, "%s %08x flag: %d", otg_ioctl_name->name, otg_ioctl_name->set, flag);
++ otg_event (mesg_otg_instance, flag ? otg_ioctl_name->set : _NOT(otg_ioctl_name->set), CORE, otg_ioctl_name->name);
++ return 0;
++ }
++ return 0;
++}
++
++
++
++/*!
++ * otg_message_ioctl() - ioctl
++ * @param inode inode structure.
++ * @param filp file.
++ * @param cmd ioctl command.
++ * @param arg ioctl argument.
++ * @return non-zero for error.
++ */
++int otg_message_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ int i;
++ int len;
++ int flag;
++ struct otg_admin_command admin_command;
++ struct otg_status_update status_update;
++ struct otg_firmware_info firmware_info;
++ struct otg_state otg_state;
++ struct otg_test otg_test;
++ //struct otg_ioctl_map *map = ioctl_map;
++ struct otg_ioctl_name *otg_ioctl_name;
++
++ static char func_buf[32];
++
++ //TRACE_MSG6(CORE, "cmd: %08x arg: %08x type: %02d nr: %02d dir: %02d size: %02d",
++ // cmd, arg, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
++
++ RETURN_EINVAL_UNLESS (_IOC_TYPE(cmd) == OTGADMIN_MAGIC);
++ RETURN_EINVAL_UNLESS (_IOC_NR(cmd) <= OTGADMIN_MAXNR);
++
++ RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_READ) && !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)));
++ RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_WRITE) && !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)));
++
++ return otg_message_ioctl_internal(cmd, arg);
++}
++
++
++/*!
++ * otg_message_proc_read() - implement proc file system read.
++ * Standard proc file system read function.
++ * @param file file.
++ * @param buf buffer to fill
++ * @param count size of buffer
++ * @param pos file position
++ * @return number of bytes or negative number for error
++ */
++static ssize_t otg_message_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0, avail;
++ char *bp,*ep;
++ struct list_head *lhd;
++ int state;
++
++ // get a page, max 4095 bytes of data...
++ RETURN_ENOMEM_UNLESS ((page = GET_KERNEL_PAGE()));
++
++ bp = (char *) page;
++
++ len = bp - (char *) page;
++
++ if (( avail = otg_message_block())) {
++
++ len += otg_read_message(bp, 4095);
++
++ if (len > count)
++ len = -EINVAL;
++ else if ((len > 0) && copy_to_user (buf, (char *) page, len))
++ len = -EFAULT;
++
++ }
++
++ free_page (page);
++ return len;
++}
++
++/*! otg_message_proc_ioctl() -
++ * @param inode inode structure.
++ * @param filp file.
++ * @param cmd ioctl command.
++ * @param arg ioctl argument.
++ * @return non-zero for error.
++ */
++int otg_message_proc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ return otg_message_ioctl(inode, filp, cmd, arg);
++}
++
++/*!
++ * @param filp file.
++ * @param wait buffer to fill
++ * @return number of bytes or negative number for error
++ */
++unsigned int otg_message_proc_poll(struct file *filp, struct poll_table_struct *wait)
++{
++ return otg_message_poll(filp, wait);
++}
++
++/*!
++ * @var otg_message_proc_switch_functions
++ */
++static struct file_operations otg_message_proc_switch_functions = {
++ ioctl:otg_message_proc_ioctl,
++ poll:otg_message_proc_poll,
++ read:otg_message_proc_read,
++};
++
++
++/*!
++ * otg_message_init_l24() - initialize
++ */
++int otg_message_init_l24(struct otg_instance *otg)
++{
++ struct proc_dir_entry *message = NULL;
++ init_waitqueue_head(&otg_message_queue);
++
++ THROW_IF (!(message = create_proc_entry ("otg_message", 0666, 0)), error);
++ message->proc_fops = &otg_message_proc_switch_functions;
++ CATCH(error) {
++ printk(KERN_ERR"%s: creating /proc/otg_message failed\n", __FUNCTION__);
++ if (message)
++ remove_proc_entry("otg_message", NULL);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*!
++ * otg_message_exit_l24() - exit
++ */
++void otg_message_exit_l24(void)
++{
++ remove_proc_entry("otg_message", NULL);
++}
++
++EXPORT_SYMBOL(otg_message);
++
++
+diff -uNr linux/drivers/no-otg/otgcore/otg-mesg.c linux/drivers/otg/otgcore/otg-mesg.c
+--- linux/drivers/no-otg/otgcore/otg-mesg.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-mesg.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,369 @@
++/*
++ * otg/otgcore/otg-mesg.c - OTG state machine Administration
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/otg-mesg.c
++ * @brief OTG Core Message Facility.
++ *
++ * The OTG Core Message Facility has two functions:
++ *
++ * 1. implement a message queue for messages from the otg state machine to the otg
++ * management application
++ *
++ * 2. implement an ioctl control mechanism allowing the otg managment application
++ * to pass data and commands to the otg state machine
++ *
++ * @ingroup OTGCore
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++#if defined(OTG_LINUX)
++#include <linux/poll.h>
++#include <linux/sched.h>
++#endif /* defined(OTG_LINUX) */
++
++//#define OTG_MESSAGE_BUF_SIZE 512
++#define OTG_MESSAGE_BUF_SIZE 2048
++
++struct otg_instance * mesg_otg_instance;
++
++char *otg_message_buf; // buffer
++char *otg_message_head; // next available empty space
++char *otg_message_tail; // next available data if not equal to head
++
++/*!
++ * otg_data_avail() - amount of data in buffer
++ * space data
++ * tp hp 20 - (10 - 5) = 15 (10 - 5)
++ * 0......5.data.10......20
++ *
++ * hp tp (10 - 5) = 5 20 - (10 - 5)
++ * 0.data.5......10.data.20
++ *
++ * @return Bytes available in message ring buffer.
++ */
++int otg_data_avail(void)
++{
++ int avail = (otg_message_head >= otg_message_tail) ?
++ (otg_message_head - otg_message_tail) :
++ OTG_MESSAGE_BUF_SIZE - (otg_message_tail - otg_message_head) ;
++
++ //TRACE_MSG4(CORE, "buf: %p head: %p tail: %p data avail: %d", otg_message_buf, otg_message_head, otg_message_tail, avail);
++ return avail;
++}
++
++/*!
++ * otg_space_avail() - amount of space in buffer
++ *
++ * @return Space available in message ring buffer.
++ */
++int otg_space_avail(void)
++{
++ int avail = (otg_message_head >= otg_message_tail) ?
++ OTG_MESSAGE_BUF_SIZE - (otg_message_head - otg_message_tail) :
++ (otg_message_tail - otg_message_head) ;
++
++ //TRACE_MSG4(CORE, "buf: %p head: %p tail: %p space avail: %d", otg_message_buf, otg_message_head, otg_message_tail, avail);
++ return avail;
++}
++
++/*!
++ * otg_get_byte() - return next byte
++ *
++ * @return Next byte in message ring buffer
++ */
++char otg_get_byte(void)
++{
++ char c = *otg_message_tail;
++
++ //TRACE_MSG3(CORE, "buf: %p head: %p tail: %p", otg_message_buf, otg_message_head, otg_message_tail);
++ if ((otg_message_tail - otg_message_buf) == OTG_MESSAGE_BUF_SIZE)
++ otg_message_tail = otg_message_buf;
++ else
++ otg_message_tail++;
++
++ return c;
++}
++
++/*!
++ * otg_put_byte() - put byte into buffer
++ *
++ * Put byte into message ring buffer
++ *
++ * @param byte put into message ring.
++ */
++void otg_put_byte(char byte)
++{
++ *otg_message_head = byte;
++ if ((otg_message_head - otg_message_buf) == OTG_MESSAGE_BUF_SIZE)
++ otg_message_head = otg_message_buf;
++ else
++ otg_message_head++;
++
++}
++
++/*!
++ * otg_write_message_irq() - queue message data (interrupt version)
++ *
++ * Attempt to write message data into ring buffer, return amount
++ * of data actually written.
++ *
++ * @param buf - pointer to data
++ * @param size - amount of available data
++ * @return number of bytes that where not written.
++ */
++int otg_write_message_irq (char *buf, int size)
++{
++ struct pcd_instance *pcd = NULL;
++ struct usbd_bus_instance *bus = NULL;
++
++ pcd = (struct pcd_instance *)mesg_otg_instance->pcd;
++ if (pcd)
++ bus = pcd->bus;
++
++ if (size >= (OTG_MESSAGE_BUF_SIZE - 2))
++ return size;
++
++ while (otg_space_avail() < (size + 1))
++ otg_get_byte();
++
++
++ /* copy, note that we don't have to test for space as we have
++ * already ensured that there is enough room for all of the data
++ */
++ while (size--)
++ otg_put_byte(*buf++);
++
++ //otg_put_byte('\n');
++
++ return size;
++}
++
++/*!
++ * otg_write_message() - queue message data
++ *
++ * Attempt to write message data into ring buffer, return amount
++ * of data actually written.
++ *
++ * @param buf - pointer to data
++ * @param size - amount of available data
++ * @return number of bytes that where not written.
++ */
++int otg_write_message (char *buf, int size)
++{
++ int rc;
++ unsigned long flags;
++ local_irq_save (flags);
++ rc = otg_write_message_irq(buf, size);
++ local_irq_restore (flags);
++ return size;
++}
++
++/*!
++ * otg_read_message() - get queued message data
++ *
++ * @param buf - pointer to data
++ * @param size - amount of available data
++ * @return the number of bytes read.
++ */
++int otg_read_message(char *buf, int size)
++{
++ int count = 0;
++ unsigned long flags;
++
++ local_irq_save (flags);
++
++ /* Copy bytes to the buffer while there is data available and space
++ * to put it in the buffer
++ */
++ for ( ; otg_data_avail() && size--; count++)
++ BREAK_IF((*buf++ = otg_get_byte()) == '\n');
++
++ local_irq_restore (flags);
++ return count;
++}
++
++/*!
++ * otg_data_queued() - return amount of data currently queued
++ *
++ * @return Amount of data currently queued in mesage ring buffer.
++ */
++int otg_data_queued(void)
++{
++ int count;
++ unsigned long flags;
++ local_irq_save (flags);
++ count = otg_data_avail();
++ local_irq_restore (flags);
++ //printk(KERN_INFO"%s: count: %d\n", __FUNCTION__, count);
++ return count;
++}
++
++
++/*!
++ * otg_message_init() - initialize
++ * @param otg OTG instance
++ */
++int otg_message_init(struct otg_instance *otg)
++{
++ struct proc_dir_entry *message = NULL;
++ otg_message_buf = otg_message_head = otg_message_tail = NULL;
++ THROW_UNLESS((otg_message_buf = CKMALLOC(OTG_MESSAGE_BUF_SIZE + 16, GFP_KERNEL)), error);
++ otg_message_head = otg_message_tail = otg_message_buf ;
++
++ mesg_otg_instance = otg;
++ CATCH(error) {
++ #if defined(OTG_LINUX)
++ printk(KERN_ERR"%s: creating /proc/otg_message failed\n", __FUNCTION__);
++ #endif /* defined(OTG_LINUX) */
++ #if defined(OTG_WINCE)
++ DEBUGMSG(ZONE_INIT, (_T("otg_message_init: creating //proc//otg_message failed\n")) );
++ #endif /* defined(OTG_LINUX) */
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*!
++ * otg_message_exit() - exit
++ */
++void otg_message_exit(void)
++{
++ mesg_otg_instance = NULL;
++ if (otg_message_buf)
++ LKFREE(otg_message_buf);
++ otg_message_buf = otg_message_head = otg_message_tail = NULL;
++}
++
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
++/*!
++ * otg_mesg_get_status_update() - get status update
++ * @param status_update
++ */
++void otg_mesg_get_status_update(struct otg_status_update *status_update)
++{
++
++ TRACE_MSG0(CORE, "--");
++ status_update->state = mesg_otg_instance->state;
++ status_update->meta = mesg_otg_instance->current_outputs->meta;
++ status_update->inputs = mesg_otg_instance->current_inputs;
++ status_update->outputs = mesg_otg_instance->outputs;
++ status_update->capabilities = otg_ocd_ops ? otg_ocd_ops->capabilities : 0;
++
++ strncpy(status_update->fw_name, otg_firmware_loaded->fw_name, OTGADMIN_MAXSTR);
++ strncpy(status_update->state_name, otg_get_state_name(mesg_otg_instance->state), OTGADMIN_MAXSTR);
++
++ if (mesg_otg_instance->function_name)
++ strncpy(status_update->function_name, mesg_otg_instance->function_name, OTGADMIN_MAXSTR);
++
++ TRACE_MSG5(CORE, "state: %02x meta: %02x inputs: %08x outputs: %04x",
++ status_update->state, status_update->meta, status_update->inputs,
++ status_update->outputs, status_update->capabilities);
++}
++
++
++/*!
++ * otg_mesg_get_firmware_info() - get firmware info
++ * @param firmware_info
++ */
++void otg_mesg_get_firmware_info(struct otg_firmware_info *firmware_info)
++{
++ memset(firmware_info, 0, sizeof(firmware_info));
++ // XXX irq lock
++
++ firmware_info->number_of_states = otg_firmware_loaded->number_of_states;
++ firmware_info->number_of_tests = otg_firmware_loaded->number_of_tests;
++ memcpy(&firmware_info->fw_name, otg_firmware_loaded->fw_name, sizeof(firmware_info->fw_name));
++
++}
++
++/*!
++ * otg_mesg_set_firmware_info() - set firmware info
++ * @param firmware_info
++ */
++int otg_mesg_set_firmware_info(struct otg_firmware_info *firmware_info)
++{
++
++ if (otg_firmware_loading) {
++
++ if ( (otg_firmware_loading->number_of_states == firmware_info->number_of_states) &&
++ (otg_firmware_loading->number_of_tests == firmware_info->number_of_tests)
++ ) {
++ TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: loaded");
++ otg_firmware_loaded = otg_firmware_loading;
++ otg_firmware_loading = NULL;
++ return 0;
++ }
++ else {
++ TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: abandoned");
++ LKFREE(otg_firmware_loading->otg_states);
++ LKFREE(otg_firmware_loading->otg_tests);
++ LKFREE(otg_firmware_loading);
++ return -EINVAL;
++ }
++ }
++
++ TRACE_MSG2(CORE, "OTGADMIN_SET_INFO: otg_firmware_loaded: %x otg_firmware_orig: %x",
++ otg_firmware_loaded, otg_firmware_orig);
++ if (otg_firmware_loaded && (otg_firmware_loaded != otg_firmware_orig)) {
++ LKFREE(otg_firmware_loaded->otg_states);
++ LKFREE(otg_firmware_loaded->otg_tests);
++ LKFREE(otg_firmware_loaded);
++ otg_firmware_loaded = otg_firmware_orig;
++ TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: unloaded");
++ }
++ if (firmware_info->number_of_states && firmware_info->number_of_tests) {
++ int size;
++ otg_firmware_loaded = NULL;
++ TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: setup");
++ THROW_UNLESS((otg_firmware_loading = CKMALLOC(sizeof(struct otg_firmware), GFP_KERNEL)), error);
++ size = sizeof(struct otg_state) * firmware_info->number_of_states;
++ THROW_UNLESS((otg_firmware_loading->otg_states = CKMALLOC(size, GFP_KERNEL)), error);
++ size = sizeof(struct otg_test) * firmware_info->number_of_tests;
++ THROW_UNLESS((otg_firmware_loading->otg_tests = CKMALLOC(size, GFP_KERNEL)), error);
++
++ otg_firmware_loading->number_of_states = firmware_info->number_of_states;
++ otg_firmware_loading->number_of_tests = firmware_info->number_of_tests;
++ memcpy(otg_firmware_loading->fw_name, &firmware_info->fw_name, sizeof(firmware_info->fw_name));
++
++ CATCH(error) {
++ TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: setup error");
++ if (otg_firmware_loading) {
++ if (otg_firmware_loading->otg_states) LKFREE(otg_firmware_loading->otg_states);
++ if (otg_firmware_loading->otg_tests) LKFREE(otg_firmware_loading->otg_tests);
++ LKFREE(otg_firmware_loading);
++ return -EINVAL;
++ }
++ }
++
++ }
++ return 0;
++}
++
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++
+diff -uNr linux/drivers/no-otg/otgcore/otg-trace-l24.c linux/drivers/otg/otgcore/otg-trace-l24.c
+--- linux/drivers/no-otg/otgcore/otg-trace-l24.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-trace-l24.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,174 @@
++/*
++ * otg/otgcore/otg-trace-l24.c
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++/*!
++ * @file otg/otgcore/otg-trace-l24.c
++ * @brief OTG Core Linux Debug Trace Facility
++ *
++ * This allows access to the OTG Core Trace via /proc/trace_otg. Each time
++ * this file is opened and read it will contain a snapshot of the most
++ * recent trace messages.
++ *
++ * Reading the trace resets it, the next read will open a new snapshot.
++ *
++ * N.B. There is no protection from multiple reads.
++ *
++ * N.B. This is for debugging and is not normally enabled for production software.
++ *
++ * @ingroup OTGCore
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++#include <linux/vmalloc.h>
++#include <stdarg.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
++
++DECLARE_MUTEX(otg_trace_sem_l24);
++
++
++/* *
++ * otg_trace_proc_read_l24 - implement proc file system read.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Standard proc file system read function.
++ */
++static ssize_t otg_trace_proc_read_l24 (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++ int oindex;
++ int rc;
++
++ u64 ticks = 0;
++
++ unsigned char *cp;
++ int skip = 0;
++
++ otg_trace_t px;
++ otg_trace_t ox;
++ otg_trace_t vx;
++ otg_trace_t *o, *p;
++
++ RETURN_ENOMEM_IF (!(page = GET_KERNEL_PAGE()));
++
++ _MOD_INC_USE_COUNT;
++
++ // Lock out tag changes while reading
++ DOWN(&otg_trace_sem_l24);
++ len = otg_trace_proc_read((char *)page, count, (int *)pos);
++
++ if (len > count)
++ len = -EINVAL;
++
++ else if (len > 0 && copy_to_user (buf, (char *) page, len))
++ len = -EFAULT;
++
++ free_page (page);
++
++ UP(&otg_trace_sem_l24);
++ free_page (page);
++ _MOD_DEC_USE_COUNT;
++ return len;
++}
++
++#define MAX_TRACE_CMD_LEN 64
++/* *
++ * otg_trace_proc_write_l24 - implement proc file system write.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Proc file system write function.
++ */
++static ssize_t otg_trace_proc_write_l24 (struct file *file, const char *buf, size_t count, loff_t * pos)
++{
++ char command[MAX_TRACE_CMD_LEN+1];
++ size_t l = MIN(count, MAX_TRACE_CMD_LEN);
++
++ RETURN_ZERO_UNLESS(count);
++ RETURN_EINVAL_IF (copy_from_user (command, buf, l));
++
++
++ RETURN_EINVAL_IF(copy_from_user (command, buf, l));
++
++ return otg_trace_proc_write(command, l, (int *)pos);
++#if 0
++ else {
++ n -= l;
++ while (n > 0) {
++ if (copy_from_user (&c, buf + (count - n), 1)) {
++ count = -EFAULT;
++ break;
++ }
++ n -= 1;
++ }
++ // Terminate command[]
++ if (l > 0 && command[l-1] == '\n') {
++ l -= 1;
++ }
++ command[l] = 0;
++ }
++#endif
++}
++
++/* Module init ************************************************************** */
++
++
++
++static struct file_operations otg_trace_proc_operations_functions = {
++ read: otg_trace_proc_read_l24,
++ write: otg_trace_proc_write_l24,
++};
++
++/*! otg_trace_init_l24
++ *
++ * Return non-zero if not successful.
++ */
++int otg_trace_init_l24 (void)
++{
++ struct proc_dir_entry *p;
++
++ // create proc filesystem entries
++ if ((p = create_proc_entry ("trace_otg", 0, 0)) == NULL)
++ printk(KERN_INFO"%s PROC FS failed\n", "trace_otg");
++ else
++ p->proc_fops = &otg_trace_proc_operations_functions;
++
++ return 0;
++}
++
++/*! otg_trace_exit_l24 - remove procfs entry, free trace data space.
++ */
++void otg_trace_exit_l24 (void)
++{
++ otg_trace_t *p;
++ unsigned long flags;
++ remove_proc_entry ("trace_otg", NULL);
++}
++
++#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++int otg_trace_init_l24 (void) {return 0;}
++void otg_trace_exit_l24 (void) {}
++#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++
+diff -uNr linux/drivers/no-otg/otgcore/otg-trace.c linux/drivers/otg/otgcore/otg-trace.c
+--- linux/drivers/no-otg/otgcore/otg-trace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg-trace.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,615 @@
++/*
++ * otg/otgcore/otg-trace.c
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ *
++ */
++/*!
++ * @file otg/otgcore/otg-trace.c
++ * @brief OTG Core Debug Trace Facility
++ *
++ * This implements the OTG Core Trace Facility.
++ *
++ * @ingroup OTGCore
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#if defined(OTG_LINUX)
++#include <linux/vmalloc.h>
++#include <stdarg.h>
++#endif /* defined(OTG_LINUX) */
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++
++#define STATIC static
++
++#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
++
++DECLARE_MUTEX(otg_trace_sem);
++
++static int otg_trace_exiting;
++
++#define OTG_TRACE_NAME "trace_otg"
++
++typedef struct otg_trace_snapshot {
++ int first;
++ int next;
++ int total;
++ otg_trace_t *traces;
++} otg_trace_snapshot;
++
++otg_trace_snapshot otg_snapshot1;
++otg_trace_snapshot otg_snapshot2;
++
++static otg_trace_snapshot *otg_trace_current_traces;
++static otg_trace_snapshot *otg_trace_other_traces;
++
++STATIC otg_trace_snapshot *rel_snapshot(otg_trace_snapshot *tss)
++{
++ RETURN_NULL_UNLESS(tss);
++ if (tss->traces) {
++ vfree(tss->traces);
++ tss->traces = NULL;
++ }
++ //vfree(tss);
++ return NULL;
++}
++
++STATIC void init_snapshot(otg_trace_snapshot *tss)
++{
++ tss->first = tss->next = tss->total = 0;
++ memset(tss->traces,0,sizeof(otg_trace_t) * TRACE_MAX);
++}
++
++STATIC otg_trace_snapshot *get_snapshot(otg_trace_snapshot *tss)
++{
++ //otg_trace_snapshot *tss;
++ unsigned long flags;
++ //UNLESS ((tss = vmalloc(sizeof(otg_trace_snapshot)))) {
++ // printk(KERN_ERR "Cannot allocate memory for OTG trace snapshot.\n");
++ // return NULL;
++ //}
++
++ UNLESS ((tss->traces = vmalloc(sizeof(otg_trace_t) * TRACE_MAX))) {
++ printk(KERN_ERR "Cannot allocate memory for OTG trace log.\n");
++ return rel_snapshot(tss);
++ }
++ init_snapshot(tss);
++ return tss;
++}
++
++/*! otg_trace_get_next
++ */
++STATIC otg_trace_t *otg_trace_get_next(otg_trace_snapshot *tss, otg_tag_t tag, const char *fn, otg_trace_types_t otg_trace_type, int n)
++{
++ otg_trace_t *p;
++
++ // Get the next (n) trace slots.
++
++ p = tss->traces + tss->next;
++
++ while (n-- > 0) {
++ tss->next = (tss->next + 1) & TRACE_MASK;
++ if (tss->next == tss->first) {
++ // We have wraparound, bump tss->first
++ tss->first = (tss->first + 1) & TRACE_MASK;
++ }
++ tss->total++;
++ }
++ // End of next trace slot.
++
++ otg_get_trace_info(p);
++ p->otg_trace_type = otg_trace_type;
++ p->tag = tag;
++ p->va.s.function = fn;
++
++ return p;
++}
++
++/* otg_trace_next_va
++ */
++STATIC otg_trace_t *otg_trace_next_va(otg_trace_snapshot *tss, otg_trace_t *p)
++{
++ /* Return the next trace slot in a va group.
++ No need to be atomic, just worry about wraparound. */
++ int nxt = (p - tss->traces);
++ nxt = (nxt + 1) & TRACE_MASK;
++ p = tss->traces + nxt;
++ return(p);
++}
++
++/* otg_trace_setup
++ */
++void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup)
++{
++ otg_trace_t *p;
++ otg_trace_snapshot *tss;
++ unsigned long flags;
++ local_irq_save(flags);
++ UNLESS ((tss = otg_trace_current_traces)) {
++ local_irq_restore(flags);
++ return;
++ }
++ // Reserve the trace slots.
++ UNLESS ((p = otg_trace_get_next(tss,tag,fn,otg_trace_setup_n,1))) {
++ local_irq_restore(flags);
++ return;
++ }
++ p->va_num_args = 0;
++ memcpy(&p->va.s.trace.setup, setup, sizeof(p->va.s.trace.setup) /*sizeof(struct usbd_device_request)*/);
++ local_irq_restore(flags);
++}
++
++/* otg_trace_msg
++ */
++void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...)
++{
++ int n;
++ otg_trace_t *p;
++ otg_trace_snapshot *tss;
++ unsigned long flags;
++
++ // Figure out how many trace slots we're going to need.
++ n = 1;
++ if (nargs > 1) {
++ n = 2;
++ // Too many arguments, bail.
++ RETURN_IF (nargs > (OTG_TRACE_MAX_IN_VA+1));
++ }
++
++ local_irq_save(flags);
++ UNLESS ((tss = otg_trace_current_traces)) {
++ local_irq_restore(flags);
++ return;
++ }
++ // Reserve the trace slots.
++ UNLESS((p = otg_trace_get_next(tss,tag,fn,otg_trace_msg_va_start_n,n))) {
++ local_irq_restore(flags);
++ return;
++ }
++ p->va.s.trace.msg32.msg = fmt;
++ p->va_num_args = nargs;
++ if (nargs > 0) {
++ va_list ap;
++ va_start(ap,fmt);
++ p->va.s.trace.msg32.val = va_arg(ap,u32);
++ if (--nargs > 0) {
++ // We need the next trace slot.
++ int i;
++ while (nargs >= 8) {
++ p = otg_trace_next_va(tss,p);
++ p->otg_trace_type = otg_trace_msg_va_list_n;
++ for (i = 0; i < 8; i++) p->va.l.val[i] = va_arg(ap,u32);
++ nargs -= 8;
++ }
++ p = otg_trace_next_va(tss,p);
++ p->otg_trace_type = otg_trace_msg_va_list_n;
++ for (i = 0; i < nargs; i++) p->va.l.val[i] = va_arg(ap,u32);
++ }
++ va_end(ap);
++ }
++ local_irq_restore(flags);
++}
++
++/* Proc Filesystem *************************************************************************** */
++
++/* int slot_in_data
++ */
++STATIC int slot_in_data(otg_trace_snapshot *tss, int slot)
++{
++ // Return 1 if slot is in the valid data region, 0 otherwise.
++ return (((tss->first < tss->next) && (slot >= tss->first) && (slot < tss->next)) ||
++ ((tss->first > tss->next) && ((slot < tss->next) || (slot >= tss->first))));
++
++}
++
++/*! otg_trace_read_slot
++ *
++ * Place a slot pointer in *ps (and possibly *pv), with the older entry (if any) in *po.
++ * Return: -1 at end of data
++ * 0 if not a valid enty
++ * 1 if entry valid but no older valid entry
++ * 2 if both entry and older are valid.
++ */
++STATIC int otg_trace_read_slot(otg_trace_snapshot *tss, int index, otg_trace_t **ps, otg_trace_t **po)
++{
++ int res;
++ int previous;
++ otg_trace_t *s,*o;
++
++ *ps = *po = NULL;
++ index = (tss->first + index) & TRACE_MASK;
++ // Are we at the end of the data?
++ if (!slot_in_data(tss,index)) {
++ // End of data.
++ return(-1);
++ }
++ /* Nope, there's data to show. */
++ s = tss->traces + index;
++ if (!s->tag ||
++ s->otg_trace_type == otg_trace_msg_invalid_n ||
++ s->otg_trace_type == otg_trace_msg_va_list_n) {
++ /* Ignore this slot, it's not valid, or is part
++ of a previously processed varargs. */
++ return(0);
++ }
++ *ps = s;
++ res = 1;
++ // Is there a previous event (for "ticks" calculation)?
++ previous = (index - 1) & TRACE_MASK;
++ if (previous != tss->next && tss->total > 1) {
++ // There is a valid previous event.
++ res = 2;
++ o = tss->traces + previous;
++ /* If the previous event was a varargs event, we want
++ a copy of the first slot, not the last. */
++ while (o->otg_trace_type == otg_trace_msg_va_list_n) {
++ previous = (previous - 1) & TRACE_MASK;
++ if (previous == tss->next) {
++ res = 1;
++ o = NULL;
++ break;
++ }
++ o = tss->traces + previous;
++ }
++ *po = o;
++ }
++ return(res);
++}
++
++
++/*! otg_trace_proc_read - implement proc file system read.
++ *
++ * Standard proc file system read function.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ */
++int otg_trace_proc_read(char *page, int count, int * pos)
++{
++ int len = 0;
++ int index;
++ int oindex;
++ int rc;
++
++ u64 ticks = 0;
++
++ unsigned char *cp;
++ int skip = 0;
++
++ otg_trace_t *o;
++ otg_trace_t *s;
++ otg_trace_snapshot *tss;
++
++ DOWN(&otg_trace_sem);
++
++ /* Grab the current snapshot, and replace it with the other. This
++ * needs to be atomic WRT otg_trace_msg() calls.
++ */
++ UNLESS (*pos) {
++ unsigned long flags;
++ tss = otg_trace_other_traces;
++ init_snapshot(tss); // clear previous
++ local_irq_save(flags);
++ otg_trace_other_traces = otg_trace_current_traces; // swap snapshots
++ otg_trace_current_traces = tss;
++ local_irq_restore(flags);
++ }
++
++ tss = otg_trace_other_traces;
++
++ /* Get the index of the entry to read - this needs to be atomic WRT tag operations.
++ */
++ s = o = NULL;
++ oindex = index = (*pos)++;
++ do {
++ rc = otg_trace_read_slot(tss,index,&s,&o);
++ switch (rc) {
++ case -1: // End of data.
++ UP(&otg_trace_sem);
++ return(0);
++
++ case 0: // Invalid slot, skip it and try the next.
++ index = (*pos)++;
++ break;
++
++ case 1: // s valid, o NULL
++ case 2: // s and o valid
++ break;
++ }
++ } while (rc == 0);
++
++ len = 0;
++
++ UNLESS (oindex)
++ len += sprintf((char *) page + len, "Tag Index Ints Framenum Ticks\n");
++
++ /* If there is a previous trace event, we want to calculate how many
++ * ticks have elapsed siince it happened. Unfortunately, determining
++ * if there _is_ a previous event isn't obvious, since we have to watch
++ * out for startup, varargs and wraparound.
++ */
++ if (o) {
++
++ ticks = otg_tmr_elapsed(&s->va.s.ticks, &o->va.s.ticks);
++
++ if ((o->va.s.interrupts != s->va.s.interrupts) || (o->tag != s->tag) || (o->in_interrupt != s->in_interrupt))
++ skip++;
++ }
++
++ len += sprintf((char *) page + len, "%s%02x %c %8u %8d ", skip?"\n":"",
++ s->tag, s->id_gnd ? 'A' : 'B', index, s->va.s.interrupts);
++
++ len += sprintf((char *) page + len, "%03x ", s->va.s.framenum);
++
++ if (ticks < 10000)
++ len += sprintf((char *) page + len, "%8duS", ticks);
++ else if (ticks < 10000000)
++ len += sprintf((char *) page + len, "%8dmS", ticks >> 10);
++ else
++ len += sprintf((char *) page + len, "%8dS ", ticks >> 20);
++
++ len += sprintf((char *) page + len, " %s ", s->in_interrupt ? "--" : "==");
++ len += sprintf((char *) page + len, "%-24s: ",s->va.s.function);
++
++ switch (s->otg_trace_type) {
++ case otg_trace_msg_invalid_n:
++ case otg_trace_msg_va_list_n:
++ len += sprintf((char *) page + len, " -- N/A");
++ break;
++
++ case otg_trace_msg_va_start_n:
++ if (s->va_num_args <= 1)
++ len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val);
++
++ else {
++ otg_trace_t *v = otg_trace_next_va(tss,s);
++ len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val,
++ v->va.l.val[0], v->va.l.val[1], v->va.l.val[2], v->va.l.val[3],
++ v->va.l.val[4], v->va.l.val[5], v->va.l.val[6]);
++ }
++ break;
++
++ case otg_trace_msg_n:
++ len += sprintf((char *) page + len, s->va.s.trace.msg.msg);
++ break;
++
++ case otg_trace_msg32_n:
++ len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val);
++ break;
++
++ case otg_trace_msg16_n:
++ len += sprintf((char *) page + len, s->va.s.trace.msg16.msg, s->va.s.trace.msg16.val0, s->va.s.trace.msg16.val1);
++ break;
++
++ case otg_trace_msg8_n:
++ len += sprintf((char *) page + len, s->va.s.trace.msg8.msg,
++ s->va.s.trace.msg8.val0, s->va.s.trace.msg8.val1, s->va.s.trace.msg8.val2,
++ s->va.s.trace.msg8.val3);
++ break;
++
++ case otg_trace_setup_n:
++ cp = (unsigned char *)&s->va.s.trace.setup;
++ len += sprintf((char *) page + len,
++ " -- request [%02x %02x %02x %02x %02x %02x %02x %02x]",
++ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
++ break;
++ }
++ len += sprintf((char *) page + len, "\n");
++
++ UP(&otg_trace_sem);
++ return len;
++}
++
++/*! otg_trace_proc_write - implement proc file system write.
++ * @file
++ * @buf
++ * @count
++ * @pos
++ *
++ * Proc file system write function.
++ */
++int otg_trace_proc_write (const char *buf, int count, int * pos)
++{
++#define MAX_TRACE_CMD_LEN 64
++ char command[MAX_TRACE_CMD_LEN+1];
++ size_t n = count;
++ size_t l;
++ char c;
++
++ if (n > 0) {
++ l = MIN(n,MAX_TRACE_CMD_LEN);
++ if (copy_from_user (command, buf, l))
++ count = -EFAULT;
++ else {
++ n -= l;
++ while (n > 0) {
++ if (copy_from_user (&c, buf + (count - n), 1)) {
++ count = -EFAULT;
++ break;
++ }
++ n -= 1;
++ }
++ // Terminate command[]
++ if (l > 0 && command[l-1] == '\n') {
++ l -= 1;
++ }
++ command[l] = 0;
++ }
++ }
++
++ if (0 >= count) {
++ printk(KERN_INFO"%s: count <= 0 %d\n", __FUNCTION__, count);
++ return count;
++ }
++
++
++ return count;
++}
++
++static u32 otg_tags_mask = 0x0;
++extern void otg_trace_exit (void);
++
++/*! otg_trace_obtain_tag(void)
++ */
++otg_tag_t otg_trace_obtain_tag(void)
++{
++ /* Return the next unused tag value [1..32] if one is available,
++ * return 0 if none is available.
++ */
++ otg_tag_t tag = 0;
++ DOWN(&otg_trace_sem);
++ if (otg_tags_mask == 0xffffffff || otg_trace_exiting) {
++ // They're all in use.
++ UP(&otg_trace_sem);
++ return tag;
++ }
++ if (otg_tags_mask != 0x00000000) {
++ // 2nd or later tag, search for an unused one
++ while (otg_tags_mask & (0x1 << tag)) {
++ tag += 1;
++ }
++ }
++
++ // Successful 1st or later tag.
++ otg_tags_mask |= 0x1 << tag;
++ UP(&otg_trace_sem);
++ return tag + 1;
++}
++
++/*! otg_trace_invalidate_tag(otg_tag_t tag)
++ */
++otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag)
++{
++ otg_trace_t *p,*e;
++ otg_trace_snapshot *css,*oss;
++ unsigned long flags;
++
++ // Nothing to do
++ RETURN_ZERO_IF ((0 >= tag) || (tag > 32));
++
++ // Grab a local copy of the snapshot pointers.
++ local_irq_save(flags);
++ css = otg_trace_current_traces;
++ oss = otg_trace_other_traces;
++ local_irq_restore(flags);
++
++
++ // Run through all the trace messages, and invalidate any with the given tag.
++
++ DOWN(&otg_trace_sem);
++ if (css)
++ for (e = TRACE_MAX + (p = css->traces); p < e; p++) {
++ if (p->tag == tag) {
++ p->otg_trace_type = otg_trace_msg_invalid_n;
++ p->tag = 0;
++ }
++ }
++ if (oss)
++ for (e = TRACE_MAX + (p = oss->traces); p < e; p++) {
++ if (p->tag == tag) {
++ p->otg_trace_type = otg_trace_msg_invalid_n;
++ p->tag = 0;
++ }
++ }
++
++ // Turn off the tag
++ otg_tags_mask &= ~(0x1 << (tag-1));
++ if (otg_tags_mask == 0x00000000) { /* otg_trace_exit (); */ }
++ UP(&otg_trace_sem);
++ return 0;
++}
++
++
++
++/* Module init ************************************************************** */
++
++#define OT otg_trace_init_test
++otg_tag_t OT;
++
++/*! otg_trace_init
++ *
++ * Return non-zero if not successful.
++ */
++int otg_trace_init (void)
++{
++ otg_trace_exiting = 0;
++ otg_trace_current_traces = otg_trace_other_traces = NULL;
++ UNLESS ((otg_trace_current_traces = get_snapshot(&otg_snapshot1)) &&
++ (otg_trace_other_traces = get_snapshot(&otg_snapshot2)))
++ {
++ printk(KERN_ERR"%s: malloc failed (2x) %d\n", __FUNCTION__, sizeof(otg_trace_t) * TRACE_MAX);
++ otg_trace_current_traces = rel_snapshot(otg_trace_current_traces);
++ otg_trace_other_traces = rel_snapshot(otg_trace_other_traces);
++ return -ENOMEM;
++ }
++ OT = otg_trace_obtain_tag();
++ RETURN_ENOMEM_IF(!OT);
++ TRACE_MSG0(OT,"--");
++ return 0;
++}
++
++/*! otg_trace_exit - remove procfs entry, free trace data space.
++ */
++void otg_trace_exit (void)
++{
++ otg_trace_t *p;
++ otg_tag_t tag;
++
++ unsigned long flags;
++ otg_trace_snapshot *c,*o;
++
++ otg_trace_invalidate_tag(OT);
++ otg_trace_exiting = 1;
++
++ local_irq_save (flags);
++
++ /* Look for any outstanding tags. */
++ for (tag = 32; otg_tags_mask && tag > 0; tag--)
++ if (otg_tags_mask & (0x1 << (tag-1)))
++ otg_trace_invalidate_tag(tag);
++
++ c = otg_trace_current_traces;
++ o = otg_trace_other_traces;
++ otg_trace_current_traces = otg_trace_other_traces = NULL;
++ local_irq_restore (flags);
++
++ c = rel_snapshot(c);
++ o = rel_snapshot(o);
++}
++
++#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++int otg_trace_init (void) {return 0;}
++void otg_trace_exit (void) {}
++otg_tag_t otg_trace_obtain_tag(void) { return 0; }
++void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup) { }
++void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...) { }
++otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag) { return 0; }
++#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
++
++OTG_EXPORT_SYMBOL(otg_trace_setup);
++OTG_EXPORT_SYMBOL(otg_trace_msg);
++OTG_EXPORT_SYMBOL(otg_trace_obtain_tag);
++OTG_EXPORT_SYMBOL(otg_trace_invalidate_tag);
++
++#if 0
++// These are only needed when debugging the trace code itself.
++OTG_EXPORT_SYMBOL(otg_trace_get_next);
++OTG_EXPORT_SYMBOL(otg_trace_next_va);
++OTG_EXPORT_SYMBOL(slot_in_data);
++OTG_EXPORT_SYMBOL(otg_trace_read_slot);
++OTG_EXPORT_SYMBOL(otg_trace_proc_read);
++#endif
++
+diff -uNr linux/drivers/no-otg/otgcore/otg.c linux/drivers/otg/otgcore/otg.c
+--- linux/drivers/no-otg/otgcore/otg.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/otg.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,936 @@
++/*
++ * otg/otgcore/otg.c - OTG state machine
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/otg.c
++ * @brief OTG Core State Machine Event Processing
++ *
++ * The OTG State Machine receives "input" information passed to it
++ * from the other drivers (pcd, tcd, hcd and ocd) that describe what
++ * is happening.
++ *
++ * The State Machine uses the inputs to move from state to state. Each
++ * state defines four things:
++ *
++ * 1. Reset - what inputs to set or reset on entry to the state.
++ *
++ * 2. Outputs - what output functions to call to set or reset.
++ *
++ * 3. Timeout - an optional timeout value to set
++ *
++ * 4. Tests - a series of tests that allow the state machine to move to
++ * new states based on current or new inputs.
++ *
++ * @ingroup OTGCore
++ */
++#ifndef OTG_REGRESS
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-tcd.h>
++#include <otg/otg-hcd.h>
++#include <otg/otg-pcd.h>
++#include <otg/otg-ocd.h>
++
++
++struct hcd_ops *otg_hcd_ops;
++struct ocd_ops *otg_ocd_ops;
++struct pcd_ops *otg_pcd_ops;
++struct tcd_ops *otg_tcd_ops;
++struct usbd_ops *otg_usbd_ops;
++
++extern struct otg_instance otg_instance_private;
++extern struct hcd_instance hcd_instance_private;
++extern struct ocd_instance ocd_instance_private;
++extern struct pcd_instance pcd_instance_private;
++extern struct tcd_instance tcd_instance_private;
++
++#if 0
++/* otg_vbus - return vbus status
++ *
++ * XXX Should we default to set or reset if there is no vbus function
++ */
++int otg_vbus(struct otg_instance *otg)
++{
++ TRACE_MSG2(CORE, "otg_tcd_ops: %p vbus: %p", otg_tcd_ops, otg_tcd_ops ? otg_tcd_ops->vbus : NULL);
++ return (otg_tcd_ops && otg_tcd_ops->vbus) ? otg_tcd_ops->vbus(otg) : 1;
++}
++#endif
++
++#if defined (OTG_WINCE)
++#define TRACE_SM_CURRENT(t, m, o) \
++
++#else
++#define TRACE_SM_CURRENT(t, m, o) \
++ TRACE_MSG5(t, "SM_CURRENT: RESET: %08x SET: %08x %s (%s) %s",\
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs), \
++ o->current_outputs->name, \
++ o->previous_outputs->name, \
++ m \
++ );
++#endif //OTG_WINCE
++#define TRACE_SM_CHANGE(t, m, o) \
++ TRACE_MSG5(t, "SM_CHANGE: RESET: %08x SET: %08x %s (%s) %s",\
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs), \
++ o->current_outputs->name, \
++ o->previous_outputs->name, \
++ m \
++ );
++
++#define TRACE_SM_NEW(t, m, o) \
++ TRACE_MSG5(t, "SM_NEW: RESET: %08x SET: %08x %s (%s) %s",\
++ (u32)(~o->current_inputs), \
++ (u32)(o->current_inputs), \
++ o->current_outputs->name, \
++ o->previous_outputs->name, \
++ m \
++ );
++
++
++#define TRACE_SM_INPUTS(t, m, u, c) \
++ TRACE_MSG4(t, "SM_INPUTS: RESET: %08x SET: %08x CUR: %08x %s",\
++ (u32)(u >> 32), \
++ (u32)(u & 0xffffffff), \
++ c, \
++ m \
++ )
++
++#endif
++
++
++
++DECLARE_MUTEX (otg_sem);
++
++/*!
++ * Output change lookup table - this maps the current output and the desired
++ * output to what should be done. This is just so that we don't redo changes,
++ * if the output does not change we do not want to re-call the output function
++ */
++u8 otg_output_lookup[4][4] = {
++ /* NC SET RESET PULSE, <--- current/ new */
++ { NC, NC, NC, PULSE, }, /* NC */
++ { SET, NC, SET, PULSE, }, /* SET */
++ { RESET, RESET, NC, PULSE, }, /* RESET */
++ { PULSE, PULSE, PULSE, PULSE, }, /* UNKNOWN */
++};
++
++
++/*!
++ * otg_new() - check OTG new inputs and select new state to be in
++ *
++ * This is used by the OTG event handler to see if the state should
++ * change based on the current input values.
++ *
++ * @param otg pointer to the otg instance.
++ * @return either the next OTG state or invalid_state if no change.
++ */
++static int otg_new(struct otg_instance *otg)
++{
++ int state = otg->state;
++ struct otg_test *otg_test = otg_firmware_loaded ? otg_firmware_loaded->otg_tests : NULL;
++ u64 input_mask = ((u64)otg->current_inputs) | ((u64)(~otg->current_inputs) << 32); // get a copy of current inputs
++
++ UNLESS(otg_test) return invalid_state;
++
++ TRACE_MSG3(CORE, "OTG_NEW: %s inputs: %08x %08x", otg_get_state_name(state),
++ (u32)(input_mask>>32&0xffffffff), (u32)(input_mask&0xffffffff));
++
++ /* iterate across the otg inputs table, for each entry that matches the current
++ * state, test the input_mask to see if a state transition is required.
++ */
++ for (; otg_test->target != invalid_state; otg_test++) {
++
++ u64 test1 = otg_test->test1;
++ u64 test2 = otg_test->test2;
++ u64 test3 = otg_test->test3;
++
++ CONTINUE_UNLESS(otg_test->state == state); // skip states that don't match
++
++
++ TRACE_MSG7(CORE, "OTG_NEW: %s (%s, %d) test1: %08x %08x test2 %08x %08x",
++ otg_get_state_name(otg_test->state),
++ otg_get_state_name(otg_test->target),
++ otg_test->test,
++ (u32)(test1>>32&0xffffffff), (u32)(test1&0xffffffff),
++ (u32)(test2>>32&0xffffffff), (u32)(test2&0xffffffff)
++ );
++
++ /* the otg inputs table has multiple masks that define between multiple tests. Each
++ * test is a simple OR to check if specific inputs are present.
++ */
++ CONTINUE_UNLESS (
++ (!otg_test->test1 || ((test1 = otg_test->test1 & input_mask))) &&
++ (!otg_test->test2 || ((test2 = otg_test->test2 & input_mask))) &&
++ (!otg_test->test3 || ((test3 = otg_test->test3 & input_mask))) /*&&
++ (!otg_test->test4 || (otg_test->test4 & input_mask)) */ );
++
++ TRACE_MSG7(CORE, "OTG_NEW: GOTO %s test1: %08x %08x test2 %08x %08x test3 %08x %08x",
++ otg_get_state_name(otg_test->target),
++ (u32)(test1>>32&0xffffffff), (u32)(test1&0xffffffff),
++ (u32)(test2>>32&0xffffffff), (u32)(test2&0xffffffff),
++ (u32)(test3>>32&0xffff), (u32)(test3&0xffff)
++ );
++
++ return otg_test->target;
++ }
++ return invalid_state;
++}
++
++char mbuf[96];
++
++/*!
++ * otg_write_state_message_irq() -
++ *
++ * Send a message to the otg management application.
++ *
++ * @param msg
++ * @param reset
++ * @param inputs
++ */
++void otg_write_state_message_irq(char *msg, u64 reset, u32 inputs)
++{
++ sprintf(mbuf, "State: %s reset: %08x set: %08x inputs: %08x ", msg, (u32)(reset>>32), (u32)(reset&0xffffffff), inputs);
++ mbuf[95] = '\0';
++ otg_message(mbuf);
++}
++
++/*!
++ * otg_write_output_message_irq() -
++ *
++ * Send a message to the otg management application.
++ *
++ * @param msg
++ * @param val
++ */
++void otg_write_output_message_irq(char *msg, int val)
++{
++ strcpy(mbuf, "Output: ");
++ strncat(mbuf, msg, 64 - strlen(mbuf));
++ if (val == 2) strncat(mbuf, "/", 64 - strlen(mbuf));
++ mbuf[95] = '\0';
++ otg_message(mbuf);
++}
++
++/*!
++ * otg_write_timer_message_irq() -
++ *
++ * Send a message to the otg management application.
++ *
++ * @param msg
++ * @param val
++ */
++void otg_write_timer_message_irq(char *msg, int val)
++{
++ if (val < 10000)
++ sprintf(mbuf, "Timer: %s %d uS %u", msg, val, otg_tmr_ticks());
++ else if (val < 10000000)
++ //sprintf(time_buf, " %d mS\n", ticks / 1000);
++ sprintf(mbuf, "Timer: %s %d mS %u", msg, val >> 10, otg_tmr_ticks());
++ else
++ //sprintf(time_buf, " %d S\n", ticks / 1000000);
++ sprintf(mbuf, "Timer: %s %d S %u", msg, val >> 20, otg_tmr_ticks());
++
++ mbuf[95] = '\0';
++ otg_message(mbuf);
++}
++
++/*!
++ * otg_write_info_message_irq() -
++ *
++ * Send a message to the otg management application.
++ *
++ * @param msg
++ */
++void otg_write_info_message(char *msg)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ sprintf(mbuf, "Info: %s", msg);
++ mbuf[95] = '\0';
++ otg_message(mbuf);
++ local_irq_restore (flags);
++}
++
++/*!
++ * otg_write_reset_message_irq() -
++ *
++ * Send a message to the otg management application.
++ *
++ * @param msg
++ * @param val
++ */
++void otg_write_reset_message(char *msg, int val)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ sprintf(mbuf, "State: %s reset: %x", msg, val);
++ mbuf[95] = '\0';
++ otg_message(mbuf);
++ local_irq_restore (flags);
++}
++
++OTG_EXPORT_SYMBOL(otg_write_info_message);
++
++char otg_change_names[4] = {
++ '_', ' ', '/', '#',
++};
++
++/*!
++ * otg_do_event_irq() - process OTG events and determine OTG outputs to reflect new state
++ *
++ * This function is passed a mask with changed input values. This
++ * is passed to the otg_new() function to see if the state should
++ * change. If it changes then the output functions required for
++ * the new state are called.
++ *
++ * @param otg pointer to the otg instance.
++ * @param inputs input mask
++ * @param tag trace tag to use for tracing
++ * @param msg message for tracing
++ * @return non-zero if state changed.
++ */
++static int otg_do_event_irq(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
++{
++ u32 current_inputs = otg->current_inputs;
++ int current_state = otg->state;
++ u32 inputs_set = (u32)(inputs & 0xffffffff); // get changed inputs that SET something
++ u32 inputs_reset = (u32) (inputs >> 32); // get changed inputs that RESET something
++ int target;
++
++ RETURN_ZERO_UNLESS(otg && inputs);;
++ TRACE_SM_INPUTS(tag, msg, inputs, current_inputs);
++
++ /* Special Overrides - These are special tests that satisfy specific injunctions from the
++ * OTG Specification.
++ */
++ if (inputs_set & inputs_reset) { // verify that there is no overlap between SET and RESET masks
++ TRACE_MSG1(CORE, "OTG_EVENT: ERROR attempting to set and reset the same input: %08x", inputs_set & inputs_reset);
++ return 0;
++ }
++ /* don't allow bus_req and bus_drop to be set at the same time
++ */
++ if ((inputs_set & (bus_req | bus_drop)) == (bus_req | bus_drop) ) {
++ TRACE_MSG2(CORE, "OTG_EVENT: ERROR attempting to set both bus_req and bus_drop: %08x %08x",
++ inputs_set, (bus_req | bus_drop));
++ return 0;
++ }
++ /* set bus_drop_ if bus_req, set bus_req_ if bus_drop
++ */
++ if (inputs_set & bus_req) {
++ inputs |= bus_drop_;
++ TRACE_MSG1(CORE, "OTG_EVENT: forcing bus_drop/: %08x", inputs_set);
++ }
++ if (inputs_set & bus_drop) {
++ inputs |= bus_req_;
++ TRACE_MSG1(CORE, "OTG_EVENT: forcing bus_req/: %08x", inputs_set);
++ }
++
++ otg->current_inputs &= ~inputs_reset;
++ otg->current_inputs |= inputs_set;
++ TRACE_MSG3(CORE, "OTG_EVENT: reset: %08x set: %08x inputs: %08x", inputs_reset, inputs_set, otg->current_inputs);
++
++ TRACE_SM_CHANGE(tag, msg, otg);
++
++ RETURN_ZERO_IF(otg->active);
++
++ otg->active++;
++
++ /* Search the state input change table to see if we need to change to a new state.
++ * This may take several iterations.
++ */
++ while (invalid_state != (target = otg_new(otg))) {
++
++ struct otg_state *otg_state;
++ int original_state = otg->state;
++ u64 current_outputs;
++ u64 output_results;
++ u64 new_outputs;
++ int i;
++
++ /* if previous output started timer, then cancel timer before proceeding
++ */
++ if ((otg_state = otg->current_outputs) && otg_state->tmout && otg->start_timer) {
++ TRACE_MSG0(CORE, "reseting timer");
++ otg->start_timer(otg, 0);
++ }
++
++ BREAK_UNLESS(otg_firmware_loaded);
++
++ BREAK_UNLESS(target < otg_firmware_loaded->number_of_states);
++
++ otg_state = otg_firmware_loaded->otg_states + target;
++
++ BREAK_UNLESS(otg_state->name);
++
++ otg->previous = otg->state;
++ otg->state = target;
++ otg->tickcount = otg_tmr_ticks();
++
++
++ otg->previous_outputs= otg->current_outputs;
++ //otg->current_outputs = NULL;
++
++
++ /* A matching input table rule has been found, we are transitioning to a new
++ * state. We need to find the new state entry in the output table.
++ * XXX this could be a table lookup instead of linear search.
++ */
++
++ current_outputs = otg->outputs;
++ new_outputs = otg_state->outputs;
++ output_results = 0;
++
++ TRACE_SM_NEW(tag, msg, otg);
++
++ /* reset any inputs that the new state want's reset
++ */
++ otg_do_event_irq(otg, otg_state->reset | TMOUT_, tag, otg_state->name);
++
++ otg_write_state_message_irq(otg_state->name, otg_state->reset, otg->current_inputs);
++
++#if 1
++ switch (target) { /* C.f. 6.6.1.12 b_conn reset */
++ case otg_disabled:
++ otg->current_inputs = 0;
++ otg->outputs = 0;
++ break;
++ default:
++ //otg_event_irq(otg, not(b_conn), "a_host/ & a_suspend/: set b_conn/");
++ break;
++ }
++#endif
++ TRACE_MSG5(CORE, "OTG_EVENT: CALLING OUTPUT MAX:%d OUTPUTS CURRENT: %08x %08x NEW: %08x %08x",
++ MAX_OUTPUTS,
++ (u32)(current_outputs >> 32),
++ (u32)(current_outputs & 0xffffffff),
++ (u32)(new_outputs >> 32),
++ (u32)(new_outputs & 0xffffffff)
++ );
++
++ /* Iterate across the outputs bitmask, calling the appropriate functions
++ * to make required changes. The current outputs are saved and we DO NOT
++ * make calls to change output values until they change again.
++ */
++ for (i = 0; i < MAX_OUTPUTS; i++) {
++
++ u8 current_output = (u8)(current_outputs & 0x3);
++ u8 new_output = (u8)(new_outputs & 0x3);
++ u8 changed = otg_output_lookup[new_output][current_output];
++
++ output_results >>= 2;
++
++ switch (changed) {
++ case NC:
++ output_results |= ((current_outputs & 0x3) << (MAX_OUTPUTS * 2));
++ break;
++ case SET:
++ case RESET:
++ output_results |= (((u64)changed) << (MAX_OUTPUTS * 2));
++ case PULSE:
++
++
++ otg_write_output_message_irq(otg_output_names[i], changed);
++
++ //TRACE_MSG3(CORE, "OTG_EVENT: CHECKING OUTPUT %s %d %s",
++ // otg_state->name, i, otg_output_names[i]);
++
++ BREAK_UNLESS(otg->otg_output_ops[i]); // Check if we have an output routine
++
++ TRACE_MSG7(CORE, "OTG_EVENT: CALLING OUTPUT %s %d %s%c cur: %02x new: %02x chng: %02x",
++ otg_state->name, i, otg_output_names[i],
++ otg_change_names[changed&0x3],
++ current_output, new_output,
++ changed);
++
++ otg->otg_output_ops[i](otg, changed); // Output changed, call function to do it
++
++ //TRACE_MSG2(CORE, "OTG_EVENT: OUTPUT FINISED %s %s", otg_state->name, otg_output_names[i]);
++ break;
++ }
++
++ current_outputs >>= 2;
++ new_outputs >>= 2;
++ }
++
++ output_results >>= 2;
++ otg->outputs = output_results;
++ otg->current_outputs = otg_state;
++
++ //TRACE_MSG2(CORE, "OTG_EVENT: STATE: otg->current_outputs: %08x %08x",
++ // (u32)(otg->outputs & 0xffffffff), (u32)(otg->outputs >> 32));
++
++ if (((otg->outputs & pcd_en_out_set) == pcd_en_out_set) &&
++ ((otg->outputs & hcd_en_out_set) == hcd_en_out_set))
++ {
++ TRACE_MSG0(CORE, "WARNING PCD_EN and HCD_EN both set");
++ printk(KERN_INFO "%s: WARNING PCD_EN and HCD_EN both set\n", __FUNCTION__);
++ }
++
++ /* start timer?
++ */
++ CONTINUE_UNLESS(otg_state->tmout);
++ TRACE_MSG1(CORE, "setting timer: %d", otg_state->tmout);
++ if (otg->start_timer) {
++ otg_write_timer_message_irq(otg_state->name, otg_state->tmout);
++ otg->start_timer(otg, otg_state->tmout);
++ }
++ else {
++ //TRACE_MSG0(CORE, "NO TIMER");
++ otg_do_event_irq(otg, TMOUT_, CORE, otg_state->name);
++ }
++
++ }
++ //TRACE_MSG0(CORE, "finishing");
++ otg->active = 0;
++
++ if (current_state == otg->state)
++ TRACE_MSG0(CORE, "OTG_EVENT: NOT CHANGED");
++
++ otg->active = 0;
++ return 0;
++}
++
++/*!
++ * otg_write_input_message_irq() -
++
++ * @param inputs input mask
++ * @param tag trace tag to use for tracing
++ * @param msg message for tracing
++ */
++void otg_write_input_message_irq(u64 inputs, otg_tag_t tag, char *msg)
++{
++ u32 reset = (u32)(inputs >> 32);
++ u32 set = (u32) (inputs & 0xffffffff);
++
++ char buf[64];
++ //snprintf(buf, sizeof(buf), "Input: %08x %08x %s", *inputs >> 32, *inputs & 0xffffffff, msg ? msg : "NULL");
++ TRACE_MSG3(tag, "Inputs: %08x %08x %s", set, reset, msg ? msg : "NULL");
++ #ifdef OTG_WINCE
++ sprintf(buf, "Inputs: %08x %08x %s", reset, set, msg ? msg : "NULL");
++ #else /* OTG_WINCE */
++ snprintf(buf, sizeof(buf), "Inputs: %08x %08x %s", reset, set, msg ? msg : "NULL");
++ #endif /* OTG_WINCE */
++ buf[63] = '\0';
++ otg_message(buf);
++}
++
++
++/*!
++ * otg_event_input_message_irq() -
++ * @param otg pointer to the otg instance.
++ * @param inputs input mask
++ * @param tag trace tag to use for tracing
++ * @param msg message for tracing
++ * @return non-zero if state changed.
++ */
++int otg_event_irq(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
++{
++ TRACE_SM_INPUTS(tag, msg, inputs, otg->current_inputs);
++ //otg_write_input_message_irq((u32)(inputs >> 32), (u32) (inputs & 0xffffffff), tag, msg);
++ otg_write_input_message_irq(inputs, tag, msg);
++ return otg_do_event_irq(otg, inputs, tag, msg);
++}
++
++/*!
++ * otg_event() -
++ * @param otg pointer to the otg instance.
++ * @param inputs input mask
++ * @param tag trace tag to use for tracing
++ * @param msg message for tracing
++ * @return non-zero if state changed.
++ */
++int otg_event(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
++{
++ int rc;
++ unsigned long flags;
++ RETURN_ZERO_UNLESS(otg);
++ local_irq_save (flags);
++ rc = otg_event_irq(otg, inputs, tag, msg);
++ local_irq_restore (flags);
++ return rc;
++}
++
++
++/*!
++ * otg_event_set_irq() -
++ * @param otg pointer to the otg instance.
++ * @param changed
++ * @param flag
++ * @param input input mask
++ * @param tag trace tag to use for tracing
++ * @param msg message for tracing
++ * @return non-zero if state changed.
++ */
++int otg_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *msg)
++{
++ RETURN_ZERO_UNLESS(changed);
++ TRACE_MSG4(tag, "%s: %08x changed: %d flag: %d", msg, input, changed, flag);
++ return otg_event(otg, flag ? input : _NOT(input), tag, msg);
++}
++
++
++/*!
++ * otg_init() - create and initialize otg instance
++ *
++ * Called to initialize the OTG state machine. This will cause the state
++ * to change from the invalid_state to otg_disabled.
++ *
++ * If the device has the OCD_CAPABILITIES_AUTO flag set then
++ * an initial enable_otg event is generated. This will cause
++ * the state to move from otg_disabled to otg_enabled. The
++ * requird drivers will be initialized by calling the appropriate
++ * output functions:
++ *
++ * - pcd_init_func
++ * - hcd_init_func
++ * - tcd_init_func
++ *
++ * @param otg pointer to the otg instance.
++ */
++void otg_init (struct otg_instance *otg)
++{
++ DOWN(&otg_sem);
++ otg->outputs = tcd_init_out_ | pcd_init_out_ | hcd_init_out_;
++
++ /* This will move the state machine into the otg_disabled state
++ */
++ otg_event(otg, enable_otg, CORE, "enable_otg"); // XXX
++
++ if (otg_ocd_ops->capabilities & OCD_CAPABILITIES_AUTO)
++ otg_event(otg, AUTO, CORE, "AUTO"); // XXX
++
++ UP(&otg_sem);
++}
++
++
++/*!
++ * otg_exit()
++ *
++ * This is called by the driver that started the state machine to
++ * cause it to exit. The state will move to otg_disabled.
++ *
++ * The appropriate output functions will be called to disable the
++ * peripheral drivers.
++ *
++ * @param otg pointer to the otg instance.
++ */
++void otg_exit (struct otg_instance *otg)
++{
++ //TRACE_MSG0(CORE, "DOWN OTG_SEM");
++ DOWN(&otg_sem);
++
++ //TRACE_MSG0(CORE, "OTG_EXIT");
++ //otg_event(otg, exit_all | not(a_bus_req) | a_bus_drop | not(b_bus_req), "tcd_otg_exit");
++
++ otg_event(otg, enable_otg_, CORE, "enable_otg_");
++
++ while (otg->state != otg_disabled) {
++ // TRACE_MSG pointless here, module will be gon before we can look at it.
++ #ifdef OTG_WINCE
++ //DEBUGMSG(KERN_ERR"%s: waiting for state machine to disable\n", __FUNCTION__);
++ #else /* OTG_WINCE */
++ printk(KERN_ERR"%s: waiting for state machine to disable\n", __FUNCTION__);
++ #endif /* OTG_WINCE */
++ SCHEDULE_TIMEOUT(10 * HZ);
++ }
++ //TRACE_MSG0(CORE, "UP OTG_SEM");
++ UP(&otg_sem);
++}
++
++
++OTG_EXPORT_SYMBOL(otg_event);
++OTG_EXPORT_SYMBOL(otg_event_irq);
++OTG_EXPORT_SYMBOL(otg_init);
++OTG_EXPORT_SYMBOL(otg_exit);
++OTG_EXPORT_SYMBOL(otg_event_set_irq);
++
++/* ********************************************************************************************* */
++
++/*!
++ * otg_tcd_init_func() -
++ *
++ * This is a default tcd_init_func. It will be used
++ * if no other is provided.
++ *
++ * @param otg pointer to the otg instance.
++ * @param flag set or reset
++ */
++void otg_tcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ otg_event(otg, TCD_OK, CORE, "TCD_OK");
++}
++
++/*!
++ * otg_pcd_init_func() -
++ *
++ * This is a default pcd_init_func. It will be used
++ * if no other is provided.
++ *
++ * @param otg pointer to the otg instance.
++ * @param flag set or reset
++ */
++void otg_pcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ otg_event(otg, PCD_OK, CORE, "PCD_OK");
++}
++
++/*!
++ * otg_hcd_init_func() -
++ *
++ * This is a default hcd_init_func. It will be used
++ * if no other is provided.
++ *
++ * @param otg pointer to the otg instance.
++ * @param flag set or reset
++ */
++void otg_hcd_init_func (struct otg_instance *otg, u8 flag)
++{
++ otg_event(otg, HCD_OK, CORE, "HCD_OK");
++}
++
++/*!
++ * otg_ocd_init_func() -
++ *
++ * This is a default hcd_init_func. It will be used
++ * if no other is provided.
++ *
++ * @param otg pointer to the otg instance.
++ * @param flag set or reset
++ */
++void otg_ocd_init_func (struct otg_instance *otg, u8 flag)
++{
++ otg_event(otg, HCD_OK, CORE, "OCD_OK");
++}
++
++/*!
++ * otg_hcd_set_ops() -
++ * @param hcd_ops - host operations table to use
++ */
++struct hcd_instance * otg_set_hcd_ops(struct hcd_ops *hcd_ops)
++{
++ otg_hcd_ops = hcd_ops;
++ if (hcd_ops) {
++ otg_instance_private.otg_output_ops[HCD_INIT_OUT] = otg_hcd_ops->hcd_init_func;
++ otg_instance_private.otg_output_ops[HCD_EN_OUT] = otg_hcd_ops->hcd_en_func;
++ otg_instance_private.otg_output_ops[LOC_SOF_OUT] = otg_hcd_ops->loc_sof_func;
++ otg_instance_private.otg_output_ops[LOC_SUSPEND_OUT] = otg_hcd_ops->loc_suspend_func;
++ otg_instance_private.otg_output_ops[REMOTE_WAKEUP_EN_OUT] = otg_hcd_ops->remote_wakeup_en_func;
++ otg_instance_private.otg_output_ops[HNP_EN_OUT] = otg_hcd_ops->hnp_en_func;
++ }
++ else
++ otg_instance_private.otg_output_ops[HCD_INIT_OUT] =
++ otg_instance_private.otg_output_ops[HCD_EN_OUT] =
++ otg_instance_private.otg_output_ops[LOC_SOF_OUT] =
++ otg_instance_private.otg_output_ops[LOC_SUSPEND_OUT] =
++ otg_instance_private.otg_output_ops[REMOTE_WAKEUP_EN_OUT] =
++ otg_instance_private.otg_output_ops[HNP_EN_OUT] = NULL;
++
++
++ UNLESS (otg_instance_private.otg_output_ops[HCD_INIT_OUT])
++ otg_instance_private.otg_output_ops[HCD_INIT_OUT] = otg_hcd_init_func;
++
++ return &hcd_instance_private;
++}
++
++/*!
++ * otg_ocd_set_ops() -
++ *
++ * @param ocd_ops - ocd operations table to use
++ */
++struct ocd_instance * otg_set_ocd_ops(struct ocd_ops *ocd_ops)
++{
++ otg_ocd_ops = ocd_ops;
++ if (ocd_ops) {
++ otg_instance_private.otg_output_ops[OCD_INIT_OUT] = otg_ocd_ops->ocd_init_func;
++ otg_instance_private.start_timer = ocd_ops->start_timer;
++ }
++ else {
++ otg_instance_private.otg_output_ops[OCD_INIT_OUT] = NULL;
++ otg_instance_private.start_timer = NULL;
++ }
++
++ UNLESS (otg_instance_private.otg_output_ops[OCD_INIT_OUT])
++ otg_instance_private.otg_output_ops[OCD_INIT_OUT] = otg_ocd_init_func;
++
++ return &ocd_instance_private;
++}
++
++/*!
++ * otg_pcd_set_ops() -
++ * @param pcd_ops - pcd operations table to use
++ */
++struct pcd_instance * otg_set_pcd_ops(struct pcd_ops *pcd_ops)
++{
++ otg_pcd_ops = pcd_ops;
++ if (pcd_ops) {
++ otg_instance_private.otg_output_ops[PCD_INIT_OUT] = otg_pcd_ops->pcd_init_func;
++ otg_instance_private.otg_output_ops[PCD_EN_OUT] = otg_pcd_ops->pcd_en_func;
++ otg_instance_private.otg_output_ops[REMOTE_WAKEUP_OUT] = otg_pcd_ops->remote_wakeup_func;
++ }
++ else
++ otg_instance_private.otg_output_ops[PCD_INIT_OUT] =
++ otg_instance_private.otg_output_ops[PCD_EN_OUT] =
++ otg_instance_private.otg_output_ops[REMOTE_WAKEUP_OUT] = NULL;
++
++ UNLESS (otg_instance_private.otg_output_ops[PCD_INIT_OUT])
++ otg_instance_private.otg_output_ops[PCD_INIT_OUT] = otg_pcd_init_func;
++
++ return &pcd_instance_private;
++}
++
++/*!
++ * otg_tcd_set_ops() -
++ * @param tcd_ops - tcd operations table to use
++ */
++struct tcd_instance * otg_set_tcd_ops(struct tcd_ops *tcd_ops)
++{
++ otg_tcd_ops = tcd_ops;
++ if (tcd_ops) {
++ otg_instance_private.otg_output_ops[TCD_INIT_OUT] = otg_tcd_ops->tcd_init_func;
++ otg_instance_private.otg_output_ops[TCD_EN_OUT] = otg_tcd_ops->tcd_en_func;
++ otg_instance_private.otg_output_ops[CHRG_VBUS_OUT] = otg_tcd_ops->chrg_vbus_func;
++ otg_instance_private.otg_output_ops[DRV_VBUS_OUT] = otg_tcd_ops->drv_vbus_func;
++ otg_instance_private.otg_output_ops[DISCHRG_VBUS_OUT] = otg_tcd_ops->dischrg_vbus_func;
++ otg_instance_private.otg_output_ops[DP_PULLUP_OUT] = otg_tcd_ops->dp_pullup_func;
++ otg_instance_private.otg_output_ops[DM_PULLUP_OUT] = otg_tcd_ops->dm_pullup_func;
++ otg_instance_private.otg_output_ops[DP_PULLDOWN_OUT] = otg_tcd_ops->dp_pulldown_func;
++ otg_instance_private.otg_output_ops[DM_PULLDOWN_OUT] = otg_tcd_ops->dm_pulldown_func;
++ //otg_instance_private.otg_output_ops[PERIPHERAL_HOST] = otg_tcd_ops->peripheral_host_func;
++ otg_instance_private.otg_output_ops[CLR_OVERCURRENT_OUT] = otg_tcd_ops->overcurrent_func;
++ otg_instance_private.otg_output_ops[DM_DET_OUT] = otg_tcd_ops->dm_det_func;
++ otg_instance_private.otg_output_ops[DP_DET_OUT] = otg_tcd_ops->dp_det_func;
++ otg_instance_private.otg_output_ops[CR_DET_OUT] = otg_tcd_ops->cr_det_func;
++ otg_instance_private.otg_output_ops[AUDIO_OUT] = otg_tcd_ops->audio_func;
++ otg_instance_private.otg_output_ops[CHARGE_PUMP_OUT] = otg_tcd_ops->charge_pump_func;
++ otg_instance_private.otg_output_ops[BDIS_ACON_OUT] = otg_tcd_ops->bdis_acon_func;
++ otg_instance_private.otg_output_ops[MX21_VBUS_DRAIN] = otg_tcd_ops->mx21_vbus_drain_func;
++ otg_instance_private.otg_output_ops[ID_PULLDOWN_OUT] = otg_tcd_ops->id_pulldown_func;
++ otg_instance_private.otg_output_ops[UART_OUT] = otg_tcd_ops->uart_func;
++ otg_instance_private.otg_output_ops[MONO_OUT] = otg_tcd_ops->mono_func;
++ }
++ else
++ otg_instance_private.otg_output_ops[TCD_INIT_OUT] =
++ otg_instance_private.otg_output_ops[TCD_EN_OUT] =
++ otg_instance_private.otg_output_ops[CHRG_VBUS_OUT] =
++ otg_instance_private.otg_output_ops[DRV_VBUS_OUT] =
++ otg_instance_private.otg_output_ops[DISCHRG_VBUS_OUT] =
++ otg_instance_private.otg_output_ops[DP_PULLUP_OUT] =
++ otg_instance_private.otg_output_ops[DM_PULLUP_OUT] =
++ otg_instance_private.otg_output_ops[DP_PULLDOWN_OUT] =
++ otg_instance_private.otg_output_ops[DM_PULLDOWN_OUT] =
++ //otg_instance_private.otg_output_ops[PERIPHERAL_HOST] =
++ otg_instance_private.otg_output_ops[CLR_OVERCURRENT_OUT] =
++ otg_instance_private.otg_output_ops[DM_DET_OUT] =
++ otg_instance_private.otg_output_ops[DP_DET_OUT] =
++ otg_instance_private.otg_output_ops[CR_DET_OUT] =
++ otg_instance_private.otg_output_ops[AUDIO_OUT] =
++ otg_instance_private.otg_output_ops[CHARGE_PUMP_OUT] =
++ otg_instance_private.otg_output_ops[BDIS_ACON_OUT] =
++ otg_instance_private.otg_output_ops[MX21_VBUS_DRAIN] =
++ otg_instance_private.otg_output_ops[ID_PULLDOWN_OUT] =
++ otg_instance_private.otg_output_ops[UART_OUT] =
++ otg_instance_private.otg_output_ops[MONO_OUT] = NULL;
++
++ UNLESS (otg_instance_private.otg_output_ops[TCD_INIT_OUT])
++ otg_instance_private.otg_output_ops[TCD_INIT_OUT] = otg_tcd_init_func;
++
++ return &tcd_instance_private;
++}
++
++/*!
++ * otg_set_usbd_ops() -
++ * @param usbd_ops
++ */
++int otg_set_usbd_ops(struct usbd_ops *usbd_ops)
++{
++ otg_usbd_ops = usbd_ops;
++ return 0;
++}
++
++
++/*!
++ * otg_get_trace_info()
++ */
++void otg_get_trace_info(otg_trace_t *p)
++{
++ p->id_gnd = otg_instance_private.current_inputs & ID_GND ? 1 : 0;
++ p->va.s.ticks = (otg_ocd_ops && otg_ocd_ops->ticks) ? otg_ocd_ops->ticks () : 0;
++ p->va.s.interrupts = (otg_ocd_ops && otg_ocd_ops->interrupts) ? otg_ocd_ops->interrupts : 0;
++ p->va.s.framenum = (otg_pcd_ops && otg_pcd_ops->framenum) ? otg_pcd_ops->framenum() : 0;
++ p->in_interrupt = in_interrupt();
++}
++
++/*!
++ * otg_tmr_ticks() -
++ * @return number of ticks.
++ */
++u64 otg_tmr_ticks(void)
++{
++ return (otg_ocd_ops && otg_ocd_ops->ticks) ? otg_ocd_ops->ticks () : 0;
++}
++
++/*!
++ * otg_tmr_elapsed() -
++ * @param t1
++ * @param t2
++ * @return number of uSecs between t1 and t2 ticks.
++ */
++u64 otg_tmr_elapsed(u64 *t1, u64 *t2)
++{
++ return (otg_ocd_ops && otg_ocd_ops->elapsed) ? otg_ocd_ops->elapsed (t1, t2) : 0;
++}
++
++/*!
++ * otg_tmr_framenum() -
++ * @return the current USB frame number.
++ */
++u16 otg_tmr_framenum(void)
++{
++ return (otg_pcd_ops && otg_pcd_ops->framenum) ? otg_pcd_ops->framenum() : 0;
++}
++
++/*!
++ * otg_tmr_interrupts() -
++ * @return the current number of interrupts.
++ */
++u32 otg_tmr_interrupts(void)
++{
++ return (otg_ocd_ops && otg_ocd_ops->interrupts) ? otg_ocd_ops->interrupts : 0;
++}
++
++
++OTG_EXPORT_SYMBOL(otg_hcd_ops);
++OTG_EXPORT_SYMBOL(otg_ocd_ops);
++OTG_EXPORT_SYMBOL(otg_pcd_ops);
++OTG_EXPORT_SYMBOL(otg_tcd_ops);
++OTG_EXPORT_SYMBOL(otg_set_hcd_ops);
++OTG_EXPORT_SYMBOL(otg_set_ocd_ops);
++OTG_EXPORT_SYMBOL(otg_set_pcd_ops);
++OTG_EXPORT_SYMBOL(otg_set_tcd_ops);
++OTG_EXPORT_SYMBOL(otg_set_usbd_ops);
++OTG_EXPORT_SYMBOL(otg_tmr_ticks);
++OTG_EXPORT_SYMBOL(otg_tmr_elapsed);
++OTG_EXPORT_SYMBOL(otg_write_input_message_irq);
++
++
++#if defined(OTG_WINCE)
++#else /* defined(OTG_WINCE) */
++#endif /* defined(OTG_WINCE) */
++
+diff -uNr linux/drivers/no-otg/otgcore/sources linux/drivers/otg/otgcore/sources
+--- linux/drivers/no-otg/otgcore/sources 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/sources 2006-09-01 21:41:34.000000000 +0200
+@@ -0,0 +1,41 @@
++!if 0
++Copyright (c) Microsoft Corporation. All rights reserved.
++!endif
++!if 0
++Use of this source code is subject to the terms of the Microsoft end-user
++license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
++If you did not accept the terms of the EULA, you are not authorized to use
++this source code. For a copy of the EULA, please see the LICENSE.RTF on your
++install media.
++!endif
++
++SYNCHRONIZE_DRAIN=1
++
++INCLUDES= \
++ $(_PUBLICROOT)\common\ddk\inc; $(_PUBLICROOT)\common\oak\inc; $(_PUBLICROOT)\common\sdk\inc; \
++ $(_WINCEROOT)\public\common\oak\DRIVERS\otg;
++
++
++TARGETNAME=otgcore
++TARGETTYPE=LIBRARY
++
++
++SOURCES= \
++ core-init-w42.c \
++ otg.c \
++ otg-mesg.c \
++ otg-mesg-w42.c \
++ otg-ops.c \
++ usbp-bops.c \
++ usbp-fops.c \
++ otg-fw.c \
++ otg-fw-df.c \
++ otg-fw-mn.c \
++ usbp.c \
++ otg-trace.c \
++ otg-trace-w42.c \
++ ep0.c \
++
++# usbp-procfs.c \
++
++
+diff -uNr linux/drivers/no-otg/otgcore/usbp-bops.c linux/drivers/otg/otgcore/usbp-bops.c
+--- linux/drivers/no-otg/otgcore/usbp-bops.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/usbp-bops.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,1857 @@
++/*
++ * otg/otgcore/usbp-bops.c - USB Device Prototype
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/usbp-bops.c
++ * @brief Bus Interface related functions.
++ *
++ * This implements the functions used to implement Peripheral Controller Drivers (PCD.)
++ *
++ * @ingroup USBP
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/otg-api.h>
++#include <otg/otg-trace.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++#include <otg/otg-pcd.h>
++
++/* ********************************************************************************************* */
++/*!
++ * Note that all of the list functions overlapped operation using the usbd_bus_sem;
++ *
++ * usbd_device_bh
++ *
++ * usbd_register_bus
++ * usbd_deregister_bus
++ * usbd_enable_function_irq
++ * usbd_disable_function
++ */
++DECLARE_MUTEX(usbd_bus_sem);
++void usbd_device_bh (void *data);
++
++/* ********************************************************************************************* */
++/*!
++ * Function driver enable/disable
++ *
++ * Called by usbd_enable_function/usbd_disable_function to call the selected
++ * function drivers function_enable or function_disable function.
++ */
++int usbd_strings_init (void);
++void usbd_strings_exit(void);
++
++extern struct usbd_function_instance *usbd_find_function (char *name);
++
++struct usbd_bus_instance *usbd_bus_instance;
++OTG_EXPORT_SYMBOL(usbd_bus_instance);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Bus Interface Management:
++ * usbd_register_bus()
++ * usbd_deregister_bus()
++ */
++
++/*! urb_link_init() - initialize urb linke
++ *
++ * Initialize an urb_link to be a single element list.
++ * If the urb_link is being used as a distinguished list head
++ * the list is empty when the head is the only link in the list.
++ *
++ * @param ul link to urb
++ */
++static INLINE void urb_link_init (urb_link * ul)
++{
++ ul->prev = ul->next = ul;
++}
++
++static struct usbd_function_operations ep0_ops;
++struct usbd_function_driver ep0_driver;
++
++
++/*!
++ * usbd_register_bus() - called by a USB BUS INTERFACE driver to register a bus driver
++ *
++ * Used by a USB Bus interface driver to register itself with the usb device layer.
++ *
++ * @param driver
++ * @param ep0_wMaxPacketSize
++ * @return non-zero if error
++ */
++struct usbd_bus_instance *usbd_register_bus (struct usbd_bus_driver *driver, int ep0_wMaxPacketSize)
++{
++ int i;
++ struct usbd_bus_instance *bus = NULL;
++
++ DOWN(&usbd_bus_sem);
++
++ THROW_IF(usbd_bus_instance, error);
++ THROW_IF((bus = CKMALLOC (sizeof (struct usbd_bus_instance), GFP_ATOMIC)) == NULL, error);
++
++ bus->driver = driver;
++ bus->endpoints = bus->driver->max_endpoints;
++ bus->otg_bmAttributes = bus->driver->otg_bmAttributes;
++
++ THROW_IF(!(bus->endpoint_array = CKMALLOC(sizeof (struct usbd_endpoint_instance) * bus->endpoints, GFP_ATOMIC)), error);
++
++ for (i = 0; i < bus->endpoints; i++) {
++ struct usbd_endpoint_instance *endpoint = bus->endpoint_array + i;
++ endpoint->physical_endpoint = i;
++ urb_link_init (&endpoint->rdy);
++ urb_link_init (&endpoint->tx);
++ }
++
++ urb_link_init (&bus->finished);
++
++ ZERO(ep0_ops);
++ ZERO(ep0_driver);
++ ep0_driver.name = "EP0";
++ ep0_driver.fops = &ep0_ops;
++
++
++ THROW_IF((bus->ep0 = CKMALLOC (sizeof (struct usbd_function_instance), GFP_ATOMIC)) == NULL, error);
++ bus->ep0->function_driver = &ep0_driver;
++ THROW_IF(!(bus->ep0->endpoint_map_array = CKMALLOC(sizeof(struct usbd_endpoint_map) * 2, GFP_KERNEL)), error);
++ bus->ep0->endpoint_map_array[0].wMaxPacketSize[0] = ep0_wMaxPacketSize;
++ bus->ep0->endpoint_map_array[0].wMaxPacketSize[1] = ep0_wMaxPacketSize;
++
++ bus->device_state = STATE_CREATED;
++ bus->status = USBD_OPENING;
++
++ usbd_bus_instance = bus;
++
++ CATCH(error) {
++ if (bus) {
++ if (bus->endpoint_array)
++ LKFREE(bus->endpoint_array);
++ LKFREE(bus);
++ }
++ bus->endpoints = 0;
++ #if defined(OTG_LINUX)
++ printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
++ #endif /* defined(OTG_LINUX) */
++ #if defined(OTG_WINCE)
++ DEBUGMSG(ZONE_INIT, (_T("usbd_register_bus: FAILED\n")));
++ #endif /* defined(OTG_LINUX) */
++ bus = NULL;
++ }
++
++ UP(&usbd_bus_sem);
++ return bus;
++}
++
++/*!
++ * usbd_deregister_bus() - called by a USB BUS INTERFACE driver to deregister a bus driver
++ *
++ * Used by a USB Bus interface driver to de-register itself with the usb device
++ * layer.
++ *
++ * @param bus
++ */
++void usbd_deregister_bus (struct usbd_bus_instance *bus)
++{
++ DOWN(&usbd_bus_sem);
++
++ usbd_bus_instance = NULL;
++
++ if (bus->ep0) {
++ if (bus->ep0->endpoint_map_array)
++ LKFREE(bus->ep0->endpoint_map_array);
++ LKFREE(bus->ep0);
++ }
++
++ LKFREE (bus->arg);
++ LKFREE (bus->endpoint_array);
++ LKFREE (bus);
++ bus->endpoints = 0;
++ UP(&usbd_bus_sem);
++}
++
++OTG_EXPORT_SYMBOL(usbd_register_bus);
++OTG_EXPORT_SYMBOL(usbd_deregister_bus);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Function Management:
++ * usbd_enable_function()
++ * usbd_disable_function()
++ *
++ */
++
++/*!
++ * alloc_function_alternates() - allocate alternate instance array
++ *
++ * Return a pointer to an array of alternate instances. Each instance contains a pointer
++ * to a filled in alternate descriptor and a pointer to the endpoint descriptor array.
++ *
++ * Returning NULL will cause the caller to cleanup all previously allocated memory.
++ * @param bInterfaceNumber
++ * @param interface_description
++ * @param alternates
++ * @param alternate_description_array
++ * @return pointer to alternate instance array
++ */
++static struct usbd_alternate_instance *
++alloc_function_alternates (int bInterfaceNumber,
++ struct usbd_interface_description *interface_description,
++ int alternates, struct usbd_alternate_description *alternate_description_array)
++{
++ int alternate_num;
++ struct usbd_alternate_instance *alternate_instance_array = NULL;
++
++ // allocate array of alternate instances
++ RETURN_NULL_IF(!(alternate_instance_array = (struct usbd_alternate_instance *)
++ CKMALLOC (sizeof (struct usbd_alternate_instance) * alternates, GFP_KERNEL)));
++
++ // iterate across the alternate descriptions
++ for (alternate_num = 0; alternate_num < alternates; alternate_num++) {
++
++ struct usbd_alternate_description *alternate_description = alternate_description_array + alternate_num;
++ struct usbd_alternate_instance *alternate_instance = alternate_instance_array + alternate_num;
++ struct usbd_interface_descriptor *interface_descriptor;
++
++ interface_descriptor = alternate_description->interface_descriptor;
++ if (interface_descriptor->bInterfaceNumber != bInterfaceNumber) {
++ //TRACE_MSG2(USBD, "bInterfaceNumber mis-match: %d should be %d",
++ // interface_descriptor->bInterfaceNumber, bInterfaceNumber);
++ LKFREE(alternate_instance_array);
++ return NULL;
++ }
++
++ interface_descriptor->bNumEndpoints = alternate_description->endpoints;
++ interface_descriptor->iInterface = usbd_alloc_string (alternate_description->iInterface );
++
++ alternate_instance->class_list = alternate_description->class_list;
++ alternate_instance->classes = alternate_description->classes;
++ alternate_instance->endpoint_list = alternate_description->endpoint_list;
++ alternate_instance->endpoint_indexes = alternate_description->endpoint_indexes;
++
++ // save number of alternates, classes and endpoints for this alternate
++ alternate_instance->endpoints = alternate_description->endpoints;
++ alternate_instance->interface_descriptor = interface_descriptor;
++ }
++ return alternate_instance_array;
++}
++
++/*!
++ * alloc_function_interfaces() - allocate interface instance array
++ *
++ * Return a pointer to an array of interface instances. Each instance contains a pointer
++ * to a filled in interface descriptor and a pointer to the endpoint descriptor array.
++ *
++ * Returning NULL will cause the caller to cleanup all previously allocated memory.
++ *
++ * @param bNumInterfaces
++ * @param interface_description_array
++ * @return interface instance
++ */
++static struct usbd_interfaces_instance *
++alloc_function_interfaces (int bNumInterfaces, struct usbd_interface_description *interface_description_array)
++{
++ int interface_num;
++ struct usbd_interfaces_instance *interfaces_instance_array = NULL;
++
++ // allocate array of interface instances
++ RETURN_NULL_IF(!(interfaces_instance_array = (struct usbd_interfaces_instance *)
++ CKMALLOC (sizeof (struct usbd_interfaces_instance) * bNumInterfaces, GFP_KERNEL)));
++
++ // iterate across the interface descriptions
++ for (interface_num = 0; interface_num < bNumInterfaces; interface_num++) {
++
++ struct usbd_interface_description *interface_description = interface_description_array + interface_num;
++ struct usbd_interfaces_instance *interfaces_instance = interfaces_instance_array + interface_num;
++
++ interfaces_instance->alternates_instance_array =
++ alloc_function_alternates (interface_num, interface_description,
++ interface_description->alternates, interface_description->alternate_list);
++ interfaces_instance->alternates = interface_description->alternates;
++ }
++ return interfaces_instance_array;
++}
++
++
++/*!
++ * alloc_function_configurations() - allocate configuration instance array
++ *
++ * Return a pointer to an array of configuration instances. Each instance contains a pointer
++ * to a filled in configuration descriptor and a pointer to the interface instances array.
++ *
++ * Returning NULL will cause the caller to cleanup all previously allocated memory.
++ *
++ * @param bNumConfigurations
++ * @param configuration_description_array
++ * @param otg_descriptor
++ * @param remote_wakeup_supported
++ * @param bMaxPower
++ * @return configuration instance
++ */
++static struct usbd_configuration_instance *
++alloc_function_configurations (struct usbd_function_driver *function_driver,
++ int remote_wakeup_supported,
++ int bMaxPower)
++{
++
++ int bNumConfigurations = function_driver->bNumConfigurations;
++ struct usbd_configuration_description *configuration_description_array = function_driver->configuration_description;
++ struct usbd_otg_descriptor *otg_descriptor = function_driver->otg_descriptor;
++ int config_num;
++ struct usbd_configuration_instance *configuration_instance_array = NULL;
++
++ //TRACE_MSG2(USBD, "remote: %x bMaxPower: %x", remote_wakeup_supported, bMaxPower);
++
++ // allocate array
++ RETURN_NULL_IF(!(configuration_instance_array = (struct usbd_configuration_instance *)
++ CKMALLOC (sizeof (struct usbd_configuration_instance) * bNumConfigurations, GFP_KERNEL)));
++ // fill in array
++ for (config_num = 0; config_num < bNumConfigurations; config_num++) {
++ int interface_num;
++ int length;
++
++ struct usbd_configuration_description *configuration_description = configuration_description_array + config_num;
++ struct usbd_configuration_descriptor *configuration_descriptor;
++
++ configuration_descriptor = configuration_description->configuration_descriptor;
++
++ // setup fields in configuration descriptor
++ // XXX c.f. 9.4.7 zero is default, so config MUST BE 1 to n, not 0 to n-1
++ // XXX N.B. the configuration itself is fetched 0 to n-1.
++
++ configuration_descriptor->bConfigurationValue = config_num + 1;
++ configuration_descriptor->wTotalLength = 0;
++ configuration_descriptor->bNumInterfaces = function_driver->bNumInterfaces;
++ configuration_descriptor->iConfiguration = usbd_alloc_string (configuration_description->iConfiguration);
++ configuration_descriptor->bMaxPower = bMaxPower;
++ configuration_descriptor->bmAttributes = BMATTRIBUTE_RESERVED |
++ bMaxPower ? 0 : BMATTRIBUTE_SELF_POWERED |
++ remote_wakeup_supported ? BMATTRIBUTE_REMOTE_WAKEUP : 0;
++
++ // save the configuration descriptor in the configuration instance array
++ configuration_instance_array[config_num].configuration_descriptor = configuration_descriptor;
++
++ RETURN_NULL_IF (!(configuration_instance_array[config_num].interfaces_instance_array =
++ alloc_function_interfaces (function_driver->bNumInterfaces,
++ function_driver->interface_list)));
++
++ length = sizeof(struct usbd_configuration_descriptor);
++
++ for (interface_num = 0; interface_num < configuration_descriptor->bNumInterfaces; interface_num++) {
++
++ int alternate_num;
++ struct usbd_interfaces_instance *interfaces_instance =
++ configuration_instance_array[config_num].interfaces_instance_array + interface_num;
++
++ TRACE_MSG2(USBD, "len: %02x:%02d configuration", length, length);
++ for (alternate_num = 0; alternate_num < interfaces_instance->alternates; alternate_num++) {
++ int class_num;
++ int endpoint;
++ struct usbd_alternate_instance *alternate_instance =
++ interfaces_instance->alternates_instance_array + alternate_num;
++
++ length += sizeof (struct usbd_interface_descriptor);
++
++ TRACE_MSG2(USBD, "len: %02x:%02d interface", length, length);
++ for (class_num = 0; class_num < alternate_instance->classes; class_num++) {
++ struct usbd_generic_class_descriptor * class_descriptor =
++ *(alternate_instance->class_list + class_num);
++ length += class_descriptor->bLength;
++ TRACE_MSG2(USBD, "len: %02x:%02d class_num", length, length);
++ }
++
++ for (endpoint = 0; endpoint < alternate_instance->endpoints; endpoint++) {
++ struct usbd_endpoint_descriptor * endpoint_descriptor =
++ *(alternate_instance->endpoint_list + endpoint);
++ length += endpoint_descriptor->bLength;
++ TRACE_MSG2(USBD, "len: %02x:%02d endpoint", length, length);
++ }
++ }
++ }
++ length += otg_descriptor ? sizeof(struct usbd_otg_descriptor) : 0;
++ configuration_descriptor->wTotalLength = cpu_to_le16 ((u16)length);
++ // XXX only support a single configuration currently
++ configuration_instance_array[config_num].bNumInterfaces = function_driver->bNumInterfaces;
++ TRACE_MSG3(USBD, "configuration_instance_array[%d]: %p wTotalLength: %d", config_num,
++ &configuration_instance_array[config_num], length);
++ }
++ return configuration_instance_array;
++}
++
++
++/*!
++ * bus_function_enable() - enable a usbd function driver for use
++ *
++ * This will copy descriptors from the function driver and get them ready
++ * for use.
++ * @param bus
++ * @param function
++ * @param serial_number
++ * @return non-zero if error
++ */
++static int
++bus_function_enable (struct usbd_bus_instance *bus, struct usbd_function_instance *function, char *serial_number)
++{
++ struct usbd_function_driver *function_driver = function->function_driver;
++ struct usbd_device_description *device_description;
++ struct usbd_device_descriptor *device_descriptor;
++#ifdef CONFIG_OTG_HIGH_SPEED
++ struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ struct usbd_otg_descriptor *otg_descriptor;
++ int rc = 0;
++
++ function->bus = bus;
++
++ RETURN_EINVAL_IF(function_driver->fops->function_enable && function_driver->fops->function_enable (function));
++ RETURN_ZERO_IF(!(device_description = function_driver->device_description));
++ RETURN_ZERO_IF(!(device_descriptor = device_description->device_descriptor));
++
++ device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
++ device_descriptor->iManufacturer = usbd_alloc_string (device_description->iManufacturer);
++ device_descriptor->iProduct = usbd_alloc_string (device_description->iProduct);
++
++ if (strlen (serial_number))
++ device_descriptor->iSerialNumber = usbd_alloc_string (serial_number);
++ else
++ device_descriptor->iSerialNumber = usbd_alloc_string (device_description->iSerialNumber);
++
++ device_descriptor->bNumConfigurations = function_driver->bNumConfigurations;
++ device_descriptor->idVendor = function_driver->idVendor;
++ device_descriptor->idProduct = function_driver->idProduct;
++ device_descriptor->bcdDevice = function_driver->bcdDevice;
++
++ if ((otg_descriptor = device_description->otg_descriptor)) {
++ otg_descriptor->bmAttributes = usbd_otg_bmattributes(function);
++ function_driver->otg_descriptor = otg_descriptor;
++ }
++
++ /* call alloc_function_configurations() to allocate the configuration descriptor array
++ */
++ RETURN_EINVAL_IF (!(function_driver->configuration_instance_array =
++ alloc_function_configurations (function_driver,
++ bus->driver->capabilities & REMOTE_WAKEUP_SUPPORTED,
++ bus->driver->bMaxPower
++ )));
++
++ function_driver->device_descriptor = device_descriptor;
++#ifdef CONFIG_OTG_HIGH_SPEED
++ TRACE_MSG0(USBD, "HIGH SPEED");
++ if ((device_qualifier_descriptor = device_description->device_qualifier_descriptor)) {
++ device_qualifier_descriptor->bNumConfigurations = function_driver->bNumConfigurations;
++ function_driver->device_qualifier_descriptor = device_qualifier_descriptor;
++ }
++#endif /* CONFIG_OTG_HIGH_SPEED */
++ //TRACE_MSG0(USBD, "finished");
++ return rc;
++}
++
++/*!
++ * usbd_function_disable() - disable a usbd function driver
++ * @param function
++ */
++void usbd_function_disable (struct usbd_function_instance *function)
++{
++ int configuration;
++ struct usbd_function_driver *function_driver = function->function_driver;
++ struct usbd_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
++
++ if (function->function_driver->fops->function_disable)
++ function->function_driver->fops->function_disable (function);
++
++ RETURN_IF(!function_driver->configuration_instance_array);
++
++ // iterate across the descriptors list and de-allocate all structures
++ if (function_driver->configuration_instance_array) {
++ for (configuration = 0; configuration < function_driver->bNumConfigurations; configuration++) {
++ int interface_num;
++ struct usbd_configuration_instance *configuration_instance = configuration_instance_array + configuration;
++
++ for (interface_num = 0; interface_num < configuration_instance->bNumInterfaces; interface_num++) {
++
++ //int alternate_num;
++ struct usbd_interfaces_instance *interfaces_instance =
++ configuration_instance->interfaces_instance_array + interface_num;
++
++ LKFREE (interfaces_instance->alternates_instance_array);
++ }
++ LKFREE (configuration_instance->interfaces_instance_array);
++ }
++ }
++ LKFREE (configuration_instance_array);
++ function->bus = NULL;
++}
++
++
++/*!
++ * usbd_enable_function() - called to enable the desired function
++ *
++ * Used by a USB Bus interface driver to create a virtual device.
++ *
++ * @param bus
++ * @param arg
++ * @param serial_number
++ * @return non-zero if error
++ */
++int usbd_enable_function(struct usbd_bus_instance *bus, char *arg, char *serial_number)
++{
++ struct usbd_function_instance *function = NULL;
++ struct usbd_function_driver *function_driver = NULL;
++ LIST_NODE *lhd = NULL;
++ int len = 0;
++ int i;
++ int rc = -EINVAL;
++ int epn, endpointsRequested;
++ int endpoints;
++
++ DOWN(&usbd_bus_sem);
++
++ if (arg && bus->arg)
++ LKFREE(bus->arg);
++
++ if (arg) {
++ bus->arg = LSTRDUP(arg);
++ len = strlen(arg);
++ }
++
++ /* initialize the strings pool, and zero endpoint array urbs
++ */
++ THROW_IF(usbd_strings_init (), error);
++
++ for (i = 1; i < bus->endpoints; i++) {
++ struct usbd_endpoint_instance *endpoint = bus->endpoint_array + i;
++ endpoint->rcv_urb = endpoint->tx_urb = NULL;
++ }
++
++ /* find requested function
++ */
++ if ((function = usbd_find_function(arg))) {
++
++ function_driver = function->function_driver;
++
++ TRACE_MSG1(USBD, "request endpoints: %x", function_driver);
++
++ switch(function->function_type) {
++ case function_simple:
++ THROW_IF(bus->driver->bops->request_endpoints( bus, function->endpoint_map_array,
++ function->function_driver->endpointsRequested,
++ function->function_driver->requestedEndpoints), error);
++ break;
++ case function_interface:
++ break;
++ case function_composite:
++ THROW_IF(bus->driver->bops->request_endpoints( bus, function->endpoint_map_array,
++ function->endpoints,
++ function->requestedEndpoints), error);
++ break;
++ }
++
++
++ bus_function_enable (bus, function, serial_number);
++ }
++
++ THROW_IF (!(bus->function_instance = function), error);
++
++
++ /* if composite we need to compose the interface list and endpoint map
++ */
++ if(function_composite == function->function_type) {
++ char *name;
++ int i;
++ }
++
++ /* we need to de-compose the endpoint request array into the individual
++ * interface endpoint map array.
++ */
++ for (endpoints = 0, i = 0; i < function->interfaces; i++) {
++ struct usbd_function_instance *interface_function = function->interfaces_array[i];
++ interface_function->endpoint_map_array = function->endpoint_map_array;
++ endpoints += interface_function->endpoints;
++ }
++
++
++ switch(bus->function_instance->function_type) {
++ case function_simple:
++ case function_composite:
++ THROW_IF(bus->driver->bops->set_endpoints( bus,
++ function->function_driver->endpointsRequested,
++ function->endpoint_map_array), error);
++ break;
++ case function_interface:
++ break;
++ }
++
++ // device bottom half
++ PREPARE_WORK_ITEM(bus->device_bh, usbd_device_bh, bus);
++ bus->status = USBD_OK;
++ bus->bus_state = usbd_bus_state_enabled;
++ bus->ep0->endpoint_map_array->endpoint = bus->endpoint_array;
++ THROW_IF (bus_function_enable (bus, bus->ep0, NULL), error);
++
++ // iterate across the logical endpoint map to copy appropriate information
++ // into the physical endpoint instance array
++
++ endpointsRequested = bus->function_instance->function_driver->endpointsRequested;
++
++ for (epn = 0; epn < /*bus->function_instance->*/endpointsRequested; epn++) {
++
++ struct usbd_endpoint_map *endpoint_map = bus->function_instance->endpoint_map_array + epn;
++ int physicalEndpoint = endpoint_map->physicalEndpoint[0];
++ struct usbd_endpoint_instance *endpoint = bus->endpoint_array + physicalEndpoint;
++
++ endpoint_map->endpoint = endpoint;
++ endpoint->bEndpointAddress = endpoint_map->bEndpointAddress[0];
++ endpoint->bmAttributes = endpoint_map->bmAttributes[0];
++
++ switch(endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
++ case USB_DIR_IN:
++ endpoint->tx_transferSize = endpoint_map->transferSize[0];
++ endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
++ endpoint->last = 0;
++ endpoint->tx_urb = NULL;
++ break;
++
++ case USB_DIR_OUT:
++ endpoint->rcv_transferSize = endpoint_map->transferSize[0];
++ endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
++ endpoint->rcv_urb = NULL;
++ break;
++ }
++ }
++
++ /* if composite we need to de-compose the endpoint map into the individual
++ * interface endpoint maps.
++ */
++ if(function_composite == function->function_type) {
++ }
++
++ rc = 0;
++
++ CATCH(error) {
++ usbd_strings_exit();
++ }
++ UP(&usbd_bus_sem);
++ return rc;
++}
++
++int usbd_enable_function_irq (struct usbd_bus_instance *bus, char *arg, char *serial_number)
++{
++ return usbd_enable_function(bus, arg, serial_number);
++}
++
++/*!
++ * usbd_disable_function() - called to disable the current function
++ *
++ * Used by a USB Bus interface driver to destroy a virtual device.
++ *
++ * @param bus
++ */
++void usbd_disable_function (struct usbd_bus_instance *bus)
++{
++ DOWN(&usbd_bus_sem);
++
++ // prevent any more bottom half scheduling
++ bus->status = USBD_CLOSING;
++ UP(&usbd_bus_sem);
++
++ /* XXX
++ * if composite ???
++ */
++ switch(bus->function_instance->function_type) {
++ case function_simple:
++ case function_interface:
++ break;
++ case function_composite:
++ break;
++ }
++
++ // wait for pending device bottom half to finish
++//XXX FIXME
++ //while (bus->device_bh.data /*|| device->function_bh.data */) {
++ while (PENDING_WORK_ITEM(bus->device_bh)){
++
++ //printk(KERN_INFO"%s: waiting for usbd_device_bh %ld %p interrupt: %d\n", __FUNCTION__,
++ // bus->device_bh.sync, bus->device_bh.data, in_interrupt());
++
++ // This can probably be either, but for consistency's sake...
++#if 1
++ //I.e. run this task immediately and then delay up to 2000 secdons ...
++#ifdef LINUX24
++ queue_task(&bus->device_bh, &tq_immediate);
++ mark_bh (IMMEDIATE_BH);
++#else
++ SCHEDULE_WORK(bus->device_bh);
++#endif
++ // schedule_task(&device->device_bh);
++
++ SCHEDULE_TIMEOUT (2000 * HZ);
++#else
++ //Generic version ...
++ SCHEDULE_IMMEDIATE_WORK(bus->device_bh);
++ SCHEDULE_TIMEOUT(2000); //Seconds
++#endif
++ }
++ DOWN(&usbd_bus_sem);
++
++ // tell the function driver to close
++ usbd_function_disable (bus->ep0);
++ usbd_function_disable (bus->function_instance);
++
++ // free alternates memory
++ if (bus->alternates) {
++ bus->bNumInterfaces = 0;
++ LKFREE(bus->alternates);
++ bus->alternates = NULL;
++ }
++ if (bus->function_instance) {
++#if 0
++ if (bus->function_instance->endpoint_map_array)
++ LKFREE(bus->function_instance->endpoint_map_array);
++ LKFREE(bus->function_instance);
++#endif
++ bus->function_instance = NULL;
++ }
++ usbd_strings_exit();
++ bus->status = USBD_CLOSED;
++ UP(&usbd_bus_sem);
++}
++
++OTG_EXPORT_SYMBOL(usbd_enable_function);
++OTG_EXPORT_SYMBOL(usbd_enable_function_irq);
++OTG_EXPORT_SYMBOL(usbd_disable_function);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Bus Event Handling:
++ * usbd_bus_event_handler()
++ *
++ */
++static usbd_device_state_t event_states[DEVICE_CLOSE] = {
++ STATE_UNKNOWN, STATE_INIT, STATE_ATTACHED, STATE_POWERED,
++ STATE_DEFAULT, STATE_ADDRESSED, STATE_CONFIGURED, STATE_UNKNOWN,
++ STATE_UNKNOWN, STATE_UNKNOWN, STATE_ADDRESSED, STATE_SUSPENDED,
++ STATE_UNKNOWN, STATE_POWERED, STATE_ATTACHED,
++};
++
++static usbd_device_status_t event_status[DEVICE_CLOSE+1] = {
++ USBD_UNKNOWN, // DEVICE_UNKNOWN
++ USBD_OPENING, // DEVICE_INIT
++ USBD_OPENING, // DEVICE_CREATE
++ USBD_OPENING, // DEVICE_HUB_CONFIGURED
++ USBD_RESETING, // DEVICE_RESET
++ USBD_OK, // DEVICE_ADDRESS_ASSIGNED
++ USBD_OK, // DEVICE_CONFIGURED
++ USBD_OK, // DEVICE_SET_INTERFACE
++ USBD_OK, // DEVICE_SET_FEATURE
++ USBD_OK, // DEVICE_CLEAR_FEATURE
++ USBD_OK, // DEVICE_DE_CONFIGURED
++ USBD_SUSPENDED, // DEVICE_BUS_INACTIVE
++ USBD_OK, // DEVICE_BUS_ACTIVITY
++ USBD_RESETING, // DEVICE_POWER_INTERRUPTION
++ USBD_RESETING, // DEVICE_HUB_RESET
++ USBD_CLOSING, // DEVICE_DESTROY
++ USBD_CLOSED, // DEVICE_CLOSE
++};
++
++/*!
++ * usbd_bus_event_handler_irq() - called to respond to various usb events
++ *
++ * This is called from an interrupt context.
++ *
++ * Used by a Bus driver to indicate an event.
++ * @param bus
++ * @param event
++ * @param data
++ */
++void usbd_bus_event_handler_irq (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
++{
++ RETURN_UNLESS(bus);
++
++ /* get the next bus device state by table lookup of event, we need to save the
++ * current state IFF we are suspending so that it can be restored on resume.
++ */
++ switch (event) {
++ case DEVICE_BUS_INACTIVE:
++ bus->suspended_state = bus->device_state;
++ /* FALL THROUGH */
++ default:
++ bus->device_state = event_states[event];
++ //TRACE_MSG0(USBD, "default");
++ break;
++ case DEVICE_UNKNOWN:
++ //TRACE_MSG0(USBD, "UNKNOWN");
++ break;
++ case DEVICE_BUS_ACTIVITY:
++ bus->device_state = bus->suspended_state;
++ //TRACE_MSG0(USBD, "ACTIVITY");
++ break;
++
++ case DEVICE_SET_INTERFACE:
++ case DEVICE_SET_FEATURE:
++ case DEVICE_CLEAR_FEATURE:
++ //TRACE_MSG0(USBD, "SET");
++ break;
++ }
++
++ /* set the bus status by table lookup of event.
++ */
++ switch (event) {
++ case DEVICE_BUS_ACTIVITY:
++ case DEVICE_BUS_INACTIVE:
++ BREAK_IF(USBD_CLOSING != bus->status);
++ /* FALL THROUGH */
++ default:
++ bus->status = event_status[event];
++ //TRACE_MSG0(USBD, "DEFAULT");
++ break;
++ }
++
++ /* we need to reset things on some transitions
++ */
++ switch (bus->device_state) {
++ default:
++ // if we lost configuration then get rid of alternate settings
++ if (bus->alternates) {
++ LKFREE(bus->alternates);
++ bus->alternates = NULL;
++ }
++ bus->bNumInterfaces = 0;
++ bus->device_feature_settings = 0;
++ bus->ConfigurationValue = 0;
++ case STATE_CONFIGURED:
++ break;
++ case STATE_SUSPENDED:
++ // XXX Checkme - is suspend equivalent to end of session?
++ // C.f. OTG 6.5.1-6.5.3 imply that these must be reset at the end of a session or reset
++ //bus->device_feature_settings &=
++ // ~(FEATURE(USB_OTG_A_HNP_ENABLE) | FEATURE(USB_OTG_B_HNP_ENABLE) | FEATURE(USB_OTG_A_ALT_HNP_ENABLE));
++ break;
++ }
++ /* Pass the event to the bus interface driver and then the function driver and
++ * any interface function drivers.
++ */
++ bus->driver->bops->event_handler (bus, event, data);
++ bus->function_instance->function_driver->fops->event_handler(bus->function_instance, event, data);
++ #if 0
++ // XXX pass to interface function drivers
++ #endif
++}
++
++/*!
++ * usbd_bus_event_handler() - process bus event
++ * @param bus
++ * @param event
++ * @param data
++ */
++void usbd_bus_event_handler (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ usbd_bus_event_handler_irq(bus, event, data);
++ local_irq_restore (flags);
++}
++
++OTG_EXPORT_SYMBOL(usbd_bus_event_handler);
++OTG_EXPORT_SYMBOL(usbd_bus_event_handler_irq);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Device Request Processing:
++ * usbd_device_request()
++ *
++ */
++
++/*!
++ * C.f. 9.4 Standard Requests and table 9.3
++ *
++ * Encode valid requests into a bitmap for each recipient type for
++ * both directions. This is needed because there are some requests
++ * that appear to be a standard request but are not described in
++ * Chapter nine. For example the mouse driver hid request.
++ *
++ * So we only process the actual set of standard requests that are
++ * defined in chapter nine and even if it appears to be standard but
++ * is not in chapter nine then we pass it to the function driver.
++ *
++ * @{
++ */
++
++#define STD(x) (1<<(x+1))
++
++/*! @{ */
++/*! h2d_standard_requests and d2h_standard_requests
++ *
++ * These tables list all of the valid Chapter Nine requests. Any request
++ * not listed in these tables will NOT be processed by the EP0 function and
++ * will instead be passed to the appropriate function driver.
++ */
++u32 h2d_standard_requests[4] = {
++ // 0 - Device
++ STD(USB_REQ_CLEAR_FEATURE) |
++ STD(USB_REQ_SET_FEATURE) |
++ STD(USB_REQ_SET_ADDRESS) |
++ STD(USB_REQ_SET_DESCRIPTOR) |
++ STD(USB_REQ_SET_CONFIGURATION) ,
++ // 1 - Interface
++ STD(USB_REQ_CLEAR_FEATURE) |
++ STD(USB_REQ_SET_FEATURE) |
++ STD(USB_REQ_SET_INTERFACE) ,
++ // 2 - Endpoint
++ STD(USB_REQ_CLEAR_FEATURE) |
++ STD(USB_REQ_SET_FEATURE) ,
++ // 3 - Other
++ 0,
++};
++
++u32 d2h_standard_requests[4] = {
++ // 0 - Device
++ STD(USB_REQ_GET_STATUS) |
++ STD(USB_REQ_GET_DESCRIPTOR) |
++ STD(USB_REQ_GET_CONFIGURATION),
++ // 1 - Interface
++ STD(USB_REQ_GET_STATUS) |
++ STD(USB_REQ_GET_INTERFACE) ,
++ // 2 - Endpoint
++ STD(USB_REQ_GET_STATUS) |
++ STD(USB_REQ_SYNCH_FRAME) ,
++ // 3 - Other
++ 0,
++};
++
++/* @} */
++
++
++/*!
++ * devreq_set_configuration() - process a received urb
++ *
++ * Used by a USB Bus interface driver to pass received device request to
++ * the appropriate USB Function driver.
++ *
++ * @param function
++ * @param request
++ * @return non-zero if errror
++ */
++static int devreq_set_configuration(struct usbd_function_instance *function, int wValue)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ struct usbd_function_driver *function_driver = bus->function_instance->function_driver;
++ int bNumConfigurations = function_driver->bNumConfigurations;
++ int bNumInterfaces;
++ u8 ConfigurationValue;
++
++ struct usbd_configuration_instance *configuration_instance;
++ struct usbd_configuration_descriptor *configuration_descriptor;
++
++ // get rid of previous interface and alternates
++ if (bus->bNumInterfaces && bus->alternates) {
++ bus->bNumInterfaces = 0;
++ LKFREE(bus->alternates);
++ bus->alternates = NULL;
++ }
++
++ // c.f. 9.4.7 - the top half of wValue is reserved
++ //
++ // c.f. 9.4.7 - zero is the default or addressed state, in our case this
++ // is the same is configuration zero, but will be fixed in usbd.c when used.
++
++ ConfigurationValue = wValue & 0x7f;
++
++ RETURN_EINVAL_IF(ConfigurationValue > bNumConfigurations);
++
++ /* save ConfigurationValue for GET_CONFIGURATION request
++ */
++ bus->ConfigurationValue = ConfigurationValue;
++
++ /* A ConfigurationValue of zero is for the default configuration (i.e.) the
++ * first one. A non-zero value needs to be decremented to allow it to be used
++ * as an index.
++ */
++ ConfigurationValue = !ConfigurationValue ? 0 : ConfigurationValue -1;
++
++ configuration_instance =
++ &function_driver->configuration_instance_array[ConfigurationValue];
++
++ configuration_descriptor = configuration_instance->configuration_descriptor;
++
++ RETURN_EINVAL_IF(!configuration_descriptor);
++
++ bNumInterfaces = configuration_instance->bNumInterfaces;
++
++ /* reset interface and alternate settings
++ */
++ RETURN_EINVAL_IF (!(bus->alternates = (u8 *) CKMALLOC(bNumInterfaces, GFP_ATOMIC)));
++ bus->bNumInterfaces = bNumInterfaces;
++
++ /* Call function driver set_configuration() operation and if available any
++ * interface drivers set_configuration() operations.
++ */
++ if (function_driver->fops->set_configuration) {
++ function_driver->fops->function_enable && function_driver->fops->set_configuration (function, wValue);
++ }
++ /*
++ * XXX
++ */
++
++ usbd_bus_event_handler (bus, DEVICE_CONFIGURED, 0);
++ return 0;
++}
++
++/*!
++ * devreq_set_interface_altsetting() -
++ *
++ * Used by a USB Bus interface driver to pass received device request to
++ * the appropriate USB Function driver.
++ *
++ * @param function
++ * @param request
++ * @return non-zero if errror
++ */
++static int devreq_set_interface_altsetting(struct usbd_function_instance *function, int wIndex, int wValue)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ struct usbd_function_driver *function_driver = function->function_driver;
++
++ RETURN_EINVAL_IF(wIndex > bus->bNumInterfaces); // wIndex is interface
++
++ bus->alternates[wIndex] = (u8) wValue;
++
++ /* Call function driver set_interface() operation and if available any
++ * interface drivers set_interface() operations.
++ */
++ if (function_driver->fops->set_interface)
++ function_driver->fops->function_enable && function_driver->fops->set_interface (function, wIndex, wValue);
++ /*
++ * XXX
++ */
++
++ usbd_bus_event_handler (bus, DEVICE_SET_INTERFACE, 0);
++
++ return 0;
++}
++
++/*!
++ * devreq_get_device_feature_settings() - process a received urb
++ *
++ * Used by a USB Bus interface driver to pass received device request to
++ * the appropriate USB Function driver.
++ *
++ * @param function
++ * @param request
++ * @return non-zero if errror
++ */
++int devreq_get_device_feature_settings(struct usbd_function_instance *function)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ return bus->device_feature_settings;
++}
++
++
++/*! devreq_device_feature - handle set/clear feature requests for device
++ * Used by the USB Device Core to set/clear endpoint halt status.
++ *
++ * We assume that if the udc driver does not implement anything then
++ * we should just return zero for ok.
++ */
++int devreq_device_feature (struct usbd_bus_instance *bus, int features, int flag)
++{
++ struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
++ //u32 features = bus->device_feature_settings;
++
++ TRACE_MSG0(USBD, "BUS_DEVICE FEATURE");
++
++ /* if A-Device has enabled hnp
++ */
++ if (features & FEATURE(USB_OTG_B_HNP_ENABLE) )
++ otg_event(pcd->otg, HNP_ENABLED, USBD, "DEVICE FEATURE - B_HNP_ENABLE");
++
++ /* if A-Device does not support HNP on this port
++ */
++ else if ( features & FEATURE(USB_OTG_A_ALT_HNP_ENABLE) )
++ ; //otg_event(pcd->otg, not(a_hnp_support));
++
++ /* if A-Device does support HNP
++ */
++ else if (features & FEATURE(USB_OTG_A_HNP_SUPPORT))
++ ; //otg_event(pcd->otg, a_hnp_support);
++
++ return 0;
++ //return usbd_pcd_ops.device_feature ? usbd_pcd_ops.device_feature() : 0;
++}
++
++/*!
++ * copy_config() - copy data into buffer
++ */
++static int copy_config (u8 *cp, void *data, int actual_length, int max_buf)
++{
++ int available = max_buf - actual_length;
++ int length = MIN(*(u8 *)data, available);
++ RETURN_ZERO_UNLESS (data);
++ RETURN_ZERO_UNLESS (length);
++ memcpy (cp, data, length);
++ return length;
++}
++
++/*!
++ * copy_endpoint() - copy data into buffer
++ */
++static int copy_endpoint (struct usbd_function_instance *function, u8 *cp,
++ struct usbd_endpoint_descriptor *endpoint, int endpoint_index, int actual_length, int max_buf, int hs)
++{
++ int available = max_buf - actual_length;
++ int length = MIN(endpoint->bLength, available);
++ struct usbd_endpoint_descriptor endpoint_copy;
++
++ RETURN_ZERO_IF (!length);
++ memcpy (&endpoint_copy, endpoint, endpoint->bLength);
++ usbd_endpoint_update(function, endpoint_index, &endpoint_copy, hs);
++ memcpy (cp, &endpoint_copy, length);
++ return length;
++}
++
++
++/*!
++ * usbd_old_get_descriptor() - copy a descriptor into buffer
++ *
++ * Return non-zero for error.
++ */
++int usbd_old_get_descriptor (struct usbd_function_instance *function, u8 *buffer, int max, int descriptor_type, int index)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ struct usbd_function_driver *function_driver = bus->function_instance->function_driver;
++ int actual_length = 0;
++
++ switch (descriptor_type) {
++ case USB_DT_DEVICE:
++ {
++ struct usbd_device_descriptor *device_descriptor = function_driver->device_descriptor;
++
++ // copy descriptor for this device
++ actual_length += copy_config (buffer + actual_length, device_descriptor, actual_length, max);
++
++ // correct the correct control endpoint 0 max packet size into the descriptor
++ device_descriptor = (struct usbd_device_descriptor *) buffer;
++ device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
++ }
++ break;
++
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ case USB_DT_DEVICE_QUALIFIER: // c.f. 9.6.2 Device Qualifier
++ {
++ struct usbd_device_qualifier_descriptor *device_qualifier_descriptor =
++ function_driver->device_qualifier_descriptor;
++
++ // copy descriptor for this device
++ actual_length += copy_config (buffer + actual_length, device_qualifier_descriptor, actual_length, max);
++
++ }
++ break;
++
++ case USB_DT_OTHER_SPEED_CONFIGURATION:
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++
++ case USB_DT_CONFIGURATION:
++ {
++ #ifdef CONFIG_OTG_HIGH_SPEED
++ int hs = bus->HighSpeedFlag ? descriptor_type == USB_DT_CONFIGURATION:
++ descriptor_type == USB_DT_OTHER_SPEED_CONFIGURATION;
++ #else /* CONFIG_OTG_HIGH_SPEED */
++ int hs = 0;
++ #endif /* CONFIG_OTG_HIGH_SPEED */
++ int interface_num;
++
++ struct usbd_configuration_instance *configuration_instance =
++ &function_driver->configuration_instance_array[index];
++
++ struct usbd_configuration_descriptor *configuration_descriptor =
++ configuration_instance->configuration_descriptor;
++
++ struct usbd_otg_descriptor *otg_descriptor = function_driver->otg_descriptor;
++
++ RETURN_EINVAL_IF (!configuration_descriptor);
++ RETURN_EINVAL_IF (index > function_driver->device_descriptor->bNumConfigurations);
++
++ actual_length += copy_config (buffer + actual_length, configuration_descriptor, actual_length, max);
++
++ // iterate across all bNumInterfaces for specified configuration
++ for (interface_num = 0; interface_num < configuration_descriptor->bNumInterfaces; interface_num++) {
++
++ int alternate_num;
++ struct usbd_interfaces_instance *interfaces_instance =
++ configuration_instance->interfaces_instance_array + interface_num;
++
++ // iterate across all interface alternates
++ for (alternate_num = 0; alternate_num < interfaces_instance->alternates; alternate_num++) {
++
++ int class_num;
++ int endpoint;
++
++ struct usbd_alternate_instance *alternate_instance =
++ interfaces_instance->alternates_instance_array + alternate_num;
++
++ //struct usbd_interface_descriptor *usbd_interface_descriptor;
++
++ // copy descriptor for this interface
++ actual_length += copy_config (buffer + actual_length,
++ alternate_instance->interface_descriptor, actual_length, max);
++
++ // iterate across all classes for the alternate interface
++ for (class_num = 0; class_num < alternate_instance->classes; class_num++)
++ actual_length += copy_config (buffer + actual_length,
++ *(alternate_instance->class_list + class_num),
++ actual_length, max);
++
++ // iterate across all endpoints for the alternate interface
++ //interface_descriptor = alternate_instance->interface_descriptor;
++
++ for (endpoint = 0; endpoint < alternate_instance->endpoints ; endpoint++) {
++
++ TRACE_MSG2(USBD, "endpoint: %d index: %d",
++ endpoint, alternate_instance->endpoint_indexes[endpoint]);
++
++ actual_length += copy_endpoint (
++ bus->function_instance,
++ buffer + actual_length,
++ *(( alternate_instance->endpoint_list) + endpoint),
++ alternate_instance->endpoint_indexes[endpoint],
++ actual_length,
++ max,
++ hs);
++ }
++ }
++ }
++
++ /* copy the OTG descriptor if required
++ */
++ actual_length += copy_config (buffer + actual_length, otg_descriptor, actual_length, max);
++
++ /* set the configuration attributes and power fields in the configuration descriptor
++ */
++ configuration_descriptor = (struct usbd_configuration_descriptor *)buffer;
++
++ configuration_descriptor->bmAttributes = BMATTRIBUTE_RESERVED;
++
++ if (bus->device_feature_settings & FEATURE(USB_DEVICE_REMOTE_WAKEUP))
++ configuration_descriptor->bmAttributes |= BMATTRIBUTE_REMOTE_WAKEUP;
++
++ if (bus->driver->bMaxPower == 0) {
++ configuration_descriptor->bmAttributes |= BMATTRIBUTE_SELF_POWERED;
++ configuration_descriptor->bMaxPower = 1;
++ }
++ else
++ configuration_descriptor->bMaxPower = bus->driver->bMaxPower;
++
++ TRACE_MSG2(USBD, "bmAttributes: %02x bMaxPower: %02x",
++ configuration_descriptor->bmAttributes, configuration_descriptor->bMaxPower);
++ }
++ break;
++
++ case USB_DT_STRING:
++ {
++ struct usbd_string_descriptor *string_descriptor = NULL;
++ RETURN_EINVAL_IF (!(string_descriptor = usbd_get_string_descriptor ((u8)index)));
++ actual_length += copy_config (buffer + actual_length, string_descriptor, actual_length, max);
++ }
++ break;
++ default:
++ return -EINVAL;
++ }
++ return actual_length;
++}
++
++
++
++
++/*!
++ * setclear() - set or reset a bit in a mask
++ * @param features
++ * @param flag
++ * @param value
++ */
++static void setclear(u32 *features, u32 flag, u32 value)
++{
++ if (value) *features |= flag;
++ else *features &= ~flag;
++}
++
++/*! do_standard_device_request - process a device request
++ *
++ * Process a received device request. If not a Chapter nine request pass it
++ * to the other loaded function driver device_request() function.
++ *
++ * Return non-zero to indicate failure.
++ */
++static int do_standard_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ u8 bRequest = request->bRequest;
++ u8 bmRequestType = request->bmRequestType;
++ u16 wValue = le16_to_cpu(request->wValue);
++ u16 wIndex = le16_to_cpu(request->wIndex);
++ u16 wLength = le16_to_cpu(request->wLength);
++ u16 endpoint_index;
++
++ usbd_device_state_t device_state = usbd_get_device_state(function);
++
++ switch (device_state) {
++ case STATE_CREATED:
++ case STATE_ATTACHED:
++ case STATE_POWERED:
++ TRACE_MSG1(USBD, "bad device_state: %d", device_state);
++ return -EINVAL;
++
++ case STATE_INIT:
++ case STATE_DEFAULT:
++ switch (bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_GET_INTERFACE:
++ case USB_REQ_GET_STATUS:
++ case USB_REQ_SET_DESCRIPTOR:
++ case USB_REQ_SET_INTERFACE:
++ case USB_REQ_SYNCH_FRAME:
++ TRACE_MSG2(USBD, "bad request: %d for this device_state: %d", bRequest, device_state);
++ return -EINVAL;
++
++ case USB_REQ_GET_CONFIGURATION:
++ case USB_REQ_SET_ADDRESS:
++ case USB_REQ_SET_CONFIGURATION:
++ case USB_REQ_GET_DESCRIPTOR:
++ case USB_REQ_SET_FEATURE:
++ break;
++ }
++ case STATE_ADDRESSED:
++ case STATE_CONFIGURED:
++ case STATE_SUSPENDED:
++ break;
++ case STATE_UNKNOWN:
++ TRACE_MSG1(USBD, "unknown device_state: %d", device_state);
++ return -EINVAL;
++ }
++
++ /* Handle all requests that return data (direction bit set on bm RequestType).
++ * N.B. no Chapter 9 requests send additional data.
++ */
++ if ((bmRequestType & USB_REQ_DIRECTION_MASK)) {
++ struct usbd_urb *urb;
++ int rc = 0;
++ switch (bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_ADDRESS:
++ case USB_REQ_SET_CONFIGURATION:
++ case USB_REQ_SET_DESCRIPTOR:
++ case USB_REQ_SET_FEATURE:
++ case USB_REQ_SET_INTERFACE:
++ case USB_REQ_SYNCH_FRAME:
++ TRACE_MSG0(USBD, "bad direction");
++ return -EINVAL;
++ }
++
++ RETURN_EINVAL_IF(!wLength);
++
++ /* allocate urb, no callback, urb will be automatically de-allocated
++ */
++ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0 (function, wLength, NULL)));
++
++ switch (bRequest) {
++
++ case USB_REQ_GET_STATUS:
++ urb->actual_length = 2;
++ urb->buffer[0] = urb->buffer[1] = 0;
++
++ rc = 0;
++ switch (bmRequestType & USB_REQ_RECIPIENT_MASK) {
++ case USB_REQ_RECIPIENT_DEVICE:
++
++ UNLESS (usbd_get_bMaxPower(function)) urb->buffer[0] |= USB_STATUS_SELFPOWERED;
++ urb->buffer[0] |=
++ (devreq_get_device_feature_settings(function) & FEATURE(USB_DEVICE_REMOTE_WAKEUP)) ?
++ USB_STATUS_REMOTEWAKEUP : 0;
++ break;
++ case USB_REQ_RECIPIENT_ENDPOINT:
++ RETURN_EINVAL_UNLESS((endpoint_index = usbd_find_endpoint_index(bus, wIndex)) < bus->endpoints);
++ urb->buffer[0] = usbd_endpoint_halted (function, endpoint_index);
++ break;
++ case USB_REQ_RECIPIENT_INTERFACE:
++ break;
++ case USB_REQ_RECIPIENT_OTHER:
++ default:
++ TRACE_MSG0(USBD, "bad recipient");
++ rc = -EINVAL;
++ }
++ break;
++
++ case USB_REQ_GET_DESCRIPTOR:
++ rc = usbd_old_get_descriptor (function, urb->buffer, wLength, wValue >> 8, wValue & 0xff);
++ if (rc != -EINVAL) {
++ urb->actual_length = rc;
++ rc = 0;
++ }
++ else
++ TRACE_MSG0(USBD, "bad description");
++ break;
++
++ case USB_REQ_GET_CONFIGURATION:
++ TRACE_MSG1(USBD, "GET CONFIGURATION: %d", bus->ConfigurationValue);
++ urb->actual_length = 1;
++ urb->buffer[0] = bus->ConfigurationValue;
++ break;
++
++ case USB_REQ_GET_INTERFACE:
++ RETURN_EINVAL_IF(wIndex > bus->bNumInterfaces);
++ urb->actual_length = 1;
++ urb->buffer[0] = bus->alternates[wIndex];
++ break;
++ default:
++ TRACE_MSG0(USBD, "bad descriptor type");
++ rc = 1;
++ }
++
++ if (!(urb->actual_length % usbd_endpoint_zero_wMaxPacketSize(function, usbd_high_speed(function))) &&
++ (urb->actual_length < wLength))
++ urb->flags |= USBD_URB_SENDZLP;
++
++ RETURN_ZERO_UNLESS(rc || usbd_start_in_urb(urb));
++ /* only get here if error */
++ usbd_free_urb(urb);
++ TRACE_MSG0(USBD, "get failed");
++ return -EINVAL;
++ }
++ /* Handle the requests that do not return data.
++ */
++ else {
++ int setclear_flag = USB_REQ_SET_FEATURE == bRequest;
++ switch (bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++ case USB_REQ_SET_FEATURE:
++ TRACE_MSG2(USBD, "FEATURE: recipient: %d wValue: %d",
++ bmRequestType & USB_REQ_RECIPIENT_MASK, wValue);
++ switch (bmRequestType & USB_REQ_RECIPIENT_MASK) {
++ case USB_REQ_RECIPIENT_DEVICE:
++ //switch (wValue) {
++ // otg_event(pcd->otg, HNP_ENABLED, PCD, "DEVICE FEATURE - B_HNP_ENABLE");
++ // break;
++ //}
++ switch (wValue) {
++ case USB_OTG_A_ALT_HNP_ENABLE: // C.f. OTG 6.5.3
++ case USB_OTG_A_HNP_SUPPORT: // C.f. OTG 6.5.2
++ case USB_OTG_B_HNP_ENABLE: // C.f. OTG 6.5.1
++ RETURN_EINVAL_UNLESS(setclear_flag); // cleared by reset
++ case USB_DEVICE_REMOTE_WAKEUP:
++ break;
++ default:
++ return -EINVAL;
++ }
++ setclear(&bus->device_feature_settings, FEATURE(wValue), setclear_flag);
++ return devreq_device_feature(bus, FEATURE(wValue), setclear_flag);
++
++ case USB_REQ_RECIPIENT_ENDPOINT:
++ RETURN_EINVAL_UNLESS(USB_ENDPOINT_HALT == wValue);
++
++ setclear(&(bus->endpoint_array[wIndex].feature_setting),
++ FEATURE(wValue), bRequest == USB_REQ_SET_FEATURE);
++
++ /* wIndex contains bEndpointAddress, also find and verify the endpoint map index as well.
++ * Then clear the endpoint using the bus interface driver halt_endpoint() operation,
++ * if that is ok, then inform the function driver using the endpoint_cleared() operation.
++ *
++ */
++ RETURN_EINVAL_UNLESS((endpoint_index = usbd_find_endpoint_index(bus, wIndex)) < bus->endpoints);
++ RETURN_EINVAL_IF(function->bus->driver->bops->halt_endpoint(bus, wIndex,
++ endpoint_index, setclear_flag));
++
++ if (function->function_driver->fops->endpoint_cleared && !setclear_flag)
++ function->function_driver->fops->endpoint_cleared(function, wIndex, endpoint_index );
++
++ return 0;
++
++ case USB_REQ_RECIPIENT_INTERFACE:
++ case USB_REQ_RECIPIENT_OTHER:
++ default:
++ TRACE_MSG0(USBD, "bad recipient");
++ return -EINVAL;
++ }
++
++ case USB_REQ_SET_ADDRESS:
++ if (bus->driver->bops->set_address) bus->driver->bops->set_address (bus, wValue);
++ usbd_bus_event_handler (bus, DEVICE_ADDRESS_ASSIGNED, wValue);
++ return 0;
++
++ case USB_REQ_SET_DESCRIPTOR:
++ TRACE_MSG0(USBD, "set descriptor not supported");
++ return -EINVAL;
++
++ case USB_REQ_SET_CONFIGURATION:
++ return devreq_set_configuration(function, wValue);
++
++ case USB_REQ_SET_INTERFACE:
++ return devreq_set_interface_altsetting(function, wIndex, wValue);
++
++ case USB_REQ_GET_CONFIGURATION:
++ case USB_REQ_GET_DESCRIPTOR:
++ case USB_REQ_GET_INTERFACE:
++ case USB_REQ_GET_STATUS:
++ case USB_REQ_SYNCH_FRAME:
++ TRACE_MSG0(USBD, "unkown");
++ return -EINVAL;
++ }
++ }
++ TRACE_MSG0(USBD, "not possible");
++ return -EINVAL;
++}
++
++
++/*!
++ * usbd_device_request() - process a device request
++ *
++ * Used by a USB Bus interface driver to pass received device request to
++ * the appropriate USB Function driver.
++ *
++ * @param function
++ * @param request
++ * @return non-zero if errror
++ */
++int usbd_device_request(struct usbd_bus_instance *bus, struct usbd_device_request *request)
++{
++ struct usbd_function_instance *function = bus->function_instance;
++ u8 bRequest = request->bRequest;
++ u8 bmRequestType = request->bmRequestType;
++ u16 wValue = le16_to_cpu(request->wValue);
++ u16 wIndex = le16_to_cpu(request->wIndex);
++ u16 wLength = le16_to_cpu(request->wLength);
++
++ TRACE_MSG5(USBD, "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x",
++ bmRequestType, bRequest, wValue, wIndex, wLength);
++
++ /* Handle only USB Standard Requests (c.f. USB Spec table 9-2, D6..5 must be 0),
++ * otherwise call the currently enabled function specific receive setup.
++ */
++ if (!(bmRequestType & USB_REQ_TYPE_MASK) &&
++ ((bmRequestType & USB_DIR_IN ? d2h_standard_requests : h2d_standard_requests)
++ [bmRequestType & 0x3] & STD(bRequest)))
++ return do_standard_device_request(function, request);
++
++ /* Standard Requests not in Chapter nine, Class and Vendor device requests
++ * must be handled by the function driver or interface driver as appropriate.
++ */
++ switch(bmRequestType & USB_REQ_RECIPIENT_MASK) {
++ case USB_REQ_RECIPIENT_INTERFACE:
++ case USB_REQ_RECIPIENT_ENDPOINT:
++ /* XXX
++ * if function->interfaces[] is valid then we shuffle request off to
++ * interface driver for interface and endpoint recipients, otherwise
++ * fall through.
++ */
++
++ /*
++ * XXX for now just fall through for all.
++ */
++
++ case USB_REQ_RECIPIENT_DEVICE:
++ case USB_REQ_RECIPIENT_OTHER:
++ default:
++ return function->function_driver->fops->device_request(function, request);
++ }
++}
++
++OTG_EXPORT_SYMBOL(usbd_device_request);
++OTG_EXPORT_SYMBOL(usbd_old_get_descriptor);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Device I/O:
++ * usbd_urb_finished()
++ * usbd_first_urb_detached()
++ * usbd_find_endpoint_address()
++ */
++
++/*!
++ * do_urb_callback() - tell function that an urb has been transmitted.
++ *
++ * Must be called from an interrupt or with interrupts disabled.
++ *
++ * Used by a USB Bus driver to pass a sent urb back to the function
++ * driver via the endpoints done queue.
++ *
++ * If there is no callback or if the URB call back returns non-zero then the
++ * urb must be de-allocated here.
++ *
++ * @param urb
++ * @param rc
++ */
++static void do_urb_callback (struct usbd_urb *urb, int rc)
++{
++ RETURN_UNLESS (urb);
++ if (!urb->callback || urb->callback(urb,rc))
++ usbd_free_urb(urb);
++}
++
++/*!
++ * urb_append_irq() - append a linked list of urbs to another linked list
++ * @param hd link to urb list
++ * @param urb to append to list
++ */
++static INLINE void urb_append_irq (urb_link * hd, struct usbd_urb *urb)
++{
++ urb_link *new;
++ urb_link *pul;
++ RETURN_UNLESS (hd && urb);
++ new = &urb->link;
++ pul = hd->prev;
++ new->prev->next = hd;
++ hd->prev = new->prev;
++ new->prev = pul;
++ pul->next = new;
++}
++
++/*!
++ * urb_append() - irq safe version
++ * @param hd list of urbs
++ * @param urb urb to append
++ */
++void urb_append(urb_link *hd, struct usbd_urb *urb)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ urb_append_irq(hd, urb);
++ local_irq_restore (flags);
++}
++
++
++/*!
++ * usbd_urb_finished() - tell function that an urb has been finished.
++ *
++ * Used by a USB Bus driver to pass a sent urb back to the function
++ * driver via the endpoints finished queue.
++ * @param urb urb to process
++ * @param rc result code
++ *
++ */
++void usbd_urb_finished(struct usbd_urb *urb, int rc)
++{
++ urb->status = (usbd_urb_status_t)rc;
++ #if defined(OTG_LINUX)
++ urb->jiffies = jiffies;
++ #endif /* defined(OTG_LINUX) */
++ if (USBD_OK != urb->bus->status)
++ do_urb_callback (urb, rc);
++ else {
++ urb_append_irq (&(urb->bus->finished), urb);
++ RETURN_IF (PENDING_WORK_ITEM(urb->bus->device_bh));
++#ifdef LINUX24
++ //FIXME XXX
++ queue_task (&urb->bus->device_bh, &tq_immediate);
++ mark_bh (IMMEDIATE_BH);
++#else
++ SCHEDULE_WORK(urb->bus->device_bh);
++#endif
++ }
++}
++void usbd_urb_finished_irq (struct usbd_urb *urb, int rc)
++{
++ usbd_urb_finished(urb, rc);
++}
++
++/*!
++ * @name STRUCT
++ * @brief
++ * Structure member address manipulation macros.
++ *
++ * These are used by client code (code using the urb_link routines), since
++ * the urb_link structure is embedded in the client data structures.
++ *
++ * Note: a macro offsetof equivalent to member_offset is defined in stddef.h
++ * but this is kept here for the sake of portability.
++ *
++ * p2surround returns a pointer to the surrounding structure given
++ * type of the surrounding structure, the name memb of the structure
++ * member pointed at by ptr. For example, if you have:
++ *
++ * struct foo {
++ * int x;
++ * float y;
++ * char z;
++ * } thingy;
++ *
++ * char *cp = &thingy.z;
++ *
++ * then
++ * &thingy == p2surround(struct foo, z, cp)
++ *
++ * @{
++ */
++
++#define _cv_(ptr) ((char*)(void*)(ptr))
++#define member_offset(type,memb) (_cv_(&(((type*)0)->memb))-(char*)0)
++#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
++
++/*!
++ * @name list
++ * @brief List support functions
++ *
++ * @{
++ */
++
++/*!
++ * urb_link() - return first urb_link in list
++ *
++ * Return the first urb_link in a list with a distinguished
++ * head "hd", or NULL if the list is empty. This will also
++ * work as a predicate, returning NULL if empty, and non-NULL
++ * otherwise.
++ *
++ * Called from interrupt.
++ *
++ * @return link to urb
++ */
++static INLINE urb_link *first_urb_link_irq (urb_link * hd)
++{
++ urb_link *nx;
++ return (!hd || !(nx = hd->next) || (nx == hd)) ? NULL : nx;
++}
++
++/*!
++ * first_urb_irq() - return first urb in list
++ * Return the first urb in a list with a distinguished
++ * head "hd", or NULL if the list is empty.
++ *
++ * Called from interrupt.
++ *
++ * @param hd linked list of urbs
++ * @return pointer to urb
++ */
++static INLINE struct usbd_urb *first_urb_irq (urb_link * hd)
++{
++ urb_link *nx;
++ return (!(nx = first_urb_link_irq (hd))) ? NULL : p2surround (struct usbd_urb, link, nx);
++}
++
++
++
++/*!
++ * usbd_first_urb_detached_irq() - detach an return first urb
++ * Detach and return the first urb in a list with a distinguished
++ * head "hd", or NULL if the list is empty.
++ *
++ * @param hd linked list of urbs
++ * @return pointer to urb or NULL
++ */
++struct usbd_urb *usbd_first_urb_detached_irq (urb_link * hd)
++{
++ struct usbd_urb *urb;
++ urb_link *ul;
++ RETURN_NULL_IF (!(urb = first_urb_irq (hd)));
++ ul = &urb->link;
++ ul->next->prev = ul->prev;
++ ul->prev->next = ul->next;
++ ul->prev = ul->next = ul;
++ return urb;
++}
++/* @} */
++
++/*!
++ * usbd_first_urb_detached() - detach and return urb
++ *
++ * Detach and return the first urb in a list with a distinguished
++ * head "hd", or NULL if the list is empty.
++ *
++ * @param hd list of urbs
++ * @return pointer to urb or NULL
++ */
++struct usbd_urb *usbd_first_urb_detached (urb_link * hd)
++{
++ struct usbd_urb *urb;
++ unsigned long flags;
++ local_irq_save (flags);
++ urb = usbd_first_urb_detached_irq (hd);
++ local_irq_restore (flags);
++ return urb;
++}
++
++
++/*!
++ * usbd_find_endpoint_index()
++ * @param bus
++ * @param bEndpointAddress
++ * Find the endpoint map index for the specified bEndpointAddress.
++ */
++int usbd_find_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress)
++{
++ int i;
++ for (i = 0; i < bus->endpoints; i++)
++ BREAK_IF (bus->endpoint_array[i].bEndpointAddress == bEndpointAddress);
++ return i;
++}
++
++OTG_EXPORT_SYMBOL(usbd_urb_finished);
++OTG_EXPORT_SYMBOL(usbd_urb_finished_irq);
++OTG_EXPORT_SYMBOL(usbd_first_urb_detached);
++OTG_EXPORT_SYMBOL(usbd_first_urb_detached_irq);
++OTG_EXPORT_SYMBOL(usbd_find_endpoint_index);
++
++/* ********************************************************************************************** */
++/* usbb bus bottom half ************************************************************************* */
++
++/*!
++ * usbd_device_bh() - Bottom half handler to process sent or received urbs.
++ * @param data
++ */
++void usbd_device_bh (void *data)
++{
++ struct usbd_bus_instance *bus = data;
++ struct usbd_endpoint_instance *endpoint;
++ struct usbd_urb *urb;
++
++ RETURN_IF (!bus || !(endpoint = bus->endpoint_array));
++ DOWN(&usbd_bus_sem);
++
++ for (; (urb = usbd_first_urb_detached (&bus->finished)); do_urb_callback (urb, urb->status));
++
++ #if defined(OTG_LINUX)
++ if (USBD_CLOSING == bus->status)
++ bus->device_bh.data = NULL;
++ #endif /* defined(OTG_LINUX) */
++ UP(&usbd_bus_sem);
++}
++
++/* ********************************************************************************************** */
++/* Module init ********************************************************************************** */
++
++extern char * usbd_function_name(int n);
++struct usbd_ops usbd_ops;
++otg_tag_t USBD;
++
++/*!
++ * usbd_device_init() - initialize
++ */
++int usbd_device_init (void)
++{
++ USBD = otg_trace_obtain_tag();
++ TRACE_MSG0(USBD,"--");
++ usbd_ops.function_name = usbd_function_name;
++ otg_set_usbd_ops(&usbd_ops);
++ return 0;
++}
++
++/*!
++ * usbd_device_exit() - de-initialize
++ */
++void usbd_device_exit (void)
++{
++ otg_set_usbd_ops(NULL);
++ otg_trace_invalidate_tag(USBD);
++}
++
++
+diff -uNr linux/drivers/no-otg/otgcore/usbp-fops.c linux/drivers/otg/otgcore/usbp-fops.c
+--- linux/drivers/no-otg/otgcore/usbp-fops.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/usbp-fops.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,1123 @@
++/*
++ * otg/otgcore/usbp-fops.c - USB Function support
++ *
++ * Copyright (c) 2004-2005 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/usbp-fops.c
++ * @brief Function driver related functions.
++ *
++ * This implements the functions used to implement USB Function drivers.
++ *
++ * @ingroup USBP
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#include <otg/usbp-chap9.h>
++#include <otg/otg-trace.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++
++struct usbd_string_descriptor **usb_strings;
++void urb_append(urb_link *hd, struct usbd_urb *urb);
++
++LIST_NODE_INIT(usbd_function_instances); // list of all registered configuration function modules
++LIST_NODE_INIT(usbd_interface_instances); // list of all registered interface function modules
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Function Registration:
++ * usbd_register_function()
++ * usbd_register_interface()
++ * usbd_register_composite()
++ * usbd_deregister_function()
++ * usbd_find_function()
++ * usbd_find_interface()
++ *
++ */
++
++/*!
++ * usbd_register_function_internal() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param function_driver
++ * @param privdata
++ * @return function instance
++ *
++ */
++static struct usbd_function_instance *
++usbd_register_function_internal(struct usbd_function_driver *function_driver, char *name,
++ usbd_function_types_t function_type, char **interface_list, void *privdata)
++{
++ struct usbd_function_instance *function = NULL;
++
++ TRACE_MSG3(USBD, "interface: %s driver: %s endpoints: %d", name,
++ function_driver->name, function_driver->endpointsRequested);
++
++ if (!(function = (struct usbd_function_instance *) CKMALLOC (sizeof (struct usbd_function_instance), GFP_KERNEL))) {
++ #if defined(OTG_LINUX)
++ printk(KERN_ERR,"usbd_function_instance allocation failed.\n");
++ #endif /* defined(OTG_LINUX) */
++ #if defined(OTG_WINCE)
++ DEBUGMSG(ZONE_INIT, (_T("usbd_register_function: FAILED\n")));
++ #endif /* defined(OTG_LINUX) */
++ return(NULL);
++ }
++ function->name = LSTRDUP(name);
++ function->function_driver = function_driver;
++ function->privdata = privdata;
++ function->function_type = function_type;
++ function->interfaces_list = interface_list;
++
++ //function->endpointsRequested = function->function_driver->endpointsRequested;
++ //function->requestedEndpoitns = function->function_driver->requestedEndpoints;
++
++ switch(function_type) {
++ case function_simple:
++ case function_interface:
++ break;
++ case function_composite:
++ break;
++ }
++
++ if (!(function->endpoint_map_array = (struct usbd_endpoint_map *)
++ CKMALLOC (sizeof(struct usbd_endpoint_map) *
++ function_driver->endpointsRequested, GFP_KERNEL))) {
++ #if defined(OTG_LINUX)
++ printk(KERN_ERR,"usbd_endpoint_map allocation failed.\n");
++ #endif /* defined(OTG_LINUX) */
++ #if defined(OTG_WINCE)
++ DEBUGMSG(ZONE_INIT, (_T("usbd_register_function: FAILED\n")));
++ #endif /* defined(OTG_LINUX) */
++ LKFREE(function);
++ return(NULL);
++ }
++
++ switch(function_type) {
++ case function_simple:
++ case function_interface:
++ case function_composite:
++ break;
++ }
++ return function;
++}
++
++/*!
++ * usbd_register_function() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param function_driver
++ * @param privdata
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *
++usbd_register_function (struct usbd_function_driver *function_driver, char * name, void *privdata)
++{
++ struct usbd_function_instance *function =
++ usbd_register_function_internal(function_driver, name, function_simple, NULL, privdata);
++ TRACE_MSG1(USBD, "%s", name);
++
++ LIST_ADD_TAIL (&function->instances, &usbd_function_instances);
++ return function;
++}
++
++/*!
++ * usbd_register_interface() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param function_driver
++ * @param privdata
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *
++usbd_register_interface(struct usbd_function_driver *function_driver, char * name, void *privdata)
++{
++ struct usbd_function_instance *function =
++ usbd_register_function_internal(function_driver, name, function_interface, NULL, privdata);
++ TRACE_MSG1(USBD, "%s", name);
++ LIST_ADD_TAIL (&function->instances, &usbd_interface_instances);
++ return function;
++}
++
++/*!
++ * usbd_register_composite() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param function_driver
++ * @param privdata
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *
++usbd_register_composite (struct usbd_function_driver *function_driver, char * name, char **interfaces_list, void *privdata)
++{
++ struct usbd_function_instance *function = NULL;
++ struct usbd_function_instance **interfaces_array = NULL;
++ struct usbd_endpoint_request *requestedEndpoints = NULL;
++ struct usbd_endpoint_map *endpoint_map_array = NULL;
++
++ int i, j, k, l;
++ char *interface_name;
++ int endpoints = 0;
++ int cfg_length = 0;
++
++ TRACE_MSG1(USBD, "%s", name);
++ THROW_UNLESS((function = usbd_register_function_internal(function_driver,
++ name, function_composite, interfaces_list, privdata)), error);
++
++ /* list and count interfaces, then allocate interfaces_array.
++ */
++ for (i = 0; (interface_name = function->interfaces_list[i]); i++) {
++ TRACE_MSG2(USBD, "INTERFACE[%02d] %20s", i, interface_name);
++ }
++ function->interfaces = i;
++
++ TRACE_MSG1(USBD, "interfaces: %d", function->interfaces);
++
++ THROW_UNLESS((interfaces_array = (struct usbd_function_instance **)
++ CKMALLOC (sizeof(struct usbd_function_instance) * function->interfaces, GFP_KERNEL)), error);
++ function->interfaces_array = interfaces_array;
++
++#if 0
++ /* Find all interfaces and compose the interface list, count the endpoints
++ * and allocte the endpoint request array. Also find and total descriptor sizes.
++ */
++ for (i = 0; i < function->interfaces; i++) {
++ struct usbd_function_instance *interface_function;
++ struct usbd_interface_description *interface_description = interface_function->interface_list;
++ THROW_UNLESS(interface_function = usbd_find_interface(interfaces_list[i]), error);
++
++ TRACE_MSG4(USBD, "interface_function: %x name: %s driver: %s %d", interface_function,
++ interface_function->name,
++ interface_function->function_driver->name,
++ interface_function->function_driver->endpointsRequested);
++
++ interfaces_array[i] = interface_function;
++ endpoints += interface_function->function_driver->endpointsRequested;
++ TRACE_MSG4(USBD, "ENDPOINT [%02d] %20s %02d %02d",
++ i, interfaces_list[i], interface_function->function_driver->endpointsRequested, endpoints);
++
++ /* iterate across all interface descriptions */
++ for (j = 0; j < bNumInterfaces; j++) {
++ struct usbd_alternate_instance *alternate_instance = interface_description[j];
++
++ /* iterate across all alternates for this interface */
++ for (k = 0; k < interface_description[j].alternates; k++) {
++
++
++
++ }
++ }
++
++ }
++#endif
++ function->endpoints = endpoints;
++ TRACE_MSG2(USBD, "endpoints: %d %d", endpoints, function->endpoints);
++
++
++ /* requeset the endpoints from the bus interface driver
++ */
++ THROW_UNLESS((requestedEndpoints = (struct usbd_endpoint_request *)
++ CKMALLOC (sizeof(struct usbd_endpoint_request) * function->endpoints, GFP_KERNEL)), error);
++
++ function->requestedEndpoints = requestedEndpoints;
++#if 0
++ /* we need to compose the endpoint request array
++ */
++ for (endpoints = 0, i = 0; i < function->interfaces; i++) {
++ struct usbd_function_instance *interface_function = interfaces_array[i];
++ struct usbd_interface_description *interface_description = interface_function->interface_list;
++
++ for (j = 0; j < interface_function->endpoints; j++) {
++ memcpy(&requestedEndpoints[endpoints], &interface_function->requestedEndpoints[j],
++ sizeof(struct usbd_endpoint_request));
++ requestedEndpoints[endpoints].interface_num = i;
++ }
++ }
++#endif
++
++
++ /* Insert into function list
++ */
++ LIST_ADD_TAIL (&function->instances, &usbd_function_instances);
++ return function;
++
++ CATCH(error) {
++ if (requestedEndpoints) LKFREE(requestedEndpoints);
++ if (interfaces_array) LKFREE(interfaces_array);
++ if (function) usbd_deregister_function(function);
++ return NULL;
++ }
++}
++
++/*!
++ * usbd_deregister_function() - de-register a usbd function driver instance
++ *
++ * USBD Function drivers call this to de-register with the USBD Core layer.
++ * @param function_instance
++ */
++void usbd_deregister_function (struct usbd_function_instance *function_instance)
++{
++ RETURN_UNLESS (function_instance);
++ LIST_DEL (function_instance->instances);
++ if (function_instance->name) LKFREE(function_instance->name);
++ if (function_instance->endpoint_map_array) LKFREE(function_instance->endpoint_map_array);
++ LKFREE(function_instance);
++}
++
++/*!
++ * usbd_find_function_internal() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param name
++ * @return function instance
++ *
++ */
++static struct usbd_function_instance *
++usbd_find_function_internal(LIST_NODE *usbd_function_instances, char *name)
++{
++ int len = name ? strlen(name) : 0;
++ LIST_NODE *lhd = NULL;
++ TRACE_MSG1(USBD, "%s", name);
++ LIST_FOR_EACH (lhd, usbd_function_instances) {
++
++ struct usbd_function_instance *function = LIST_ENTRY (lhd, struct usbd_function_instance, instances);
++ struct usbd_function_driver *function_driver;
++ function_driver = function->function_driver;
++ printk(KERN_ERR"%s: name: %s len: %d function: %s\n", __FUNCTION__, name ? name : "", len, function_driver->name);
++ CONTINUE_IF(len || strncmp(function_driver->name, name, len));
++
++ TRACE_MSG5(USBD, "%s %s %d %s %d", name, function->name, len,
++ function->function_driver->name,
++ function->function_driver->endpointsRequested);
++ CONTINUE_IF(len && strncmp(function->name, name, len));
++
++ TRACE_MSG4(USBD, "FOUND %s %x %s %d", name, function,
++ function->function_driver->name,
++ function->function_driver->endpointsRequested);
++
++ return function;
++
++ //struct usbd_function_driver *function_driver = function->function_driver;
++ //printk(KERN_ERR"%s: name: %s len: %d function: %s\n", __FUNCTION__,name?name : "", len, function_driver->name);
++ //CONTINUE_IF(len || strncmp(function_driver->name, name, len));
++ }
++ return NULL;
++}
++
++
++/*!
++ * usbd_find_function() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param name
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *
++usbd_find_function (char *name)
++{
++ return usbd_find_function_internal(&usbd_function_instances, name);
++}
++
++/*!
++ * usbd_default_function() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param name
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *
++usbd_default_function (char *name)
++{
++ return usbd_find_function_internal(&usbd_function_instances, "");
++}
++
++/*!
++ * usbd_find_interface() - register a usbd function driver
++ *
++ * USBD Function drivers call this to register with the USBD Core layer.
++ * Return NULL on failure.
++ *
++ * @param name
++ * @return function instance
++ *
++ */
++struct usbd_function_instance *usbd_find_interface(char *name)
++{
++ TRACE_MSG1(USBD, "%s", name);
++ return usbd_find_function_internal(&usbd_interface_instances, name);
++}
++
++
++/*!
++ * usbd_function_name() - return name of nth function driver
++ * @param n index to function name
++ */
++char * usbd_function_name(int n)
++{
++ struct usbd_function_instance *function = NULL;
++ LIST_NODE *lhd = NULL;
++
++ LIST_FOR_EACH (lhd, &usbd_function_instances) {
++ struct usbd_function_driver *function_driver;
++ function = LIST_ENTRY (lhd, struct usbd_function_instance, instances);
++ function_driver = function->function_driver;
++
++ TRACE_MSG2(USBD, "name: [%d] %s", n, function_driver->name);
++
++ CONTINUE_IF(n--);
++ return (char *)function_driver->name;
++ };
++ return NULL;
++}
++
++OTG_EXPORT_SYMBOL(usbd_register_function);
++OTG_EXPORT_SYMBOL(usbd_register_interface);
++OTG_EXPORT_SYMBOL(usbd_register_composite);
++OTG_EXPORT_SYMBOL(usbd_deregister_function);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * String Descriptors:
++ * usbd_alloc_string_descriptor()
++ * usbd_free_string_descriptor()
++ * usbd_get_string_descriptor()
++ */
++
++#define LANGID_ENGLISH "\011"
++#define LANGID_US_ENGLISH "\004"
++#define LANGIDs LANGID_US_ENGLISH LANGID_ENGLISH
++
++/*!
++ * usbd_alloc_string_zero() - allocate a string descriptor and return index number
++ *
++ * Find an empty slot in index string array, create a corresponding descriptor
++ * and return the slot number.
++ *
++ * @param str string to allocate
++ * @return the slot number
++ */
++static u8 usbd_alloc_string_zero (char *str)
++{
++ u8 bLength;
++ u16 *wData;
++ struct usbd_string_descriptor *string = NULL;
++
++ RETURN_ZERO_IF(usb_strings[0] != NULL);
++
++ bLength = sizeof (struct usbd_string_descriptor) + strlen (str);
++
++ RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *) CKMALLOC (bLength, GFP_KERNEL)));
++
++ string->bLength = bLength; // set descriptor length
++ string->bDescriptorType = USB_DT_STRING; // set descriptor type
++
++ for (wData = string->wData; *str; str += 2, wData++) // copy
++ *wData = (u16) ((str[0] << 8 | str[1]));
++
++ usb_strings[0] = string; // save in string index array
++ return 0;
++}
++
++int usbd_maxstrings = 40;
++
++/*!
++ * usbd_strings_init() - initialize usb strings pool
++ */
++int usbd_strings_init (void)
++{
++ //TRACE_MSG0(USBD, "entered");
++ RETURN_ZERO_IF(usb_strings);
++ usbd_maxstrings = MIN(usbd_maxstrings, 254);
++
++ RETURN_EINVAL_IF (!(usb_strings = CKMALLOC (sizeof (struct usbd_string_descriptor *) * usbd_maxstrings, GFP_KERNEL)));
++ if (usbd_alloc_string_zero (LANGIDs) != 0) {
++ LKFREE (usb_strings);
++ return -1;
++ }
++ return 0;
++}
++
++/*!
++ * usbd_strings_exit() - de-initialize usb strings pool
++ */
++void usbd_strings_exit(void)
++{
++ int i;
++ //TRACE_MSG0(USBD, "entered");
++ RETURN_IF (!usb_strings);
++ for (i = 0; i < usbd_maxstrings; i++)
++ usbd_free_string_descriptor((u8)i);
++ LKFREE (usb_strings);
++ usb_strings = NULL;
++}
++
++
++/*!
++ * usbd_get_string_descriptor() - find and return a string descriptor
++ *
++ * Find an indexed string and return a pointer to a it.
++ * @param index of string
++ * @return pointer to string descriptor or NULL
++ */
++struct usbd_string_descriptor *usbd_get_string_descriptor (u8 index)
++{
++ RETURN_NULL_IF (index >= usbd_maxstrings);
++ return usb_strings[index];
++}
++
++/*!
++ * usbd_realloc_string() - allocate a string descriptor and return index number
++ *
++ * Find an empty slot in index string array, create a corresponding descriptor
++ * and return the slot number.
++ * @param index
++ * @param str
++ * @return new index
++ */
++u8 usbd_realloc_string (u8 index, char *str)
++{
++ struct usbd_string_descriptor *string;
++ u8 bLength;
++ u16 *wData;
++
++ RETURN_ZERO_IF(!str || !strlen (str));
++ //TRACE_MSG2(USBD, "index: %d str: %s", index, str);
++
++ // XXX should have semaphores...
++
++ if ((index < usbd_maxstrings) && (string = usb_strings[index])) {
++ usb_strings[index] = NULL;
++ LKFREE (string);
++ }
++
++ bLength = sizeof (struct usbd_string_descriptor) + 2 * strlen (str);
++
++ RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *)CKMALLOC (bLength, GFP_KERNEL)));
++
++ string->bLength = bLength;
++ string->bDescriptorType = USB_DT_STRING;
++
++ for (wData = string->wData; *str;)
++ *wData++ = (u16) (*str++);
++
++ // store in string index array
++ usb_strings[index] = string;
++ return index;
++}
++
++/*!
++ * usbd_alloc_string() - allocate a string descriptor and return index number
++ *
++ * Find an empty slot in index string array, create a corresponding descriptor
++ * and return the slot number.
++ * @param str
++ * @return index
++ *
++ * XXX rename to usbd_alloc_string_descriptor
++ */
++u8 usbd_alloc_string (char *str)
++{
++ int i;
++ struct usbd_string_descriptor *string = NULL;
++ u8 bLength;
++ u16 *wData;
++
++ RETURN_ZERO_IF(!str || !strlen (str));
++
++ // find an empty string descriptor slot
++ for (i = 1; i < usbd_maxstrings; i++) {
++
++ CONTINUE_IF (usb_strings[i] != NULL);
++
++ bLength = sizeof (struct usbd_string_descriptor) + 2 * strlen (str);
++
++ RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *)CKMALLOC (bLength, GFP_KERNEL)));
++
++ string->bLength = bLength;
++ string->bDescriptorType = USB_DT_STRING;
++
++ for (wData = string->wData; *str;)
++ *wData++ = (u16) (*str++);
++
++ // store in string index array
++ usb_strings[i] = string;
++ return i;
++ }
++ return 0;
++}
++
++
++/*!
++ * usbd_free_string_descriptor() - deallocate a string descriptor
++ *
++ * Find and remove an allocated string.
++ * @param index
++ *
++ */
++void usbd_free_string_descriptor (u8 index)
++{
++ struct usbd_string_descriptor *string;
++
++ if ((index < usbd_maxstrings) && (string = usb_strings[index])) {
++ usb_strings[index] = NULL;
++ LKFREE (string);
++ }
++}
++
++OTG_EXPORT_SYMBOL(usbd_realloc_string);
++OTG_EXPORT_SYMBOL(usbd_alloc_string);
++OTG_EXPORT_SYMBOL(usbd_free_string_descriptor);
++OTG_EXPORT_SYMBOL(usbd_get_string_descriptor);
++OTG_EXPORT_SYMBOL(usbd_maxstrings);
++
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Device Information:
++ * usbd_high_speed()
++ * usbd_get_bMaxPower()
++ * usbd_endpoint_wMaxPacketsize()
++ * usbd_endpoint_wMaxPacketsize_ep0()
++ * usbd_endpoint_bEndpointAddress()
++ *
++ */
++
++
++/*!
++ * usbd_high_speed() - return high speed status
++ * @return true if operating at high speed
++ */
++int usbd_high_speed(struct usbd_function_instance *function)
++{
++ // XXX TODO - per function modifications for composite devices
++ return function->bus->HighSpeedFlag ? 1 : 0;
++}
++
++/*!
++ * usbd_get_bMaxPower() - process a received urb
++ *
++ * Used by a USB Bus interface driver to pass received device request to
++ * the appropriate USB Function driver.
++ *
++ * @param function
++ * @param request
++ * @return non-zero if errror
++ */
++int usbd_get_bMaxPower(struct usbd_function_instance *function)
++{
++ struct usbd_bus_instance *bus = function->bus;
++ return bus->driver->bMaxPower;
++}
++
++
++/*!
++ * usbd_endpoint_wMaxPacketSize() - get maximum packet size for endpoint
++ * @param function
++ * @param endpoint_index
++ * @param hs highspeed flag
++ * @return endpoint size
++ */
++int usbd_endpoint_wMaxPacketSize(struct usbd_function_instance *function, int endpoint_index, int hs)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
++ return le16_to_cpu(endpoint_map[endpoint_index].wMaxPacketSize[hs]);
++}
++
++/*!
++ * usbd_endpoint_zero_wMaxPacketSize() - get maximum packet size for endpoint zero
++ * @param function
++ * @param hs highspeed flag
++ * @return endpoint size
++ */
++int usbd_endpoint_zero_wMaxPacketSize(struct usbd_function_instance *function, int hs)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ RETURN_ZERO_IF(!(endpoint_map = function->bus->ep0->endpoint_map_array));
++ return le16_to_cpu(endpoint_map[0].wMaxPacketSize[hs]);
++}
++
++/*!
++ * usbd_endpoint_bEndpointAddress() - get endpoint addrsess
++ * @param function
++ * @param endpoint_index
++ * @param hs high speed flag
++ * @return endpoint address
++ */
++int usbd_endpoint_bEndpointAddress(struct usbd_function_instance *function, int endpoint_index, int hs)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
++ return endpoint_map[endpoint_index].bEndpointAddress[hs];
++}
++
++OTG_EXPORT_SYMBOL(usbd_endpoint_wMaxPacketSize);
++OTG_EXPORT_SYMBOL(usbd_endpoint_zero_wMaxPacketSize);
++OTG_EXPORT_SYMBOL(usbd_endpoint_bEndpointAddress);
++OTG_EXPORT_SYMBOL(usbd_high_speed);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Device Control:
++ *
++ * XXX usbd_request_endpoints()
++ * XXX usbd_configure_endpoints()
++ *
++ * usbd_get_device_state()
++ * usbd_get_device_status()
++ * usbd_framenum()
++ * usbd_ticks()
++ * usbd_elapsed()
++ */
++
++/*!
++ * usbd_flush_endpoint_irq() - flush urbs from endpoint
++ *
++ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
++ *
++ * @param endpoint flush urbs on this endpoint
++ */
++void usbd_flush_endpoint_irq (struct usbd_endpoint_instance *endpoint)
++{
++ struct usbd_urb *urb;
++
++ if (endpoint->bEndpointAddress)
++ TRACE_MSG1(USBD, "bEndpointAddress: %02x", endpoint->bEndpointAddress);
++
++ if ((urb = endpoint->tx_urb))
++ usbd_cancel_urb(urb);
++
++ for (; (urb = usbd_first_urb_detached_irq (&endpoint->tx)); usbd_cancel_urb(urb));
++
++ if ((urb = endpoint->rcv_urb))
++ usbd_cancel_urb(urb);
++
++ for (; (urb = usbd_first_urb_detached_irq (&endpoint->rdy)); usbd_cancel_urb(urb));
++}
++
++/*!
++ * usbd_flush_endpoint() - flush urbs from endpoint
++ *
++ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
++ *
++ * @param endpoint flush urbs on this endpoint
++ */
++void usbd_flush_endpoint (struct usbd_endpoint_instance *endpoint)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ usbd_flush_endpoint_irq(endpoint);
++ local_irq_restore (flags);
++}
++
++/*!
++ * usbd_flush_endpoint_address() - flush endpoint
++ * @param function
++ * @param endpoint_index
++ */
++void usbd_flush_endpoint_index (struct usbd_function_instance *function, int endpoint_index)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ struct usbd_endpoint_instance *endpoint;
++
++ RETURN_IF(!function);
++ RETURN_IF(!(endpoint_map = function->endpoint_map_array));
++ RETURN_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
++ usbd_flush_endpoint (endpoint);
++}
++
++/*!
++ * usbd_get_device_state() - return device state
++ * @param function
++ * @return current device state
++ */
++usbd_device_state_t usbd_get_device_state(struct usbd_function_instance *function)
++{
++ //TRACE_MSG1(USBD, "%d", function->bus->device_state);
++ return (function && function->bus) ? function->bus->device_state : STATE_UNKNOWN;
++}
++
++/*!
++ * usbd_get_device_status() - return device status
++ * @param function
++ * @return current device status
++ */
++usbd_device_status_t usbd_get_device_status(struct usbd_function_instance *function)
++{
++ //TRACE_MSG1(USBD, "%d", function->bus->status);
++ return (function && function->bus) ? function->bus->status : USBD_UNKNOWN;
++}
++
++/*!
++ * usbd_framenum() - return framenum
++ * @param function
++ * @return current framenum
++ */
++int usbd_framenum(struct usbd_function_instance * function)
++{
++ RETURN_ZERO_UNLESS(function);
++ RETURN_ZERO_UNLESS(function->bus->driver->bops->framenum);
++ return function->bus->driver->bops->framenum ();
++}
++
++/*!
++ * usbd_ticks() - return ticks
++ * @param function
++ * @return current ticks
++ */
++u64 usbd_ticks(struct usbd_function_instance *function)
++{
++ RETURN_ZERO_UNLESS(function);
++ RETURN_ZERO_UNLESS(function->bus->driver->bops->ticks);
++ return function->bus->driver->bops->ticks ();
++}
++
++/*!
++ * usbd_elapsed() - return elapsed
++ * @param function
++ * @param t1
++ * @param t2
++ * @return elapsed uSecs between t1 and t2
++ */
++u64 usbd_elapsed(struct usbd_function_instance *function, u64 *t1, u64 *t2)
++{
++ RETURN_ZERO_UNLESS(function);
++ RETURN_ZERO_UNLESS(function->bus->driver->bops->elapsed);
++ return function->bus->driver->bops->elapsed (t1, t2);
++}
++
++
++//OTG_EXPORT_SYMBOL(usbd_set_endpoint_halt);
++//OTG_EXPORT_SYMBOL(usbd_endpoint_halted);
++OTG_EXPORT_SYMBOL(usbd_get_device_state);
++OTG_EXPORT_SYMBOL(usbd_get_device_status);
++OTG_EXPORT_SYMBOL(usbd_framenum);
++OTG_EXPORT_SYMBOL(usbd_ticks);
++OTG_EXPORT_SYMBOL(usbd_elapsed);
++OTG_EXPORT_SYMBOL(usbd_flush_endpoint);
++OTG_EXPORT_SYMBOL(usbd_flush_endpoint_index);
++
++/* ********************************************************************************************* */
++/* ********************************************************************************************* */
++/*!
++ * Endpoint I/O:
++ * usbd_alloc_urb()
++ * usbd_start_in_urb()
++ * usbd_start_out_urb()
++ * usbd_cancel_urb()
++ *
++ */
++
++/*!
++ * usbd_alloc_urb() - allocate an URB appropriate for specified endpoint
++ *
++ * Allocate an urb structure. The usb device urb structure is used to
++ * contain all data associated with a transfer, including a setup packet for
++ * control transfers.
++ *
++ * @param function
++ * @param endpoint_index
++ * @param length
++ * @param callback
++ * @return urb
++ */
++struct usbd_urb *usbd_alloc_urb (struct usbd_function_instance *function, int endpoint_index,
++ int length, int (*callback) (struct usbd_urb *, int))
++{
++ struct usbd_urb *urb = NULL;
++ struct usbd_endpoint_map *endpoint_map;
++ struct usbd_endpoint_instance *endpoint;
++ unsigned long flags;
++
++ RETURN_NULL_IF(!(endpoint_map = function->endpoint_map_array));
++ RETURN_NULL_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
++
++ local_irq_save(flags);
++ THROW_IF (!(urb = (struct usbd_urb *)CKMALLOC (sizeof (struct usbd_urb), GFP_ATOMIC)), error);
++ urb->endpoint = endpoint;
++ urb->bus = function->bus;
++ urb->function_instance = function;
++ urb->link.prev = urb->link.next = &urb->link;
++ urb->callback = callback;
++ urb->buffer_length = urb->actual_length = 0;
++
++ if (length) {
++ urb->request_length = length;
++
++ /* For receive we always overallocate to ensure that receiving another
++ * full sized packet when we are only expecting a short packet will
++ * not overflow the buffer
++ */
++ if (!endpoint->bEndpointAddress || endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
++ length = ((length / endpoint->wMaxPacketSize) + 1) * endpoint->wMaxPacketSize;
++ }
++ urb->buffer_length = length;
++
++ #if 0
++ if (urb->endpoint && urb->endpoint->bEndpointAddress && urb->function_instance &&
++ urb->function_instance->function_driver->fops->alloc_urb_data)
++ {
++ THROW_IF(urb->function_instance->function_driver->fops->alloc_urb_data (urb, length), error);
++ }
++ else
++ #endif
++ THROW_IF(!(urb->buffer = (u8 *)CKMALLOC (length, GFP_ATOMIC)), error);
++
++ }
++
++ CATCH(error) {
++ #if defined(OTG_LINUX)
++ printk(KERN_ERR"%s: dealloc %p\n", __FUNCTION__, urb);
++ #endif /* defined(OTG_LINUX) */
++ #if defined(OTG_WINCE)
++ DEBUGMSG(ZONE_INIT, (_T("usbd_alloc_urb: FAILED\n")));
++ #endif /* defined(OTG_LINUX) */
++ usbd_free_urb(urb);
++ urb = NULL;
++ }
++ local_irq_restore(flags);
++ return urb;
++}
++
++/*!
++ * usbd_halt_endpoint() -
++ *
++ * @param function function that owns endpoint
++ * @param endpoint endpoint number
++ * @return non-zero if endpoint is halted.
++ */
++int usbd_halt_endpoint (struct usbd_function_instance *function, int endpoint_index)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ struct usbd_endpoint_instance *endpoint;
++
++ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
++ RETURN_ZERO_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
++
++ return function->bus->driver->bops->halt_endpoint (function->bus, endpoint->bEndpointAddress, endpoint_index, 1);
++}
++
++
++/*!
++ * usbd_alloc_urb_ep0() - allocate an urb for endpoint zero
++ * @param function
++ * @param length
++ * @param callback
++ * @return urb
++ */
++struct usbd_urb *usbd_alloc_urb_ep0 (struct usbd_function_instance *function, int length,
++ int (*callback) (struct usbd_urb *, int))
++{
++ return usbd_alloc_urb(function->bus->ep0, 0, length, callback);
++}
++
++/*!
++ * usbd_free_urb() - deallocate an URB and associated buffer
++ *
++ * Deallocate an urb structure and associated data.
++ * @param urb
++ */
++void usbd_free_urb (struct usbd_urb *urb)
++{
++ RETURN_IF (!urb);
++ if (urb->buffer) {
++ #if 0
++ if (urb->function_instance && urb->function_instance->function_driver->fops->dealloc_urb_data)
++ urb->function_instance->function_driver->fops->dealloc_urb_data ((void *) urb->buffer);
++ else
++ #endif
++ LKFREE ((void *) urb->buffer);
++ }
++ LKFREE (urb);
++}
++
++
++/*!
++ * usbd_start_in_urb() - submit a urb to send
++ *
++ * Used by a USB Function driver to submit data to be sent in an urb to the
++ * appropriate USB Bus driver via the endpoints transmit queue.
++ *
++ * @param urb to send
++ * @return non-zero if error
++ */
++int usbd_start_in_urb (struct usbd_urb *urb)
++{
++ RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
++ if (urb->endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)) {
++ usbd_urb_finished(urb, SEND_STALLED);
++ return 0;
++ }
++ urb->status = SEND_IN_QUEUE;
++ #if defined(OTG_LINUX)
++ urb->jiffies = jiffies;
++ #endif /* defined(OTG_LINUX) */
++ urb_append (&(urb->endpoint->tx), urb);
++ return urb->bus->driver->bops->start_endpoint_in(urb->bus, urb->endpoint);
++}
++
++/*!
++ * usbd_start_out_urb() - recycle a received urb
++ *
++ * Used by a USB Function interface driver to recycle an urb.
++ *
++ * @param urb to process
++ * @return non-zero if error
++ */
++int usbd_start_out_urb (struct usbd_urb *urb)
++{
++ RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
++ if (urb->endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)) {
++ usbd_urb_finished(urb, RECV_STALLED);
++ return 0;
++ }
++ urb->actual_length = 0;
++ urb->status = RECV_IN_QUEUE;
++ #if defined(OTG_LINUX)
++ urb->jiffies = jiffies;
++ #endif /* defined(OTG_LINUX) */
++ urb_append (&(urb->endpoint->rdy), urb);
++ return urb->bus->driver->bops->start_endpoint_out(urb->bus, urb->endpoint);
++}
++
++/*!
++ * usbd_cancel_urb() - cancel an urb being sent
++ *
++ * @param urb to process
++ * @return non-zero if error
++ */
++int usbd_cancel_urb (struct usbd_urb *urb)
++{
++ //TRACE_MSG0(USBD, "entered");
++ return urb->bus->driver->bops->cancel_urb_irq (urb);
++}
++
++
++/*!
++ * usbd_endpoint_halted() - return halt status
++ *
++ * @param function function that owns endpoint
++ * @param endpoint endpoint number
++ * @return non-zero if endpoint is halted.
++ */
++int usbd_endpoint_halted (struct usbd_function_instance *function, int endpoint_index)
++{
++ struct usbd_endpoint_instance *endpoint;
++ struct usbd_endpoint_map *endpoint_map;
++ //TRACE_MSG0(USBD, "entered");
++ //
++ RETURN_ZERO_UNLESS((endpoint_map = function->endpoint_map_array));
++ RETURN_ZERO_UNLESS((endpoint = endpoint_map[endpoint_index].endpoint));
++ return function->bus->driver->bops->endpoint_halted (function->bus, endpoint->bEndpointAddress, endpoint_index);
++}
++
++
++OTG_EXPORT_SYMBOL(usbd_alloc_urb);
++OTG_EXPORT_SYMBOL(usbd_alloc_urb_ep0);
++OTG_EXPORT_SYMBOL(usbd_free_urb);
++
++OTG_EXPORT_SYMBOL(usbd_start_in_urb);
++OTG_EXPORT_SYMBOL(usbd_start_out_urb);
++OTG_EXPORT_SYMBOL(usbd_cancel_urb);
++OTG_EXPORT_SYMBOL(usbd_halt_endpoint);
++
++/* ********************************************************************************************* */
++
++/*!
++ * usbd_function_get_privdata() - get private data pointer
++ * @param function
++ * @return void * pointer to private data
++ */
++void *usbd_function_get_privdata(struct usbd_function_instance *function)
++{
++ return(function->privdata);
++}
++
++/*!
++ * usbd_function_set_privdata() - set private data structure in function
++ * @param function
++ * @param privdata
++ */
++void usbd_function_set_privdata(struct usbd_function_instance *function, void *privdata)
++{
++ function->privdata = privdata;
++}
++
++
++
++
++/*!
++ * usbd_endpoint_transferSize() - get transferSize for endpoint
++ * @param function
++ * @param endpoint_index
++ * @param hs highspeed flag
++ * @return transfer size
++ */
++int usbd_endpoint_transferSize(struct usbd_function_instance *function, int endpoint_index, int hs)
++{
++ struct usbd_endpoint_map *endpoint_map;
++ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
++ return endpoint_map[endpoint_index].transferSize[hs];
++}
++
++/*!
++ * usbd_endpoint_update() - update endpoint address and size
++ * @param function
++ * @param endpoint_index
++ * @param endpoint descriptor
++ * @param hs high speed flag
++ */
++void usbd_endpoint_update(struct usbd_function_instance *function, int endpoint_index,
++ struct usbd_endpoint_descriptor *endpoint, int hs)
++{
++ endpoint->bEndpointAddress = usbd_endpoint_bEndpointAddress(function, endpoint_index, hs);
++ endpoint->wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, endpoint_index, hs);
++}
++
++/*!
++ * usbd_otg_bmattributes() - return attributes
++ * @param function
++ * @return endpoint attributes
++ */
++int usbd_otg_bmattributes(struct usbd_function_instance *function)
++{
++ // XXX TODO - per function modifications for composite devices
++ return function->bus->otg_bmAttributes;
++}
++
++OTG_EXPORT_SYMBOL(usbd_function_get_privdata);
++OTG_EXPORT_SYMBOL(usbd_function_set_privdata);
++OTG_EXPORT_SYMBOL(usbd_endpoint_transferSize);
++OTG_EXPORT_SYMBOL(usbd_otg_bmattributes);
++OTG_EXPORT_SYMBOL(usbd_endpoint_update);
+diff -uNr linux/drivers/no-otg/otgcore/usbp-procfs.c linux/drivers/otg/otgcore/usbp-procfs.c
+--- linux/drivers/no-otg/otgcore/usbp-procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otgcore/usbp-procfs.c 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,302 @@
++/*
++ * otg/otgcore/usbp-procfs.c - USB Device Core Layer
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otgcore/usbp-procfs.c
++ * @brief Implements /proc/usbd-functions, which displays descriptors for the current selected function.
++ *
++ *
++ * @ingroup USBP
++ */
++
++#include <otg/otg-compat.h>
++#include <otg/otg-module.h>
++
++#ifdef LINUX24
++EXPORT_NO_SYMBOLS;
++#endif
++
++
++MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
++MOD_DESCRIPTION ("USB Device Core Support Procfs");
++EMBED_LICENSE();
++
++#include <otg/usbp-chap9.h>
++#include <otg/usbp-func.h>
++#include <otg/usbp-bus.h>
++
++EMBED_USBD_INFO ("usbdprocfs 2.0-beta");
++
++#define MAX_INTERFACES 2
++
++extern struct usbd_bus_instance *usbd_bus_instance;
++
++/* Proc Filesystem *************************************************************************** */
++/* *
++ * dohex
++ *
++ */
++static void dohexdigit (char *cp, unsigned char val)
++{
++ if (val < 0xa) {
++ *cp = val + '0';
++ } else if ((val >= 0x0a) && (val <= 0x0f)) {
++ *cp = val - 0x0a + 'a';
++ }
++}
++
++/* *
++ * dohex
++ *
++ */
++static void dohexval (char *cp, unsigned char val)
++{
++ dohexdigit (cp++, val >> 4);
++ dohexdigit (cp++, val & 0xf);
++}
++
++/* *
++ * dump_descriptor
++ */
++static int dump_descriptor (char *buf, char *sp)
++{
++ int num;
++ int len = 0;
++
++ RETURN_ZERO_UNLESS(sp);
++
++ num = *sp;
++
++ //printk(KERN_INFO"%s: %p %d %d %d\n", __FUNCTION__, buf, *buf, buf[0], num);
++
++ while (sp && num--) {
++ dohexval (buf, *sp++);
++ buf += 2;
++ *buf++ = ' ';
++ len += 3;
++ }
++ len++;
++ *buf = '\n';
++ return len;
++}
++
++/* dump_descriptors
++ */
++static int dump_config_descriptor(char *buf, char *sp)
++{
++ struct usbd_configuration_descriptor *config = (struct usbd_configuration_descriptor *) sp;
++
++ int wTotalLength = le16_to_cpu(config->wTotalLength);
++ int bConfigurationValue = config->bConfigurationValue;
++ int interface_num;
++ int class_num;
++ int endpoint_num;
++ int total;
++
++ interface_num = class_num = endpoint_num = 0;
++
++ for (total = 0; wTotalLength > 0; ) {
++ //printk(KERN_INFO"%s: wTotalLength: %d total: %d bLength: %d type: %d\n",
++ // __FUNCTION__, wTotalLength, total, sp[0], sp[1]);
++ BREAK_UNLESS(sp[0]);
++ switch (sp[1]) {
++ case USB_DT_CONFIGURATION:
++ interface_num = class_num = endpoint_num = 0;
++ total += sprintf(buf + total, "\nConfiguration descriptor [%d ] ",
++ bConfigurationValue);
++ break;
++ case USB_DT_INTERFACE:
++ class_num = 0;
++ total += sprintf(buf + total, "\nInterface descriptor [%d:%d:%d ] ",
++ bConfigurationValue, ++interface_num, class_num);
++ break;
++ case USB_DT_ENDPOINT:
++ class_num = endpoint_num = 0;
++ total += sprintf(buf + total, "Endpoint descriptor [%d:%d:%d:%d] ",
++ bConfigurationValue, interface_num, class_num, ++endpoint_num);
++ break;
++ case USB_DT_OTG:
++ class_num = endpoint_num = 0;
++ total += sprintf(buf + total, "OTG descriptor [%d ] ", bConfigurationValue);
++ break;
++ default:
++ endpoint_num = 0;
++ total += sprintf(buf + total, "Class descriptor [%d:%d:%d ] ",
++ bConfigurationValue, interface_num, ++class_num);
++ break;
++ }
++ total += dump_descriptor(buf + total, sp);
++ wTotalLength -= sp[0];
++ sp += sp[0];
++ }
++ total += sprintf(buf + total, "\n");
++ return total;
++}
++
++/*! *
++ * usbd_device_proc_read - implement proc file system read.
++ * @param file
++ * @param buf
++ * @param count
++ * @param pos
++ *
++ * Standard proc file system read function.
++ *
++ * We let upper layers iterate for us, *pos will indicate which device to return
++ * statistics for.
++ */
++static ssize_t usbd_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
++{
++ unsigned long page;
++ int len = 0;
++ int index;
++
++ u8 config_descriptor[512];
++ int config_size;
++
++ //struct list_head *lhd;
++
++ // get a page, max 4095 bytes of data...
++// if (!(page = GET_FREE_PAGE(GFP_KERNEL))) {
++
++ if (!(page = GET_KERNEL_PAGE())) {
++ return -ENOMEM;
++ }
++
++ len = 0;
++ index = (*pos)++;
++
++ if (index == 0) {
++ len += sprintf ((char *) page + len, "usb-device list\n");
++ }
++
++ //printk(KERN_INFO"%s: index: %d len: %d\n", __FUNCTION__, index, len);
++
++ if (usbd_bus_instance && usbd_bus_instance->function_instance) {
++ int configuration = index;
++ struct usbd_function_instance *function_instance = usbd_bus_instance->function_instance;
++ struct usbd_function_driver *function_driver = function_instance->function_driver;
++ struct usbd_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
++ if (configuration_instance_array) {
++
++ if (index == 0) {
++ len += sprintf ((char *) page + len, "\nDevice descriptor ");
++ len += dump_descriptor ((char *) page + len, (char *) function_driver->device_descriptor);
++#ifdef CONFIG_OTG_HIGH_SPEED
++ len += sprintf ((char *) page + len, "\nDevice Qualifier descriptor ");
++ len += dump_descriptor ((char *) page + len,
++ (char *) function_driver->device_qualifier_descriptor);
++#endif
++ }
++ if (configuration < function_driver->bNumConfigurations) {
++
++ if ((config_size = usbd_old_get_descriptor(usbd_bus_instance->ep0, config_descriptor,
++ sizeof(config_descriptor),
++ USB_DT_CONFIGURATION, 0)) > index) {
++ len += dump_config_descriptor((char *)page + len, config_descriptor );
++ }
++#ifdef CONFIG_OTG_HIGH_SPEED
++ if ((config_size = usbd_old_get_descriptor(usbd_bus_instance->ep0, config_descriptor,
++ sizeof(config_descriptor),
++ USB_DT_OTHER_SPEED_CONFIGURATION, index)) > 0) {
++ len += dump_config_descriptor((char *)page + len, config_descriptor );
++ }
++
++#endif
++ }
++ else if (configuration == function_driver->bNumConfigurations) {
++ int i;
++ int k;
++ struct usbd_string_descriptor *string_descriptor;
++
++ //len += sprintf ((char *) page + len, "\n\n");
++
++ if ((string_descriptor = usbd_get_string_descriptor (0)) != NULL) {
++ len += sprintf ((char *) page + len, "String [%2d] ", 0);
++
++ for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
++ len += sprintf ((char *) page + len, "%02x %02x ",
++ string_descriptor->wData[k] >> 8,
++ string_descriptor->wData[k] & 0xff);
++ len++;
++ }
++ len += sprintf ((char *) page + len, "\n");
++ }
++
++ for (i = 1; i < usbd_maxstrings; i++) {
++
++ if ((string_descriptor = usbd_get_string_descriptor (i)) != NULL) {
++
++ len += sprintf((char *)page+len, "String [%2d:%2d] ",
++ i, string_descriptor->bLength);
++
++ // bLength = sizeof(struct usbd_string_descriptor) + 2*strlen(str)-2;
++
++ for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
++ *(char *) (page + len) = (char) string_descriptor->wData[k];
++ len++;
++ }
++ len += sprintf ((char *) page + len, "\n");
++ }
++ }
++ len += sprintf((char *)page + len, "\n--\n");
++ }
++ }
++ }
++
++ //printk(KERN_INFO"%s: len: %d count: %d\n", __FUNCTION__, len, count);
++
++ if (len > count) {
++ //printk(KERN_INFO"%s: len > count\n", __FUNCTION__);
++ //printk(KERN_INFO"%s", page);
++ len = -EINVAL;
++ }
++ else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
++ //printk(KERN_INFO"%s: EFAULT\n", __FUNCTION__);
++ len = -EFAULT;
++ }
++ else {
++ //printk(KERN_INFO"%s: OK\n", __FUNCTION__);
++ }
++ free_page (page);
++ return len;
++}
++
++/* Module init ******************************************************************************* */
++#if defined(OTG_WINCE)
++
++#else /* defined(OTG_WINCE) */
++
++static struct file_operations usbd_device_proc_operations_functions = {
++ read:usbd_device_proc_read_functions,
++};
++
++static int usbd_procfs_init (void)
++{
++ struct proc_dir_entry *p;
++ // create proc filesystem entries
++ if ((p = create_proc_entry ("usb-functions", 0, 0)) == NULL)
++ return -ENOMEM;
++ p->proc_fops = &usbd_device_proc_operations_functions;
++ return 0;
++}
++
++static void usbd_procfs_exit (void)
++{
++ // remove proc filesystem entry
++ remove_proc_entry ("usb-functions", NULL);
++}
++
++module_init (usbd_procfs_init);
++module_exit (usbd_procfs_exit);
++
++#endif /* defined(OTG_WINCE) */
++
+diff -uNr linux/drivers/no-otg/otghw/atlas-hardware.h linux/drivers/otg/otghw/atlas-hardware.h
+--- linux/drivers/no-otg/otghw/atlas-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/atlas-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * otg/include/atlas-hardware.h -- Atlas Transceiver hardware specific defines
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup ATLAS
++ * @ingroup tcdgroup
++ */
++/*!
++ * @file otghw/atlas-hardware.h
++ * @brief Hardware defines for Freescale USBOTG Hardware
++ *
++ * @ingroup ATLAS
++ */
++
++/* References are to:
++ *
++ * Atlas DTS 0.7 - 04/02/27
++ */
++
++/*
++ * SPI Register Summary
++ */
++
++#define ATLAS_FSENB (1 << 0)
++#define ATLAS_USB_SUSPEND (1 << 1)
++#define ATLAS_USB_PU (1 << 2)
++#define ATLAS_UDP_PD (1 << 3)
++#define ATLAS_UDM_PD (1 << 4)
++#define ATLAS_PULLOVR (1 << 5)
++#define ATLAS_VUSB_EN (1 << 6)
++#define ATLAS_USB_PS (1 << 7)
++#define ATLAS_VBUS_REG_EN (1 << 8)
++#define ATLAS_VBUS_PD_ENB (1 << 9)
++#define ATLAS_CURRLIM (1 << 10)
++#define ATLAS_SE0_CONN (1 << 11)
++#define ATLAS_DLP_SRP (1 << 12)
++#define ATLAS_USB_XCVR_EN (1 << 13)
++#define ATLAS_VBUS_REG_LVL (1 << 14)
++
++#define ATLAS_DATA_MODE_MASK (3 << 15)
++#define ATLAS_DATA_MODE_USE (0 << 15)
++#define ATLAS_DATA_MODE_BSE (1 << 15)
++#define ATLAS_DATA_MODE_DM (2 << 15)
++#define ATLAS_DATA_MODE_NU (3 << 15)
++
++#define ATLAS_RS232ENB (1 << 17)
++#define ATLAS_ID_INTERRUPT (1 << 20)
++#define ATLAS_AUDIO_EN (1 << 21)
++#define ATLAS_STEREO_EN (1 << 22)
++
++
+diff -uNr linux/drivers/no-otg/otghw/bvd-hardware.h linux/drivers/otg/otghw/bvd-hardware.h
+--- linux/drivers/no-otg/otghw/bvd-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/bvd-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,601 @@
++/*
++ * otg/otghw/bvd-hardware.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ *
++ * TODO
++ *
++ * 1. see if using UDCCSR0_ACM/AREN will help
++ *
++ */
++/*!
++ * @file otghw/bvd-hardware.h
++ * @brief Hardware defines for Intel PXA-270 Hardware
++ *
++ * @ingroup BVD
++ */
++
++
++#ifndef UDCOTGICR
++#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */
++#endif
++
++#ifndef UDCOTGISR
++#define UDCOTGISR __REG(0x4060001c)
++
++#define UDCOTGISR_IRSF (1 << 24) /* OTG SET_FEATURE command recvd */
++#define UDCOTGISR_IRXR (1 << 17) /* Extra Transciever Interrupt Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRXF (1 << 16) /* Extra Transciever Interrupt Falling Edge Interrupt Enable */
++#define UDCOTGISR_IRVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge Interrupt Enable */
++#define UDCOTGISR_IRVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge Interrupt Enable */
++#define UDCOTGISR_IRSVR (1 << 5) /* OTG Session Valid Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRSVF (1 << 4) /* OTG Session Valid Falling Edge Interrupt Enable */
++#define UDCOTGISR_IRSDR (1 << 3) /* OTG A-Device SRP Detect Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRSDF (1 << 2) /* OTG A-Device SRP Detect Falling Edge Interrupt Enable */
++#define UDCOTGISR_IRIDR (1 << 1) /* OTG ID Change Rising Edge Interrupt Enable */
++#define UDCOTGISR_IRIDF (1 << 0) /* OTG ID Change Falling Edge */
++
++
++#endif
++
++
++#ifndef UP2OCR
++#define UP2OCR __REG(0x40600020)
++
++#define UP2OCR_SEOS_OFF (0x00 << 24)
++#define UP2OCR_SEOS_DSEO (0x02 << 24)
++#define UP2OCR_SEOS_HSEO (0x03 << 24)
++#define UP2OCR_SEOS_DEXT (0x04 << 24)
++#define UP2OCR_SEOS_HEXT (0x05 << 24)
++#define UP2OCR_SEOS_DINT (0x06 << 24)
++#define UP2OCR_SEOS_HINT (0x07 << 24)
++
++#define UP2OCR_HXOE (0x1 << 17)
++#define UP2OCR_HXS (0x1 << 16)
++
++#define UP2OCR_IDON (0x1 << 10)
++#define UP2OCR_EXSUS (0x1 << 9)
++#define UP2OCR_EXSP (0x1 << 8)
++#define UP2OCR_DMPUBE (0x1 << 7)
++#define UP2OCR_DPPUBE (0x1 << 6)
++#define UP2OCR_DMPUE (0x1 << 5)
++#define UP2OCR_DPPUE (0x1 << 4)
++#define UP2OCR_DMPDE (0x1 << 3)
++#define UP2OCR_DPPDE (0x1 << 2)
++#define UP2OCR_CPVPE (0x1 << 1)
++#define UP2OCR_CPVEN (0x1 << 0)
++
++#endif
++
++#ifndef UP3OCR
++#define UP3OCR __REG(0x40600024)
++#endif
++
++/*
++ * UDCCSR0 Bit Definitions C.f. Sheet 1 or 3
++ */
++#define UDCCSR0_ACM (1 << 9)
++#define UDCCSR0_AREN (1 << 8)
++
++
++/*
++ * Mainstone Miscellanous Write Register (MSCWR2) C.f. 3.2.2.6 (DVK)
++ *
++ * USB_OTG_RST enable external usb otg transceiver
++ * USB_OTG_SEL enable usb otg (disables ffuart)
++ * nUSBC_SC enable usb client detection
++ */
++#ifndef MSCWR2_USB_OTG_SEL
++#define MSCWR2_USB_OTG_SEL MST_MSCWR2_USB_OTG_SEL
++#endif
++#ifndef MSCWR2_USB_OTG_RST
++#define MSCWR2_USB_OTG_RST MST_MSCWR2_USB_OTG_RST
++#endif
++#ifndef MSCRD1_USB_CBL
++#define MSCRD1_USB_CBL MST_MSCRD_USB_CBL
++#endif
++#ifndef MSCWR2_nUSBC_SC
++#define MSCWR2_nUSBC_SC MST_MSCWR2_nUSBC_SC
++#endif
++
++/*
++ * USB_P2_N GPIO configuration - C.f. 24.2
++ *
++ * These should be in
++ */
++#define GPIO34_USB_P2_2 (34 | GPIO_ALT_FN_1_OUT)
++#define GPIO35_USB_P2_1 (35 | GPIO_ALT_FN_2_IN)
++#define GPIO36_USB_P2_4 (36 | GPIO_ALT_FN_1_OUT)
++#define GPIO37_USB_P2_8 (37 | GPIO_ALT_FN_1_OUT)
++#define GPIO38_USB_P2_3 (38 | GPIO_ALT_FN_3_IN)
++#define GPIO39_USB_P2_6 (39 | GPIO_ALT_FN_1_OUT)
++#define GPIO40_USB_P2_5 (40 | GPIO_ALT_FN_3_IN)
++#define GPIO41_USB_P2_7 (41 | GPIO_ALT_FN_2_IN)
++
++
++#if 0
++/* UDC endpiont0 states */
++#define EP0_WAIT_FOR_SETUP 0
++#define EP0_DATA_STATE_XMIT 1
++#define EP0_DATA_STATE_NEED_ZLP 2
++#define EP0_WAIT_FOR_OUT_STATUS 3
++
++/* UDC register definitions */
++#define UDCCR __REG(0x40600000) /* UDC Control Register */
++#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */
++#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */
++#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
++#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */
++#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */
++
++#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
++#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */
++#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */
++#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */
++#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */
++#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */
++#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */
++#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */
++#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */
++#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */
++#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */
++#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */
++#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */
++#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */
++#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */
++#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */
++#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */
++#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */
++#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */
++#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */
++#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */
++#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */
++#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */
++#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */
++
++#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */
++#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */
++#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */
++#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */
++#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */
++#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */
++#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */
++#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */
++#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */
++#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */
++#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */
++#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */
++#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */
++#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */
++#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */
++#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */
++#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */
++#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */
++#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */
++#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */
++#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */
++#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */
++#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */
++#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */
++
++#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */
++#define UDCDRA __REG(0x40600304) /* Data Register - EPA */
++#define UDCDRB __REG(0x40600308) /* Data Register - EPB */
++#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */
++#define UDCDRD __REG(0x40600310) /* Data Register - EPD */
++#define UDCDRE __REG(0x40600314) /* Data Register - EPE */
++#define UDCDRF __REG(0x40600318) /* Data Register - EPF */
++#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */
++#define UDCDRH __REG(0x40600320) /* Data Register - EPH */
++#define UDCDRI __REG(0x40600324) /* Data Register - EPI */
++#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */
++#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */
++#define UDCDRL __REG(0x40600330) /* Data Register - EPL */
++#define UDCDRM __REG(0x40600334) /* Data Register - EPM */
++#define UDCDRN __REG(0x40600338) /* Data Register - EPN */
++#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */
++#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */
++#define UDCDRR __REG(0x40600344) /* Data Register - EPR */
++#define UDCDRS __REG(0x40600348) /* Data Register - EPS */
++#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */
++#define UDCDRU __REG(0x40600350) /* Data Register - EPU */
++#define UDCDRV __REG(0x40600354) /* Data Register - EPV */
++#define UDCDRW __REG(0x40600358) /* Data Register - EPW */
++#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */
++
++#define UDCCRA __REG(0x40600404) /* Configuration register EPA */
++#define UDCCRB __REG(0x40600408) /* Configuration register EPB */
++#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */
++#define UDCCRD __REG(0x40600410) /* Configuration register EPD */
++#define UDCCRE __REG(0x40600414) /* Configuration register EPE */
++#define UDCCRF __REG(0x40600418) /* Configuration register EPF */
++#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */
++#define UDCCRH __REG(0x40600420) /* Configuration register EPH */
++#define UDCCRI __REG(0x40600424) /* Configuration register EPI */
++#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */
++#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */
++#define UDCCRL __REG(0x40600430) /* Configuration register EPL */
++#define UDCCRM __REG(0x40600434) /* Configuration register EPM */
++#define UDCCRN __REG(0x40600438) /* Configuration register EPN */
++#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */
++#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */
++#define UDCCRR __REG(0x40600444) /* Configuration register EPR */
++#define UDCCRS __REG(0x40600448) /* Configuration register EPS */
++#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */
++#define UDCCRU __REG(0x40600450) /* Configuration register EPU */
++#define UDCCRV __REG(0x40600454) /* Configuration register EPV */
++#define UDCCRW __REG(0x40600458) /* Configuration register EPW */
++#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */
++
++/* UDC Control Register (UDCCR) */
++#define UDCCR_DWRE (1 <<16) /* Device Remote Wake-up Feature */
++#define UDCCR_ACN (1 <<11) /* Active UDC Configuration Number */
++#define UDCCR_AIN (1 << 8) /* Active UDC Interface Number */
++#define UDCCR_AAISN (1 << 5) /* Active UDC Alternative Interface Setting Number */
++#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active Configuration */
++#define UDCCR_EMCE (1 << 3) /* Endpoint Meory Configuration Error */
++#define UDCCR_UDR (1 << 2) /* UDC Resume */
++#define UDCCR_UDA (1 << 1) /* UDC Active */
++#define UDCCR_UDE (1 << 0) /* UDC Enable */
++
++#define UDCCR_ACN_MASK 0x3
++#define UDCCR_AIN_MASK 0x7
++#define UDCCR_AAISN_MASK 0x7
++
++#define UDCICR0_IE0 (1<<0) /* EP0 Interrupt Enable */
++#define UDCICR0_IEA (1<<2) /* EPA Interrupt Enable */
++#define UDCICR0_IEB (1<<4) /* EPB Interrupt Enable */
++#define UDCICR0_IEC (1<<6) /* EPC Interrupt Enable */
++#define UDCICR0_IED (1<<8) /* EPD Interrupt Enable */
++#define UDCICR0_IEE (1<<10) /* EPE Interrupt Enable */
++#define UDCICR0_IEF (1<<12) /* EPF Interrupt Enable */
++#define UDCICR0_IEG (1<<14) /* EPG Interrupt Enable */
++#define UDCICR0_IEH (1<<16) /* EPH Interrupt Enable */
++#define UDCICR0_IEI (1<<18) /* EPI Interrupt Enable */
++#define UDCICR0_IEJ (1<<20) /* EPJ Interrupt Enable */
++#define UDCICR0_IEK (1<<22) /* EPK Interrupt Enable */
++#define UDCICR0_IEL (1<<24) /* EPL Interrupt Enable */
++#define UDCICR0_IEM (1<<26) /* EPM Interrupt Enable */
++#define UDCICR0_IEN (1<<28) /* EPN Interrupt Enable */
++#define UDCICR0_IEP (1<<30) /* EPP Interrupt Enable */
++#define UDCICR1_IEQ (1<<0) /* EPQ Interrupt Enable */
++#define UDCICR1_IER (1<<2) /* EPR Interrupt Enable */
++#define UDCICR1_IES (1<<4) /* EPS Interrupt Enable */
++#define UDCICR1_IET (1<<6) /* EPT Interrupt Enable */
++#define UDCICR1_IEU (1<<8) /* EPU Interrupt Enable */
++#define UDCICR1_IEV (1<<10) /* EPV Interrupt Enable */
++#define UDCICR1_IEW (1<<12) /* EPW Interrupt Enable */
++#define UDCICR1_IEX (1<<14) /* EPX Interrupt Enable */
++#define UDCICR1_IERS (1<<27) /* Reset */
++#define UDCICR1_IESU (1<<28) /* Suspend */
++#define UDCICR1_IERU (1<<29) /* Resume */
++#define UDCICR1_IESOF (1<<30) /* Start Of Frame */
++#define UDCICR1_IECC (1<<31) /* Configuration Changed */
++
++#define UDCISR0_IE0 (1<<0) /* EP0 Interrupt Enable */
++#define UDCISR0_IEA (1<<2) /* EPA Interrupt Enable */
++#define UDCISR0_IEB (1<<4) /* EPB Interrupt Enable */
++#define UDCISR0_IEC (1<<6) /* EPC Interrupt Enable */
++#define UDCISR0_IED (1<<8) /* EPD Interrupt Enable */
++#define UDCISR0_IEE (1<<10) /* EPE Interrupt Enable */
++#define UDCISR0_IEF (1<<12) /* EPF Interrupt Enable */
++#define UDCISR0_IEG (1<<14) /* EPG Interrupt Enable */
++#define UDCISR0_IEH (1<<16) /* EPH Interrupt Enable */
++#define UDCISR0_IEI (1<<18) /* EPI Interrupt Enable */
++#define UDCISR0_IEJ (1<<20) /* EPJ Interrupt Enable */
++#define UDCISR0_IEK (1<<22) /* EPK Interrupt Enable */
++#define UDCISR0_IEL (1<<24) /* EPL Interrupt Enable */
++#define UDCISR0_IEM (1<<26) /* EPM Interrupt Enable */
++#define UDCISR0_IEN (1<<28) /* EPN Interrupt Enable */
++#define UDCISR0_IEP (1<<30) /* EPP Interrupt Enable */
++#define UDCISR1_IEQ (1<<0) /* EPQ Interrupt Enable */
++#define UDCISR1_IER (1<<2) /* EPR Interrupt Enable */
++#define UDCISR1_IES (1<<4) /* EPS Interrupt Enable */
++#define UDCISR1_IET (1<<6) /* EPT Interrupt Enable */
++#define UDCISR1_IEU (1<<8) /* EPU Interrupt Enable */
++#define UDCISR1_IEV (1<<10) /* EPV Interrupt Enable */
++#define UDCISR1_IEW (1<<12) /* EPW Interrupt Enable */
++#define UDCISR1_IEX (1<<14) /* EPX Interrupt Enable */
++#define UDCISR1_IERS (1<<27) /* Reset */
++#define UDCISR1_IESU (1<<28) /* Suspend */
++#define UDCISR1_IERU (1<<29) /* Resume */
++#define UDCISR1_IESOF (1<<30) /* Start Of Frame */
++#define UDCISR1_IECC (1<<31) /* Configuration Changed */
++
++#define UDC_INT_FIFOERROR (0x2)
++#define UDC_INT_PACKETCMP (0x1)
++
++#define UDC_FNR_MASK (0x7ff)
++
++/* UDC Endpoint 0 Control Status Register (UDCCS0) */
++#define UDCCSR0_OPR (1 << 0) /* OUT packet ready */
++#define UDCCSR0_IPR (1 << 1) /* IN packet ready */
++#define UDCCSR0_FTF (1 << 2) /* Flush Tx FIFO */
++#define UDCCSR0_DME (1 << 3) /* DMA Enable */
++#define UDCCSR0_SST (1 << 4) /* Sent stall */
++#define UDCCSR0_FST (1 << 5) /* Force stall */
++#define UDCCSR0_RNE (1 << 6) /* Receive FIFO not empty */
++#define UDCCSR0_SA (1 << 7) /* Setup Active */
++
++/* UDC Endpoint A-X */
++#define UDCCSR_FS (1 << 0) /* FIFO service */
++#define UDCCSR_PC (1 << 1) /* Packet complete */
++#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
++#define UDCCSR_DME (1 << 3) /* DMA Enable */
++#define UDCCSR_SST (1 << 4) /* Sent STALL */
++#define UDCCSR_FST (1 << 5) /* Force STALL */
++#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty */
++#define UDCCSR_BNF (1 << 6) /* Buffer Not Full */
++#define UDCCSR_SP (1 << 7) /* Short packet */
++#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
++#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
++
++#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST)
++#define UDC_BCR_MASK (0x3ff)
++
++#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
++#define UDCCONR_DE (1 << 1) /* Double-buffering Enable */
++#define UDCCONR_MPS (1 << 2) /* Maximum Packet Size */
++#define UDCCONR_ED (1 <<12) /* USB Endpoint Direction */
++#define UDCCONR_ET (1 <<13) /* Endpoint Type */
++#define UDCCONR_EN (1 <<15) /* Endpoint Number */
++#define UDCCONR_AISN (1 <<19) /* Alternate Interface Number */
++#define UDCCONR_IN (1 <<22) /* Interface Number */
++#define UDCCONR_CN (1 <<25) /* Configuration Number */
++
++#define UDC_CON_CN_MASK (0x3)
++#define UDC_CON_IN_MASK (0x7)
++#define UDC_CON_AISN_MASK (0x7)
++#define UDC_CON_EN_MASK (0xf)
++#define UDC_CON_ET_MASK (0x3)
++#define UDC_CON_MPS_MASK (0x3ff)
++
++/* DMA Request to Channel Map Register */
++
++/* Endpoint 0 state definitions */
++#define WAIT_FOR_SETUP 0
++#define DATA_STATE_XMIT 1
++#define DATA_STATE_RECV 2
++#define DATA_STATE_PENDING_XMIT 3
++#define DATA_STATE_NEED_ZLP 4
++#define WAIT_FOR_OUT_STATUS 5
++
++#endif
++
++
++#define UDCCR __REG(0x40600000) /* UDC Control Register */
++#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */
++#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation
++ Protocol Port Support */
++#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol
++ Support */
++#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol
++ Enable */
++#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */
++#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */
++#define UDCCR_ACN_S 11
++#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */
++#define UDCCR_AIN_S 8
++#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface
++ Setting Number */
++#define UDCCR_AAISN_S 5
++#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active
++ Configuration */
++#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration
++ Error */
++#define UDCCR_UDR (1 << 2) /* UDC Resume */
++#define UDCCR_UDA (1 << 1) /* UDC Active */
++#define UDCCR_UDE (1 << 0) /* UDC Enable */
++
++#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */
++#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */
++#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */
++#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */
++
++#define UDC_INT_FIFOERROR (0x2)
++#define UDC_INT_PACKETCMP (0x1)
++
++#define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
++#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
++#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
++#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
++#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
++#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
++
++#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
++#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */
++#define UDCISR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
++#define UDCISR1_IECC (1 << 31) /* IntEn - Configuration Change */
++#define UDCISR1_IESOF (1 << 30) /* IntEn - Start of Frame */
++#define UDCISR1_IERU (1 << 29) /* IntEn - Resume */
++#define UDCISR1_IESU (1 << 28) /* IntEn - Suspend */
++#define UDCISR1_IERS (1 << 27) /* IntEn - Reset */
++
++
++#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */
++#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */
++#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */
++#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt
++ Rising Edge Interrupt Enable */
++#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt
++ Falling Edge Interrupt Enable */
++#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge
++ Interrupt Enable */
++#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge
++ Interrupt Enable */
++#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge
++ Interrupt Enable */
++#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge
++ Interrupt Enable */
++#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge
++ Interrupt Enable */
++#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge
++ Interrupt Enable */
++#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising
++ Edge Interrupt Enable */
++#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling
++ Edge Interrupt Enable */
++#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge
++ Interrupt Enable */
++#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
++ Interrupt Enable */
++
++#define UDCCSN(x) __REG2(0x40600100, (x) << 2)
++#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
++#define UDCCSR0_SA (1 << 7) /* Setup Active */
++#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
++#define UDCCSR0_FST (1 << 5) /* Force Stall */
++#define UDCCSR0_SST (1 << 4) /* Sent Stall */
++#define UDCCSR0_DME (1 << 3) /* DMA Enable */
++#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */
++#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */
++#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */
++
++#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */
++#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */
++#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */
++#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */
++#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */
++#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */
++#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */
++#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */
++#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */
++#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */
++#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */
++#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */
++#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */
++#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */
++#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */
++#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */
++#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */
++#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */
++#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */
++#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */
++#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */
++#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */
++#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */
++
++#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
++#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
++#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */
++#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */
++#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */
++#define UDCCSR_FST (1 << 5) /* Force STALL */
++#define UDCCSR_SST (1 << 4) /* Sent STALL */
++#define UDCCSR_DME (1 << 3) /* DMA Enable */
++#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
++#define UDCCSR_PC (1 << 1) /* Packet Complete */
++#define UDCCSR_FS (1 << 0) /* FIFO needs service */
++
++#define UDCBCN(x) __REG2(0x40600200, (x)<<2)
++#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */
++#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */
++#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */
++#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */
++#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */
++#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */
++#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */
++#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */
++#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */
++#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */
++#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */
++#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */
++#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */
++#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */
++#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */
++#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */
++#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */
++#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */
++#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */
++#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */
++#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */
++#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */
++#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */
++#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */
++
++#define UDCDN(x) __REG2(0x40600300, (x)<<2)
++#define PHYS_UDCDN(x) (0x40600300 + ((x)<<2))
++#define PUDCDN(x) (volatile u32 *)(io_p2v(PHYS_UDCDN((x))))
++#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */
++#define UDCDRA __REG(0x40600304) /* Data Register - EPA */
++#define UDCDRB __REG(0x40600308) /* Data Register - EPB */
++#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */
++#define UDCDRD __REG(0x40600310) /* Data Register - EPD */
++#define UDCDRE __REG(0x40600314) /* Data Register - EPE */
++#define UDCDRF __REG(0x40600318) /* Data Register - EPF */
++#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */
++#define UDCDRH __REG(0x40600320) /* Data Register - EPH */
++#define UDCDRI __REG(0x40600324) /* Data Register - EPI */
++#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */
++#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */
++#define UDCDRL __REG(0x40600330) /* Data Register - EPL */
++#define UDCDRM __REG(0x40600334) /* Data Register - EPM */
++#define UDCDRN __REG(0x40600338) /* Data Register - EPN */
++#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */
++#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */
++#define UDCDRR __REG(0x40600344) /* Data Register - EPR */
++#define UDCDRS __REG(0x40600348) /* Data Register - EPS */
++#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */
++#define UDCDRU __REG(0x40600350) /* Data Register - EPU */
++#define UDCDRV __REG(0x40600354) /* Data Register - EPV */
++#define UDCDRW __REG(0x40600358) /* Data Register - EPW */
++#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */
++
++#define UDCCN(x) __REG2(0x40600400, (x)<<2)
++#define UDCCRA __REG(0x40600404) /* Configuration register EPA */
++#define UDCCRB __REG(0x40600408) /* Configuration register EPB */
++#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */
++#define UDCCRD __REG(0x40600410) /* Configuration register EPD */
++#define UDCCRE __REG(0x40600414) /* Configuration register EPE */
++#define UDCCRF __REG(0x40600418) /* Configuration register EPF */
++#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */
++#define UDCCRH __REG(0x40600420) /* Configuration register EPH */
++#define UDCCRI __REG(0x40600424) /* Configuration register EPI */
++#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */
++#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */
++#define UDCCRL __REG(0x40600430) /* Configuration register EPL */
++#define UDCCRM __REG(0x40600434) /* Configuration register EPM */
++#define UDCCRN __REG(0x40600438) /* Configuration register EPN */
++#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */
++#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */
++#define UDCCRR __REG(0x40600444) /* Configuration register EPR */
++#define UDCCRS __REG(0x40600448) /* Configuration register EPS */
++#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */
++#define UDCCRU __REG(0x40600450) /* Configuration register EPU */
++#define UDCCRV __REG(0x40600454) /* Configuration register EPV */
++#define UDCCRW __REG(0x40600458) /* Configuration register EPW */
++#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */
++
++#define UDCCONR_CN (0x03 << 25) /* Configuration Number */
++#define UDCCONR_CN_S (25)
++#define UDCCONR_IN (0x07 << 22) /* Interface Number */
++#define UDCCONR_IN_S (22)
++#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */
++#define UDCCONR_AISN_S (19)
++#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */
++#define UDCCONR_EN_S (15)
++#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */
++#define UDCCONR_ET_S (13)
++#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */
++#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */
++#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */
++#define UDCCONR_ET_NU (0x00 << 13) /* Not used */
++#define UDCCONR_ED (1 << 12) /* Endpoint Direction */
++#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */
++#define UDCCONR_MPS_S (2)
++#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */
++#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
++
++
++#define UDC_INT_FIFOERROR (0x2)
++#define UDC_INT_PACKETCMP (0x1)
++
++#define UDC_FNR_MASK (0x7ff)
++
++#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST)
++#define UDC_BCR_MASK (0x3ff)
++
++
+diff -uNr linux/drivers/no-otg/otghw/cea-936.h linux/drivers/otg/otghw/cea-936.h
+--- linux/drivers/no-otg/otghw/cea-936.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/cea-936.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,148 @@
++/*
++ * otg/carkit.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ *
++ * Notes
++ *
++ * 1. Document references are to CEA-936a - Dec 12, 2003
++ *
++ */
++/*!
++ * @defgroup CEA
++ * @ingroup tcdgroup
++ */
++/*!
++ * @file otghw/cea-936.h
++ * @brief Hardware defines for CEA-936 Hardware
++ *
++ * @ingroup CEA
++ */
++
++
++/*
++ * Command Descriptions - C.f. 10.3
++ */
++#define CARKIT_GET_DEVICE 0x01
++#define CARKIT_GET_CARKIT 0x02
++#define CARKIT_AUDIO_EN 0x03
++#define CARKIT_SET_CRNT 0x04
++#define CARKIT_SET_UART 0x05
++#define CARKIT_CARKIT_MASTER 0x06
++
++/*
++ * generic get command
++ */
++struct carkit_get {
++ u8 strt;
++ u8 command_type;
++ u8 crc;
++ u8 terminator;
++};
++
++struct carkit_set {
++ u8 strt;
++ u8 command_type;
++ u8 command_value;
++ u8 crc;
++ u8 terminator;
++};
++
++struct carkit_get_carkit_ack {
++ u8 ack;
++ u8 terminator;
++};
++
++/*
++ * Get Device - C.f 10.3.1
++ */
++
++struct carkit_get_device_carkit {
++ u8 ack;
++ u8 device_id;
++ u16 vendor_id;
++ u16 product_id;
++ u8 crc;
++ u8 terminator;
++};
++
++#define CARKIT_DEVICE_ID_GENERIC 0x01
++#define CARKIT_DEVICE_ID_ENHANCED 0x02
++#define CARKIT_DEVICE_ID_PROPRIETARY 0x03
++
++
++/*
++ * Get CarKit - C.f. 10.3.2
++ */
++
++struct carkit_get_carkit_carkit {
++ u8 ack;
++ u16 cr_ftrs;
++ u8 cr_sts;
++ u8 crc;
++ u8 terminator;
++};
++
++#define CARKIT_CR_FTRS_0_STERO (1 << 0)
++#define CARKIT_CR_FTRS_0_CRNT_ADJ (1 << 1)
++#define CARKIT_CR_FTRS_0_UART_MAX (7 << 2)
++#define CARKIT_CR_FTRS_0_UART_MSTR (1 << 5)
++
++#define CARKIT_CR_FTRS_1_PH_REMOVE_FTR (1 << 0)
++#define CARKIT_CR_FTRS_1_CAR_OFF_FTR (1 << 1)
++#define CARKIT_CR_FTRS_1_CRDL_BTN_FTR (1 << 2)
++
++#define CARKIT_CR_PH_REMOVE_STS (1 << 0)
++#define CARKIT_CR_CAR_OFF_STS (1 << 1)
++#define CARKIT_CR_CRDL_BTN_STS (1 << 2)
++#define CARKIT_CR_PH_RMV_CHG (1 << 4)
++#define CARKIT_CR_CAR_OFF_CHG (1 << 5)
++#define CARKIT_CR_CRDL_BTN_CHG (1 << 6)
++
++
++/*
++ * Set Carkit - C.f. 10.3.3
++ */
++#define CARKIT_CR_CTL_PH_RMV_IEN (1 << 0)
++#define CARKIT_CR_CAR_OFF_IEN (1 << 1)
++#define CARKIT_CR_CRDL_BTN_IEN (1 << 2)
++#define CARKIT_CR_CARKIT_MSTR (1 << 5)
++#define CARKIT_CR_PULSE_ID (1 << 6)
++#define CARKIT_CR_ID_INT_EN (1 << 7)
++
++
++/*
++ * Audio En - C.f. 10.3.4
++ */
++#define CARKIT_AUDIO_MODE_MONO (1 << 0)
++#define CARKIT_AUDIO_MODE_STEREO (1 << 1)
++
++/*
++ * Set Crnt - C.f. 10.3.5
++ */
++#define CARKIT_CRNT_LMT (0xf)
++
++
++/*
++ * Set UART - C.f. 10.3.6
++ */
++#define CARKIT_UART_SPEED_9600 (1 << 0)
++#define CARKIT_UART_SPEED_19200 (1 << 1)
++#define CARKIT_UART_SPEED_38400 (1 << 3)
++#define CARKIT_UART_SPEED_57600 (1 << 4)
++#define CARKIT_UART_SPEED_115200 (1 << 4)
++
++
++/*
++ * Special chars - C.f. 10.4
++ */
++#define CARKIT_STRT 0x41
++#define CARKIT_ESC 0x18
++#define CARKIT_ACK 0x06
++#define CARKIT_NYET 0x30
++#define CARKIT_NAK 0x15
++#define CARKIT_NSUP 0x1f
++#define CARKIT_CR 0x0d
++
++
+diff -uNr linux/drivers/no-otg/otghw/fsotg-hardware.h linux/drivers/otg/otghw/fsotg-hardware.h
+--- linux/drivers/no-otg/otghw/fsotg-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/fsotg-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,1054 @@
++/*
++ * otghw/fsotg-hardware.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++
++/*!
++ * @defgroup FSOTG Freescale USBOTG Support
++ * @ingroup libgroup
++ */
++/*!
++ * @file otghw/fsotg-hardware.h
++ * @brief Hardware defines for Freescale USBOTG Hardware
++ *
++ * This supports the Freescale implementation of the Trans Dimension
++ * USBOTG.
++ *
++ * This is used on:
++ *
++ * - i.MX21
++ * - SCM-A11
++ * - Argon+
++ * - Zeus
++ *
++ * @ingroup FSOTG
++ */
++
++#if defined(CONFIG_ARCH_MX2ADS)
++#include <otghw/mx2ads.h>
++#include <otghw/mx2ads-hardware.h>
++#endif /* defined(CONFIG_ARCH_MX2ADS) */
++
++#if defined(CONFIG_ARCH_SCMA11EVB)
++#endif /* defined(CONFIG_ARCH_SCMA11EVB) */
++
++
++
++/*!
++ * @name OTG_SYS_CTRL
++ * C.f. 23.8 USB Control Register
++ */
++ /*! @{ */
++
++//#define OTG_SYS_CTRL (OTG_SYS_BASE+0x00)
++
++#define SYS_CTRL_I2C_WU_INT_STAT (1 << 27)
++#define SYS_CTRL_OTG_WU_INT_STAT (1 << 26)
++#define SYS_CTRL_HOST_WU_INT_STAT (1 << 25)
++#define SYS_CTRL_FNT_WU_INT_STAT (1 << 24)
++
++#define SYS_CTRL_I2C_WU_INT_EN (1 << 19)
++#define SYS_CTRL_OTG_WU_INT_EN (1 << 18)
++#define SYS_CTRL_HOST_WU_INT_EN (1 << 17)
++#define SYS_CTRL_FNT_WU_INT_EN (1 << 16)
++
++#define SYS_CTRL_OTG_BYP_VAL (0x3 << 11)
++#define SYS_CTRL_HOST1_BYP_VAL (0x3 << 9)
++
++#define SYS_CTRL_OTG_PWR_MASK (1 << 6)
++#define SYS_CTRL_HOST1_PWR_MASK (1 << 6)
++#define SYS_CTRL_HOST2_PWR_MASK (1 << 4)
++#define SYS_CTRL_USB_BYP (1 << 2)
++#define SYS_CTRL_HOST1_TXEN_OE (1 << 1)
++/*! @} */
++
++/*!
++ * @name C.f. 23.9 USBOTG Module Registers
++ */
++ /*! @{ */
++
++#define OTG_CORE_HWMODE (OTG_CORE_BASE+0x00) // 32bit core hardware mode reg
++
++#define XCVR_D_D 0x00
++#define XCVR_SE_D 0x01
++#define XCVR_D_SE 0x02
++#define XCVR_SE_SE 0x03
++
++#define MODULE_ANASDBEN (1 << 14)
++#define MODULE_OTGXCVR (0x3 << 6)
++#define MODULE_HOSTXCVR (0x3 << 4)
++#define MODULE_CRECFG (0x3)
++#define MODULE_CRECFG_HHNP (0x0)
++#define MODULE_CRECFG_HOST (0x1)
++#define MODULE_CRECFG_FUNC (0x2)
++#define MODULE_CRECFG_SHNP (0x3)
++
++#define OTG_CORE_CINT_STAT (OTG_CORE_BASE+0x04) // 32bit core int status reg
++
++#define MODULE_FCINTDSPEN (1 << 6)
++
++#define MODULE_ASHNPINT (1 << 5)
++#define MODULE_ASFCINT (1 << 4)
++#define MODULE_ASHCINT (1 << 3)
++#define MODULE_HNPINT (1 << 2)
++#define MODULE_FCINT (1 << 1)
++#define MODULE_HCINT (1)
++
++#define OTG_CORE_CINT_STEN (OTG_CORE_BASE+0x08) // 32bit core int enable reg
++
++#define MODULE_ASHNPINT_EN (1 << 5)
++#define MODULE_ASFCINT_EN (1 << 4)
++#define MODULE_ASHCINT_EN (1 << 3)
++#define MODULE_HNPINT_EN (1 << 2)
++#define MODULE_FCINT_EN (1 << 1)
++#define MODULE_HCINT_EN (1)
++
++#define OTG_CORE_CLK_CTRL (OTG_CORE_BASE+0x0C) // 32bit core clock control reg
++
++#define MODULE_FUNC_CLK (1 << 2)
++#define MODULE_HOST_CLK (1 << 1)
++#define MODULE_MAIN_CLK (1)
++
++#define OTG_CORE_RST_CTRL (OTG_CORE_BASE+0x10) // 32bit core reset control reg
++
++#define MODULE_RSTI2C (1 << 15)
++#define MODULE_RSTCTRL (1 << 5)
++#define MODULE_RSTFC (1 << 4)
++#define MODULE_RSTFSIE (1 << 3)
++#define MODULE_RSTRH (1 << 2)
++#define MODULE_RSTHSIE (1 << 1)
++#define MODULE_RSTHC (1)
++
++#define OTG_CORE_FRM_INTVL (OTG_CORE_BASE+0x14) // 32bit core frame interval reg
++
++#define MODULE_RESET_FRAME (1 << 15)
++
++#define OTG_CORE_FRM_REMAIN (OTG_CORE_BASE+0x18) // 32bit core frame remaining reg
++
++#define OTG_CORE_HNP_CSTAT (OTG_CORE_BASE+0x1C) // 32bit core HNP current state reg
++
++#define MODULE_HNPDAT (1 << 30)
++#define MODULE_VBUSBSE (1 << 29)
++#define MODULE_VBUSABSV (1 << 28)
++#define MODULE_VBUSGTAVV (1 << 27)
++
++#define MODULE_ARMTHNPE (1 << 25)
++#define MODULE_BHNPEN (1 << 24)
++
++#define MODULE_SLAVE (1 << 22)
++#define MODULE_MASTER (1 << 21)
++#define MODULE_BGEN (1 << 20)
++#define MODULE_CMPEN (1 << 19)
++#define MODULE_ISBDEV (1 << 18)
++#define MODULE_ISADEV (1 << 17)
++
++#define MODULE_SWVBUSPUL (1 << 15)
++
++#define MODULE_SWAUTORST (1 << 12)
++#define MODULE_SWPUDP (1 << 11)
++
++#define MODULE_SWPDDM (1 << 9)
++#define MODULE_HNPSTATE (0x1f << 8)
++#define MODULE_CLRERROR (1 << 3)
++#define MODULE_ADROPBUS (1 << 2)
++#define MODULE_ABBUSREQ (1 << 1)
++
++#define HNP_A_IDLE (0x10 << 8)
++#define HNP_A_MASTER (0x11 << 8)
++#define HNP_A_SLAVE (0x12 << 8)
++#define HNP_A_WAIT_VPULSE (0x13 << 8)
++
++#define HNP_A_WAIT_DPULSE (0x14 << 8)
++#define HNP_A_WAIT_CONN_A (0x15 << 8)
++#define HNP_A_WAIT_CONN_B (0x16 << 8)
++#define HNP_A_WAIT_VRISE (0x17 << 8)
++#define HNP_A_SUSPEND (0x18 << 8)
++#define HNP_A_WAIT_VFALL (0x19 << 8)
++#define HNP_A_VBUS_ERR (0x1a << 8)
++#define HNP_CONN_DEBOUNCE (0x1b << 8)
++#define HNP_A_WAIT_ABREQ (0x1c << 8)
++#define HNP_B_IDLE (0x00 << 8)
++#define HNP_B_MASTER (0x01 << 8)
++#define HNP_B_SLAVE (0x02 << 8)
++#define HNP_B_SRP_INIT_V (0x03 << 8)
++#define HNP_B_SRP_INIT_D (0x04 << 8)
++#define HNP_B_PRE_WAIT_CONN_AB_SHORT_DB (0x05 << 8)
++#define HNP_B_WAIT_CONN_A (0x06 << 8)
++#define HNP_B_PRE_SLAVE (0x0a << 8)
++
++
++#define OTG_CORE_HNP_TIMER1 (OTG_CORE_BASE+0x20) // 32bit core HNP timer 1 reg
++#define OTG_CORE_HNP_TIMER2 (OTG_CORE_BASE+0x24) // 32bit core HNP timer 2 reg
++#define OTG_CORE_HNP_T3PCR (OTG_CORE_BASE+0x28) // 32bit core HNP timer 3 pulse ctrl
++
++#define HNP_DATAPULSE (1 << 5)
++#define HNP_VBUSPULSE (1 << 4)
++
++#define OTG_CORE_HINT_STAT (OTG_CORE_BASE+0x2C) // 32bit core HNP int status reg
++
++#define HNP_I2COTGINT (1 << 15)
++#define HNP_AWAITBTO (1 << 8) // Hardware HNP Only
++#define HNP_AIDLEBDTO (1 << 7) // Hardware HNP Only
++#define HNP_SRPSUCFAIL (1 << 6) // Hardware HNP Only
++#define HNP_SRPINT (1 << 5)
++#define HNP_VBUSERROR (1 << 4) // Hardware HNP Only
++#define HNP_ABSEVAILD (1 << 3)
++#define HNP_ABUSVALID (1 << 2)
++#define HNP_MASSLVCHG (1 << 1) // Hardware HNP Only
++#define HNP_IDCHANGE (1)
++
++#define OTG_CORE_HINT_STEN (OTG_CORE_BASE+0x30) // 32bit core HNP int enable reg
++
++#define HNP_I2COTGINT_EN (1 << 15)
++#define HNP_AWAITBTO_EN (1 << 8)
++#define HNP_AIDLEBDTO_EN (1 << 7)
++#define HNP_SRPSUCFAIL_EN (1 << 6)
++#define HNP_SRPINT_EN (1 << 5)
++#define HNP_VBUSERROR_EN (1 << 4)
++#define HNP_ABSEVAILD_EN (1 << 3)
++#define HNP_ABUSVALID_EN (1 << 2)
++#define HNP_MASSLVCHG_EN (1 << 1)
++#define HNP_IDCHANGE_EN (1)
++
++
++#define OTG_CORE_CPUEPSEL_STAT (OTG_CORE_BASE+0x34)
++#define OTG_CORE_INTERRUPT_STEN (OTG_CORE_BASE+0x3c)
++/*! @} */
++
++
++/*!
++ * @name C.f. 23.11.11 Host Registers
++ */
++ /*! @{ */
++
++
++#define OTG_HOST_CONTROL (OTG_HOST_BASE+0x00) // 32bit host controller config reg
++
++#define HOST_CONTROL_HCRESET (1 << 31)
++#define HOST_CONTROL_RMTWUEN (1 << 4)
++
++#define HOST_CONTROL_HCUSBSTE_RESET (0 << 2)
++#define HOST_CONTROL_HCUSBSTE_RESUME (1 << 2)
++#define HOST_CONTROL_HCUSBSTE_OPERATIONAL (2 << 2)
++#define HOST_CONTROL_HCUSBSTE_SUSPEND (3 << 2)
++
++#define HOST_CONTROL_CTLBLKSR_11 (0)
++#define HOST_CONTROL_CTLBLKSR_21 (1)
++#define HOST_CONTROL_CTLBLKSR_41 (2)
++#define HOST_CONTROL_CTLBLKSR_81 (3)
++
++
++#define OTG_HOST_SINT_STAT (OTG_HOST_BASE+0x08) // 32bit host system int status reg
++
++#define HOST_PSCINT (1 << 6) // Port Status Change
++#define HOST_FMOFINT (1 << 5) // Frame Number Overflow
++#define HOST_HERRINT (1 << 4) // Host Error
++#define HOST_RESDETINT (1 << 3) // Resume Detected
++#define HOST_SOFINT (1 << 2) // Start of Frame
++#define HOST_DONEINT (1 << 1) // Done Register
++#define HOST_SORINT (1) // Schedule Overrun
++
++#define OTG_HOST_SINT_STEN (OTG_HOST_BASE+0x0C) // 32bit host system int enable reg
++
++#define HOST_PSCINT_EN (1 << 6) // Port Status Change
++#define HOST_FMOFINT_EN (1 << 5) // Frame Number Overflow
++#define HOST_HERRINT_EN (1 << 4) // Host Error
++#define HOST_RESDETINT_EN (1 << 3) // Resume Detected
++#define HOST_SOFINT_EN (1 << 2) // Start of Frame
++#define HOST_DONEINT_EN (1 << 1) // Done Register
++#define HOST_SORINT_EN (1) // Schedule Overrun
++
++#define OTG_HOST_XINT_STAT (OTG_HOST_BASE+0x18) // 32bit host X buf int status reg
++#define OTG_HOST_YINT_STAT (OTG_HOST_BASE+0x1C) // 32bit host Y buf int status reg
++
++#define OTG_HOST_XYINT_STEN (OTG_HOST_BASE+0x20) // 32bit host XY buf int enable reg
++#define OTG_HOST_XFILL_STAT (OTG_HOST_BASE+0x28) // 32bit host X filled status reg
++#define OTG_HOST_YFILL_STAT (OTG_HOST_BASE+0x2C) // 32bit host Y filled status reg
++
++#define OTG_HOST_ETD_EN (OTG_HOST_BASE+0x40) // 32bit host ETD enables reg
++#define OTG_HOST_DIR_ROUTE (OTG_HOST_BASE+0x48) // 32bit host direct routing reg
++#define OTG_HOST_IINT (OTG_HOST_BASE+0x4C) // 32bit host immediate interrupt reg
++
++#define OTG_HOST_EP_DSTAT (OTG_HOST_BASE+0x50) // 32bit host endpoints done status
++#define OTG_HOST_ETD_DONE (OTG_HOST_BASE+0x54) // 32bit host ETD done reg
++
++#define OTG_HOST_FRM_NUM (OTG_HOST_BASE+0x60) // 32bit host frame number reg
++#define OTG_HOST_LSP_THRESH (OTG_HOST_BASE+0x64) // 32bit host low speed threshold reg
++
++#define OTG_HOST_ROOTHUB_DESCA (OTG_HOST_BASE+0x68) // 32bit host root hub descriptor A
++#define OTG_HOST_ROOTHUB_DESCB (OTG_HOST_BASE+0x6C) // 32bit host root hub descriptor B
++/* @} */
++
++/*!
++ * @name C.f. 23.11.29
++ */
++/*! @{ */
++#define OTG_HOST_ROOTHUB_STATUS (OTG_HOST_BASE+0x70) // 32bit host root hub status reg
++
++#define ROOTHUB_STATUS_CLRMTWUE (1 << 31) // Clear Remote Wakeup Enable
++#define ROOTHUB_STATUS_OVRCURCHG (1 << 17) // Over Current Indicator Change
++#define ROOTHUB_STATUS_LOCPWRSC (1 << 16) // Local Power Status Change
++#define ROOTHUB_STATUS_DEVCONWUE (1 << 15) // Device Connect Wakeup Enable
++#define ROOTHUB_STATUS_OVRCURI (1 << 1) // Over Current Indicator
++#define ROOTHUB_STATUS_LOCPWRS (1) // Local Power Status
++/*! @} */
++
++
++/*!
++ * @name C.f. 23.11.30
++ */
++/*! @{ */
++#define OTG_HOST_PORT_STATUS_1 (OTG_HOST_BASE+0x74) // 32bit host port 1 status bits
++#define OTG_HOST_PORT_STATUS_2 (OTG_HOST_BASE+0x78) // 32bit host port 2 status bits
++#define OTG_HOST_PORT_STATUS_3 (OTG_HOST_BASE+0x7c) // 32bit host port 3 status bits
++
++#define PORT_STATUS_PRTRSTSC (1 << 20) // Port Reset Status Change
++#define PORT_STATUS_OVRCURIC (1 << 19) // Port Over Current Indicator Change
++#define PORT_STATUS_PRTSTATSC (1 << 18) // Port Suspend Status Change
++#define PORT_STATUS_PRTENBLSC (1 << 17) // Port Enable Status Change
++#define PORT_STATUS_CONNECTSC (1 << 16) // Connect Status Change
++
++#define PORT_STATUS_LSDEVCON (1 << 9) // Low Speed Device Attached
++#define PORT_STATUS_PRTPWRST (1 << 8) // Port Power Status
++
++#define PORT_STATUS_PRTRSTST (1 << 4) // Port Reset Status
++#define PORT_STATUS_PRTOVRCURI (1 << 3) // Port Over Current Indicator
++#define PORT_STATUS_PRTSUSPST (1 << 2) // Port Suspend Status
++#define PORT_STATUS_PRTENABST (1 << 1) // Port Enable Status
++#define PORT_STATUS_CURCONST (1) // Current Connect Status
++
++
++/* flags are the same for the interrupt, control and bulk transfer descriptors */
++// R1: sec 23.11.10.2,3 pg 23-44,47
++#define ETD_GET_COMPCODE(flags) ((flags >> 12) & 0xf)
++// R1: sec 23.11.10 Table 23-23 pg 23-40
++#define ETD_CC_NOERROR 0x0
++#define ETD_CC_CRCERR 0x1
++#define ETD_CC_BITSTUFFERR 0x2
++#define ETD_CC_DATATOGERR 0x3
++#define ETD_CC_STALL 0x4
++#define ETD_CC_DEVNOTRESPONDING 0x5
++#define ETD_CC_PIDFAILURE 0x6
++// Reserved 0x7
++#define ETD_CC_DATAOVERRUN 0x8
++#define ETD_CC_DATAUNDERRUN 0x9
++#define ETD_CC_ACK 0xA
++#define ETD_CC_NAK 0xB
++#define ETD_CC_BUFFEROVERRUN 0xC
++#define ETD_CC_BUFFERUNDERRUN 0xD
++#define ETD_CC_SCHEDOVERRUN 0xE
++#define ETD_CC_NOTACCESSED 0xF
++
++// R1: sec 23.11.10.2,3 pg 23-44,47 (contd)
++#define ETD_GET_ERRORCNT(flags) (((flags) >> 8) & 0xf)
++#define ETD_GET_DATATOGL(flags) (((flags) >> 6) & 0x3)
++#define ETD_SET_DATATOGL(v) (((v) & 0x3) << 6)
++#define ETD_GET_DELAYINT(flags) (((flags) >> 3) & 0x7)
++#define ETD_SET_DELAYINT(v) (((v) & 0x7) << 3)
++#define ETD_GET_BUFROUND(flags) (((flags) >> 2) & 0x1)
++#define ETD_SET_BUFROUND(v) (((v) & 0x1) << 2)
++#define ETD_GET_DIRPID(flags) ((flags) & 0x3)
++#define ETD_SET_DIRPID(v) ((v) & 0x3)
++#define ETD_FLIP_DIRPID(flags) ((flags) ^ 0x3) /* xor with 0x3 flips 2<->1 (IN<->OUT) */
++#define ETD_DIRPID_SETUP 0x0 // OUT
++#define ETD_DIRPID_OUT 0x1
++#define ETD_DIRPID_IN 0x2
++#define ETD_DIRPID_RESERVED 0x3
++
++// For non-isoc td.w3.val -
++#define ETD_GET_BUFSIZE(w3) (((w3) >> 21) & 0xfff)
++#define ETD_SET_BUFSIZE(v) (((v) & 0xfff) << 21)
++#define ETD_GET_TOTBYECNT(w3) ((w3) & 0xfffff)
++#define ETD_SET_TOTBYECNT(v) ((v) & 0xfffff)
++
++/* isoc flags shares the COMPCODE and DELAYINT bitfields with the other TDs,
++ but the remaining bits are different. */
++#define ETD_GET_AUTOISO(flags) (((flags) >> 11) & 0x1)
++#define ETD_SET_AUTOISO(v) (((v) & 0x1) << 11)
++#define ETD_GET_FRAMECNT(flags) (((flags) >> 8) & 0x1)
++#define ETD_SET_FRAMECNT(v) (((v) & 0x1) << 8)
++// For isoc td.w3.val -
++/* pkt1 and pkt0 use the COMPCODE bitfield, and add a PKTLEN field. */
++#define ETD_GET_PKTLEN(pkt) ((pkt) & 0x3ff)
++#define ETD_SET_PKTLEN(v) ((v) & 0x3ff)
++
++
++// ETD endpoint descriptor (etd->epd) bitfield access
++// R1: sec 23.11.10.1 pg 23-41 (word0)
++#define ETD_GET_SNDNAK(epd) (((epd) >> 30) & 0x1)
++#define ETD_SET_SNDNAK(v) (((v) & 0x1) << 30)
++#define ETD_GET_TOGCRY(epd) (((epd) >> 28) & 0x1)
++#define ETD_SET_TOGCRY(v) (((v) & 0x1) << 28)
++#define ETD_GET_HALTED(epd) (((epd) >> 27) & 0x1)
++#define ETD_SET_HALTED(v) (((v) & 0x1) << 27)
++#define ETD_GET_MAXPKTSIZ(epd) (((epd) >> 16) & 0x3ff)
++#define ETD_SET_MAXPKTSIZ(v) (((v) & 0x3ff) << 16)
++#define ETD_GET_FORMAT(epd) (((epd) >> 14) & 0x3)
++#define ETD_SET_FORMAT(v) (((v) & 0x3) << 14)
++#define ETD_FORMAT_CONTROL 0x0
++#define ETD_FORMAT_ISOC 0x1
++#define ETD_FORMAT_BULK 0x2
++#define ETD_FORMAT_INTERRUPT 0x3
++#define ETD_GET_SPEED(epd) (((epd) >> 13) & 0x1)
++#define ETD_SET_SPEED(v) (((v) & 0x1) << 13)
++#define ETD_SPEED_FULL 0x0
++#define ETD_SPEED_LOW 0x1
++#define ETD_GET_DIRECT(epd) (((epd) >> 11) & 0x3)
++#define ETD_SET_DIRECT(v) (((v) & 0x3) << 11)
++/* xor with 3 flips 2<->1 */
++#define ETD_FLIP_DIRECT(epd) ((epd) ^ (0x3 << 11))
++#define ETD_DIRECT_TD00 0x0
++#define ETD_DIRECT_OUT 0x1
++#define ETD_DIRECT_IN 0x2
++#define ETD_DIRECT_TD11 0x3
++#define ETD_GET_ENDPNT(epd) (((epd) >> 7) & 0xf)
++#define ETD_SET_ENDPNT(v) (((v) & 0xf) << 7)
++#define ETD_GET_ADDRESS(epd) ((epd) & 0x7f)
++#define ETD_SET_ADDRESS(v) ((v) & 0x7f)
++
++// etd_urb_state[] values
++#define ETD_URB_COMPLETED 0
++#define ETD_URB_SETUP_STATUS 1
++#define ETD_URB_SETUP_DATA 2
++#define ETD_URB_SETUP_START 3
++#define ETD_URB_BULK_START 4
++#define ETD_URB_BULKWZLP 5
++#define ETD_URB_BULKWZLP_START 6
++#define ETD_URB_INTERRUPT_START 7
++#define ETD_URB_ISOC_START 8
++/*! @} */
++
++
++/*!
++ * @name C.f. 23.12.8 Function Registers
++ */
++/*! @{ */
++
++#define OTG_FUNC_CMD_STAT (OTG_FUNC_BASE+0x00) // 32bit func command status reg
++
++#define COMMAND_SOFTRESET (1 << 7)
++#define COMMAND_BADISOAP (1 << 3)
++#define COMMAND_SUPDET (1 << 2)
++#define COMMAND_RSMINPROG (1 << 1)
++#define COMMAND_RESETDET (1)
++
++
++#define OTG_FUNC_DEV_ADDR (OTG_FUNC_BASE+0x04) // 32bit func device address reg
++
++#define OTG_FUNC_SINT_STAT (OTG_FUNC_BASE+0x08) // 32bit func system int status reg
++
++#define SYSTEM_DONEREGINTDS (1 << 5)
++#define SYSTEM_SOFDETINT (1 << 4)
++#define SYSTEM_DONEREGINT (1 << 3)
++#define SYSTEM_SUSPDETINT (1 << 2)
++#define SYSTEM_RSMFININT (1 << 1)
++#define SYSTEM_RESETINT (1)
++
++#define OTG_FUNC_SINT_STEN (OTG_FUNC_BASE+0x0C) // 32bit func system int enable reg
++
++#define SYSTEM_DONEREGINTDS_EN (1 << 5)
++#define SYSTEM_SOFDETINT_EN (1 << 4)
++#define SYSTEM_DONEREGINT_EN (1 << 3)
++#define SYSTEM_SUSPDETINT_EN (1 << 2)
++#define SYSTEM_RSMFININT_EN (1 << 1)
++#define SYSTEM_RESETINT_EN (1)
++
++
++#define OTG_FUNC_XINT_STAT (OTG_FUNC_BASE+0x10) // 32bit func X buf int status reg
++#define OTG_FUNC_YINT_STAT (OTG_FUNC_BASE+0x14) // 32bit func Y buf int status reg
++#define OTG_FUNC_XYINT_STEN (OTG_FUNC_BASE+0x18) // 32bit func XY buf int enable reg
++#define OTG_FUNC_XFILL_STAT (OTG_FUNC_BASE+0x1C) // 32bit func X filled status reg
++
++#define OTG_FUNC_YFILL_STAT (OTG_FUNC_BASE+0x20) // 32bit func Y filled status reg
++#define OTG_FUNC_EP_EN (OTG_FUNC_BASE+0x24) // 32bit func endpoints enable reg
++#define OTG_FUNC_EP_RDY (OTG_FUNC_BASE+0x28) // 32bit func endpoints ready reg
++#define OTG_FUNC_IINT (OTG_FUNC_BASE+0x2C) // 32bit func immediate interrupt reg
++
++#define OTG_FUNC_EP_DSTAT (OTG_FUNC_BASE+0x30) // 32bit func endpoints done status
++#define OTG_FUNC_EP_DEN (OTG_FUNC_BASE+0x34) // 32bit func endpoints done enable
++#define OTG_FUNC_EP_TOGGLE (OTG_FUNC_BASE+0x38) // 32bit func endpoints toggle bits
++#define OTG_FUNC_FRM_NUM (OTG_FUNC_BASE+0x3C) // 32bit func frame number reg
++
++
++#define EP0_STALL (1 << 31)
++#define EP0_SETUP (1 << 30)
++#define EP0_OVERRUN (1 << 29)
++#define EP0_AUTOISO (1 << 27)
++
++
++/* generic endpoint register manipulations
++ */
++#define EP_OUT 0x1
++#define EP_IN 0x2
++#define EP_BOTH 0x3
++
++#define ETD_MASK(n) (1 << n)
++#define ep_num_both(n) (EP_BOTH << n)
++#define ep_num_dir(n, dir) ((dir ? EP_IN : EP_OUT) << (n*2))
++#define ep_num_out(n) ep_num_dir(n, USB_DIR_OUT)
++#define ep_num_in(n) ep_num_dir(n, USB_DIR_IN)
++
++
++/* ep descriptor access
++ */
++static __inline__ u32 etd_word(int n, int word)
++{
++ u32 offset = n * 16;
++ offset += word * 4;
++ return OTG_ETD_BASE + offset;
++}
++
++/* ep descriptor access
++ */
++static __inline__ u32 ep_word(int n, int dir, int word)
++{
++ u32 offset = n * 2;
++ offset += dir ? 1 : 0;
++ offset *= 16;
++ offset += word * 4;
++ return OTG_EP_BASE + offset;
++}
++
++/* endpoint data buffer access
++ *
++ * This is a simplistic allocator, will do until we want to support ISO or host mode.
++ *
++ * This works because we are assuming a maximum of 16 allocate endpoints, and no
++ * overlapped endpoints (both in and out are allocated).
++ */
++
++static volatile __inline__ u16 data_x_buf(int n, int dir)
++{
++ return 0x40 * (n * 4 + 2 * (dir ? 1 : 0));
++}
++static volatile __inline__ u16 data_y_buf(int n, int dir)
++{
++ return 0x40 * (n * 4 + 2 * (dir ? 1 : 0) + 1);
++}
++
++static volatile __inline__ u8 * data_x_address(int n, int dir)
++{
++ return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_x_buf(n, dir));
++}
++static volatile __inline__ u8 * data_y_address(int n, int dir)
++{
++ return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_y_buf(n, dir));
++}
++/*! @} */
++
++/*!
++ * @name C.f. 23.13.3 DMA Registers
++ */
++/*! @{ */
++#define OTG_DMA_REV_NUM (OTG_DMA_BASE+0x000) // 32bit dma revision number reg
++#define OTG_DMA_DINT_STAT (OTG_DMA_BASE+0x004) // 32bit dma int status reg
++#define OTG_DMA_DINT_STEN (OTG_DMA_BASE+0x008) // 32bit dma int enable reg
++#define OTG_DMA_ETD_ERR (OTG_DMA_BASE+0x00C) // 32bit dma ETD error status reg
++#define OTG_DMA_EP_ERR (OTG_DMA_BASE+0x010) // 32bit dma EP error status reg
++#define OTG_DMA_ETD_EN (OTG_DMA_BASE+0x020) // 32bit dma ETD DMA enable reg
++#define OTG_DMA_EP_EN (OTG_DMA_BASE+0x024) // 32bit dma EP DMA enable reg
++#define OTG_DMA_ETD_ENXREQ (OTG_DMA_BASE+0x028) // 32bit dma ETD DMA enable Xtrig req
++#define OTG_DMA_EP_ENXREQ (OTG_DMA_BASE+0x02C) // 32bit dma EP DMA enable Ytrig req
++#define OTG_DMA_ETD_ENXYREQ (OTG_DMA_BASE+0x030) // 32bit dma ETD DMA enble XYtrig req
++#define OTG_DMA_EP_ENXYREQ (OTG_DMA_BASE+0x034) // 32bit dma EP DMA enable XYtrig req
++#define OTG_DMA_ETD_BURST4 (OTG_DMA_BASE+0x038) // 32bit dma ETD DMA enble burst4 reg
++#define OTG_DMA_EP_BURST4 (OTG_DMA_BASE+0x03C) // 32bit dma EP DMA enable burst4 reg
++#define OTG_DMA_MISC_CTRL (OTG_DMA_BASE+0x040) // 32bit dma EP misc control reg
++#define OTG_DMA_ETD_CH_CLR (OTG_DMA_BASE+0x044) // 32bit dma ETD clear channel reg
++#define OTG_DMA_EP_CH_CLR (OTG_DMA_BASE+0x048) // 32bit dma EP clear channel reg
++
++
++#define OTG_DMA_ETD_CH_CLR (OTG_DMA_BASE+0x044) // 32bit dma ETD clear channel reg
++#define OTG_DMA_ETD_ERR (OTG_DMA_BASE+0x00C) // 32bit dma ETD error status reg
++#define OTG_DMA_ETD_EN (OTG_DMA_BASE+0x020) // 32bit dma ETD DMA enable reg
++#define OTG_DMA_ETD_ENXREQ (OTG_DMA_BASE+0x028) // 32bit dma ETD DMA enable Xtrig req
++#define OTG_DMA_ETD_ENXYREQ (OTG_DMA_BASE+0x030) // 32bit dma ETD DMA enble XYtrig req
++#define OTG_DMA_ETD_BURST4 (OTG_DMA_BASE+0x038) // 32bit dma ETD DMA enble burst4 reg
++
++
++
++#define OTG_DMA_EP_CH_CLR (OTG_DMA_BASE+0x048) // 32bit dma EP clear channel reg
++#define OTG_DMA_EP_ERR (OTG_DMA_BASE+0x010) // 32bit dma EP error status reg
++#define OTG_DMA_EP_EN (OTG_DMA_BASE+0x024) // 32bit dma EP DMA enable reg
++#define OTG_DMA_EP_ENXREQ (OTG_DMA_BASE+0x02C) // 32bit dma EP DMA enable Ytrig req
++#define OTG_DMA_EP_ENXYREQ (OTG_DMA_BASE+0x034) // 32bit dma EP DMA enable XYtrig req
++#define OTG_DMA_EP_BURST4 (OTG_DMA_BASE+0x03C) // 32bit dma EP DMA enable burst4 reg
++
++
++#define dma_num_dir(n, dir) (n * 2 + (dir ? 1 : 0))
++#define dma_num_out(n) dma_num_dir(n, USB_DIR_OUT)
++#define dma_num_in(n) dma_num_dir(n, USB_DIR_IN)
++
++#define OTG_DMA_ETD_MSA(x) (OTG_DMA_BASE+0x100+x*4)
++#define OTG_DMA_EPN_MSA(x) (OTG_DMA_BASE+0x180+x*4)
++#define OTG_DMA_ETDN_BPTR(x) (OTG_DMA_BASE+0x280+x*4)
++#define OTG_DMA_EPN_BPTR(x) (OTG_DMA_BASE+0x284+x*4)
++
++/*! @} */
++
++/* ********************************************************************************************** */
++/*!
++ * Warning: the MX21 memory mapped region appears to require 32-bit access only.
++ * As of this writing, only the ETD region has been tested, but it does show the
++ * following behavior:
++ *
++ * Step 1: *(volatile u32 *)(void*)0xe40243f8 == 00000000
++ * Step 2: *(volatile u16 *)(void*)0xe40243f8 = 0x0084;
++ * Step 3: *(volatile u32 *)(void*)0xe40243f8 == 00840084
++ * Step 4: *(volatile u8 *)(void*)(0xe40243f8+3) = 0x01;
++ * Step 5: *(volatile u32 *)(void*)0xe40243f8 == 01010101
++ *
++ * Any access to less than 32 bits is replicated as many times as required
++ * to make 32 bits, and the surrounding 32-bit region is changed.
++ *
++ * Just to add insult to injury, gcc 3.2.3 wants to store constants
++ * that are small enough using byte instructions. E.g.
++ *
++ * mm->host.System_Interrupt_Enables = (SIEN_PSCIEN | SIEN_FMOFIEN | SIEN_HERRIEN | SIEN_RESDETIEN |
++ * SIEN_DONEIEN | SIEN_SORIEN);
++ *
++ * becomes:
++ *
++ * ldrb r2, [r3, #140]
++ * mov r2, #123
++ * strb r2, [r3, #140]
++ * ldrb r2, [r3, #141]
++ * strb r1, [r3, #141]
++ * ldrb r2, [r3, #142]
++ * strb r1, [r3, #142]
++ * ldrb r2, [r3, #143]
++ * strb r1, [r3, #143]
++ *
++ * which, given the 32-bit access restrictions above,
++ * is not going to work very well. Changing the original assignment to:
++ *
++ * *&(mm->host.System_Interrupt_Enables) = (SIEN_PSCIEN | SIEN_FMOFIEN | SIEN_HERRIEN | SIEN_RESDETIEN |
++ * SIEN_DONEIEN | SIEN_SORIEN);
++ *
++ * which should be identical, from a language definition point of view,
++ * produces:
++ *
++ * mov r2, #123
++ * str r2, [r3, #140]
++ *
++ */
++
++
++/*!
++ * @name TransferDescriptors
++ *
++ * Note that the MX21 needs to run in little-endian mode for OTG, but
++ * since the memory can only be accessed in 32-bit quantities, anything
++ * smaller will be built in regular memory, then transfered one word at
++ * a time to the memory-mapped registers, and that word access will flip
++ * the order of bytes. u16 quantities survive this flipping because they
++ * get "pre-flipped" in regular memory.
++ *
++ *
++ * An Endpoint Transfer Descriptor (ETD) consists of 4x32bit words.
++ * The first word is the Endpoint Descriptor, the last three are
++ * the transfer descriptor. Transfer descriptors come in 3 formats,
++ * CONTROL/BULK, INTERRUPT, and ISOCRONOUS. Becasue of the memory
++ * access restrictions to less than 32 bits described above, only
++ * the words are mapped directly, The smaller fields are assembled
++ * into 32-bit words before being placed into the live ETD.
++ *
++ */
++ /*! @{ */
++
++/*!
++ * @struct transfer_descriptor_w1
++ * All three types of TD have the same format for w1.
++ */
++typedef struct transfer_descriptor_w1 {
++#if defined(LITTLE_ENDIAN)
++ u16 x;
++ u16 y;
++#else
++ u16 y;
++ u16 x;
++#endif
++} __attribute__ ((packed)) volatile transfer_descriptor_w1;
++
++/*!
++ * @struct control_bulk_transfer_descriptor_w2
++ * There are 3 different formats for w2.
++ * C.f. R1: sec 23.11.10.2 pg 23-43
++ */
++typedef struct control_bulk_transfer_descriptor_w2 {
++#if defined(LITTLE_ENDIAN)
++ u8 rtrydelay;
++ u8 reserved;
++ u16 flags;
++#else
++ u16 flags;
++ u8 reserved;
++ u8 rtrydelay;
++#endif
++} __attribute__ ((packed)) volatile control_bulk_transfer_descriptor_w2;
++
++/*!
++ * @struct interrupt_transfer_descriptor_w2
++ * C.f. R1: sec 23.11.10.3 pg 23-46
++ */
++typedef struct interrupt_transfer_descriptor_w2 {
++#if defined(LITTLE_ENDIAN)
++ u8 polinterv;
++ u8 relpolpos;
++ u16 flags;
++#else
++ u16 flags;
++ u8 relpolpos;
++ u8 polinterv;
++#endif
++} __attribute__ ((packed)) volatile interrupt_transfer_descriptor_w2;
++
++/*!
++ * @struct isoc_transfer_descriptor_w2
++ * C.f. R1: sec 23.11.10.4 pg 23-48
++ */
++typedef struct isoc_transfer_descriptor_w2 {
++#if defined(LITTLE_ENDIAN)
++ u16 startfrm;
++ u16 flags;
++#else
++ u16 flags;
++ u16 startfrm;
++#endif
++} __attribute__ ((packed)) volatile isoc_transfer_descriptor_w2;
++
++
++
++/*!
++ * @struct isoc_transfer_descriptor_w3
++ * There are 2 different formats for w3.
++ * All but isoc use a packet size and 20-bit bytecount, accessed through w3.val.
++ */
++typedef struct isoc_transfer_descriptor_w3 {
++#if defined(LITTLE_ENDIAN)
++ u16 pkt0;
++ u16 pkt1;
++#else
++ u16 pkt1;
++ u16 pkt0;
++#endif
++} __attribute__ ((packed)) volatile isoc_transfer_descriptor_w3;
++
++/*!
++ * @name transfer_descriptor
++ */
++/*! @{ */
++typedef struct transfer_descriptor {
++ union {
++ u32 val;
++ transfer_descriptor_w1 bufsrtad;
++ } volatile w1;
++ union {
++ u32 val;
++ control_bulk_transfer_descriptor_w2 cb;
++ interrupt_transfer_descriptor_w2 intr;
++ isoc_transfer_descriptor_w2 isoc;
++ } volatile w2;
++ union {
++ u32 val;
++ isoc_transfer_descriptor_w3 isoc;
++ } volatile w3;
++} __attribute__ ((packed)) volatile transfer_descriptor;
++
++/*! @} */
++
++/*!
++ * @name endpoint_transfer_descriptor
++ * C.f. R1: sec 23.11.10 pg 23-41
++ */
++ /*! @{ */
++typedef struct endpoint_transfer_descriptor {
++ u32 epd;
++ transfer_descriptor td;
++} __attribute__ ((packed)) volatile endpoint_transfer_descriptor; // ETD
++
++/*! @} */
++
++
++/*!
++ * @name DataBuffs
++ *
++ * There is no predetermined size for data buffers, so
++ * this structure was chosen as an arbitrary, but generally
++ * adequate size.
++ */
++/*! @{ */
++
++/*!
++ * @struct fs_data_buff
++ */
++typedef struct fs_data_buff {
++ u32 data[DATA_BUFF_SIZE/sizeof(u32)]; // Cannot safely write less than 32-bit quantities
++} volatile fs_data_buff;
++
++
++/*!
++ * @struct fs_hcpriv
++ */
++typedef struct fs_hcpriv {
++ struct bus_hcpriv *bus_hcpriv;
++ u32 sof_count;
++ u32 free_etds;
++ endpoint_transfer_descriptor sdp_etd[NUM_ETDS]; // Setup data phase save area
++ void *sdp_data[NUM_ETDS];
++ u8 etd_urb_state[NUM_ETDS];
++ u16 free_buffs;
++ u16 buff_list[NUM_DATA_BUFFS];
++} fs_hcpriv;
++
++
++/*!
++ * get_data_buff() - get data buff
++ */
++static __inline__ fs_data_buff *get_data_buff(fs_hcpriv *fs_hcpriv)
++{
++ // Get the next available free data_buff, return NULL if none available.
++ unsigned long flags;
++ fs_data_buff *db;
++ u16 ndx;
++ local_irq_save(flags);
++ if (0xffff != (ndx = fs_hcpriv->free_buffs)) {
++ fs_hcpriv->free_buffs = fs_hcpriv->buff_list[ndx];
++ db = ndx + (fs_data_buff *)OTG_DATA_BASE;
++ }
++ else
++ db = NULL;
++ local_irq_restore(flags);
++ return(db);
++}
++
++/*!
++ * rel_data_buff() - release data buff
++ */
++static __inline__ fs_data_buff *rel_data_buff(fs_hcpriv *fs_hcpriv, fs_data_buff *db)
++{
++ // Release db to the pool of available data_buffs.
++ unsigned long flags;
++ u16 ndx;
++ if (NULL != db) {
++ local_irq_save(flags);
++ ndx = db - (fs_data_buff *)OTG_DATA_BASE;
++ fs_hcpriv->buff_list[ndx] = fs_hcpriv->free_buffs;
++ fs_hcpriv->free_buffs = ndx;
++#if 0
++ db->next = fs_hcpriv->free_buffs;
++ fs_hcpriv->free_buffs = db;
++#endif
++ local_irq_restore(flags);
++ }
++ return(NULL);
++}
++
++/*!
++ * data_buff_boff() - get data buffer offset given address
++ */
++static __inline__ u16 data_buff_boff(fs_data_buff *db)
++{
++ return((u16)(((void *) db) - ((void *) OTG_DATA_BASE)));
++}
++
++/*!
++ * data_buff_addr() - get data buffer address given offset
++ */
++static __inline__ fs_data_buff *data_buff_addr(u16 boff)
++{
++ // Return the address of the fs_data_buffer that is boff bytes from the start of data buffer memory.
++ return(boff + ((void *) OTG_DATA_BASE));
++}
++/*! @} */
++
++/* ********************************************************************************************** */
++
++/*!
++ * @name FSUSBOTGIO
++ * @brief Freescale USBOTG I/O support.
++ */
++ /*! @{ */
++
++/*!
++ * fs_rb() - read a byte
++ * @param port
++ * @return byte read
++ */
++static u8 __inline__ fs_rb(u32 port)
++{
++ return *(volatile u8 *) (IO_ADDRESS(port));
++}
++
++/*!
++ * fs_rl() - read a long
++ * @param port
++ * @return word read
++ */
++static u32 __inline__ fs_rl(u32 port)
++{
++ return *(volatile u32 *) (IO_ADDRESS(port));
++}
++
++/*!
++ * fs_wb() - write a byte
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_wb(u32 port, u8 val)
++{
++ *(volatile u8 *)(IO_ADDRESS(port)) = val;
++}
++
++/*!
++ * fs_orb() - or a byte
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_orb(u32 port, u8 val)
++{
++ u8 set = fs_rb(port) | val;
++ *(volatile u8 *)(IO_ADDRESS(port)) = set;
++}
++
++/*!
++ * fs_andb() - and a byte
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_andb(u32 port, u8 val)
++{
++ u8 set = fs_rb(port) & val;
++ *(volatile u8 *)(IO_ADDRESS(port)) = set;
++}
++
++/*!
++ * fs_wl() - write a long
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_wl(u32 port, u32 val)
++{
++ u32 set;
++ *(volatile u32 *)(IO_ADDRESS(port)) = val;
++ set = fs_rl(port);
++}
++
++/*!
++ * fs_orl() - or a long
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_orl(u32 port, u32 val)
++{
++ u32 set = fs_rl(port);
++ *(volatile u32 *)(IO_ADDRESS(port)) = (set | val);
++}
++
++/*!
++ * fs_andl() - and a long
++ * @param port
++ * @param val
++ */
++static void __inline__ fs_andl(u32 port, u32 val)
++{
++ u32 set = fs_rl(port);
++ *(volatile u32 *)(IO_ADDRESS(port)) = (set & val);
++}
++
++/*!
++ * fs_host_port_stat() - get host start port address for ports 1-3
++ * @param n
++ * @returns port address
++ */
++static u32 inline fs_host_port_stat(int n)
++{
++ switch (n) {
++ default:
++ case 1:
++ return OTG_HOST_PORT_STATUS_1;
++ case 2:
++ return OTG_HOST_PORT_STATUS_2;
++ case 3:
++ return OTG_HOST_PORT_STATUS_3;
++ }
++}
++
++
++/*!
++ * fs_wl_set() - set a word and verify
++ * @param tag
++ * @param port
++ * @param val
++ */
++static void inline fs_wl_set(otg_tag_t tag, u32 port, u32 val)
++{
++ u32 set;
++ *(volatile u32 *)(IO_ADDRESS(port)) = val;
++ set = fs_rl(port);
++ if ((set & val) != val) {
++ TRACE_MSG1(tag, "SET FAILED: %08x", set);
++ }
++}
++
++/*!
++ * fs_wl_clr() - clr a word and verify
++ * @param tag
++ * @param port
++ * @param clr
++ */
++static void inline fs_wl_clr(otg_tag_t tag, u32 port, u32 clr)
++{
++ u32 set;
++ *(volatile u32 *)(IO_ADDRESS(port)) = clr;
++ set = fs_rl(port);
++ if (set & clr) {
++ TRACE_MSG1(tag, "CLEAR FAILED 1: %08x", set);
++ *(volatile u32 *)(IO_ADDRESS(port)) = clr;
++ set = fs_rl(port);
++ if (set & clr)
++ TRACE_MSG1(tag, "CLEAR FAILED 2: %08x", set);
++ }
++}
++
++
++/*!
++ * fs_memcpy32() - emulage memcpy using long copy
++ * @param dp destination pointer
++ * @param sp source pointer
++ * @param words number of 32bit words to copy
++ *
++ */
++static void inline fs_memcpy32(u32 *dp, u32 *sp, volatile int words)
++{
++ while (words--) *dp++ = *sp++;
++}
++/*!
++ * fs_memcpy() - emulage memcpy using byte copy
++ * @param dp destination pointer
++ * @param sp source pointer
++ * @param bytes number of 8bit bytes to copy
++ */
++static void inline fs_memcpy(u8 *dp, u8 *sp, volatile int bytes)
++{
++ while (bytes--) *dp++ = *sp++;
++}
++/*!
++ * fs_clear_words() - clear memory
++ * @param addr address to clear from
++ * @param words number of 32bit words to clear.
++ */
++static void inline fs_clear_words(volatile u32 *addr, int words)
++{
++ while (words--) *addr++ = 0;
++}
++
++/*! @} */
++
+diff -uNr linux/drivers/no-otg/otghw/isp1301-hardware.h linux/drivers/otg/otghw/isp1301-hardware.h
+--- linux/drivers/no-otg/otghw/isp1301-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/isp1301-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,218 @@
++/*
++ * otg/otghw/isp1301-hardware.h -- ISP1301 hardware specific defines
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otghw/isp1301-hardware.h
++ * @brief Public Structures And Defines For ISP1301 Hardware.
++ *
++ * The Phillips ISP1301 is an OTG Transceiver. There a additional
++ * compatible parts such as the Maxim MAX3301E
++ *
++ * @ingroup ISP1301TCD
++ */
++
++
++/*!
++ * @name ADR/PSW - C.f. 8.9.1
++ *
++ * The i2c address is either 0x2c or 0x2d depending on the level of the
++ * ADR/PSW pin after device reset. Note that this pin can be programmed as
++ * an output via the Mode Control 2 register, bit PSW_OE to enable an
++ * @{
++ */
++
++#define ISP1301_I2C_ADDR_LOW 0x2c
++#define ISP1301_I2C_ADDR_HIGH 0x2d
++/*! @} */
++
++/*!
++ * @name ISP1301 Registers C.f. 11.1
++ * @{
++ */
++
++#define ISP1301_VENDOR_ID 0x00
++#define ISP1301_PRODUCT_ID 0x02
++#define ISP1301_VERSION_ID 0x14
++
++#define ISP1301_VENDOR_ID_LOW 0x00
++#define ISP1301_PRODUCT_ID_LOW 0x02
++#define ISP1301_VERSION_ID_LOW 0x14
++#define ISP1301_VENDOR_ID_HIGH 0x01
++#define ISP1301_PRODUCT_ID_HIGH 0x03
++#define ISP1301_VERSION_ID_HIGH 0x15
++
++/* these are all single byte registers
++ */
++#define ISP1301_MODE_CONTROL_1 0x04
++#define ISP1301_MODE_CONTROL_1_SET 0x04
++#define ISP1301_MODE_CONTROL_1_CLR 0x05
++
++#define ISP1301_MODE_CONTROL_2 0x12
++#define ISP1301_MODE_CONTROL_2_SET 0x12
++#define ISP1301_MODE_CONTROL_2_CLR 0x13
++
++#define ISP1301_OTG_CONTROL 0x06
++#define ISP1301_OTG_CONTROL_SET 0x06
++#define ISP1301_OTG_CONTROL_CLR 0x07
++
++#define ISP1301_OTG_STATUS 0x10
++
++#define ISP1301_INTERRUPT_SOURCE 0x08
++
++#define ISP1301_INTERRUPT_LATCH 0x0a
++#define ISP1301_INTERRUPT_LATCH_SET 0x0a
++#define ISP1301_INTERRUPT_LATCH_CLR 0x0b
++
++#define ISP1301_INTERRUPT_ENABLE_LOW 0x0c
++#define ISP1301_INTERRUPT_ENABLE_LOW_SET 0x0c
++#define ISP1301_INTERRUPT_ENABLE_LOW_CLR 0x0d
++
++#define ISP1301_INTERRUPT_ENABLE_HIGH 0x0e
++#define ISP1301_INTERRUPT_ENABLE_HIGH_SET 0x0e
++#define ISP1301_INTERRUPT_ENABLE_HIGH_CLR 0x0f
++/*! @} */
++
++
++/*!
++ * @name Mode Control 1 register - C.f. Table 17 and Table 18
++ * @{
++ */
++#define ISP1301_UART_EN (1 << 6)
++#define ISP1301_OE_INT_EN (1 << 5)
++#define ISP1301_BDIS_ACON_EN (1 << 4)
++#define ISP1301_TRANSP_EN (1 << 3)
++#define ISP1301_DAT_SE0 (1 << 2)
++#define ISP1301_SUSPEND_REG (1 << 1)
++#define ISP1301_SPEED_REG (1 << 0)
++/*! @} */
++
++
++/*!
++ * @name Mode Control 2 register - C.f. Table 19 and Table 20
++ * @{
++ */
++#define ISP1301_EN2V7 (1 << 7)
++#define ISP1301_PSW_OE (1 << 6)
++#define ISP1301_AUDIO_EN (1 << 5)
++#define ISP1301_TRANSP_BDIR (3 << 3)
++#define ISP1301_BI_DI (1 << 2)
++#define ISP1301_SPD_SUSP_CTRL (1 << 1)
++#define ISP1301_GLOBAL_PWR_ON (1 << 0)
++/*! @} */
++
++
++/*!
++ * @name OTG Control register - C.f. Table 21 and Table 22
++ * @{
++ */
++#define ISP1301_VBUS_CHRG (1 << 7)
++#define ISP1301_VBUS_DISCHRG (1 << 6)
++#define ISP1301_VBUS_DRV (1 << 5)
++#define ISP1301_ID_PULLDOWN (1 << 4)
++#define ISP1301_DM_PULLDOWN (1 << 3)
++#define ISP1301_DP_PULLDOWN (1 << 2)
++#define ISP1301_DM_PULLUP (1 << 1)
++#define ISP1301_DP_PULLUP (1 << 0)
++
++#define ISP1301_VBUS_RESET (ISP1301_VBUS_CHRG | ISP1301_VBUS_DISCHRG | ISP1301_VBUS_DRV)
++
++/*! @} */
++
++
++/*!
++ * @name OTG Status register - C.f. Table 23 and Table 24
++ * @{
++ */
++#define ISP1301_B_SESS_VLD (1 << 7)
++#define ISP1301_B_SESS_END (1 << 6)
++/*! @} */
++
++
++/*!
++ * @name Interrupt Source Register
++ * Interrupt Source register - C.f. Table 25 and Table 26
++ * Interrupt Latch register - C.f. Table 27 and Table 28
++ * Interrupt Enable Low register - C.f. Table 29 and Table 30
++ * Interrupt Enable High register - C.f. Table 31 and Table 32
++ * @{
++ */
++#define ISP1301_CR_INT (1 << 7)
++#define ISP1301_BDIS_ACON (1 << 6)
++#define ISP1301_ID_FLOAT (1 << 5)
++#define ISP1301_DM_HI (1 << 4)
++#define ISP1301_ID_GND (1 << 3)
++#define ISP1301_DP_HI (1 << 2)
++#define ISP1301_SESS_VLD (1 << 1)
++#define ISP1301_VBUS_VLD (1 << 0)
++
++//#define ISP1301_SE1 (ISP1301_DM_HI | ISP1301_DP_HI)
++
++/*! @} */
++
++/*!
++ * @name Maxim MAX3301E
++ *
++ * This part is compatible with the ISP1301 with minor differences:
++ *
++ * Mode Control 1 register is called Control Register 1. It is almost
++ * identical except for:
++ *
++ * bit isp1301 max3301e
++ * 3 transp_en not used
++ * @{
++ */
++#define MAX3301E_CONTROL_REGISTER_1 0x04
++#define MAX3301E_CONTROL_REGISTER_1_SET 0x04
++#define MAX3301E_CONTROL_REGISTER_1_CLR 0x05
++/*! @} */
++
++/*!
++ * @name Mode Control 2
++ * Mode Control 2 is called Special Function Register 1. Mostly the same
++ * except for:
++ *
++ * bit isp1301 max3301e
++ * 7 en2v7 gp_en
++ * 6 psw_oe sess_end
++ * 5 audio_en int_source
++ * @{
++ */
++#define MAX3301E_SPECIAL_FUNCTION_1 0x12
++#define MAX3301E_SPECIAL_FUNCTION_1_SET 0x12
++#define MAX3301E_SPECIAL_FUNCTION_1_CLR 0x13
++#define MAX3301E_GP_EN (1 << 7)
++#define MAX3301E_SESS_END (1 << 6)
++#define MAX3301E_INT_SOURCE (1 << 5)
++/*! @} */
++
++/*!
++ * @name OTG Status
++ * The OTG Status is not present, but B_SESS_END seems to be available
++ * in the Mode Control 2 register bit 6.
++ *
++ * An additional register is available for MAX3301E specific features.
++ *
++ * Special Function Register 2
++ * @{
++ */
++
++#define MAX3301E_SPECIAL_FUNCTION_2 0x16
++#define MAX3301E_SPECIAL_FUNCTION_2_SET 0x16
++#define MAX3301E_SPECIAL_FUNCTION_2_CLR 0x17
++#define MAX3301E_SDWN (1 << 0)
++#define MAX3301E_IRQ_MODE (1 << 1)
++#define MAX3301E_XCVR_INPUT_DISC (1 << 2)
++#define MAX3301E_REQ_SET (1 << 3)
++/*! @} */
++
++
++
++
+diff -uNr linux/drivers/no-otg/otghw/isp1301.h linux/drivers/otg/otghw/isp1301.h
+--- linux/drivers/no-otg/otghw/isp1301.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/isp1301.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,158 @@
++/*
++ * otg/otghw/isp1301/isp1301.h -- USB Transceiver Controller driver
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup ISP1301TCD Phillips ISP1301
++ * @ingroup tcdgroup
++ */
++/*!
++ * @file otg/otghw/isp1301.h
++ * @brief Private structures and defines for ISP1301 Transciever Controller Driver.
++ *
++ * This file contains the private defines and structures for the ISP1301 Transceiver
++ * Driver.
++ *
++ * @ingroup ISP1301TCD
++ */
++
++/*!
++ * @name ISP1301 ISP1301 configuration
++ * @{
++ */
++
++#ifdef CONFIG_OMAP_H2
++#define ISP1301_GPIO (2)
++#define TCD_ISP1301_I2C_ADDR ISP1301_I2C_ADDR_HIGH;
++#endif
++
++#define ISP1301_NAME "isp1301"
++
++#define ISP1301_LOC_CONN 0x01
++
++#define ISP1301_INT_SRC 0xeb
++
++/*!
++ * @enum otg_transceiver
++ * Define ISP1301 compatible transceivers
++ */
++typedef enum otg_transceiver {
++ unknown_transceiver, /*!< unknown */
++ isp1301, /*!< Phillips ISP1301 */
++ max3301e /*!< Maxim MAX3301e */
++} otg_transceiver_t;
++
++/*!
++ * @struct otg_transceiver_map
++ * How to determine transceiver model and manufacturer
++ */
++struct otg_transceiver_map {
++ otg_transceiver_t transceiver_type; /*!< transceiver type */
++ u16 vendor; /*!< vendor number */
++ u16 product; /*!< product number */
++ u16 revision; /*!< revision number */
++ char *name; /*!< name */
++};
++
++/*!
++ * @struct isp1301_private
++ * Information required for operation
++ */
++struct isp1301_private {
++ WORK_STRUCT bh; /*!< work structure for bottom half handler */
++ u16 vendor; /*!< vendor number found */
++ u16 product; /*!< product number found */
++ u16 revision; /*!< revision number found */
++ u32 flags; /*!< flags */
++ u8 int_src; /*!< current interrupt source */
++ struct otg_transceiver_map *transceiver_map; /*! pointer to transceiver map for this transceiver */
++};
++
++/*!
++ * @enum tx_mode
++ * This defines the various ways that the ISP1301 can be
++ * wired into the host USB.
++ */
++typedef enum tx_mode {
++ dat_se0_bidirectional, /*!< 3-Wire */
++ vp_vm_bidirectional, /*!< 4-Wire */
++ dat_se0_unidirectional /*!< 6-Wire */
++} tx_mode_t;
++
++/*!
++ * @enum spd_ctrl
++ * This defines how the speed and suspend pins are controlled
++ * for this host.
++ */
++typedef enum spd_ctrl {
++ spd_susp_pins, /*!< controlled by SPEED and SUSPEND pins */
++ spd_susp_reg, /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
++} spd_ctrl_t;
++
++
++extern struct tcd_ops tcd_ops;
++extern struct isp1301_private isp1301_private;
++extern struct tcd_instance *tcd_instance;
++
++/* isp1301.c */
++extern int isp1301_mod_init(WORK_PROC );
++extern int isp1301_mod_init__(void );
++extern void isp1301_mod_exit(void);
++extern void isp1301_tcd_en(struct otg_instance *, u8 );
++extern void isp1301_chrg_vbus(struct otg_instance *, u8 );
++extern void isp1301_drv_vbus(struct otg_instance *, u8 );
++extern void isp1301_dischrg_vbus(struct otg_instance *, u8 );
++extern void isp1301_dp_pullup_func(struct otg_instance *, u8 );
++extern void isp1301_dm_pullup_func(struct otg_instance *, u8 );
++extern void isp1301_dp_pulldown_func(struct otg_instance *, u8 );
++extern void isp1301_dm_pulldown_func(struct otg_instance *, u8 );
++extern void isp1301_peripheral_host_func(struct otg_instance *, u8 );
++extern void isp1301_dm_det_func(struct otg_instance *, u8 );
++extern void isp1301_dp_det_func(struct otg_instance *, u8 );
++extern void isp1301_cr_det_func(struct otg_instance *, u8 );
++extern void isp1301_bdis_acon_func(struct otg_instance *, u8 );
++extern void isp1301_mx21_vbus_drain_func(struct otg_instance *, u8 );
++extern void isp1301_id_pulldown_func(struct otg_instance *, u8 );
++extern void isp1301_audio_func(struct otg_instance *, u8 );
++extern void isp1301_uart_func(struct otg_instance *, u8 );
++extern void isp1301_mono_func(struct otg_instance *, u8 );
++
++extern void isp1301_otg_timer(struct otg_instance *, u8 );
++extern void isp1301_bh(void *);
++extern int isp1301_id (struct otg_instance *);
++extern int isp1301_vbus (struct otg_instance *);
++extern void isp1301_configure(tx_mode_t, spd_ctrl_t );
++
++extern void isp1301_bh_wakeup(int);
++
++/* thread */
++extern int isp1301_thread_init (void (bh_proc)(void *));
++extern void isp1301_thread_exit (wait_queue_head_t *);
++extern void isp1301_thread_wakeup(int enabled, int first);
++
++
++
++/* i2c-xxx.c */
++int i2c_configure(char *name, int addr);
++extern void i2c_close(void);
++extern u8 i2c_readb(u8 );
++extern u16 i2c_readw(u8 );
++extern u32 i2c_readl(u8 );
++extern void i2c_writeb(u8 , u8 );
++
++
++/* ********************************************************************************************* */
++#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
++#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
++#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
++#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/otghw/max3353e-hardware.h linux/drivers/otg/otghw/max3353e-hardware.h
+--- linux/drivers/no-otg/otghw/max3353e-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/max3353e-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,141 @@
++/*
++ * otg/otg/max3353e-hardware.h -- MAX3353E hardware specific defines
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@lbelcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otg/otg/max3353e-hardware.h
++ * @brief Public structures and defines for MAX3353E Hardware.
++ *
++ * The Maxim MAX3353E is an OTG Charge Pump with controllable
++ * pullup resistors.
++ *
++ * @ingroup MAX3353ETCD
++ */
++
++
++/*!
++ * @name ADR/PSW - C.f. Slave Address
++ *
++ * The high/low address is selected with the ADD pin.
++ *
++ * @{
++ */
++
++#define MAX3353E_I2C_ADDR_LOW 0x16
++#define MAX3353E_I2C_ADDR_HIGH 0x2C
++
++/*! @} */
++
++
++
++/*!
++ * @name MAX3353E Registers C.f. Table 2 - Register Address Map
++ * @{
++ */
++
++#define MAX3353E_MANUFACTURER_REGISTER_0 0x00
++#define MAX3353E_MANUFACTURER_REGISTER_1 0x01
++#define MAX3353E_MANUFACTURER_REGISTER_2 0x02
++#define MAX3353E_MANUFACTURER_REGISTER_3 0x03
++
++#define MAX3353E_PRODUCT_ID_REGISTER_0 0x04
++#define MAX3353E_PRODUCT_ID_REGISTER_1 0x05
++#define MAX3353E_PRODUCT_ID_REGISTER_2 0x06
++#define MAX3353E_PRODUCT_ID_REGISTER_3 0x07
++
++#define MAX3353E_CONTROL_REGISTER_1 0x10
++#define MAX3353E_CONTROL_REGISTER_2 0x11
++
++#define MAX3353E_STATUS_REGISTER 0x13
++
++#define MAX3353E_INTERRUPT_MASK 0x14
++#define MAX3353E_INTERRUPT_EDGE 0x15
++#define MAX3353E_INTERRUPT_LATCH 0x16
++
++/*! @} */
++
++
++/*!
++ * @name Control Register 1
++ * @{
++ */
++#define MAX3353E_DM_PULLDOWN (1 << 7)
++#define MAX3353E_DP_PULLDOWN (1 << 6)
++#define MAX3353E_DM_PULLUP (1 << 5)
++#define MAX3353E_DP_PULLUP (1 << 4)
++
++#define MAX3353E_BDISC_ACONN (1 << 2)
++#define MAX3353E_IRQ_MODE (1 << 1)
++
++/*! @} */
++
++/*!
++ * @name Control Register 2
++ * @{
++ */
++#define MAX3353E_VBUS_DISCHG (1 << 4)
++#define MAX3353E_VBUS_DRV (1 << 3)
++#define MAX3353E_VBUS_CHG2 (1 << 2)
++#define MAX3353E_VBUS_CHG1 (1 << 1)
++#define MAX3353E_DSWIN (1 << 0)
++
++/*! @} */
++
++/*!
++ * @name Status Register
++ * @{
++ */
++#define MAX3353E_B_HNP (1 << 6)
++#define MAX3353E_A_HNP (1 << 5)
++#define MAX3353E_ID_FLOAT (1 << 4)
++#define MAX3353E_ID_GND (1 << 3)
++#define MAX3353E_SESSION_END (1 << 2)
++#define MAX3353E_SESSION_VALID_EN (1 << 1)
++#define MAX3353E_VBUS_VALID (1 << 0)
++
++/*! @} */
++
++/*!
++ * @name Interrupt Mask
++ * @{
++ */
++#define MAX3353E_A_HNP_EN (1 << 5)
++#define MAX3353E_ID_FLOAT_EN (1 << 4)
++#define MAX3353E_ID_GND_EN (1 << 3)
++#define MAX3353E_SESSION_END_EN (1 << 2)
++#define MAX3353E_SESSION_VALID_EN (1 << 1)
++#define MAX3353E_VBUS_VALID_EN (1 << 0)
++
++/*! @} */
++
++/*!
++ * @name Interrupt Edge
++ * @{
++ */
++#define MAX3353E_SESSION_VALID_ED (1 << 1)
++#define MAX3353E_VBUS_VALID_ED (1 << 0)
++
++/*! @} */
++
++/*!
++ * @name Interrupt Latch
++ * @{
++ */
++#define MAX3353E_A_HNP_RQ (1 << 7)
++#define MAX3353E_ID_FLOAT_RQ (1 << 6)
++#define MAX3353E_ID_GND_RQ (1 << 5)
++#define MAX3353E_SESSION_END_RQ (1 << 4)
++#define MAX3353E_SESSION_VALID_RN (1 << 3)
++#define MAX3353E_VBUS_VALID_RN (1 << 2)
++#define MAX3353E_SESSION_VALID_RP (1 << 1)
++#define MAX3353E_VBUS_VALID_RP (1 << 0)
++
++/*! @} */
++
+diff -uNr linux/drivers/no-otg/otghw/mx2ads-hardware.h linux/drivers/otg/otghw/mx2ads-hardware.h
+--- linux/drivers/no-otg/otghw/mx2ads-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/mx2ads-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,111 @@
++/*
++ * otghw/mx2ads-hardware.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @file otghw/mx2ads-hardware.h
++ * @brief MX2ADS Hardware constants
++ *
++ * @ingroup MX2ADS
++ */
++
++
++/*!
++ * @name MX2ETDS
++ * R1 = i.MX21 Application Processor Reference Manual Rev 0.6 2003/11/01 TO 1.0
++ * (aka "IMX21RM_TO1.pdf")
++ * R2 = "USBOTG_L3_Specification_v.C1.0.pdf"
++ * @{
++ */
++
++#define NUM_ETDS 32
++#define DATA_BUFF_SIZE 64
++#define DATA_BUFFER_TOTAL 4096
++#define NUM_DATA_BUFFS (4096/DATA_BUFF_SIZE)
++//#define LITTLE_ENDIAN 1
++
++/* @} */
++
++
++/*!
++ * @name MX2Interrupts
++ * @{
++ */
++#define OTG_USBWKUP 53
++#define OTG_USBDMA 54
++#define OTG_USBHOST 55
++#define OTG_USBFUNC 56
++#define OTG_USBHNP 57
++#define OTG_USBCTRL 58
++/* @} */
++
++/*!
++ * @name AHBMemoryMap
++ * C.F. Table 23-5 AHB Memory Map
++ * @{
++ */
++#ifndef OTG_BASE_ADDR
++#define OTG_BASE_ADDR 0x10024000
++
++#define OTG_CORE_BASE (OTG_BASE_ADDR+0x000) // base location for core
++#define OTG_FUNC_BASE (OTG_BASE_ADDR+0x040) // base location for function
++#define OTG_HOST_BASE (OTG_BASE_ADDR+0x080) // base location for host
++#define OTG_I2C_BASE (OTG_BASE_ADDR+0x100) // base location for I2C
++
++#define OTG_ETD_BASE (OTG_BASE_ADDR+0x200) // base location for etd memory
++#define OTG_EP_BASE (OTG_BASE_ADDR+0x400) // base location for ep memory
++#define OTG_SYS_BASE (OTG_BASE_ADDR+0x600) // base location for system
++
++#define OTG_DMA_BASE (OTG_BASE_ADDR+0x800) // base location for dma
++
++#define OTG_DATA_BASE (OTG_BASE_ADDR+0x1000) // base location for data memory
++
++#define OTG_SYS_CTRL (OTG_SYS_BASE+0x000) // base location for system
++#endif
++/* @} */
++
++/*!
++ * @name I2CTransceiver
++ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
++ * These are the I2C controller and access registers.
++ *
++ * N.B. I2C_ERROR is not documented.
++ * @{
++ */
++
++
++#define I2C_BUSY (1 << 7)
++#define I2C_ERROR (1 << 2)
++#define I2C_HWSMODE (1 << 1)
++#define I2C_I2COE (1 << 0)
++
++#define I2C_SCLK_TO_SCL_DIVISION (OTG_I2C_BASE+0x1E)
++
++#define I2C_INTERRUPT_AND_CONTROL (OTG_I2C_BASE+0x1F)
++
++#define I2C_STATUS_MASK (0x7)
++
++#define I2C_NOACK_EN (1 << 6)
++#define I2C_RWREADY_EN (1 << 5)
++#define I2C_OTGXCVRINT_EN (1 << 4)
++
++#define I2C_NOACK (1 << 2)
++#define I2C_RWREADY (1 << 1)
++#define I2C_OTGXCVRINT (1 << 0)
++
++#define MX2_OTG_XCVR_DEVAD OTG_I2C_BASE+0x18
++#define MX2_SEQ_OP_REG OTG_I2C_BASE+0x19
++#define MX2_SEQ_RD_STARTAD OTG_I2C_BASE+0x1a
++#define MX2_I2C_OP_CTRL_REG OTG_I2C_BASE+0x1b
++#define MX2_SCLK_TO_SCL_HPER OTG_I2C_BASE+0x1e
++#define MX2_I2C_INTERRUPT_AND_CTRL OTG_I2C_BASE+0x1f
++
++/* @} */
++
+diff -uNr linux/drivers/no-otg/otghw/mx2ads.h linux/drivers/otg/otghw/mx2ads.h
+--- linux/drivers/no-otg/otghw/mx2ads.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/mx2ads.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,46 @@
++/*
++ * otghw/mx2ads.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ */
++
++/*!
++ * @defgroup MX2ADS Freescale MX2ADS
++ * @ingroup platformgroup
++ */
++/*!
++ * @file otghw/mx2ads.h
++ * @brief MX2ADS Platform constants
++ *
++ * Notes
++ *
++ * 1. Interrupts - we seem to get all interrupts on the ctrl interrupt.
++ *
++ * 2. Clearing - it appears that clearing the status bits sometimes fails, This
++ * has been observed in SINT_STAT and XFILL_STAT.
++ *
++ * 3. Double buffer - without DMA it does not appear to be possible to use
++ * both X and Y buffers for OUT transfers because we can not apparantely guarantee
++ * the order that the X and Y buffers will be used. If we get an interrupt with
++ * both X and Y active we cannot determine which order to use them. As long as
++ * we get each interrupt fast enough this is not a problem as we can then just
++ * use whichever is active.
++ *
++ * 4. Remote Wakeup - cannot set RSMINPROG bit
++ *
++ * @ingroup MX2ADS
++ */
++
++
++#define UDC_NAME "MX21"
++#define UDC_MAX_ENDPOINTS 32
++#define EP0_PACKETSIZE 64
++
++
++extern otg_tag_t MX2;
++
+diff -uNr linux/drivers/no-otg/otghw/td243-hardware.h linux/drivers/otg/otghw/td243-hardware.h
+--- linux/drivers/no-otg/otghw/td243-hardware.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/otg/otghw/td243-hardware.h 2006-09-01 21:41:35.000000000 +0200
+@@ -0,0 +1,709 @@
++/*
++ * otg/pcd/mx2/td243-hardware.h
++ *
++ * Copyright (c) 2004 Belcarra
++ *
++ * By:
++ * Stuart Lynne <sl@belcarra.com>,
++ * Tom Rushworth <tbr@belcarra.com>,
++ * Bruce Balden <balden@belcarra.com>
++ *
++ */
++/*!
++ * @defgroup TD243 Transdimension USBOTG
++ * @ingroup libgroup
++ */
++/*!
++ * @file /otg/otghw/td243-hardware.h
++ * @brief Hardware defines for Transimension USBOTG Hardware
++ *
++ * @ingroup TD243
++ */
++
++
++/*
++ * C.f. 23.8 USB Control Register
++ */
++
++#define SYS_CTRL_I2C_WU_INT_STAT (1 << 27)
++#define SYS_CTRL_OTG_WU_INT_STAT (1 << 26)
++#define SYS_CTRL_HOST_WU_INT_STAT (1 << 25)
++#define SYS_CTRL_FNT_WU_INT_STAT (1 << 24)
++
++#define SYS_CTRL_I2C_WU_INT_EN (1 << 19)
++#define SYS_CTRL_OTG_WU_INT_EN (1 << 18)
++#define SYS_CTRL_HOST_WU_INT_EN (1 << 17)
++#define SYS_CTRL_FNT_WU_INT_EN (1 << 16)
++
++#define SYS_CTRL_OTG_BYP_VAL (0x3 << 11)
++#define SYS_CTRL_HOST1_BYP_VAL (0x3 << 9)
++
++
++
++#define SYS_CTRL_OTG_PWR_MASK (1 << 6)
++#define SYS_CTRL_HOST1_PWR_MASK (1 << 6)
++#define SYS_CTRL_HOST2_PWR_MASK (1 << 4)
++#define SYS_CTRL_USB_BYP (1 << 2)
++#define SYS_CTRL_HOST1_TXEN_OE (1 << 1)
++
++
++/*
++ * C.f. 23.9 USBOTG Module Registers
++ */
++
++#define OTG_CORE_HWMODE (OTG_CORE_BASE+0x00) // 32bit core hardware mode reg
++
++#define XCVR_D_D 0x00
++#define XCVR_SE_D 0x01
++#define XCVR_D_SE 0x02
++#define XCVR_SE_SE 0x03
++
++#define MODULE_ANASDBEN (1 << 14)
++#define MODULE_OTGXCVR (0x3 << 6)
++#define MODULE_HOSTXCVR (0x3 << 4)
++#define MODULE_CRECFG (0x3)
++#define MODULE_CRECFG_HHNP (0x0)
++#define MODULE_CRECFG_HOST (0x1)
++#define MODULE_CRECFG_FUNC (0x2)
++#define MODULE_CRECFG_SHNP (0x3)
++
++#define OTG_CORE_CINT_STAT (OTG_CORE_BASE+0x04) // 32bit core int status reg
++
++#define MODULE_FCINTDSPEN (1 << 6)
++
++#define MODULE_ASHNPINT (1 << 5)
++#define MODULE_ASFCINT (1 << 4)
++#define MODULE_ASHCINT (1 << 3)
++#define MODULE_HNPINT (1 << 2)
++#define MODULE_FCINT (1 << 1)
++#define MODULE_HCINT (1)
++
++#define OTG_CORE_CINT_STEN (OTG_CORE_BASE+0x08) // 32bit core int enable reg
++
++#define MODULE_ASHNPINT_EN (1 << 5)
++#define MODULE_ASFCINT_EN (1 << 4)
++#define MODULE_ASHCINT_EN (1 << 3)
++#define MODULE_HNPINT_EN (1 << 2)
++#define MODULE_FCINT_EN (1 << 1)
++#define MODULE_HCINT_EN (1)
++
++#define OTG_CORE_CLK_CTRL (OTG_CORE_BASE+0x0C) // 32bit core clock control reg
++
++#define MODULE_FUNC_CLK (1 << 2)
++#define MODULE_HOST_CLK (1 << 1)
++#define MODULE_MAIN_CLK (1)
++
++#define OTG_CORE_RST_CTRL (OTG_CORE_BASE+0x10) // 32bit core reset control reg
++
++#define MODULE_RSTI2C (1 << 15)
++#define MODULE_RSTCTRL (1 << 5)
++#define MODULE_RSTFC (1 << 4)
++#define MODULE_RSTFSIE (1 << 3)
++#define MODULE_RSTRH (1 << 2)
++#define MODULE_RSTHSIE (1 << 1)
++#define MODULE_RSTHC (1)
++
++#define OTG_CORE_FRM_INTVL (OTG_CORE_BASE+0x14) // 32bit core frame interval reg
++
++#define MODULE_RESET_FRAME (1 << 15)
++
++#define OTG_CORE_FRM_REMAIN (OTG_CORE_BASE+0x18) // 32bit core frame remaining reg
++
++#define OTG_CORE_HNP_CSTAT (OTG_CORE_BASE+0x1C) // 32bit core HNP current state reg
++
++#define MODULE_HNPDAT (1 << 30)
++#define MODULE_VBUSBSE (1 << 29)
++#define MODULE_VBUSABSV (1 << 28)
++#define MODULE_VBUSGTAVV (1 << 27)
++
++#define MODULE_ARMTHNPE (1 << 25)
++#define MODULE_BHNPEN (1 << 24)
++
++#define MODULE_SLAVE (1 << 22)
++#define MODULE_MASTER (1 << 21)
++#define MODULE_BGEN (1 << 20)
++#define MODULE_CMPEN (1 << 19)
++#define MODULE_ISBDEV (1 << 18)
++#define MODULE_ISADEV (1 << 17)
++
++#define MODULE_SWVBUSPUL (1 << 15)
++
++#define MODULE_SWAUTORST (1 << 12)
++#define MODULE_SWPUDP (1 << 11)
++
++#define MODULE_SWPDDM (1 << 9)
++#define MODULE_HNPSTATE (0x1f << 8)
++#define MODULE_CLRERROR (1 << 3)
++#define MODULE_ADROPBUS (1 << 2)
++#define MODULE_ABBUSREQ (1 << 1)
++
++#define HNP_A_IDLE (0x10 << 8)
++#define HNP_A_MASTER (0x11 << 8)
++#define HNP_A_SLAVE (0x12 << 8)
++#define HNP_A_WAIT_VPULSE (0x13 << 8)
++
++#define HNP_A_WAIT_DPULSE (0x14 << 8)
++#define HNP_A_WAIT_CONN_A (0x15 << 8)
++#define HNP_A_WAIT_CONN_B (0x16 << 8)
++#define HNP_A_WAIT_VRISE (0x17 << 8)
++#define HNP_A_SUSPEND (0x18 << 8)
++#define HNP_A_WAIT_VFALL (0x19 << 8)
++#define HNP_A_VBUS_ERR (0x1a << 8)
++#define HNP_CONN_DEBOUNCE (0x1b << 8)
++#define HNP_A_WAIT_ABREQ (0x1c << 8)
++#define HNP_B_IDLE (0x00 << 8)
++#define HNP_B_MASTER (0x01 << 8)
++#define HNP_B_SLAVE (0x02 << 8)
++#define HNP_B_SRP_INIT_V (0x03 << 8)
++#define HNP_B_SRP_INIT_D (0x04 << 8)
++#define HNP_B_PRE_WAIT_CONN_AB_SHORT_DB (0x05 << 8)
++#define HNP_B_WAIT_CONN_A (0x06 << 8)
++#define HNP_B_PRE_SLAVE (0x0a << 8)
++
++
++#define OTG_CORE_HNP_TIMER1 (OTG_CORE_BASE+0x20) // 32bit core HNP timer 1 reg
++#define OTG_CORE_HNP_TIMER2 (OTG_CORE_BASE+0x24) // 32bit core HNP timer 2 reg
++#define OTG_CORE_HNP_T3PCR (OTG_CORE_BASE+0x28) // 32bit core HNP timer 3 pulse ctrl
++
++#define HNP_DATAPULSE (1 << 5)
++#define HNP_VBUSPULSE (1 << 4)
++
++#define OTG_CORE_HINT_STAT (OTG_CORE_BASE+0x2C) // 32bit core HNP int status reg
++
++#define HNP_I2COTGINT (1 << 15)
++#define HNP_AWAITBTO (1 << 8) // Hardware HNP Only
++#define HNP_AIDLEBDTO (1 << 7) // Hardware HNP Only
++#define HNP_SRPSUCFAIL (1 << 6) // Hardware HNP Only
++#define HNP_SRPINT (1 << 5)
++#define HNP_VBUSERROR (1 << 4) // Hardware HNP Only
++#define HNP_ABSEVAILD (1 << 3)
++#define HNP_ABUSVALID (1 << 2)
++#define HNP_MASSLVCHG (1 << 1) // Hardware HNP Only
++#define HNP_IDCHANGE (1)
++
++#define OTG_CORE_HINT_STEN (OTG_CORE_BASE+0x30) // 32bit core HNP int enable reg
++
++#define HNP_I2COTGINT_EN (1 << 15)
++#define HNP_AWAITBTO_EN (1 << 8)
++#define HNP_AIDLEBDTO_EN (1 << 7)
++#define HNP_SRPSUCFAIL_EN (1 << 6)
++#define HNP_SRPINT_EN (1 << 5)
++#define HNP_VBUSERROR_EN (1 << 4)
++#define HNP_ABSEVAILD_EN (1 << 3)
++#define HNP_ABUSVALID_EN (1 << 2)
++#define HNP_MASSLVCHG_EN (1 << 1)
++#define HNP_IDCHANGE_EN (1)
++
++
++#define OTG_CORE_CPUEPSEL_STAT (OTG_CORE_BASE+0x34)
++#define OTG_CORE_INTERRUPT_STEN (OTG_CORE_BASE+0x3c)
++
++
++/*
++ * C.f. 23.11.11 Host Registers
++ */
++
++
++#define OTG_HOST_CONTROL (OTG_HOST_BASE+0x00) // 32bit host controller config reg
++
++#define HOST_CONTROL_HCRESET (1 << 31)
++#define HOST_CONTROL_RMTWUEN (1 << 4)
++
++#define HOST_CONTROL_HCUSBSTE_RESET (0 << 2)
++#define HOST_CONTROL_HCUSBSTE_RESUME (1 << 2)
++#define HOST_CONTROL_HCUSBSTE_OPERATIONAL (2 << 2)
++#define HOST_CONTROL_HCUSBSTE_SUSPEND (3 << 2)
++
++#define HOST_CONTROL_CTLBLKSR_11 (0)
++#define HOST_CONTROL_CTLBLKSR_21 (1)
++#define HOST_CONTROL_CTLBLKSR_41 (2)
++#define HOST_CONTROL_CTLBLKSR_81 (3)
++
++
++#define OTG_HOST_SINT_STAT (OTG_HOST_BASE+0x08) // 32bit host system int status reg
++
++#define HOST_PSCINT (1 << 6) // Port Status Change
++#define HOST_FMOFINT (1 << 5) // Frame Number Overflow
++#define HOST_HERRINT (1 << 4) // Host Error
++#define HOST_RESDETINT (1 << 3) // Resume Detected
++#define HOST_SOFINT (1 << 2) // Start of Frame
++#define HOST_DONEINT (1 << 1) // Done Register
++#define HOST_SORINT (1) // Schedule Overrun
++
++#define OTG_HOST_SINT_STEN (OTG_HOST_BASE+0x0C) // 32bit host system int enable reg
++
++#define HOST_PSCINT_EN (1 << 6) // Port Status Change
++#define HOST_FMOFINT_EN (1 << 5) // Frame Number Overflow
++#define HOST_HERRINT_EN (1 << 4) // Host Error
++#define HOST_RESDETINT_EN (1 << 3) // Resume Detected
++#define HOST_SOFINT_EN (1 << 2) // Start of Frame
++#define HOST_DONEINT_EN (1 << 1) // Done Register
++#define HOST_SORINT_EN (1) // Schedule Overrun
++
++#define OTG_HOST_XINT_STAT (OTG_HOST_BASE+0x18) // 32bit host X buf int status reg
++#define OTG_HOST_YINT_STAT (OTG_HOST_BASE+0x1C) // 32bit host Y buf int status reg
++
++#define OTG_HOST_XYINT_STEN (OTG_HOST_BASE+0x20) // 32bit host XY buf int enable reg
++#define OTG_HOST_XFILL_STAT (OTG_HOST_BASE+0x28) // 32bit host X filled status reg
++#define OTG_HOST_YFILL_STAT (OTG_HOST_BASE+0x2C) // 32bit host Y filled status reg
++
++#define OTG_HOST_ETD_EN (OTG_HOST_BASE+0x40) // 32bit host ETD enables reg
++#define OTG_HOST_DIR_ROUTE (OTG_HOST_BASE+0x48) // 32bit host direct routing reg
++#define OTG_HOST_IINT (OTG_HOST_BASE+0x4C) // 32bit host immediate interrupt reg
++
++#define OTG_HOST_EP_DSTAT (OTG_HOST_BASE+0x50) // 32bit host endpoints done status
++#define OTG_HOST_ETD_DONE (OTG_HOST_BASE+0x54) // 32bit host ETD done reg
++
++#define OTG_HOST_FRM_NUM (OTG_HOST_BASE+0x60) // 32bit host frame number reg
++#define OTG_HOST_LSP_THRESH (OTG_HOST_BASE+0x64) // 32bit host low speed threshold reg
++
++#define OTG_HOST_ROOTHUB_DESCA (OTG_HOST_BASE+0x68) // 32bit host root hub descriptor A
++#define OTG_HOST_ROOTHUB_DESCB (OTG_HOST_BASE+0x6C) // 32bit host root hub descriptor B
++
++/*
++ * C.f. 23.11.29
++ */
++#define OTG_HOST_ROOTHUB_STATUS (OTG_HOST_BASE+0x70) // 32bit host root hub status reg
++
++#define ROOTHUB_STATUS_CLRMTWUE (1 << 31) // Clear Remote Wakeup Enable
++#define ROOTHUB_STATUS_OVRCURCHG (1 << 17) // Over Current Indicator Change
++#define ROOTHUB_STATUS_LOCPWRSC (1 << 16) // Local Power Status Change
++#define ROOTHUB_STATUS_DEVCONWUE (1 << 15) // Device Connect Wakeup Enable
++#define ROOTHUB_STATUS_OVRCURI (1 << 1) // Over Current Indicator
++#define ROOTHUB_STATUS_LOCPWRS (1) // Local Power Status
++
++
++/*
++ * C.f. 23.11.30
++ */
++#define OTG_HOST_PORT_STATUS_1 (OTG_HOST_BASE+0x74) // 32bit host port 1 status bits
++#define OTG_HOST_PORT_STATUS_2 (OTG_HOST_BASE+0x78) // 32bit host port 2 status bits
++#define OTG_HOST_PORT_STATUS_3 (OTG_HOST_BASE+0x7c) // 32bit host port 3 status bits
++
++#define PORT_STATUS_PRTRSTSC (1 << 20) // Port Reset Status Change
++#define PORT_STATUS_OVRCURIC (1 << 19) // Port Over Current Indicator Change
++#define PORT_STATUS_PRTSTATSC (1 << 18) // Port Suspend Status Change
++#define PORT_STATUS_PRTENBLSC (1 << 17) // Port Enable Status Change
++#define PORT_STATUS_CONNECTSC (1 << 16) // Connect Status Change
++
++#define PORT_STATUS_LSDEVCON (1 << 9) // Low Speed Device Attached
++#define PORT_STATUS_PRTPWRST (1 << 8) // Port Power Status
++
++#define PORT_STATUS_PRTRSTST (1 << 4) // Port Reset Status
++#define PORT_STATUS_PRTOVRCURI (1 << 3) // Port Over Current Indicator
++#define PORT_STATUS_PRTSUSPST (1 << 2) // Port Suspend Status
++#define PORT_STATUS_PRTENABST (1 << 1) // Port Enable Status
++#define PORT_STATUS_CURCONST (1) // Current Connect Status
++
++
++/* flags are the same for the interrupt, control and bulk transfer descriptors */
++// R1: sec 23.11.10.2,3 pg 23-44,47
++#define ETD_GET_COMPCODE(flags) ((flags >> 12) & 0xf)
++// R1: sec 23.11.10 Table 23-23 pg 23-40
++#define ETD_CC_NOERROR 0x0
++#define ETD_CC_CRCERR 0x1
++#define ETD_CC_BITSTUFFERR 0x2
++#define ETD_CC_DATATOGERR 0x3
++#define ETD_CC_STALL 0x4
++#define ETD_CC_DEVNOTRESPONDING 0x5
++#define ETD_CC_PIDFAILURE 0x6
++// Reserved 0x7
++#define ETD_CC_DATAOVERRUN 0x8
++#define ETD_CC_DATAUNDERRUN 0x9
++#define ETD_CC_ACK 0xA
++#define ETD_CC_NAK 0xB
++#define ETD_CC_BUFFEROVERRUN 0xC
++#define ETD_CC_BUFFERUNDERRUN 0xD
++#define ETD_CC_SCHEDOVERRUN 0xE
++#define ETD_CC_NOTACCESSED 0xF
++
++// R1: sec 23.11.10.2,3 pg 23-44,47 (contd)
++#define ETD_GET_ERRORCNT(flags) (((flags) >> 8) & 0xf)
++#define ETD_GET_DATATOGL(flags) (((flags) >> 6) & 0x3)
++#define ETD_SET_DATATOGL(v) (((v) & 0x3) << 6)
++#define ETD_GET_DELAYINT(flags) (((flags) >> 3) & 0x7)
++#define ETD_SET_DELAYINT(v) (((v) & 0x7) << 3)
++#define ETD_GET_BUFROUND(flags) (((flags) >> 2) & 0x1)
++#define ETD_SET_BUFROUND(v) (((v) & 0x1) << 2)
++#define ETD_GET_DIRPID(flags) ((flags) & 0x3)
++#define ETD_SET_DIRPID(v) ((v) & 0x3)
++#define ETD_FLIP_DIRPID(flags) ((flags) ^ 0x3) /* xor with 0x3 flips 2<->1 (IN<->OUT) */
++#define ETD_DIRPID_SETUP 0x0 // OUT
++#define ETD_DIRPID_OUT 0x1
++#define ETD_DIRPID_IN 0x2
++#define ETD_DIRPID_RESERVED 0x3
++
++// For non-isoc td.w3.val -
++#define ETD_GET_BUFSIZE(w3) (((w3) >> 21) & 0xfff)
++#define ETD_SET_BUFSIZE(v) (((v) & 0xfff) << 21)
++#define ETD_GET_TOTBYECNT(w3) ((w3) & 0xfffff)
++#define ETD_SET_TOTBYECNT(v) ((v) & 0xfffff)
++
++/* isoc flags shares the COMPCODE and DELAYINT bitfields with the other TDs,
++ but the remaining bits are different. */
++#define ETD_GET_AUTOISO(flags) (((flags) >> 11) & 0x1)
++#define ETD_SET_AUTOISO(v) (((v) & 0x1) << 11)
++#define ETD_GET_FRAMECNT(flags) (((flags) >> 8) & 0x1)
++#define ETD_SET_FRAMECNT(v) (((v) & 0x1) << 8)
++// For isoc td.w3.val -
++/* pkt1 and pkt0 use the COMPCODE bitfield, and add a PKTLEN field. */
++#define ETD_GET_PKTLEN(pkt) ((pkt) & 0x3ff)
++#define ETD_SET_PKTLEN(v) ((v) & 0x3ff)
++
++
++// ETD endpoint descriptor (etd->epd) bitfield access
++// R1: sec 23.11.10.1 pg 23-41 (word0)
++#define ETD_GET_SNDNAK(epd) (((epd) >> 30) & 0x1)
++#define ETD_SET_SNDNAK(v) (((v) & 0x1) << 30)
++#define ETD_GET_TOGCRY(epd) (((epd) >> 28) & 0x1)
++#define ETD_SET_TOGCRY(v) (((v) & 0x1) << 28)
++#define ETD_GET_HALTED(epd) (((epd) >> 27) & 0x1)
++#define ETD_SET_HALTED(v) (((v) & 0x1) << 27)
++#define ETD_GET_MAXPKTSIZ(epd) (((epd) >> 16) & 0x3ff)
++#define ETD_SET_MAXPKTSIZ(v) (((v) & 0x3ff) << 16)
++#define ETD_GET_FORMAT(epd) (((epd) >> 14) & 0x3)
++#define ETD_SET_FORMAT(v) (((v) & 0x3) << 14)
++#define ETD_FORMAT_CONTROL 0x0
++#define ETD_FORMAT_ISOC 0x1
++#define ETD_FORMAT_BULK 0x2
++#define ETD_FORMAT_INTERRUPT 0x3
++#define ETD_GET_SPEED(epd) (((epd) >> 13) & 0x1)
++#define ETD_SET_SPEED(v) (((v) & 0x1) << 13)
++#define ETD_SPEED_FULL 0x0
++#define ETD_SPEED_LOW 0x1
++#define ETD_GET_DIRECT(epd) (((epd) >> 11) & 0x3)
++#define ETD_SET_DIRECT(v) (((v) & 0x3) << 11)
++/* xor with 3 flips 2<->1 */
++#define ETD_FLIP_DIRECT(epd) ((epd) ^ (0x3 << 11))
++#define ETD_DIRECT_TD00 0x0
++#define ETD_DIRECT_OUT 0x1
++#define ETD_DIRECT_IN 0x2
++#define ETD_DIRECT_TD11 0x3
++#define ETD_GET_ENDPNT(epd) (((epd) >> 7) & 0xf)
++#define ETD_SET_ENDPNT(v) (((v) & 0xf) << 7)
++#define ETD_GET_ADDRESS(epd) ((epd) & 0x7f)
++#define ETD_SET_ADDRESS(v) ((v) & 0x7f)
++
++// etd_urb_state[] values
++#define ETD_URB_COMPLETED 0
++#define ETD_URB_SETUP_STATUS 1
++#define ETD_URB_SETUP_DATA 2
++#define ETD_URB_SETUP_START 3
++#define ETD_URB_BULK_START 4
++#define ETD_URB_BULKWZLP 5
++#define ETD_URB_BULKWZLP_START 6
++#define ETD_URB_INTERRUPT_START 7
++#define ETD_URB_ISOC_START 8
++
++
++/*
++ * C.f. 23.12.8 Function Registers
++ */
++
++#define OTG_FUNC_CMD_STAT (OTG_FUNC_BASE+0x00) // 32bit func command status reg
++
++#define COMMAND_SOFTRESET (1 << 7)
++#define COMMAND_BADISOAP (1 << 3)
++#define COMMAND_SUPDET (1 << 2)
++#define COMMAND_RSMINPROG (1 << 1)
++#define COMMAND_RESETDET (1)
++
++
++#define OTG_FUNC_DEV_ADDR (OTG_FUNC_BASE+0x04) // 32bit func device address reg
++
++#define OTG_FUNC_SINT_STAT (OTG_FUNC_BASE+0x08) // 32bit func system int status reg
++
++#define SYSTEM_DONEREGINTDS (1 << 5)
++#define SYSTEM_SOFDETINT (1 << 4)
++#define SYSTEM_DONEREGINT (1 << 3)
++#define SYSTEM_SUSPDETINT (1 << 2)
++#define SYSTEM_RSMFININT (1 << 1)
++#define SYSTEM_RESETINT (1)
++
++#define OTG_FUNC_SINT_STEN (OTG_FUNC_BASE+0x0C) // 32bit func system int enable reg
++
++#define SYSTEM_DONEREGINTDS_EN (1 << 5)
++#define SYSTEM_SOFDETINT_EN (1 << 4)
++#define SYSTEM_DONEREGINT_EN (1 << 3)
++#define SYSTEM_SUSPDETINT_EN (1 << 2)
++#define SYSTEM_RSMFININT_EN (1 << 1)
++#define SYSTEM_RESETINT_EN (1)
++
++
++#define OTG_FUNC_XINT_STAT (OTG_FUNC_BASE+0x10) // 32bit func X buf int status reg
++#define OTG_FUNC_YINT_STAT (OTG_FUNC_BASE+0x14) // 32bit func Y buf int status reg
++#define OTG_FUNC_XYINT_STEN (OTG_FUNC_BASE+0x18) // 32bit func XY buf int enable reg
++#define OTG_FUNC_XFILL_STAT (OTG_FUNC_BASE+0x1C) // 32bit func X filled status reg
++
++#define OTG_FUNC_YFILL_STAT (OTG_FUNC_BASE+0x20) // 32bit func Y filled status reg
++#define OTG_FUNC_EP_EN (OTG_FUNC_BASE+0x24) // 32bit func endpoints enable reg
++#define OTG_FUNC_EP_RDY (OTG_FUNC_BASE+0x28) // 32bit func endpoints ready reg
++#define OTG_FUNC_IINT (OTG_FUNC_BASE+0x2C) // 32bit func immediate interrupt reg
++
++#define OTG_FUNC_EP_DSTAT (OTG_FUNC_BASE+0x30) // 32bit func endpoints done status
++#define OTG_FUNC_EP_DEN (OTG_FUNC_BASE+0x34) // 32bit func endpoints done enable
++#define OTG_FUNC_EP_TOGGLE (OTG_FUNC_BASE+0x38) // 32bit func endpoints toggle bits
++#define OTG_FUNC_FRM_NUM (OTG_FUNC_BASE+0x3C) // 32bit func frame number reg
++
++
++#define EP0_STALL (1 << 31)
++#define EP0_SETUP (1 << 30)
++#define EP0_OVERRUN (1 << 29)
++#define EP0_AUTOISO (1 << 27)
++
++
++/* generic endpoint register manipulations
++ */
++#define EP_OUT 0x1
++#define EP_IN 0x2
++#define EP_BOTH 0x3
++
++#define ETD_MASK(n) (1 << n)
++#define ep_num_both(n) (EP_BOTH << n)
++#define ep_num_dir(n, dir) ((dir ? EP_IN : EP_OUT) << (n*2))
++#define ep_num_out(n) ep_num_dir(n, USB_DIR_OUT)
++#define ep_num_in(n) ep_num_dir(n, USB_DIR_IN)
++
++
++/* ep descriptor access
++ */
++static __inline__ u32 etd_word(int n, int word)
++{
++ u32 offset = n * 16;
++ offset += word * 4;
++ return OTG_ETD_BASE + offset;
++}
++
++/* ep descriptor access
++ */
++static __inline__ u32 ep_word(int n, int dir, int word)
++{
++ u32 offset = n * 2;
++ offset += dir ? 1 : 0;
++ offset *= 16;
++ offset += word * 4;
++ return OTG_EP_BASE + offset;
++}
++
++/* endpoint data buffer access
++ *
++ * This is a simplistic allocator, will do until we want to support ISO or host mode.
++ *
++ * This works because we are assuming a maximum of 16 allocate endpoints, and no
++ * overlapped endpoints (both in and out are allocated).
++ */
++
++static volatile __inline__ u16 data_x_buf(int n, int dir)
++{
++ return 0x40 * (n * 4 + 2 * (dir ? 1 : 0));
++}
++static volatile __inline__ u16 data_y_buf(int n, int dir)
++{
++ return 0x40 * (n * 4 + 2 * (dir ? 1 : 0) + 1);
++}
++
++static volatile __inline__ u8 * data_x_address(int n, int dir)
++{
++ return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_x_buf(n, dir));
++}
++static volatile __inline__ u8 * data_y_address(int n, int dir)
++{
++ return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_y_buf(n, dir));
++}
++
++/*
++ * C.f. 23.13.3 DMA Registers
++ */
++#define OTG_DMA_REV_NUM (OTG_DMA_BASE+0x000) // 32bit dma revision number reg
++#define OTG_DMA_DINT_STAT (OTG_DMA_BASE+0x004) // 32bit dma int status reg
++#define OTG_DMA_DINT_STEN (OTG_DMA_BASE+0x008) // 32bit dma int enable reg
++#define OTG_DMA_ETD_ERR (OTG_DMA_BASE+0x00C) // 32bit dma ETD error status reg
++#define OTG_DMA_EP_ERR (OTG_DMA_BASE+0x010) // 32bit dma EP error status reg
++#define OTG_DMA_ETD_EN (OTG_DMA_BASE+0x020) // 32bit dma ETD DMA enable reg
++#define OTG_DMA_EP_EN (OTG_DMA_BASE+0x024) // 32bit dma EP DMA enable reg
++#define OTG_DMA_ETD_ENXREQ (OTG_DMA_BASE+0x028) // 32bit dma ETD DMA enable Xtrig req
++#define OTG_DMA_EP_ENXREQ (OTG_DMA_BASE+0x02C) // 32bit dma EP DMA enable Ytrig req
++#define OTG_DMA_ETD_ENXYREQ (OTG_DMA_BASE+0x030) // 32bit dma ETD DMA enble XYtrig req
++#define OTG_DMA_EP_ENXYREQ (OTG_DMA_BASE+0x034) // 32bit dma EP DMA enable XYtrig req
++#define OTG_DMA_ETD_BURST4 (OTG_DMA_BASE+0x038) // 32bit dma ETD DMA enble burst4 reg
++#define OTG_DMA_EP_BURST4 (OTG_DMA_BASE+0x03C) // 32bit dma EP DMA enable burst4 reg
++#define OTG_DMA_MISC_CTRL (OTG_DMA_BASE+0x040) // 32bit dma EP misc control reg
++#define OTG_DMA_ETD_CH_CLR (OTG_DMA_BASE+0x044) // 32bit dma ETD clear channel reg
++#define OTG_DMA_EP_CH_CLR (OTG_DMA_BASE+0x048) // 32bit dma EP clear channel reg
++
++
++#define OTG_DMA_ETD_CH_CLR (OTG_DMA_BASE+0x044) // 32bit dma ETD clear channel reg
++#define OTG_DMA_ETD_ERR (OTG_DMA_BASE+0x00C) // 32bit dma ETD error status reg
++#define OTG_DMA_ETD_EN (OTG_DMA_BASE+0x020) // 32bit dma ETD DMA enable reg
++#define OTG_DMA_ETD_ENXREQ (OTG_DMA_BASE+0x028) // 32bit dma ETD DMA enable Xtrig req
++#define OTG_DMA_ETD_ENXYREQ (OTG_DMA_BASE+0x030) // 32bit dma ETD DMA enble XYtrig req
++#define OTG_DMA_ETD_BURST4 (OTG_DMA_BASE+0x038) // 32bit dma ETD DMA enble burst4 reg
++
++
++
++#define OTG_DMA_EP_CH_CLR (OTG_DMA_BASE+0x048) // 32bit dma EP clear channel reg
++#define OTG_DMA_EP_ERR (OTG_DMA_BASE+0x010) // 32bit dma EP error status reg
++#define OTG_DMA_EP_EN (OTG_DMA_BASE+0x024) // 32bit dma EP DMA enable reg
++#define OTG_DMA_EP_ENXREQ (OTG_DMA_BASE+0x02C) // 32bit dma EP DMA enable Ytrig req
++#define OTG_DMA_EP_ENXYREQ (OTG_DMA_BASE+0x034) // 32bit dma EP DMA enable XYtrig req
++#define OTG_DMA_EP_BURST4 (OTG_DMA_BASE+0x03C) // 32bit dma EP DMA enable burst4 reg
++
++
++#define dma_num_dir(n, dir) (n * 2 + (dir ? 1 : 0))
++#define dma_num_out(n) dma_num_dir(n, USB_DIR_OUT)
++#define dma_num_in(n) dma_num_dir(n, USB_DIR_IN)
++
++#define OTG_DMA_ETD_MSA(x) (OTG_DMA_BASE+0x100+x*4)
++#define OTG_DMA_EPN_MSA(x) (OTG_DMA_BASE+0x180+x*4)
++#define OTG_DMA_ETDN_BPTR(x) (OTG_DMA_BASE+0x280+x*4)
++#define OTG_DMA_EPN_BPTR(x) (OTG_DMA_BASE+0x284+x*4)
++
++
++/*
++ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
++ * These are the ISP1301 shadow registers.
++ *
++ * See isp1301-hardware.h for register bit defines.
++ */
++#if 1
++#define MX2_VENDOR_ID_LOW OTG_I2C_BASE+0x00
++#define MX2_VENDOR_ID_HIGH OTG_I2C_BASE+0x01
++#define MX2_PRODUCT_ID_LOW OTG_I2C_BASE+0x02
++#define MX2_PRODUCT_ID_HIGH OTG_I2C_BASE+0x03
++
++#define MX2_MODE_CONTROL_1_SET OTG_I2C_BASE+0x04
++#define MX2_MODE_CONTROL_1_CLR OTG_I2C_BASE+0x05
++#define MX2_OTG_CONTROL_SET OTG_I2C_BASE+0x06
++#define MX2_OTG_CONTROL_CLR OTG_I2C_BASE+0x07
++
++#define MX2_INTERRUPT_SOURCE OTG_I2C_BASE+0x08
++
++#define MX2_INT_LAT_REG_SET OTG_I2C_BASE+0x0a
++#define MX2_INT_LAT_REG_CLR OTG_I2C_BASE+0x0b
++
++#define MX2_INT_FALSE_REG_SET OTG_I2C_BASE+0x0c
++#define MX2_INT_FALSE_REG_CLR OTG_I2C_BASE+0x0d
++#define MX2_INT_TRUE_REG_SET OTG_I2C_BASE+0x0e
++#define MX2_INT_TRUE_REG_CLR OTG_I2C_BASE+0x0f
++
++#define MX2_OTG_STATUS_REG OTG_I2C_BASE+0x10
++
++#define MX2_MODE_CONTROL_2_SET OTG_I2C_BASE+0x12
++#define MX2_MODE_CONTROL_2_CLR OTG_I2C_BASE+0x13
++
++#define MX2_BCD_DEV_LOW OTG_I2C_BASE+0x14
++#define MX2_BCD_DEV_HIGH OTG_I2C_BASE+0x15
++#endif
++
++/*
++ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
++ * These are the I2C controller and access registers.
++ *
++ * N.B. I2C_ERROR is not documented.
++ */
++
++
++#define I2C_BUSY (1 << 7)
++#define I2C_ERROR (1 << 2)
++#define I2C_HWSMODE (1 << 1)
++#define I2C_I2COE (1 << 0)
++
++#define I2C_SCLK_TO_SCL_DIVISION (OTG_I2C_BASE+0x1E)
++
++#define I2C_INTERRUPT_AND_CONTROL (OTG_I2C_BASE+0x1F)
++
++#define I2C_STATUS_MASK (0x7)
++
++#define I2C_NOACK_EN (1 << 6)
++#define I2C_RWREADY_EN (1 << 5)
++#define I2C_OTGXCVRINT_EN (1 << 4)
++
++#define I2C_NOACK (1 << 2)
++#define I2C_RWREADY (1 << 1)
++#define I2C_OTGXCVRINT (1 << 0)
++
++#define MX2_OTG_XCVR_DEVAD OTG_I2C_BASE+0x18
++#define MX2_SEQ_OP_REG OTG_I2C_BASE+0x19
++#define MX2_SEQ_RD_STARTAD OTG_I2C_BASE+0x1a
++#define MX2_I2C_OP_CTRL_REG OTG_I2C_BASE+0x1b
++#define MX2_SCLK_TO_SCL_HPER OTG_I2C_BASE+0x1e
++#define MX2_I2C_INTERRUPT_AND_CTRL OTG_I2C_BASE+0x1f
++
++
++/* ********************************************************************************************** */
++
++/*! mx2_rb
++ */
++static u8 __inline__ mx2_rb(u32 port)
++{
++ return *(volatile u8 *) (IO_ADDRESS(port));
++}
++
++/*! mx2_rl
++ */
++static u32 __inline__ mx2_rl(u32 port)
++{
++ return *(volatile u32 *) (IO_ADDRESS(port));
++}
++
++/*! mx2_wb
++ */
++static void __inline__ mx2_wb(u32 port, u8 val)
++{
++ *(volatile u8 *)(IO_ADDRESS(port)) = val;
++}
++
++/*! mx2_orb
++ */
++static void __inline__ mx2_orb(u32 port, u8 val)
++{
++ u8 set = mx2_rb(port) | val;
++ *(volatile u8 *)(IO_ADDRESS(port)) = set;
++}
++
++/*! mx2_andb
++ */
++static void __inline__ mx2_andb(u32 port, u8 val)
++{
++ u8 set = mx2_rb(port) & val;
++ *(volatile u8 *)(IO_ADDRESS(port)) = set;
++}
++
++/*! mx2_wl
++ */
++static void __inline__ mx2_wl(u32 port, u32 val)
++{
++ u32 set;
++ *(volatile u32 *)(IO_ADDRESS(port)) = val;
++ set = mx2_rl(port);
++}
++
++/*! mx2_orl
++ */
++static void __inline__ mx2_orl(u32 port, u32 val)
++{
++ u32 set = mx2_rl(port);
++ *(volatile u32 *)(IO_ADDRESS(port)) = (set | val);
++}
++
++/*! mx2_andl
++ */
++static void __inline__ mx2_andl(u32 port, u32 val)
++{
++ u32 set = mx2_rl(port);
++ *(volatile u32 *)(IO_ADDRESS(port)) = (set & val);
++}
++
++static u32 inline mx2_host_port_stat(int n)
++{
++ switch (n) {
++ default:
++ case 1:
++ return OTG_HOST_PORT_STATUS_1;
++ case 2:
++ return OTG_HOST_PORT_STATUS_2;
++ case 3:
++ return OTG_HOST_PORT_STATUS_3;
++ }
++}
++
diff --git a/packages/linux/linux-mtx-2-2.4.27/47-au1000_eth.patch b/packages/linux/linux-mtx-2-2.4.27/47-au1000_eth.patch
new file mode 100644
index 0000000000..b1eb6c990d
--- /dev/null
+++ b/packages/linux/linux-mtx-2-2.4.27/47-au1000_eth.patch
@@ -0,0 +1,163 @@
+--- linux/drivers/net/au1000_eth.h 2003-06-05 02:00:35.000000000 +0200
++++ patch/drivers/net/au1000_eth.h 2006-10-13 14:36:42.237757250 +0200
+@@ -233,3 +233,11 @@
+ struct timer_list timer;
+ spinlock_t lock; /* Serialise access to device */
+ };
++
++struct mii_ioctl_data {
++ u16 phy_id;
++ u16 reg_num;
++ u16 val_in;
++ u16 val_out;
++};
++
+--- linux/drivers/net/au1000_eth.c 2004-11-24 12:12:42.000000000 +0100
++++ patch/drivers/net/au1000_eth.c 2006-10-13 14:36:36.649408000 +0200
+@@ -83,8 +83,6 @@
+ static int au1000_set_config(struct net_device *dev, struct ifmap *map);
+ static void set_rx_mode(struct net_device *);
+ static struct net_device_stats *au1000_get_stats(struct net_device *);
+-static inline void update_tx_stats(struct net_device *, u32, u32);
+-static inline void update_rx_stats(struct net_device *, u32);
+ static void au1000_timer(unsigned long);
+ static int au1000_ioctl(struct net_device *, struct ifreq *, int);
+ static int mdio_read(struct net_device *, int, int);
+@@ -674,6 +672,7 @@
+ {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
+ {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
+ {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
++ {"Broadcom BCM5241 10/100 BaseT PHY",0x0143,0xBC31, &bcm_5201_ops,0},
+ {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
+ {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
+ {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
+@@ -1389,6 +1388,7 @@
+ control |= MAC_FULL_DUPLEX;
+ }
+ aup->mac->control = control;
++ aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
+ au_sync();
+
+ spin_unlock_irqrestore(&aup->lock, flags);
+@@ -1539,16 +1539,11 @@
+ }
+ }
+
+-
+-static inline void
+-update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
++static void update_tx_stats(struct net_device *dev, u32 status)
+ {
+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
+ struct net_device_stats *ps = &aup->stats;
+
+- ps->tx_packets++;
+- ps->tx_bytes += pkt_len;
+-
+ if (status & TX_FRAME_ABORTED) {
+ if (dev->if_port == IF_PORT_100BASEFX) {
+ if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
+@@ -1581,7 +1576,7 @@
+ ptxd = aup->tx_dma_ring[aup->tx_tail];
+
+ while (ptxd->buff_stat & TX_T_DONE) {
+- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
++ update_tx_stats(dev, ptxd->status);
+ ptxd->buff_stat &= ~TX_T_DONE;
+ ptxd->len = 0;
+ au_sync();
+@@ -1603,6 +1598,7 @@
+ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
++ struct net_device_stats *ps = &aup->stats;
+ volatile tx_dma_t *ptxd;
+ u32 buff_stat;
+ db_dest_t *pDB;
+@@ -1622,7 +1618,7 @@
+ return 1;
+ }
+ else if (buff_stat & TX_T_DONE) {
+- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
++ update_tx_stats(dev, ptxd->status);
+ ptxd->len = 0;
+ }
+
+@@ -1642,6 +1638,9 @@
+ else
+ ptxd->len = skb->len;
+
++ ps->tx_packets++;
++ ps->tx_bytes += ptxd->len;
++
+ ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
+ au_sync();
+ dev_kfree_skb(skb);
+@@ -1650,7 +1649,6 @@
+ return 0;
+ }
+
+-
+ static inline void update_rx_stats(struct net_device *dev, u32 status)
+ {
+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
+@@ -1840,21 +1838,36 @@
+
+ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ {
+- //u16 *data = (u16 *)&rq->ifr_data;
++ struct au1000_private *aup = (struct au1000_private *)dev->priv;
++ struct mii_ioctl_data *mii_data = (struct mii_ioctl_data *)&rq->ifr_ifru;
++ u16 val = mii_data->val_in;
++ const u32 enabled = MAC_EN_RESET0 | MAC_EN_RESET1 |
++ MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
++
++ /* Check if net device is running */
++ if (!netif_running(dev)) return -EINVAL;
++
++ /* Check if ethernet mac is in reset mode */
++ if (*aup->enable & enabled != enabled) return -EINVAL;
+
+- /* fixme */
+ switch(cmd) {
+- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+- //data[0] = PHY_ADDRESS;
+- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+- //data[3] = mdio_read(ioaddr, data[0], data[1]);
+- return 0;
+- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+- //mdio_write(ioaddr, data[0], data[1], data[2]);
+- return 0;
++ case SIOCGMIIPHY: /* Get the address of the PHY in use. */
++ mii_data->phy_id = aup->phy_addr;
++ break;
++ case SIOCGMIIREG: /* Read the specified MII register. */
++ mii_data->val_out = mdio_read(dev, mii_data->phy_id,
++ mii_data->reg_num);
++ break;
++ case SIOCSMIIREG: /* Write the specified MII register */
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ mdio_write(dev,mii_data->phy_id, mii_data->reg_num,
++ val);
+ default:
+ return -EOPNOTSUPP;
++
+ }
++ return 0;
+ }
+
+
+--- linux/drivers/net/Config.in 2006-10-13 15:05:33.697966750 +0200
++++ patch/drivers/net/Config.in 2006-10-13 14:36:47.030056750 +0200
+@@ -67,9 +67,7 @@
+ fi
+ if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+ tristate ' MIPS Au1x00 Ethernet support' CONFIG_MIPS_AU1X00_ENET
+- if [ "$CONFIG_MIPS_AU1X00_ENET" = "y" ]; then
+- bool ' Broadcom 5222 Dual Phy Support' CONFIG_BCM5222_DUAL_PHY
+- fi
++ dep_mbool ' Broadcom 5222 Dual Phy Support' CONFIG_BCM5222_DUAL_PHY $CONFIG_MIPS_AU1X00_ENET
+ fi
+ if [ "$CONFIG_SGI_IP27" = "y" ]; then
+ bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
diff --git a/packages/linux/linux-mtx-2-2.4.27/48-pptp.patch b/packages/linux/linux-mtx-2-2.4.27/48-pptp.patch
new file mode 100644
index 0000000000..5896f90370
--- /dev/null
+++ b/packages/linux/linux-mtx-2-2.4.27/48-pptp.patch
@@ -0,0 +1,5092 @@
+diff -uNr linux_org/Documentation/Configure.help linux/Documentation/Configure.help
+--- linux_org/Documentation/Configure.help 2006-10-27 14:08:20.000000000 +0200
++++ linux/Documentation/Configure.help 2006-10-27 14:11:52.000000000 +0200
+@@ -2848,6 +2848,31 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `Y'.
+
++PPTP conntrack and NAT support
++CONFIG_IP_NF_PPTP
++ This module adds support for PPTP (Point to Point Tunnelling Protocol,
++ RFC2637) conncection tracking and NAT.
++
++ If you are running PPTP sessions over a stateful firewall or NAT box,
++ you may want to enable this feature.
++
++ Please note that not all PPTP modes of operation are supported yet.
++ For more info, read top of the file net/ipv4/netfilter/ip_conntrack_pptp.c
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++GRE protocol conntrack and NAT support
++CONFIG_IP_NF_CT_PROTO_GRE
++ This module adds generic support for connection tracking and NAT of the
++ GRE protocol (RFC1701, RFC2784). Please note that this will only work
++ with GRE connections using the key field of the GRE header.
++
++ You will need GRE support to enable PPTP support.
++
++ If you want to compile it as a module, say `M' here and read
++ Documentation/modules.txt. If unsire, say `N'.
++
+ User space queueing via NETLINK
+ CONFIG_IP_NF_QUEUE
+ Netfilter has the ability to queue packets to user space: the
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux_org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-11-24 12:13:57.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack.h 2006-10-27 14:11:52.000000000 +0200
+@@ -50,19 +50,23 @@
+
+ #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+
+ /* per conntrack: protocol private data */
+ union ip_conntrack_proto {
+ /* insert conntrack proto private data here */
++ struct ip_ct_gre gre;
+ struct ip_ct_tcp tcp;
+ struct ip_ct_icmp icmp;
+ };
+
+ union ip_conntrack_expect_proto {
+ /* insert expect proto private data here */
++ struct ip_ct_gre_expect gre;
+ };
+
+ /* Add protocol helper include file here */
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+@@ -71,6 +75,7 @@
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+ /* insert conntrack helper private data (expect) here */
++ struct ip_ct_pptp_expect exp_pptp_info;
+ struct ip_ct_amanda_expect exp_amanda_info;
+ struct ip_ct_ftp_expect exp_ftp_info;
+ struct ip_ct_irc_expect exp_irc_info;
+@@ -85,16 +90,19 @@
+ /* per conntrack: application helper private data */
+ union ip_conntrack_help {
+ /* insert conntrack helper private data (master) here */
++ struct ip_ct_pptp_master ct_pptp_info;
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ #include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_pptp.h>
+
+ /* per conntrack: nat application helper private data */
+ union ip_conntrack_nat_help {
+ /* insert nat helper private data here */
++ struct ip_nat_pptp nat_pptp_info;
+ };
+ #endif
+
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
+--- linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,313 @@
++/* PPTP constants and structs */
++#ifndef _CONNTRACK_PPTP_H
++#define _CONNTRACK_PPTP_H
++
++/* state of the control session */
++enum pptp_ctrlsess_state {
++ PPTP_SESSION_NONE, /* no session present */
++ PPTP_SESSION_ERROR, /* some session error */
++ PPTP_SESSION_STOPREQ, /* stop_sess request seen */
++ PPTP_SESSION_REQUESTED, /* start_sess request seen */
++ PPTP_SESSION_CONFIRMED, /* session established */
++};
++
++/* state of the call inside the control session */
++enum pptp_ctrlcall_state {
++ PPTP_CALL_NONE,
++ PPTP_CALL_ERROR,
++ PPTP_CALL_OUT_REQ,
++ PPTP_CALL_OUT_CONF,
++ PPTP_CALL_IN_REQ,
++ PPTP_CALL_IN_REP,
++ PPTP_CALL_IN_CONF,
++ PPTP_CALL_CLEAR_REQ,
++};
++
++
++/* conntrack private data */
++struct ip_ct_pptp_master {
++ enum pptp_ctrlsess_state sstate; /* session state */
++
++ /* everything below is going to be per-expectation in newnat,
++ * since there could be more than one call within one session */
++ enum pptp_ctrlcall_state cstate; /* call state */
++ u_int16_t pac_call_id; /* call id of PAC, host byte order */
++ u_int16_t pns_call_id; /* call id of PNS, host byte order */
++};
++
++/* conntrack_expect private member */
++struct ip_ct_pptp_expect {
++ enum pptp_ctrlcall_state cstate; /* call state */
++ u_int16_t pac_call_id; /* call id of PAC */
++ u_int16_t pns_call_id; /* call id of PNS */
++};
++
++
++#ifdef __KERNEL__
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++DECLARE_LOCK_EXTERN(ip_pptp_lock);
++
++#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
++
++union pptp_ctrl_union {
++ void *rawreq;
++ struct PptpStartSessionRequest *sreq;
++ struct PptpStartSessionReply *srep;
++ struct PptpStopSessionReqest *streq;
++ struct PptpStopSessionReply *strep;
++ struct PptpOutCallRequest *ocreq;
++ struct PptpOutCallReply *ocack;
++ struct PptpInCallRequest *icreq;
++ struct PptpInCallReply *icack;
++ struct PptpInCallConnected *iccon;
++ struct PptpClearCallRequest *clrreq;
++ struct PptpCallDisconnectNotify *disc;
++ struct PptpWanErrorNotify *wanerr;
++ struct PptpSetLinkInfo *setlink;
++};
++
++
++
++#define PPTP_CONTROL_PORT 1723
++
++#define PPTP_PACKET_CONTROL 1
++#define PPTP_PACKET_MGMT 2
++
++#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
++
++struct pptp_pkt_hdr {
++ __u16 packetLength;
++ __u16 packetType;
++ __u32 magicCookie;
++};
++
++/* PptpControlMessageType values */
++#define PPTP_START_SESSION_REQUEST 1
++#define PPTP_START_SESSION_REPLY 2
++#define PPTP_STOP_SESSION_REQUEST 3
++#define PPTP_STOP_SESSION_REPLY 4
++#define PPTP_ECHO_REQUEST 5
++#define PPTP_ECHO_REPLY 6
++#define PPTP_OUT_CALL_REQUEST 7
++#define PPTP_OUT_CALL_REPLY 8
++#define PPTP_IN_CALL_REQUEST 9
++#define PPTP_IN_CALL_REPLY 10
++#define PPTP_IN_CALL_CONNECT 11
++#define PPTP_CALL_CLEAR_REQUEST 12
++#define PPTP_CALL_DISCONNECT_NOTIFY 13
++#define PPTP_WAN_ERROR_NOTIFY 14
++#define PPTP_SET_LINK_INFO 15
++
++#define PPTP_MSG_MAX 15
++
++/* PptpGeneralError values */
++#define PPTP_ERROR_CODE_NONE 0
++#define PPTP_NOT_CONNECTED 1
++#define PPTP_BAD_FORMAT 2
++#define PPTP_BAD_VALUE 3
++#define PPTP_NO_RESOURCE 4
++#define PPTP_BAD_CALLID 5
++#define PPTP_REMOVE_DEVICE_ERROR 6
++
++struct PptpControlHeader {
++ __u16 messageType;
++ __u16 reserved;
++};
++
++/* FramingCapability Bitmap Values */
++#define PPTP_FRAME_CAP_ASYNC 0x1
++#define PPTP_FRAME_CAP_SYNC 0x2
++
++/* BearerCapability Bitmap Values */
++#define PPTP_BEARER_CAP_ANALOG 0x1
++#define PPTP_BEARER_CAP_DIGITAL 0x2
++
++struct PptpStartSessionRequest {
++ __u16 protocolVersion;
++ __u8 reserved1;
++ __u8 reserved2;
++ __u32 framingCapability;
++ __u32 bearerCapability;
++ __u16 maxChannels;
++ __u16 firmwareRevision;
++ __u8 hostName[64];
++ __u8 vendorString[64];
++};
++
++/* PptpStartSessionResultCode Values */
++#define PPTP_START_OK 1
++#define PPTP_START_GENERAL_ERROR 2
++#define PPTP_START_ALREADY_CONNECTED 3
++#define PPTP_START_NOT_AUTHORIZED 4
++#define PPTP_START_UNKNOWN_PROTOCOL 5
++
++struct PptpStartSessionReply {
++ __u16 protocolVersion;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u32 framingCapability;
++ __u32 bearerCapability;
++ __u16 maxChannels;
++ __u16 firmwareRevision;
++ __u8 hostName[64];
++ __u8 vendorString[64];
++};
++
++/* PptpStopReasons */
++#define PPTP_STOP_NONE 1
++#define PPTP_STOP_PROTOCOL 2
++#define PPTP_STOP_LOCAL_SHUTDOWN 3
++
++struct PptpStopSessionRequest {
++ __u8 reason;
++};
++
++/* PptpStopSessionResultCode */
++#define PPTP_STOP_OK 1
++#define PPTP_STOP_GENERAL_ERROR 2
++
++struct PptpStopSessionReply {
++ __u8 resultCode;
++ __u8 generalErrorCode;
++};
++
++struct PptpEchoRequest {
++ __u32 identNumber;
++};
++
++/* PptpEchoReplyResultCode */
++#define PPTP_ECHO_OK 1
++#define PPTP_ECHO_GENERAL_ERROR 2
++
++struct PptpEchoReply {
++ __u32 identNumber;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 reserved;
++};
++
++/* PptpFramingType */
++#define PPTP_ASYNC_FRAMING 1
++#define PPTP_SYNC_FRAMING 2
++#define PPTP_DONT_CARE_FRAMING 3
++
++/* PptpCallBearerType */
++#define PPTP_ANALOG_TYPE 1
++#define PPTP_DIGITAL_TYPE 2
++#define PPTP_DONT_CARE_BEARER_TYPE 3
++
++struct PptpOutCallRequest {
++ __u16 callID;
++ __u16 callSerialNumber;
++ __u32 minBPS;
++ __u32 maxBPS;
++ __u32 bearerType;
++ __u32 framingType;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u16 reserved1;
++ __u16 phoneNumberLength;
++ __u16 reserved2;
++ __u8 phoneNumber[64];
++ __u8 subAddress[64];
++};
++
++/* PptpCallResultCode */
++#define PPTP_OUTCALL_CONNECT 1
++#define PPTP_OUTCALL_GENERAL_ERROR 2
++#define PPTP_OUTCALL_NO_CARRIER 3
++#define PPTP_OUTCALL_BUSY 4
++#define PPTP_OUTCALL_NO_DIAL_TONE 5
++#define PPTP_OUTCALL_TIMEOUT 6
++#define PPTP_OUTCALL_DONT_ACCEPT 7
++
++struct PptpOutCallReply {
++ __u16 callID;
++ __u16 peersCallID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 causeCode;
++ __u32 connectSpeed;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u32 physChannelID;
++};
++
++struct PptpInCallRequest {
++ __u16 callID;
++ __u16 callSerialNumber;
++ __u32 callBearerType;
++ __u32 physChannelID;
++ __u16 dialedNumberLength;
++ __u16 dialingNumberLength;
++ __u8 dialedNumber[64];
++ __u8 dialingNumber[64];
++ __u8 subAddress[64];
++};
++
++/* PptpInCallResultCode */
++#define PPTP_INCALL_ACCEPT 1
++#define PPTP_INCALL_GENERAL_ERROR 2
++#define PPTP_INCALL_DONT_ACCEPT 3
++
++struct PptpInCallReply {
++ __u16 callID;
++ __u16 peersCallID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u16 reserved;
++};
++
++struct PptpInCallConnected {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 connectSpeed;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u32 callFramingType;
++};
++
++struct PptpClearCallRequest {
++ __u16 callID;
++ __u16 reserved;
++};
++
++struct PptpCallDisconnectNotify {
++ __u16 callID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 causeCode;
++ __u16 reserved;
++ __u8 callStatistics[128];
++};
++
++struct PptpWanErrorNotify {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 crcErrors;
++ __u32 framingErrors;
++ __u32 hardwareOverRuns;
++ __u32 bufferOverRuns;
++ __u32 timeoutErrors;
++ __u32 alignmentErrors;
++};
++
++struct PptpSetLinkInfo {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 sendAccm;
++ __u32 recvAccm;
++};
++
++
++struct pptp_priv_data {
++ __u16 call_id;
++ __u16 mcall_id;
++ __u16 pcall_id;
++};
++
++#endif /* __KERNEL__ */
++#endif /* _CONNTRACK_PPTP_H */
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
+--- linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,123 @@
++#ifndef _CONNTRACK_PROTO_GRE_H
++#define _CONNTRACK_PROTO_GRE_H
++#include <asm/byteorder.h>
++
++/* GRE PROTOCOL HEADER */
++
++/* GRE Version field */
++#define GRE_VERSION_1701 0x0
++#define GRE_VERSION_PPTP 0x1
++
++/* GRE Protocol field */
++#define GRE_PROTOCOL_PPTP 0x880B
++
++/* GRE Flags */
++#define GRE_FLAG_C 0x80
++#define GRE_FLAG_R 0x40
++#define GRE_FLAG_K 0x20
++#define GRE_FLAG_S 0x10
++#define GRE_FLAG_A 0x80
++
++#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
++#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
++#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
++#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
++#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
++
++/* GRE is a mess: Four different standards */
++struct gre_hdr {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++ __u16 rec:3,
++ srr:1,
++ seq:1,
++ key:1,
++ routing:1,
++ csum:1,
++ version:3,
++ reserved:4,
++ ack:1;
++#elif defined(__BIG_ENDIAN_BITFIELD)
++ __u16 csum:1,
++ routing:1,
++ key:1,
++ seq:1,
++ srr:1,
++ rec:3,
++ ack:1,
++ reserved:4,
++ version:3;
++#else
++#error "Adjust your <asm/byteorder.h> defines"
++#endif
++ __u16 protocol;
++};
++
++/* modified GRE header for PPTP */
++struct gre_hdr_pptp {
++ __u8 flags; /* bitfield */
++ __u8 version; /* should be GRE_VERSION_PPTP */
++ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
++ __u16 payload_len; /* size of ppp payload, not inc. gre header */
++ __u16 call_id; /* peer's call_id for this session */
++ __u32 seq; /* sequence number. Present if S==1 */
++ __u32 ack; /* seq number of highest packet recieved by */
++ /* sender in this session */
++};
++
++
++/* this is part of ip_conntrack */
++struct ip_ct_gre {
++ unsigned int stream_timeout;
++ unsigned int timeout;
++};
++
++/* this is part of ip_conntrack_expect */
++struct ip_ct_gre_expect {
++ struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
++};
++
++#ifdef __KERNEL__
++struct ip_conntrack_expect;
++
++/* structure for original <-> reply keymap */
++struct ip_ct_gre_keymap {
++ struct list_head list;
++
++ struct ip_conntrack_tuple tuple;
++};
++
++
++/* add new tuple->key_reply pair to keymap */
++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
++ struct ip_conntrack_tuple *t,
++ int reply);
++
++/* change an existing keymap entry */
++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
++ struct ip_conntrack_tuple *t);
++
++/* delete keymap entries */
++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
++
++
++/* get pointer to gre key, if present */
++static inline u_int32_t *gre_key(struct gre_hdr *greh)
++{
++ if (!greh->key)
++ return NULL;
++ if (greh->csum || greh->routing)
++ return (u_int32_t *) (greh+sizeof(*greh)+4);
++ return (u_int32_t *) (greh+sizeof(*greh));
++}
++
++/* get pointer ot gre csum, if present */
++static inline u_int16_t *gre_csum(struct gre_hdr *greh)
++{
++ if (!greh->csum)
++ return NULL;
++ return (u_int16_t *) (greh+sizeof(*greh));
++}
++
++#endif /* __KERNEL__ */
++
++#endif /* _CONNTRACK_PROTO_GRE_H */
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+--- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-17 02:07:46.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2006-10-27 14:11:52.000000000 +0200
+@@ -14,7 +14,7 @@
+ union ip_conntrack_manip_proto
+ {
+ /* Add other protocols here. */
+- u_int16_t all;
++ u_int32_t all;
+
+ struct {
+ u_int16_t port;
+@@ -25,6 +25,9 @@
+ struct {
+ u_int16_t id;
+ } icmp;
++ struct {
++ u_int32_t key;
++ } gre;
+ };
+
+ /* The manipulable part of the tuple. */
+@@ -44,7 +47,7 @@
+ u_int32_t ip;
+ union {
+ /* Add other protocols here. */
+- u_int16_t all;
++ u_int64_t all;
+
+ struct {
+ u_int16_t port;
+@@ -55,6 +58,11 @@
+ struct {
+ u_int8_t type, code;
+ } icmp;
++ struct {
++ u_int16_t protocol;
++ u_int8_t version;
++ u_int32_t key;
++ } gre;
+ } u;
+
+ /* The protocol. */
+@@ -80,10 +88,16 @@
+ #ifdef __KERNEL__
+
+ #define DUMP_TUPLE(tp) \
+-DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
++DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
+ (tp), (tp)->dst.protonum, \
+- NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
+- NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
++ NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
++ NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
++
++#define DUMP_TUPLE_RAW(x) \
++ DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
++ (x), (x)->dst.protonum, \
++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
+
+ #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
+
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig
+--- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig 2003-11-17 02:07:46.000000000 +0100
+@@ -0,0 +1,139 @@
++#ifndef _IP_CONNTRACK_TUPLE_H
++#define _IP_CONNTRACK_TUPLE_H
++
++/* A `tuple' is a structure containing the information to uniquely
++ identify a connection. ie. if two packets have the same tuple, they
++ are in the same connection; if not, they are not.
++
++ We divide the structure along "manipulatable" and
++ "non-manipulatable" lines, for the benefit of the NAT code.
++*/
++
++/* The protocol-specific manipulable parts of the tuple: always in
++ network order! */
++union ip_conntrack_manip_proto
++{
++ /* Add other protocols here. */
++ u_int16_t all;
++
++ struct {
++ u_int16_t port;
++ } tcp;
++ struct {
++ u_int16_t port;
++ } udp;
++ struct {
++ u_int16_t id;
++ } icmp;
++};
++
++/* The manipulable part of the tuple. */
++struct ip_conntrack_manip
++{
++ u_int32_t ip;
++ union ip_conntrack_manip_proto u;
++};
++
++/* This contains the information to distinguish a connection. */
++struct ip_conntrack_tuple
++{
++ struct ip_conntrack_manip src;
++
++ /* These are the parts of the tuple which are fixed. */
++ struct {
++ u_int32_t ip;
++ union {
++ /* Add other protocols here. */
++ u_int16_t all;
++
++ struct {
++ u_int16_t port;
++ } tcp;
++ struct {
++ u_int16_t port;
++ } udp;
++ struct {
++ u_int8_t type, code;
++ } icmp;
++ } u;
++
++ /* The protocol. */
++ u_int16_t protonum;
++ } dst;
++};
++
++/* This is optimized opposed to a memset of the whole structure. Everything we
++ * really care about is the source/destination unions */
++#define IP_CT_TUPLE_U_BLANK(tuple) \
++ do { \
++ (tuple)->src.u.all = 0; \
++ (tuple)->dst.u.all = 0; \
++ } while (0)
++
++enum ip_conntrack_dir
++{
++ IP_CT_DIR_ORIGINAL,
++ IP_CT_DIR_REPLY,
++ IP_CT_DIR_MAX
++};
++
++#ifdef __KERNEL__
++
++#define DUMP_TUPLE(tp) \
++DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
++ (tp), (tp)->dst.protonum, \
++ NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
++ NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
++
++#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
++
++/* If we're the first tuple, it's the original dir. */
++#define DIRECTION(h) ((enum ip_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
++
++/* Connections have two entries in the hash table: one for each way */
++struct ip_conntrack_tuple_hash
++{
++ struct list_head list;
++
++ struct ip_conntrack_tuple tuple;
++
++ /* this == &ctrack->tuplehash[DIRECTION(this)]. */
++ struct ip_conntrack *ctrack;
++};
++
++#endif /* __KERNEL__ */
++
++static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
++ const struct ip_conntrack_tuple *t2)
++{
++ return t1->src.ip == t2->src.ip
++ && t1->src.u.all == t2->src.u.all;
++}
++
++static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
++ const struct ip_conntrack_tuple *t2)
++{
++ return t1->dst.ip == t2->dst.ip
++ && t1->dst.u.all == t2->dst.u.all
++ && t1->dst.protonum == t2->dst.protonum;
++}
++
++static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
++ const struct ip_conntrack_tuple *t2)
++{
++ return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
++}
++
++static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
++ const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *mask)
++{
++ return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip)
++ || ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip)
++ || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all)
++ || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all)
++ || ((t->dst.protonum ^ tuple->dst.protonum)
++ & mask->dst.protonum));
++}
++
++#endif /* _IP_CONNTRACK_TUPLE_H */
+diff -uNr linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux/include/linux/netfilter_ipv4/ip_nat_pptp.h
+--- linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_nat_pptp.h 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,11 @@
++/* PPTP constants and structs */
++#ifndef _NAT_PPTP_H
++#define _NAT_PPTP_H
++
++/* conntrack private data */
++struct ip_nat_pptp {
++ u_int16_t pns_call_id; /* NAT'ed PNS call id */
++ u_int16_t pac_call_id; /* NAT'ed PAC call id */
++};
++
++#endif /* _NAT_PPTP_H */
+diff -uNr linux_org/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
+--- linux_org/net/ipv4/netfilter/Config.in 2003-08-13 19:19:30.000000000 +0200
++++ linux/net/ipv4/netfilter/Config.in 2006-10-27 14:11:52.000000000 +0200
+@@ -7,6 +7,11 @@
+ tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
+ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+ dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CONNTRACK
++ if [ "$CONFIG_IP_NF_PPTP" != "n" ]; then
++ bool ' PPTP verbose debug' CONFIG_IP_NF_PPTP_DEBUG
++ fi
+ dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
+@@ -67,6 +72,20 @@
+ fi
+ fi
+ bool ' NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
++ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PPTP m
++ else
++ if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
++ fi
++ fi
++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
++ else
++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
++ fi
++ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
+ fi
+diff -uNr linux_org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
+--- linux_org/net/ipv4/netfilter/Makefile 2003-08-13 19:19:30.000000000 +0200
++++ linux/net/ipv4/netfilter/Makefile 2006-10-27 14:11:52.000000000 +0200
+@@ -30,8 +30,21 @@
+
+ # connection tracking
+ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
++
++# connection tracking protocol helpers
++obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
++ifdef CONFIG_IP_NF_CT_PROTO_GRE
++ export-objs += ip_conntrack_proto_gre.o
++endif
++
++# NAT protocol helpers
++obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
+
+ # connection tracking helpers
++obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
++ifdef CONFIG_IP_NF_NAT_PPTP
++ export-objs += ip_conntrack_pptp.o
++endif
+ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
+ ifdef CONFIG_IP_NF_AMANDA
+ export-objs += ip_conntrack_amanda.o
+@@ -49,6 +62,7 @@
+ endif
+
+ # NAT helpers
++obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
+ obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
+ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
+ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux_org/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-24 12:14:04.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2006-10-27 14:11:52.000000000 +0200
+@@ -142,6 +142,8 @@
+ tuple->dst.ip = iph->daddr;
+ tuple->dst.protonum = iph->protocol;
+
++ tuple->src.u.all = tuple->dst.u.all = 0;
++
+ ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
+ len - 4*iph->ihl,
+ tuple);
+@@ -157,6 +159,8 @@
+ inverse->dst.ip = orig->src.ip;
+ inverse->dst.protonum = orig->dst.protonum;
+
++ inverse->src.u.all = inverse->dst.u.all = 0;
++
+ return protocol->invert_tuple(inverse, orig);
+ }
+
+@@ -945,8 +949,8 @@
+ * so there is no need to use the tuple lock too */
+
+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+- DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+- DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
++ DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
++ DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
+
+ old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
+ struct ip_conntrack_expect *, &expect->tuple,
+@@ -1063,15 +1067,14 @@
+
+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+-
+ DEBUGP("change_expect:\n");
+- DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+- DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
+- DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
++ DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
++ DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
++ DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
+ if (expect->ct_tuple.dst.protonum == 0) {
+ /* Never seen before */
+ DEBUGP("change expect: never seen before\n");
+- if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
++ if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
+ && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+ /* Force NAT to find an unused tuple */
+diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux/net/ipv4/netfilter/ip_conntrack_core.c.orig
+--- linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-11-24 12:14:04.000000000 +0100
+@@ -0,0 +1,1446 @@
++/* Connection state tracking for netfilter. This is separated from,
++ but required by, the NAT layer; it can also be used by an iptables
++ extension. */
++
++/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
++ * Public Licence.
++ *
++ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
++ * - new API and handling of conntrack/nat helpers
++ * - now capable of multiple expectations for one master
++ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
++ * - add usage/reference counts to ip_conntrack_expect
++ * - export ip_conntrack[_expect]_{find_get,put} functions
++ * */
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/ip.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#include <linux/vmalloc.h>
++#include <linux/brlock.h>
++#include <net/checksum.h>
++#include <linux/stddef.h>
++#include <linux/sysctl.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/jhash.h>
++/* For ERR_PTR(). Yeah, I know... --RR */
++#include <linux/fs.h>
++
++/* This rwlock protects the main hash table, protocol/helper/expected
++ registrations, conntrack timers*/
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
++
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#define IP_CONNTRACK_VERSION "2.1"
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++DECLARE_RWLOCK(ip_conntrack_lock);
++DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
++
++void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
++LIST_HEAD(ip_conntrack_expect_list);
++LIST_HEAD(protocol_list);
++static LIST_HEAD(helpers);
++unsigned int ip_conntrack_htable_size = 0;
++int ip_conntrack_max = 0;
++static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
++struct list_head *ip_conntrack_hash;
++static kmem_cache_t *ip_conntrack_cachep;
++
++extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
++
++static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
++ u_int8_t protocol)
++{
++ return protocol == curr->proto;
++}
++
++struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
++{
++ struct ip_conntrack_protocol *p;
++
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ p = LIST_FIND(&protocol_list, proto_cmpfn,
++ struct ip_conntrack_protocol *, protocol);
++ if (!p)
++ p = &ip_conntrack_generic_protocol;
++
++ return p;
++}
++
++struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
++{
++ struct ip_conntrack_protocol *p;
++
++ READ_LOCK(&ip_conntrack_lock);
++ p = __ip_ct_find_proto(protocol);
++ READ_UNLOCK(&ip_conntrack_lock);
++ return p;
++}
++
++inline void
++ip_conntrack_put(struct ip_conntrack *ct)
++{
++ IP_NF_ASSERT(ct);
++ IP_NF_ASSERT(ct->infos[0].master);
++ /* nf_conntrack_put wants to go via an info struct, so feed it
++ one at random. */
++ nf_conntrack_put(&ct->infos[0]);
++}
++
++static int ip_conntrack_hash_rnd_initted;
++static unsigned int ip_conntrack_hash_rnd;
++
++static u_int32_t
++hash_conntrack(const struct ip_conntrack_tuple *tuple)
++{
++#if 0
++ dump_tuple(tuple);
++#endif
++ return (jhash_3words(tuple->src.ip,
++ (tuple->dst.ip ^ tuple->dst.protonum),
++ (tuple->src.u.all | (tuple->dst.u.all << 16)),
++ ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
++}
++
++inline int
++get_tuple(const struct iphdr *iph, size_t len,
++ struct ip_conntrack_tuple *tuple,
++ struct ip_conntrack_protocol *protocol)
++{
++ int ret;
++
++ /* Never happen */
++ if (iph->frag_off & htons(IP_OFFSET)) {
++ printk("ip_conntrack_core: Frag of proto %u.\n",
++ iph->protocol);
++ return 0;
++ }
++ /* Guarantee 8 protocol bytes: if more wanted, use len param */
++ else if (iph->ihl * 4 + 8 > len)
++ return 0;
++
++ tuple->src.ip = iph->saddr;
++ tuple->dst.ip = iph->daddr;
++ tuple->dst.protonum = iph->protocol;
++
++ ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
++ len - 4*iph->ihl,
++ tuple);
++ return ret;
++}
++
++static int
++invert_tuple(struct ip_conntrack_tuple *inverse,
++ const struct ip_conntrack_tuple *orig,
++ const struct ip_conntrack_protocol *protocol)
++{
++ inverse->src.ip = orig->dst.ip;
++ inverse->dst.ip = orig->src.ip;
++ inverse->dst.protonum = orig->dst.protonum;
++
++ return protocol->invert_tuple(inverse, orig);
++}
++
++
++/* ip_conntrack_expect helper functions */
++
++/* Compare tuple parts depending on mask. */
++static inline int expect_cmp(const struct ip_conntrack_expect *i,
++ const struct ip_conntrack_tuple *tuple)
++{
++ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
++ return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
++}
++
++static void
++destroy_expect(struct ip_conntrack_expect *exp)
++{
++ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
++ IP_NF_ASSERT(atomic_read(&exp->use) == 0);
++ IP_NF_ASSERT(!timer_pending(&exp->timeout));
++
++ kfree(exp);
++}
++
++inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
++{
++ IP_NF_ASSERT(exp);
++
++ if (atomic_dec_and_test(&exp->use)) {
++ /* usage count dropped to zero */
++ destroy_expect(exp);
++ }
++}
++
++static inline struct ip_conntrack_expect *
++__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
++{
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
++ return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
++ struct ip_conntrack_expect *, tuple);
++}
++
++/* Find a expectation corresponding to a tuple. */
++struct ip_conntrack_expect *
++ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
++{
++ struct ip_conntrack_expect *exp;
++
++ READ_LOCK(&ip_conntrack_lock);
++ READ_LOCK(&ip_conntrack_expect_tuple_lock);
++ exp = __ip_ct_expect_find(tuple);
++ if (exp)
++ atomic_inc(&exp->use);
++ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ return exp;
++}
++
++/* remove one specific expectation from all lists and drop refcount,
++ * does _NOT_ delete the timer. */
++static void __unexpect_related(struct ip_conntrack_expect *expect)
++{
++ DEBUGP("unexpect_related(%p)\n", expect);
++ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
++
++ /* we're not allowed to unexpect a confirmed expectation! */
++ IP_NF_ASSERT(!expect->sibling);
++
++ /* delete from global and local lists */
++ list_del(&expect->list);
++ list_del(&expect->expected_list);
++
++ /* decrement expect-count of master conntrack */
++ if (expect->expectant)
++ expect->expectant->expecting--;
++
++ ip_conntrack_expect_put(expect);
++}
++
++/* remove one specific expecatation from all lists, drop refcount
++ * and expire timer.
++ * This function can _NOT_ be called for confirmed expects! */
++static void unexpect_related(struct ip_conntrack_expect *expect)
++{
++ IP_NF_ASSERT(expect->expectant);
++ IP_NF_ASSERT(expect->expectant->helper);
++ /* if we are supposed to have a timer, but we can't delete
++ * it: race condition. __unexpect_related will
++ * be calledd by timeout function */
++ if (expect->expectant->helper->timeout
++ && !del_timer(&expect->timeout))
++ return;
++
++ __unexpect_related(expect);
++}
++
++/* delete all unconfirmed expectations for this conntrack */
++static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
++{
++ struct list_head *exp_entry, *next;
++ struct ip_conntrack_expect *exp;
++
++ DEBUGP("remove_expectations(%p)\n", ct);
++
++ list_for_each_safe(exp_entry, next, &ct->sibling_list) {
++ exp = list_entry(exp_entry, struct ip_conntrack_expect,
++ expected_list);
++
++ /* we skip established expectations, as we want to delete
++ * the un-established ones only */
++ if (exp->sibling) {
++ DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
++ if (drop_refcount) {
++ /* Indicate that this expectations parent is dead */
++ ip_conntrack_put(exp->expectant);
++ exp->expectant = NULL;
++ }
++ continue;
++ }
++
++ IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
++ IP_NF_ASSERT(exp->expectant == ct);
++
++ /* delete expectation from global and private lists */
++ unexpect_related(exp);
++ }
++}
++
++static void
++clean_from_lists(struct ip_conntrack *ct)
++{
++ unsigned int ho, hr;
++
++ DEBUGP("clean_from_lists(%p)\n", ct);
++ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
++
++ ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++ LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
++ LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++
++ /* Destroy all un-established, pending expectations */
++ remove_expectations(ct, 1);
++}
++
++static void
++destroy_conntrack(struct nf_conntrack *nfct)
++{
++ struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
++ struct ip_conntrack_protocol *proto;
++
++ DEBUGP("destroy_conntrack(%p)\n", ct);
++ IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
++ IP_NF_ASSERT(!timer_pending(&ct->timeout));
++
++ /* To make sure we don't get any weird locking issues here:
++ * destroy_conntrack() MUST NOT be called with a write lock
++ * to ip_conntrack_lock!!! -HW */
++ proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
++ if (proto && proto->destroy)
++ proto->destroy(ct);
++
++ if (ip_conntrack_destroyed)
++ ip_conntrack_destroyed(ct);
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* Make sure don't leave any orphaned expectations lying around */
++ if (ct->expecting)
++ remove_expectations(ct, 1);
++
++ /* Delete our master expectation */
++ if (ct->master) {
++ if (ct->master->expectant) {
++ /* can't call __unexpect_related here,
++ * since it would screw up expect_list */
++ list_del(&ct->master->expected_list);
++ master = ct->master->expectant;
++ }
++ kfree(ct->master);
++ }
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ if (master)
++ ip_conntrack_put(master);
++
++ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
++ kmem_cache_free(ip_conntrack_cachep, ct);
++ atomic_dec(&ip_conntrack_count);
++}
++
++static void death_by_timeout(unsigned long ul_conntrack)
++{
++ struct ip_conntrack *ct = (void *)ul_conntrack;
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ clean_from_lists(ct);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ ip_conntrack_put(ct);
++}
++
++static inline int
++conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
++ const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack *ignored_conntrack)
++{
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ return i->ctrack != ignored_conntrack
++ && ip_ct_tuple_equal(tuple, &i->tuple);
++}
++
++static struct ip_conntrack_tuple_hash *
++__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack *ignored_conntrack)
++{
++ struct ip_conntrack_tuple_hash *h;
++ unsigned int hash = hash_conntrack(tuple);
++
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ h = LIST_FIND(&ip_conntrack_hash[hash],
++ conntrack_tuple_cmp,
++ struct ip_conntrack_tuple_hash *,
++ tuple, ignored_conntrack);
++ return h;
++}
++
++/* Find a connection corresponding to a tuple. */
++struct ip_conntrack_tuple_hash *
++ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack *ignored_conntrack)
++{
++ struct ip_conntrack_tuple_hash *h;
++
++ READ_LOCK(&ip_conntrack_lock);
++ h = __ip_conntrack_find(tuple, ignored_conntrack);
++ if (h)
++ atomic_inc(&h->ctrack->ct_general.use);
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ return h;
++}
++
++static inline struct ip_conntrack *
++__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
++{
++ struct ip_conntrack *ct
++ = (struct ip_conntrack *)nfct->master;
++
++ /* ctinfo is the index of the nfct inside the conntrack */
++ *ctinfo = nfct - ct->infos;
++ IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
++ return ct;
++}
++
++/* Return conntrack and conntrack_info given skb->nfct->master */
++struct ip_conntrack *
++ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
++{
++ if (skb->nfct)
++ return __ip_conntrack_get(skb->nfct, ctinfo);
++ return NULL;
++}
++
++/* Confirm a connection given skb->nfct; places it in hash table */
++int
++__ip_conntrack_confirm(struct nf_ct_info *nfct)
++{
++ unsigned int hash, repl_hash;
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++
++ ct = __ip_conntrack_get(nfct, &ctinfo);
++
++ /* ipt_REJECT uses ip_conntrack_attach to attach related
++ ICMP/TCP RST packets in other direction. Actual packet
++ which created connection will be IP_CT_NEW or for an
++ expected connection, IP_CT_RELATED. */
++ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
++ return NF_ACCEPT;
++
++ hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ /* We're not in hash table, and we refuse to set up related
++ connections for unconfirmed conns. But packet copies and
++ REJECT will give spurious warnings here. */
++ /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
++
++ /* No external references means noone else could have
++ confirmed us. */
++ IP_NF_ASSERT(!is_confirmed(ct));
++ DEBUGP("Confirming conntrack %p\n", ct);
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* See if there's one in the list already, including reverse:
++ NAT could have grabbed it without realizing, since we're
++ not in the hash. If there is, we lost race. */
++ if (!LIST_FIND(&ip_conntrack_hash[hash],
++ conntrack_tuple_cmp,
++ struct ip_conntrack_tuple_hash *,
++ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
++ && !LIST_FIND(&ip_conntrack_hash[repl_hash],
++ conntrack_tuple_cmp,
++ struct ip_conntrack_tuple_hash *,
++ &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
++ list_prepend(&ip_conntrack_hash[hash],
++ &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
++ list_prepend(&ip_conntrack_hash[repl_hash],
++ &ct->tuplehash[IP_CT_DIR_REPLY]);
++ /* Timer relative to confirmation time, not original
++ setting time, otherwise we'd get timer wrap in
++ weird delay cases. */
++ ct->timeout.expires += jiffies;
++ add_timer(&ct->timeout);
++ atomic_inc(&ct->ct_general.use);
++ set_bit(IPS_CONFIRMED_BIT, &ct->status);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ return NF_ACCEPT;
++ }
++
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ return NF_DROP;
++}
++
++/* Returns true if a connection correspondings to the tuple (required
++ for NAT). */
++int
++ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack *ignored_conntrack)
++{
++ struct ip_conntrack_tuple_hash *h;
++
++ READ_LOCK(&ip_conntrack_lock);
++ h = __ip_conntrack_find(tuple, ignored_conntrack);
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ return h != NULL;
++}
++
++/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
++struct ip_conntrack *
++icmp_error_track(struct sk_buff *skb,
++ enum ip_conntrack_info *ctinfo,
++ unsigned int hooknum)
++{
++ const struct iphdr *iph = skb->nh.iph;
++ struct icmphdr *hdr;
++ struct ip_conntrack_tuple innertuple, origtuple;
++ struct iphdr *inner;
++ size_t datalen;
++ struct ip_conntrack_protocol *innerproto;
++ struct ip_conntrack_tuple_hash *h;
++
++ IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
++ IP_NF_ASSERT(skb->nfct == NULL);
++
++ hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
++ inner = (struct iphdr *)(hdr + 1);
++ datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
++
++ if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) {
++ DEBUGP("icmp_error_track: too short\n");
++ return NULL;
++ }
++
++ if (hdr->type != ICMP_DEST_UNREACH
++ && hdr->type != ICMP_SOURCE_QUENCH
++ && hdr->type != ICMP_TIME_EXCEEDED
++ && hdr->type != ICMP_PARAMETERPROB
++ && hdr->type != ICMP_REDIRECT)
++ return NULL;
++
++ /* Ignore ICMP's containing fragments (shouldn't happen) */
++ if (inner->frag_off & htons(IP_OFFSET)) {
++ DEBUGP("icmp_error_track: fragment of proto %u\n",
++ inner->protocol);
++ return NULL;
++ }
++
++ /* Ignore it if the checksum's bogus. */
++ if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
++ DEBUGP("icmp_error_track: bad csum\n");
++ return NULL;
++ }
++
++ innerproto = ip_ct_find_proto(inner->protocol);
++ /* Are they talking about one of our connections? */
++ if (inner->ihl * 4 + 8 > datalen
++ || !get_tuple(inner, datalen, &origtuple, innerproto)) {
++ DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
++ inner->protocol, inner->ihl, 8,
++ datalen);
++ return NULL;
++ }
++
++ /* Ordinarily, we'd expect the inverted tupleproto, but it's
++ been preserved inside the ICMP. */
++ if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
++ DEBUGP("icmp_error_track: Can't invert tuple\n");
++ return NULL;
++ }
++
++ *ctinfo = IP_CT_RELATED;
++
++ h = ip_conntrack_find_get(&innertuple, NULL);
++ if (!h) {
++ /* Locally generated ICMPs will match inverted if they
++ haven't been SNAT'ed yet */
++ /* FIXME: NAT code has to handle half-done double NAT --RR */
++ if (hooknum == NF_IP_LOCAL_OUT)
++ h = ip_conntrack_find_get(&origtuple, NULL);
++
++ if (!h) {
++ DEBUGP("icmp_error_track: no match\n");
++ return NULL;
++ }
++ /* Reverse direction from that found */
++ if (DIRECTION(h) != IP_CT_DIR_REPLY)
++ *ctinfo += IP_CT_IS_REPLY;
++ } else {
++ if (DIRECTION(h) == IP_CT_DIR_REPLY)
++ *ctinfo += IP_CT_IS_REPLY;
++ }
++
++ /* Update skb to refer to this connection */
++ skb->nfct = &h->ctrack->infos[*ctinfo];
++ return h->ctrack;
++}
++
++/* There's a small race here where we may free a just-assured
++ connection. Too bad: we're in trouble anyway. */
++static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
++{
++ return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
++}
++
++static int early_drop(struct list_head *chain)
++{
++ /* Traverse backwards: gives us oldest, which is roughly LRU */
++ struct ip_conntrack_tuple_hash *h;
++ int dropped = 0;
++
++ READ_LOCK(&ip_conntrack_lock);
++ h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
++ if (h)
++ atomic_inc(&h->ctrack->ct_general.use);
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ if (!h)
++ return dropped;
++
++ if (del_timer(&h->ctrack->timeout)) {
++ death_by_timeout((unsigned long)h->ctrack);
++ dropped = 1;
++ }
++ ip_conntrack_put(h->ctrack);
++ return dropped;
++}
++
++static inline int helper_cmp(const struct ip_conntrack_helper *i,
++ const struct ip_conntrack_tuple *rtuple)
++{
++ return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
++}
++
++struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
++{
++ return LIST_FIND(&helpers, helper_cmp,
++ struct ip_conntrack_helper *,
++ tuple);
++}
++
++/* Allocate a new conntrack: we return -ENOMEM if classification
++ failed due to stress. Otherwise it really is unclassifiable. */
++static struct ip_conntrack_tuple_hash *
++init_conntrack(const struct ip_conntrack_tuple *tuple,
++ struct ip_conntrack_protocol *protocol,
++ struct sk_buff *skb)
++{
++ struct ip_conntrack *conntrack;
++ struct ip_conntrack_tuple repl_tuple;
++ size_t hash;
++ struct ip_conntrack_expect *expected;
++ int i;
++ static unsigned int drop_next = 0;
++
++ if (!ip_conntrack_hash_rnd_initted) {
++ get_random_bytes(&ip_conntrack_hash_rnd, 4);
++ ip_conntrack_hash_rnd_initted = 1;
++ }
++
++ hash = hash_conntrack(tuple);
++
++ if (ip_conntrack_max &&
++ atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
++ /* Try dropping from random chain, or else from the
++ chain about to put into (in case they're trying to
++ bomb one hash chain). */
++ unsigned int next = (drop_next++)%ip_conntrack_htable_size;
++
++ if (!early_drop(&ip_conntrack_hash[next])
++ && !early_drop(&ip_conntrack_hash[hash])) {
++ if (net_ratelimit())
++ printk(KERN_WARNING
++ "ip_conntrack: table full, dropping"
++ " packet.\n");
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ if (!invert_tuple(&repl_tuple, tuple, protocol)) {
++ DEBUGP("Can't invert tuple.\n");
++ return NULL;
++ }
++
++ conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
++ if (!conntrack) {
++ DEBUGP("Can't allocate conntrack.\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ memset(conntrack, 0, sizeof(*conntrack));
++ atomic_set(&conntrack->ct_general.use, 1);
++ conntrack->ct_general.destroy = destroy_conntrack;
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
++ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
++ conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
++ for (i=0; i < IP_CT_NUMBER; i++)
++ conntrack->infos[i].master = &conntrack->ct_general;
++
++ if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
++ kmem_cache_free(ip_conntrack_cachep, conntrack);
++ return NULL;
++ }
++ /* Don't set timer yet: wait for confirmation */
++ init_timer(&conntrack->timeout);
++ conntrack->timeout.data = (unsigned long)conntrack;
++ conntrack->timeout.function = death_by_timeout;
++
++ INIT_LIST_HEAD(&conntrack->sibling_list);
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* Need finding and deleting of expected ONLY if we win race */
++ READ_LOCK(&ip_conntrack_expect_tuple_lock);
++ expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
++ struct ip_conntrack_expect *, tuple);
++ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
++
++ /* If master is not in hash table yet (ie. packet hasn't left
++ this machine yet), how can other end know about expected?
++ Hence these are not the droids you are looking for (if
++ master ct never got confirmed, we'd hold a reference to it
++ and weird things would happen to future packets). */
++ if (expected && !is_confirmed(expected->expectant))
++ expected = NULL;
++
++ /* Look up the conntrack helper for master connections only */
++ if (!expected)
++ conntrack->helper = ip_ct_find_helper(&repl_tuple);
++
++ /* If the expectation is dying, then this is a looser. */
++ if (expected
++ && expected->expectant->helper->timeout
++ && ! del_timer(&expected->timeout))
++ expected = NULL;
++
++ if (expected) {
++ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
++ conntrack, expected);
++ /* Welcome, Mr. Bond. We've been expecting you... */
++ __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
++ conntrack->master = expected;
++ expected->sibling = conntrack;
++ LIST_DELETE(&ip_conntrack_expect_list, expected);
++ expected->expectant->expecting--;
++ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
++ }
++ atomic_inc(&ip_conntrack_count);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ if (expected && expected->expectfn)
++ expected->expectfn(conntrack);
++ return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
++}
++
++/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
++static inline struct ip_conntrack *
++resolve_normal_ct(struct sk_buff *skb,
++ struct ip_conntrack_protocol *proto,
++ int *set_reply,
++ unsigned int hooknum,
++ enum ip_conntrack_info *ctinfo)
++{
++ struct ip_conntrack_tuple tuple;
++ struct ip_conntrack_tuple_hash *h;
++
++ IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
++
++ if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
++ return NULL;
++
++ /* look for tuple match */
++ h = ip_conntrack_find_get(&tuple, NULL);
++ if (!h) {
++ h = init_conntrack(&tuple, proto, skb);
++ if (!h)
++ return NULL;
++ if (IS_ERR(h))
++ return (void *)h;
++ }
++
++ /* It exists; we have (non-exclusive) reference. */
++ if (DIRECTION(h) == IP_CT_DIR_REPLY) {
++ *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
++ /* Please set reply bit if this packet OK */
++ *set_reply = 1;
++ } else {
++ /* Once we've had two way comms, always ESTABLISHED. */
++ if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
++ DEBUGP("ip_conntrack_in: normal packet for %p\n",
++ h->ctrack);
++ *ctinfo = IP_CT_ESTABLISHED;
++ } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
++ DEBUGP("ip_conntrack_in: related packet for %p\n",
++ h->ctrack);
++ *ctinfo = IP_CT_RELATED;
++ } else {
++ DEBUGP("ip_conntrack_in: new packet for %p\n",
++ h->ctrack);
++ *ctinfo = IP_CT_NEW;
++ }
++ *set_reply = 0;
++ }
++ skb->nfct = &h->ctrack->infos[*ctinfo];
++ return h->ctrack;
++}
++
++/* Netfilter hook itself. */
++unsigned int ip_conntrack_in(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack_protocol *proto;
++ int set_reply;
++ int ret;
++
++ /* FIXME: Do this right please. --RR */
++ (*pskb)->nfcache |= NFC_UNKNOWN;
++
++/* Doesn't cover locally-generated broadcast, so not worth it. */
++#if 0
++ /* Ignore broadcast: no `connection'. */
++ if ((*pskb)->pkt_type == PACKET_BROADCAST) {
++ printk("Broadcast packet!\n");
++ return NF_ACCEPT;
++ } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
++ == htonl(0x000000FF)) {
++ printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
++ NIPQUAD((*pskb)->nh.iph->saddr),
++ NIPQUAD((*pskb)->nh.iph->daddr),
++ (*pskb)->sk, (*pskb)->pkt_type);
++ }
++#endif
++
++ /* Previously seen (loopback)? Ignore. Do this before
++ fragment check. */
++ if ((*pskb)->nfct)
++ return NF_ACCEPT;
++
++ /* Gather fragments. */
++ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
++ *pskb = ip_ct_gather_frags(*pskb);
++ if (!*pskb)
++ return NF_STOLEN;
++ }
++
++ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
++
++ /* It may be an icmp error... */
++ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
++ && icmp_error_track(*pskb, &ctinfo, hooknum))
++ return NF_ACCEPT;
++
++ if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
++ /* Not valid part of a connection */
++ return NF_ACCEPT;
++
++ if (IS_ERR(ct))
++ /* Too stressed to deal. */
++ return NF_DROP;
++
++ IP_NF_ASSERT((*pskb)->nfct);
++
++ ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
++ if (ret == -1) {
++ /* Invalid */
++ nf_conntrack_put((*pskb)->nfct);
++ (*pskb)->nfct = NULL;
++ return NF_ACCEPT;
++ }
++
++ if (ret != NF_DROP && ct->helper) {
++ ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
++ ct, ctinfo);
++ if (ret == -1) {
++ /* Invalid */
++ nf_conntrack_put((*pskb)->nfct);
++ (*pskb)->nfct = NULL;
++ return NF_ACCEPT;
++ }
++ }
++ if (set_reply)
++ set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
++
++ return ret;
++}
++
++int invert_tuplepr(struct ip_conntrack_tuple *inverse,
++ const struct ip_conntrack_tuple *orig)
++{
++ return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
++}
++
++static inline int resent_expect(const struct ip_conntrack_expect *i,
++ const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *mask)
++{
++ DEBUGP("resent_expect\n");
++ DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
++ DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
++ DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
++ return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
++ || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
++ && ip_ct_tuple_equal(&i->mask, mask));
++}
++
++/* Would two expected things clash? */
++static inline int expect_clash(const struct ip_conntrack_expect *i,
++ const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *mask)
++{
++ /* Part covered by intersection of masks must be unequal,
++ otherwise they clash */
++ struct ip_conntrack_tuple intersect_mask
++ = { { i->mask.src.ip & mask->src.ip,
++ { i->mask.src.u.all & mask->src.u.all } },
++ { i->mask.dst.ip & mask->dst.ip,
++ { i->mask.dst.u.all & mask->dst.u.all },
++ i->mask.dst.protonum & mask->dst.protonum } };
++
++ return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
++}
++
++inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
++{
++ WRITE_LOCK(&ip_conntrack_lock);
++ unexpect_related(expect);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++}
++
++static void expectation_timed_out(unsigned long ul_expect)
++{
++ struct ip_conntrack_expect *expect = (void *) ul_expect;
++
++ DEBUGP("expectation %p timed out\n", expect);
++ WRITE_LOCK(&ip_conntrack_lock);
++ __unexpect_related(expect);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++}
++
++/* Add a related connection. */
++int ip_conntrack_expect_related(struct ip_conntrack *related_to,
++ struct ip_conntrack_expect *expect)
++{
++ struct ip_conntrack_expect *old, *new;
++ int ret = 0;
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* Because of the write lock, no reader can walk the lists,
++ * so there is no need to use the tuple lock too */
++
++ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
++ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
++ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
++
++ old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
++ struct ip_conntrack_expect *, &expect->tuple,
++ &expect->mask);
++ if (old) {
++ /* Helper private data may contain offsets but no pointers
++ pointing into the payload - otherwise we should have to copy
++ the data filled out by the helper over the old one */
++ DEBUGP("expect_related: resent packet\n");
++ if (related_to->helper->timeout) {
++ if (!del_timer(&old->timeout)) {
++ /* expectation is dying. Fall through */
++ old = NULL;
++ } else {
++ old->timeout.expires = jiffies +
++ related_to->helper->timeout * HZ;
++ add_timer(&old->timeout);
++ }
++ }
++
++ if (old) {
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ return -EEXIST;
++ }
++ } else if (related_to->helper->max_expected &&
++ related_to->expecting >= related_to->helper->max_expected) {
++ /* old == NULL */
++ if (!(related_to->helper->flags &
++ IP_CT_HELPER_F_REUSE_EXPECT)) {
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ if (net_ratelimit())
++ printk(KERN_WARNING
++ "ip_conntrack: max number of expected "
++ "connections %i of %s reached for "
++ "%u.%u.%u.%u->%u.%u.%u.%u\n",
++ related_to->helper->max_expected,
++ related_to->helper->name,
++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
++ return -EPERM;
++ }
++ DEBUGP("ip_conntrack: max number of expected "
++ "connections %i of %s reached for "
++ "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
++ related_to->helper->max_expected,
++ related_to->helper->name,
++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
++
++ /* choose the the oldest expectation to evict */
++ list_for_each_entry(old, &related_to->sibling_list,
++ expected_list)
++ if (old->sibling == NULL)
++ break;
++
++ /* We cannot fail since related_to->expecting is the number
++ * of unconfirmed expectations */
++ IP_NF_ASSERT(old && old->sibling == NULL);
++
++ /* newnat14 does not reuse the real allocated memory
++ * structures but rather unexpects the old and
++ * allocates a new. unexpect_related will decrement
++ * related_to->expecting.
++ */
++ unexpect_related(old);
++ ret = -EPERM;
++ } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
++ struct ip_conntrack_expect *, &expect->tuple,
++ &expect->mask)) {
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ DEBUGP("expect_related: busy!\n");
++ return -EBUSY;
++ }
++
++ new = (struct ip_conntrack_expect *)
++ kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
++ if (!new) {
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ DEBUGP("expect_relaed: OOM allocating expect\n");
++ return -ENOMEM;
++ }
++
++ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
++ memcpy(new, expect, sizeof(*expect));
++ new->expectant = related_to;
++ new->sibling = NULL;
++ atomic_set(&new->use, 1);
++
++ /* add to expected list for this connection */
++ list_add_tail(&new->expected_list, &related_to->sibling_list);
++ /* add to global list of expectations */
++ list_prepend(&ip_conntrack_expect_list, &new->list);
++ /* add and start timer if required */
++ if (related_to->helper->timeout) {
++ init_timer(&new->timeout);
++ new->timeout.data = (unsigned long)new;
++ new->timeout.function = expectation_timed_out;
++ new->timeout.expires = jiffies +
++ related_to->helper->timeout * HZ;
++ add_timer(&new->timeout);
++ }
++ related_to->expecting++;
++
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return ret;
++}
++
++/* Change tuple in an existing expectation */
++int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
++ struct ip_conntrack_tuple *newtuple)
++{
++ int ret;
++
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
++
++ DEBUGP("change_expect:\n");
++ DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
++ DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
++ DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
++ if (expect->ct_tuple.dst.protonum == 0) {
++ /* Never seen before */
++ DEBUGP("change expect: never seen before\n");
++ if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
++ && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
++ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
++ /* Force NAT to find an unused tuple */
++ ret = -1;
++ } else {
++ memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
++ memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
++ ret = 0;
++ }
++ } else {
++ /* Resent packet */
++ DEBUGP("change expect: resent packet\n");
++ if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
++ ret = 0;
++ } else {
++ /* Force NAT to choose again the same port */
++ ret = -1;
++ }
++ }
++ WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
++
++ return ret;
++}
++
++/* Alter reply tuple (maybe alter helper). If it's already taken,
++ return 0 and don't do alteration. */
++int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
++ const struct ip_conntrack_tuple *newreply)
++{
++ WRITE_LOCK(&ip_conntrack_lock);
++ if (__ip_conntrack_find(newreply, conntrack)) {
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ return 0;
++ }
++ /* Should be unconfirmed, so not in hash table yet */
++ IP_NF_ASSERT(!is_confirmed(conntrack));
++
++ DEBUGP("Altering reply tuple of %p to ", conntrack);
++ DUMP_TUPLE(newreply);
++
++ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
++ if (!conntrack->master && list_empty(&conntrack->sibling_list))
++ conntrack->helper = ip_ct_find_helper(newreply);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return 1;
++}
++
++int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
++{
++ MOD_INC_USE_COUNT;
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ list_prepend(&helpers, me);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return 0;
++}
++
++static inline int unhelp(struct ip_conntrack_tuple_hash *i,
++ const struct ip_conntrack_helper *me)
++{
++ if (i->ctrack->helper == me) {
++ /* Get rid of any expected. */
++ remove_expectations(i->ctrack, 0);
++ /* And *then* set helper to NULL */
++ i->ctrack->helper = NULL;
++ }
++ return 0;
++}
++
++void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
++{
++ unsigned int i;
++
++ /* Need write lock here, to delete helper. */
++ WRITE_LOCK(&ip_conntrack_lock);
++ LIST_DELETE(&helpers, me);
++
++ /* Get rid of expecteds, set helpers to NULL. */
++ for (i = 0; i < ip_conntrack_htable_size; i++)
++ LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
++ struct ip_conntrack_tuple_hash *, me);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ /* Someone could be still looking at the helper in a bh. */
++ br_write_lock_bh(BR_NETPROTO_LOCK);
++ br_write_unlock_bh(BR_NETPROTO_LOCK);
++
++ MOD_DEC_USE_COUNT;
++}
++
++/* Refresh conntrack for this many jiffies. */
++void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
++{
++ IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* If not in hash table, timer will not be active yet */
++ if (!is_confirmed(ct))
++ ct->timeout.expires = extra_jiffies;
++ else {
++ /* Need del_timer for race avoidance (may already be dying). */
++ if (del_timer(&ct->timeout)) {
++ ct->timeout.expires = jiffies + extra_jiffies;
++ add_timer(&ct->timeout);
++ }
++ }
++ WRITE_UNLOCK(&ip_conntrack_lock);
++}
++
++/* Returns new sk_buff, or NULL */
++struct sk_buff *
++ip_ct_gather_frags(struct sk_buff *skb)
++{
++ struct sock *sk = skb->sk;
++#ifdef CONFIG_NETFILTER_DEBUG
++ unsigned int olddebug = skb->nf_debug;
++#endif
++ if (sk) {
++ sock_hold(sk);
++ skb_orphan(skb);
++ }
++
++ local_bh_disable();
++ skb = ip_defrag(skb);
++ local_bh_enable();
++
++ if (!skb) {
++ if (sk) sock_put(sk);
++ return skb;
++ } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
++ kfree_skb(skb);
++ if (sk) sock_put(sk);
++ return NULL;
++ }
++
++ if (sk) {
++ skb_set_owner_w(skb, sk);
++ sock_put(sk);
++ }
++
++ ip_send_check(skb->nh.iph);
++ skb->nfcache |= NFC_ALTERED;
++#ifdef CONFIG_NETFILTER_DEBUG
++ /* Packet path as if nothing had happened. */
++ skb->nf_debug = olddebug;
++#endif
++ return skb;
++}
++
++/* Used by ipt_REJECT. */
++static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
++{
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++
++ ct = __ip_conntrack_get(nfct, &ctinfo);
++
++ /* This ICMP is in reverse direction to the packet which
++ caused it */
++ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
++ ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
++ else
++ ctinfo = IP_CT_RELATED;
++
++ /* Attach new skbuff, and increment count */
++ nskb->nfct = &ct->infos[ctinfo];
++ atomic_inc(&ct->ct_general.use);
++}
++
++static inline int
++do_kill(const struct ip_conntrack_tuple_hash *i,
++ int (*kill)(const struct ip_conntrack *i, void *data),
++ void *data)
++{
++ return kill(i->ctrack, data);
++}
++
++/* Bring out ya dead! */
++static struct ip_conntrack_tuple_hash *
++get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
++ void *data, unsigned int *bucket)
++{
++ struct ip_conntrack_tuple_hash *h = NULL;
++
++ READ_LOCK(&ip_conntrack_lock);
++ for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
++ h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
++ struct ip_conntrack_tuple_hash *, kill, data);
++ }
++ if (h)
++ atomic_inc(&h->ctrack->ct_general.use);
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ return h;
++}
++
++void
++ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
++ void *data)
++{
++ struct ip_conntrack_tuple_hash *h;
++ unsigned int bucket = 0;
++
++ while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
++ /* Time to push up daises... */
++ if (del_timer(&h->ctrack->timeout))
++ death_by_timeout((unsigned long)h->ctrack);
++ /* ... else the timer will get him soon. */
++
++ ip_conntrack_put(h->ctrack);
++ }
++}
++
++/* Fast function for those who don't want to parse /proc (and I don't
++ blame them). */
++/* Reversing the socket's dst/src point of view gives us the reply
++ mapping. */
++static int
++getorigdst(struct sock *sk, int optval, void *user, int *len)
++{
++ struct ip_conntrack_tuple_hash *h;
++ struct ip_conntrack_tuple tuple;
++
++ IP_CT_TUPLE_U_BLANK(&tuple);
++ tuple.src.ip = sk->rcv_saddr;
++ tuple.src.u.tcp.port = sk->sport;
++ tuple.dst.ip = sk->daddr;
++ tuple.dst.u.tcp.port = sk->dport;
++ tuple.dst.protonum = IPPROTO_TCP;
++
++ /* We only do TCP at the moment: is there a better way? */
++ if (strcmp(sk->prot->name, "TCP") != 0) {
++ DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
++ return -ENOPROTOOPT;
++ }
++
++ if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
++ DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
++ *len, sizeof(struct sockaddr_in));
++ return -EINVAL;
++ }
++
++ h = ip_conntrack_find_get(&tuple, NULL);
++ if (h) {
++ struct sockaddr_in sin;
++
++ sin.sin_family = AF_INET;
++ sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.u.tcp.port;
++ sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.ip;
++
++ DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
++ NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
++ ip_conntrack_put(h->ctrack);
++ if (copy_to_user(user, &sin, sizeof(sin)) != 0)
++ return -EFAULT;
++ else
++ return 0;
++ }
++ DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
++ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
++ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
++ return -ENOENT;
++}
++
++static struct nf_sockopt_ops so_getorigdst
++= { { NULL, NULL }, PF_INET,
++ 0, 0, NULL, /* Setsockopts */
++ SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,
++ 0, NULL };
++
++static int kill_all(const struct ip_conntrack *i, void *data)
++{
++ return 1;
++}
++
++/* Mishearing the voices in his head, our hero wonders how he's
++ supposed to kill the mall. */
++void ip_conntrack_cleanup(void)
++{
++ ip_ct_attach = NULL;
++ /* This makes sure all current packets have passed through
++ netfilter framework. Roll on, two-stage module
++ delete... */
++ br_write_lock_bh(BR_NETPROTO_LOCK);
++ br_write_unlock_bh(BR_NETPROTO_LOCK);
++
++ i_see_dead_people:
++ ip_ct_selective_cleanup(kill_all, NULL);
++ if (atomic_read(&ip_conntrack_count) != 0) {
++ schedule();
++ goto i_see_dead_people;
++ }
++
++ kmem_cache_destroy(ip_conntrack_cachep);
++ vfree(ip_conntrack_hash);
++ nf_unregister_sockopt(&so_getorigdst);
++}
++
++static int hashsize = 0;
++MODULE_PARM(hashsize, "i");
++
++int __init ip_conntrack_init(void)
++{
++ unsigned int i;
++ int ret;
++
++ /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
++ * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
++ if (hashsize) {
++ ip_conntrack_htable_size = hashsize;
++ } else {
++ ip_conntrack_htable_size
++ = (((num_physpages << PAGE_SHIFT) / 16384)
++ / sizeof(struct list_head));
++ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
++ ip_conntrack_htable_size = 8192;
++ if (ip_conntrack_htable_size < 16)
++ ip_conntrack_htable_size = 16;
++ }
++ ip_conntrack_max = 8 * ip_conntrack_htable_size;
++
++ printk("ip_conntrack version %s (%u buckets, %d max)"
++ " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
++ ip_conntrack_htable_size, ip_conntrack_max,
++ sizeof(struct ip_conntrack));
++
++ ret = nf_register_sockopt(&so_getorigdst);
++ if (ret != 0) {
++ printk(KERN_ERR "Unable to register netfilter socket option\n");
++ return ret;
++ }
++
++ ip_conntrack_hash = vmalloc(sizeof(struct list_head)
++ * ip_conntrack_htable_size);
++ if (!ip_conntrack_hash) {
++ printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
++ goto err_unreg_sockopt;
++ }
++
++ ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
++ sizeof(struct ip_conntrack), 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (!ip_conntrack_cachep) {
++ printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
++ goto err_free_hash;
++ }
++ /* Don't NEED lock here, but good form anyway. */
++ WRITE_LOCK(&ip_conntrack_lock);
++ /* Sew in builtin protocols. */
++ list_append(&protocol_list, &ip_conntrack_protocol_tcp);
++ list_append(&protocol_list, &ip_conntrack_protocol_udp);
++ list_append(&protocol_list, &ip_conntrack_protocol_icmp);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ for (i = 0; i < ip_conntrack_htable_size; i++)
++ INIT_LIST_HEAD(&ip_conntrack_hash[i]);
++
++ /* For use by ipt_REJECT */
++ ip_ct_attach = ip_conntrack_attach;
++ return ret;
++
++err_free_hash:
++ vfree(ip_conntrack_hash);
++err_unreg_sockopt:
++ nf_unregister_sockopt(&so_getorigdst);
++
++ return -ENOMEM;
++}
+diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c linux/net/ipv4/netfilter/ip_conntrack_pptp.c
+--- linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_pptp.c 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,637 @@
++/*
++ * ip_conntrack_pptp.c - Version 1.9
++ *
++ * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
++ * PPTP is a a protocol for creating virtual private networks.
++ * It is a specification defined by Microsoft and some vendors
++ * working with Microsoft. PPTP is built on top of a modified
++ * version of the Internet Generic Routing Encapsulation Protocol.
++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
++ * PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ * Limitations:
++ * - We blindly assume that control connections are always
++ * established in PNS->PAC direction. This is a violation
++ * of RFFC2673
++ *
++ * TODO: - finish support for multiple calls within one session
++ * (needs expect reservations in newnat)
++ * - testing of incoming PPTP calls
++ *
++ * Changes:
++ * 2002-02-05 - Version 1.3
++ * - Call ip_conntrack_unexpect_related() from
++ * pptp_timeout_related() to destroy expectations in case
++ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
++ * (Philip Craig <philipc@snapgear.com>)
++ * - Add Version information at module loadtime
++ * 2002-02-10 - Version 1.6
++ * - move to C99 style initializers
++ * - remove second expectation if first arrives
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++#define IP_CT_PPTP_VERSION "1.9"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
++
++DECLARE_LOCK(ip_pptp_lock);
++
++#if 0
++#include "ip_conntrack_pptp_priv.h"
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define SECS *HZ
++#define MINS * 60 SECS
++#define HOURS * 60 MINS
++#define DAYS * 24 HOURS
++
++#define PPTP_GRE_TIMEOUT (10 MINS)
++#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
++
++static int pptp_expectfn(struct ip_conntrack *ct)
++{
++ struct ip_conntrack *master;
++ struct ip_conntrack_expect *exp;
++
++ DEBUGP("increasing timeouts\n");
++ /* increase timeout of GRE data channel conntrack entry */
++ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
++ ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
++
++ master = master_ct(ct);
++ if (!master) {
++ DEBUGP(" no master!!!\n");
++ return 0;
++ }
++
++ exp = ct->master;
++ if (!exp) {
++ DEBUGP("no expectation!!\n");
++ return 0;
++ }
++
++ DEBUGP("completing tuples with ct info\n");
++ /* we can do this, since we're unconfirmed */
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(master->help.ct_pptp_info.pac_call_id)) {
++ /* assume PNS->PAC */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(master->help.ct_pptp_info.pns_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(master->help.ct_pptp_info.pns_call_id);
++ } else {
++ /* assume PAC->PNS */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(master->help.ct_pptp_info.pac_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(master->help.ct_pptp_info.pac_call_id);
++ }
++
++ /* delete other expectation */
++ if (exp->expected_list.next != &exp->expected_list) {
++ struct ip_conntrack_expect *other_exp;
++ struct list_head *cur_item, *next;
++
++ for (cur_item = master->sibling_list.next;
++ cur_item != &master->sibling_list; cur_item = next) {
++ next = cur_item->next;
++ other_exp = list_entry(cur_item,
++ struct ip_conntrack_expect,
++ expected_list);
++ /* remove only if occurred at same sequence number */
++ if (other_exp != exp && other_exp->seq == exp->seq) {
++ DEBUGP("unexpecting other direction\n");
++ ip_ct_gre_keymap_destroy(other_exp);
++ ip_conntrack_unexpect_related(other_exp);
++ }
++ }
++ }
++
++ return 0;
++}
++
++/* timeout GRE data connections */
++static int pptp_timeout_related(struct ip_conntrack *ct)
++{
++ struct list_head *cur_item, *next;
++ struct ip_conntrack_expect *exp;
++
++ /* FIXME: do we have to lock something ? */
++ for (cur_item = ct->sibling_list.next;
++ cur_item != &ct->sibling_list; cur_item = next) {
++ next = cur_item->next;
++ exp = list_entry(cur_item, struct ip_conntrack_expect,
++ expected_list);
++
++ ip_ct_gre_keymap_destroy(exp);
++ if (!exp->sibling) {
++ ip_conntrack_unexpect_related(exp);
++ continue;
++ }
++
++ DEBUGP("setting timeout of conntrack %p to 0\n",
++ exp->sibling);
++ exp->sibling->proto.gre.timeout = 0;
++ exp->sibling->proto.gre.stream_timeout = 0;
++ ip_ct_refresh(exp->sibling, 0);
++ }
++
++ return 0;
++}
++
++/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
++static inline int
++exp_gre(struct ip_conntrack *master,
++ u_int32_t seq,
++ u_int16_t callid,
++ u_int16_t peer_callid)
++{
++ struct ip_conntrack_expect exp;
++ struct ip_conntrack_tuple inv_tuple;
++
++ memset(&exp, 0, sizeof(exp));
++ /* tuple in original direction, PNS->PAC */
++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
++ exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
++ exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
++ exp.tuple.dst.protonum = IPPROTO_GRE;
++
++ exp.mask.src.ip = 0xffffffff;
++ exp.mask.src.u.all = 0;
++ exp.mask.dst.u.all = 0;
++ exp.mask.dst.u.gre.key = 0xffffffff;
++ exp.mask.dst.u.gre.version = 0xff;
++ exp.mask.dst.u.gre.protocol = 0xffff;
++ exp.mask.dst.ip = 0xffffffff;
++ exp.mask.dst.protonum = 0xffff;
++
++ exp.seq = seq;
++ exp.expectfn = pptp_expectfn;
++
++ exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
++ exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
++
++ DEBUGP("calling expect_related ");
++ DUMP_TUPLE_RAW(&exp.tuple);
++
++ /* Add GRE keymap entries */
++ if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
++ return 1;
++
++ invert_tuplepr(&inv_tuple, &exp.tuple);
++ if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
++ ip_ct_gre_keymap_destroy(&exp);
++ return 1;
++ }
++
++ if (ip_conntrack_expect_related(master, &exp) != 0) {
++ ip_ct_gre_keymap_destroy(&exp);
++ DEBUGP("cannot expect_related()\n");
++ return 1;
++ }
++
++ /* tuple in reply direction, PAC->PNS */
++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ exp.tuple.src.u.gre.key = htonl(ntohs(callid));
++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
++
++ DEBUGP("calling expect_related ");
++ DUMP_TUPLE_RAW(&exp.tuple);
++
++ /* Add GRE keymap entries */
++ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
++ invert_tuplepr(&inv_tuple, &exp.tuple);
++ ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
++ /* FIXME: cannot handle error correctly, since we need to free
++ * the above keymap :( */
++
++ if (ip_conntrack_expect_related(master, &exp) != 0) {
++ /* free the second pair of keypmaps */
++ ip_ct_gre_keymap_destroy(&exp);
++ DEBUGP("cannot expect_related():\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++static inline int
++pptp_inbound_pkt(struct tcphdr *tcph,
++ struct pptp_pkt_hdr *pptph,
++ size_t datalen,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++ u_int16_t msg, *cid, *pcid;
++ u_int32_t seq;
++
++ ctlh = (struct PptpControlHeader *)
++ ((char *) pptph + sizeof(struct pptp_pkt_hdr));
++ pptpReq.rawreq = (void *)
++ ((char *) ctlh + sizeof(struct PptpControlHeader));
++
++ msg = ntohs(ctlh->messageType);
++ DEBUGP("inbound control message %s\n", strMName[msg]);
++
++ switch (msg) {
++ case PPTP_START_SESSION_REPLY:
++ /* server confirms new control session */
++ if (info->sstate < PPTP_SESSION_REQUESTED) {
++ DEBUGP("%s without START_SESS_REQUEST\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.srep->resultCode == PPTP_START_OK)
++ info->sstate = PPTP_SESSION_CONFIRMED;
++ else
++ info->sstate = PPTP_SESSION_ERROR;
++ break;
++
++ case PPTP_STOP_SESSION_REPLY:
++ /* server confirms end of control session */
++ if (info->sstate > PPTP_SESSION_STOPREQ) {
++ DEBUGP("%s without STOP_SESS_REQUEST\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.strep->resultCode == PPTP_STOP_OK)
++ info->sstate = PPTP_SESSION_NONE;
++ else
++ info->sstate = PPTP_SESSION_ERROR;
++ break;
++
++ case PPTP_OUT_CALL_REPLY:
++ /* server accepted call, we now expect GRE frames */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ if (info->cstate != PPTP_CALL_OUT_REQ &&
++ info->cstate != PPTP_CALL_OUT_CONF) {
++ DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
++ break;
++ }
++ if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
++ info->cstate = PPTP_CALL_NONE;
++ break;
++ }
++
++ cid = &pptpReq.ocack->callID;
++ pcid = &pptpReq.ocack->peersCallID;
++
++ info->pac_call_id = ntohs(*cid);
++
++ if (htons(info->pns_call_id) != *pcid) {
++ DEBUGP("%s for unknown callid %u\n",
++ strMName[msg], ntohs(*pcid));
++ break;
++ }
++
++ DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
++ ntohs(*cid), ntohs(*pcid));
++
++ info->cstate = PPTP_CALL_OUT_CONF;
++
++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
++ if (exp_gre(ct, seq, *cid, *pcid) != 0)
++ printk("ip_conntrack_pptp: error during exp_gre\n");
++ break;
++
++ case PPTP_IN_CALL_REQUEST:
++ /* server tells us about incoming call request */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ pcid = &pptpReq.icack->peersCallID;
++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
++ info->cstate = PPTP_CALL_IN_REQ;
++ info->pac_call_id= ntohs(*pcid);
++ break;
++
++ case PPTP_IN_CALL_CONNECT:
++ /* server tells us about incoming call established */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ if (info->sstate != PPTP_CALL_IN_REP
++ && info->sstate != PPTP_CALL_IN_CONF) {
++ DEBUGP("%s but never sent IN_CALL_REPLY\n",
++ strMName[msg]);
++ break;
++ }
++
++ pcid = &pptpReq.iccon->peersCallID;
++ cid = &info->pac_call_id;
++
++ if (info->pns_call_id != ntohs(*pcid)) {
++ DEBUGP("%s for unknown CallID %u\n",
++ strMName[msg], ntohs(*cid));
++ break;
++ }
++
++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
++ info->cstate = PPTP_CALL_IN_CONF;
++
++ /* we expect a GRE connection from PAC to PNS */
++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
++ if (exp_gre(ct, seq, *cid, *pcid) != 0)
++ printk("ip_conntrack_pptp: error during exp_gre\n");
++
++ break;
++
++ case PPTP_CALL_DISCONNECT_NOTIFY:
++ /* server confirms disconnect */
++ cid = &pptpReq.disc->callID;
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
++ info->cstate = PPTP_CALL_NONE;
++
++ /* untrack this call id, unexpect GRE packets */
++ pptp_timeout_related(ct);
++ break;
++
++ case PPTP_WAN_ERROR_NOTIFY:
++ break;
++
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* I don't have to explain these ;) */
++ break;
++ default:
++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
++ ? strMName[msg]:strMName[0], msg);
++ break;
++ }
++
++ return NF_ACCEPT;
++
++}
++
++static inline int
++pptp_outbound_pkt(struct tcphdr *tcph,
++ struct pptp_pkt_hdr *pptph,
++ size_t datalen,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++ u_int16_t msg, *cid, *pcid;
++
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ msg = ntohs(ctlh->messageType);
++ DEBUGP("outbound control message %s\n", strMName[msg]);
++
++ switch (msg) {
++ case PPTP_START_SESSION_REQUEST:
++ /* client requests for new control session */
++ if (info->sstate != PPTP_SESSION_NONE) {
++ DEBUGP("%s but we already have one",
++ strMName[msg]);
++ }
++ info->sstate = PPTP_SESSION_REQUESTED;
++ break;
++ case PPTP_STOP_SESSION_REQUEST:
++ /* client requests end of control session */
++ info->sstate = PPTP_SESSION_STOPREQ;
++ break;
++
++ case PPTP_OUT_CALL_REQUEST:
++ /* client initiating connection to server */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n",
++ strMName[msg]);
++ break;
++ }
++ info->cstate = PPTP_CALL_OUT_REQ;
++ /* track PNS call id */
++ cid = &pptpReq.ocreq->callID;
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
++ info->pns_call_id = ntohs(*cid);
++ break;
++ case PPTP_IN_CALL_REPLY:
++ /* client answers incoming call */
++ if (info->cstate != PPTP_CALL_IN_REQ
++ && info->cstate != PPTP_CALL_IN_REP) {
++ DEBUGP("%s without incall_req\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
++ info->cstate = PPTP_CALL_NONE;
++ break;
++ }
++ pcid = &pptpReq.icack->peersCallID;
++ if (info->pac_call_id != ntohs(*pcid)) {
++ DEBUGP("%s for unknown call %u\n",
++ strMName[msg], ntohs(*pcid));
++ break;
++ }
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
++ /* part two of the three-way handshake */
++ info->cstate = PPTP_CALL_IN_REP;
++ info->pns_call_id = ntohs(pptpReq.icack->callID);
++ break;
++
++ case PPTP_CALL_CLEAR_REQUEST:
++ /* client requests hangup of call */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("CLEAR_CALL but no session\n");
++ break;
++ }
++ /* FUTURE: iterate over all calls and check if
++ * call ID is valid. We don't do this without newnat,
++ * because we only know about last call */
++ info->cstate = PPTP_CALL_CLEAR_REQ;
++ break;
++ case PPTP_SET_LINK_INFO:
++ break;
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* I don't have to explain these ;) */
++ break;
++ default:
++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
++ strMName[msg]:strMName[0], msg);
++ /* unknown: no need to create GRE masq table entry */
++ break;
++ }
++
++ return NF_ACCEPT;
++}
++
++
++/* track caller id inside control connection, call expect_related */
++static int
++conntrack_pptp_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++
++{
++ struct pptp_pkt_hdr *pptph;
++
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ void *datalimit;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++
++ int oldsstate, oldcstate;
++ int ret;
++
++ /* don't do any tracking before tcp handshake complete */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
++ DEBUGP("ctinfo = %u, skipping\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* not a complete TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
++ DEBUGP("tcplen = %u\n", tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* checksum invalid? */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *) tcph, tcplen, 0))) {
++ printk(KERN_NOTICE __FILE__ ": bad csum\n");
++ /* W2K PPTP server sends TCP packets with wrong checksum :(( */
++ //return NF_ACCEPT;
++ }
++
++ if (tcph->fin || tcph->rst) {
++ DEBUGP("RST/FIN received, timeouting GRE\n");
++ /* can't do this after real newnat */
++ info->cstate = PPTP_CALL_NONE;
++
++ /* untrack this call id, unexpect GRE packets */
++ pptp_timeout_related(ct);
++ }
++
++
++ pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
++ datalimit = (void *) pptph + datalen;
++
++ /* not a full pptp packet header? */
++ if ((void *) pptph+sizeof(*pptph) >= datalimit) {
++ DEBUGP("no full PPTP header, can't track\n");
++ return NF_ACCEPT;
++ }
++
++ /* if it's not a control message we can't do anything with it */
++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
++ DEBUGP("not a control packet\n");
++ return NF_ACCEPT;
++ }
++
++ oldsstate = info->sstate;
++ oldcstate = info->cstate;
++
++ LOCK_BH(&ip_pptp_lock);
++
++ /* FIXME: We just blindly assume that the control connection is always
++ * established from PNS->PAC. However, RFC makes no guarantee */
++ if (dir == IP_CT_DIR_ORIGINAL)
++ /* client -> server (PNS -> PAC) */
++ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
++ else
++ /* server -> client (PAC -> PNS) */
++ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
++ DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
++ oldsstate, info->sstate, oldcstate, info->cstate);
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return ret;
++}
++
++/* control protocol helper */
++static struct ip_conntrack_helper pptp = {
++ .list = { NULL, NULL },
++ .name = "pptp",
++ .flags = IP_CT_HELPER_F_REUSE_EXPECT,
++ .me = THIS_MODULE,
++ .max_expected = 2,
++ .timeout = 0,
++ .tuple = { .src = { .ip = 0,
++ .u = { .tcp = { .port =
++ __constant_htons(PPTP_CONTROL_PORT) } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = IPPROTO_TCP
++ }
++ },
++ .mask = { .src = { .ip = 0,
++ .u = { .tcp = { .port = 0xffff } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = 0xffff
++ }
++ },
++ .help = conntrack_pptp_help
++};
++
++/* ip_conntrack_pptp initialization */
++static int __init init(void)
++{
++ int retcode;
++
++ DEBUGP(__FILE__ ": registering helper\n");
++ if ((retcode = ip_conntrack_helper_register(&pptp))) {
++ printk(KERN_ERR "Unable to register conntrack application "
++ "helper for pptp: %d\n", retcode);
++ return -EIO;
++ }
++
++ printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip_conntrack_helper_unregister(&pptp);
++ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
++
++EXPORT_SYMBOL(ip_pptp_lock);
+diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
+--- linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,24 @@
++#ifndef _IP_CT_PPTP_PRIV_H
++#define _IP_CT_PPTP_PRIV_H
++
++/* PptpControlMessageType names */
++static const char *strMName[] = {
++ "UNKNOWN_MESSAGE",
++ "START_SESSION_REQUEST",
++ "START_SESSION_REPLY",
++ "STOP_SESSION_REQUEST",
++ "STOP_SESSION_REPLY",
++ "ECHO_REQUEST",
++ "ECHO_REPLY",
++ "OUT_CALL_REQUEST",
++ "OUT_CALL_REPLY",
++ "IN_CALL_REQUEST",
++ "IN_CALL_REPLY",
++ "IN_CALL_CONNECT",
++ "CALL_CLEAR_REQUEST",
++ "CALL_DISCONNECT_NOTIFY",
++ "WAN_ERROR_NOTIFY",
++ "SET_LINK_INFO"
++};
++
++#endif
+diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+--- linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,343 @@
++/*
++ * ip_conntrack_proto_gre.c - Version 1.2
++ *
++ * Connection tracking protocol helper module for GRE.
++ *
++ * GRE is a generic encapsulation protocol, which is generally not very
++ * suited for NAT, as it has no protocol-specific part as port numbers.
++ *
++ * It has an optional key field, which may help us distinguishing two
++ * connections between the same two hosts.
++ *
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ *
++ * PPTP is built on top of a modified version of GRE, and has a mandatory
++ * field called "CallID", which serves us for the same purpose as the key
++ * field in plain GRE.
++ *
++ * Documentation about PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/timer.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/list.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++DECLARE_RWLOCK(ip_ct_gre_lock);
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
++
++#include <linux/netfilter_ipv4/listhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
++
++/* shamelessly stolen from ip_conntrack_proto_udp.c */
++#define GRE_TIMEOUT (30*HZ)
++#define GRE_STREAM_TIMEOUT (180*HZ)
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \
++ (x)->dst.u.gre.version, \
++ ntohs((x)->dst.u.gre.protocol))
++#else
++#define DEBUGP(x, args...)
++#define DUMP_TUPLE_GRE(x)
++#endif
++
++/* GRE KEYMAP HANDLING FUNCTIONS */
++static LIST_HEAD(gre_keymap_list);
++
++static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
++ const struct ip_conntrack_tuple *t)
++{
++ return ((km->tuple.src.ip == t->src.ip) &&
++ (km->tuple.dst.ip == t->dst.ip) &&
++ (km->tuple.dst.protonum == t->dst.protonum) &&
++ (km->tuple.dst.u.all == t->dst.u.all));
++}
++
++/* look up the source key for a given tuple */
++static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
++{
++ struct ip_ct_gre_keymap *km;
++ u_int32_t key;
++
++ READ_LOCK(&ip_ct_gre_lock);
++ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
++ struct ip_ct_gre_keymap *, t);
++ if (!km) {
++ READ_UNLOCK(&ip_ct_gre_lock);
++ return 0;
++ }
++
++ key = km->tuple.src.u.gre.key;
++ READ_UNLOCK(&ip_ct_gre_lock);
++
++ return key;
++}
++
++/* add a single keymap entry, associate with specified expect */
++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
++ struct ip_conntrack_tuple *t, int reply)
++{
++ struct ip_ct_gre_keymap *km;
++
++ km = kmalloc(sizeof(*km), GFP_ATOMIC);
++ if (!km)
++ return -1;
++
++ /* initializing list head should be sufficient */
++ memset(km, 0, sizeof(*km));
++
++ memcpy(&km->tuple, t, sizeof(*t));
++
++ if (!reply)
++ exp->proto.gre.keymap_orig = km;
++ else
++ exp->proto.gre.keymap_reply = km;
++
++ DEBUGP("adding new entry %p: ", km);
++ DUMP_TUPLE_GRE(&km->tuple);
++
++ WRITE_LOCK(&ip_ct_gre_lock);
++ list_append(&gre_keymap_list, km);
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++
++ return 0;
++}
++
++/* change the tuple of a keymap entry (used by nat helper) */
++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
++ struct ip_conntrack_tuple *t)
++{
++ DEBUGP("changing entry %p to: ", km);
++ DUMP_TUPLE_GRE(t);
++
++ WRITE_LOCK(&ip_ct_gre_lock);
++ memcpy(&km->tuple, t, sizeof(km->tuple));
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++}
++
++/* destroy the keymap entries associated with specified expect */
++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
++{
++ DEBUGP("entering for exp %p\n", exp);
++ WRITE_LOCK(&ip_ct_gre_lock);
++ if (exp->proto.gre.keymap_orig) {
++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
++ list_del(&exp->proto.gre.keymap_orig->list);
++ kfree(exp->proto.gre.keymap_orig);
++ exp->proto.gre.keymap_orig = NULL;
++ }
++ if (exp->proto.gre.keymap_reply) {
++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
++ list_del(&exp->proto.gre.keymap_reply->list);
++ kfree(exp->proto.gre.keymap_reply);
++ exp->proto.gre.keymap_reply = NULL;
++ }
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++}
++
++
++/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
++
++/* invert gre part of tuple */
++static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *orig)
++{
++ tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol;
++ tuple->dst.u.gre.version = orig->dst.u.gre.version;
++
++ tuple->dst.u.gre.key = orig->src.u.gre.key;
++ tuple->src.u.gre.key = orig->dst.u.gre.key;
++
++ return 1;
++}
++
++/* gre hdr info to tuple */
++static int gre_pkt_to_tuple(const void *datah, size_t datalen,
++ struct ip_conntrack_tuple *tuple)
++{
++ struct gre_hdr *grehdr = (struct gre_hdr *) datah;
++ struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
++ u_int32_t srckey;
++
++ /* core guarantees 8 protocol bytes, no need for size check */
++
++ tuple->dst.u.gre.version = grehdr->version;
++ tuple->dst.u.gre.protocol = grehdr->protocol;
++
++ switch (grehdr->version) {
++ case GRE_VERSION_1701:
++ if (!grehdr->key) {
++ DEBUGP("Can't track GRE without key\n");
++ return 0;
++ }
++ tuple->dst.u.gre.key = *(gre_key(grehdr));
++ break;
++
++ case GRE_VERSION_PPTP:
++ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
++ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
++ return 0;
++ }
++ tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
++ break;
++
++ default:
++ printk(KERN_WARNING "unknown GRE version %hu\n",
++ tuple->dst.u.gre.version);
++ return 0;
++ }
++
++ srckey = gre_keymap_lookup(tuple);
++
++#if 0
++ DEBUGP("found src key %x for tuple ", ntohl(srckey));
++ DUMP_TUPLE_GRE(tuple);
++#endif
++ tuple->src.u.gre.key = srckey;
++
++ return 1;
++}
++
++/* print gre part of tuple */
++static unsigned int gre_print_tuple(char *buffer,
++ const struct ip_conntrack_tuple *tuple)
++{
++ return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ",
++ tuple->dst.u.gre.version,
++ ntohs(tuple->dst.u.gre.protocol),
++ ntohl(tuple->src.u.gre.key),
++ ntohl(tuple->dst.u.gre.key));
++}
++
++/* print private data for conntrack */
++static unsigned int gre_print_conntrack(char *buffer,
++ const struct ip_conntrack *ct)
++{
++ return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
++ (ct->proto.gre.timeout / HZ),
++ (ct->proto.gre.stream_timeout / HZ));
++}
++
++/* Returns verdict for packet, and may modify conntrack */
++static int gre_packet(struct ip_conntrack *ct,
++ struct iphdr *iph, size_t len,
++ enum ip_conntrack_info conntrackinfo)
++{
++ /* If we've seen traffic both ways, this is a GRE connection.
++ * Extend timeout. */
++ if (ct->status & IPS_SEEN_REPLY) {
++ ip_ct_refresh(ct, ct->proto.gre.stream_timeout);
++ /* Also, more likely to be important, and not a probe. */
++ set_bit(IPS_ASSURED_BIT, &ct->status);
++ } else
++ ip_ct_refresh(ct, ct->proto.gre.timeout);
++
++ return NF_ACCEPT;
++}
++
++/* Called when a new connection for this protocol found. */
++static int gre_new(struct ip_conntrack *ct,
++ struct iphdr *iph, size_t len)
++{
++ DEBUGP(": ");
++ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++
++ /* initialize to sane value. Ideally a conntrack helper
++ * (e.g. in case of pptp) is increasing them */
++ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
++ ct->proto.gre.timeout = GRE_TIMEOUT;
++
++ return 1;
++}
++
++/* Called when a conntrack entry has already been removed from the hashes
++ * and is about to be deleted from memory */
++static void gre_destroy(struct ip_conntrack *ct)
++{
++ struct ip_conntrack_expect *master = ct->master;
++
++ DEBUGP(" entering\n");
++
++ if (!master) {
++ DEBUGP("no master exp for ct %p\n", ct);
++ return;
++ }
++
++ ip_ct_gre_keymap_destroy(master);
++}
++
++/* protocol helper struct */
++static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
++ "gre",
++ gre_pkt_to_tuple,
++ gre_invert_tuple,
++ gre_print_tuple,
++ gre_print_conntrack,
++ gre_packet,
++ gre_new,
++ gre_destroy,
++ NULL,
++ THIS_MODULE };
++
++/* ip_conntrack_proto_gre initialization */
++static int __init init(void)
++{
++ int retcode;
++
++ if ((retcode = ip_conntrack_protocol_register(&gre))) {
++ printk(KERN_ERR "Unable to register conntrack protocol "
++ "helper for gre: %d\n", retcode);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ struct list_head *pos, *n;
++
++ /* delete all keymap entries */
++ WRITE_LOCK(&ip_ct_gre_lock);
++ list_for_each_safe(pos, n, &gre_keymap_list) {
++ DEBUGP("deleting keymap %p at module unload time\n", pos);
++ list_del(pos);
++ kfree(pos);
++ }
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++
++ ip_conntrack_protocol_unregister(&gre);
++}
++
++EXPORT_SYMBOL(ip_ct_gre_keymap_add);
++EXPORT_SYMBOL(ip_ct_gre_keymap_change);
++EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
++
++module_init(init);
++module_exit(fini);
+diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
+--- linux_org/net/ipv4/netfilter/ip_nat_core.c 2004-11-24 12:14:04.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_nat_core.c 2006-10-27 14:11:52.000000000 +0200
+@@ -430,7 +430,7 @@
+ *tuple = *orig_tuple;
+ while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
+ != NULL) {
+- DEBUGP("Found best for "); DUMP_TUPLE(tuple);
++ DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
+ /* 3) The per-protocol part of the manip is made to
+ map into the range to make a unique tuple. */
+
+@@ -572,9 +572,9 @@
+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
+ conntrack);
+ DEBUGP("Original: ");
+- DUMP_TUPLE(&orig_tp);
++ DUMP_TUPLE_RAW(&orig_tp);
+ DEBUGP("New: ");
+- DUMP_TUPLE(&new_tuple);
++ DUMP_TUPLE_RAW(&new_tuple);
+ #endif
+
+ /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
+diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c.orig linux/net/ipv4/netfilter/ip_nat_core.c.orig
+--- linux_org/net/ipv4/netfilter/ip_nat_core.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_nat_core.c.orig 2004-11-24 12:14:04.000000000 +0100
+@@ -0,0 +1,1014 @@
++/* NAT for netfilter; shared with compatibility layer. */
++
++/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
++ Public Licence. */
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/timer.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/brlock.h>
++#include <linux/vmalloc.h>
++#include <net/checksum.h>
++#include <net/icmp.h>
++#include <net/ip.h>
++#include <net/tcp.h> /* For tcp_prot in getorigdst */
++
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
++
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_protocol.h>
++#include <linux/netfilter_ipv4/ip_nat_core.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++DECLARE_RWLOCK(ip_nat_lock);
++DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
++
++/* Calculated at init based on memory size */
++static unsigned int ip_nat_htable_size;
++
++static struct list_head *bysource;
++static struct list_head *byipsproto;
++LIST_HEAD(protos);
++LIST_HEAD(helpers);
++
++extern struct ip_nat_protocol unknown_nat_protocol;
++
++/* We keep extra hashes for each conntrack, for fast searching. */
++static inline size_t
++hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
++{
++ /* Modified src and dst, to ensure we don't create two
++ identical streams. */
++ return (src + dst + proto) % ip_nat_htable_size;
++}
++
++static inline size_t
++hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
++{
++ /* Original src, to ensure we map it consistently if poss. */
++ return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
++}
++
++/* Noone using conntrack by the time this called. */
++static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
++{
++ struct ip_nat_info *info = &conn->nat.info;
++ unsigned int hs, hp;
++
++ if (!info->initialized)
++ return;
++
++ IP_NF_ASSERT(info->bysource.conntrack);
++ IP_NF_ASSERT(info->byipsproto.conntrack);
++
++ hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
++ conn->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.protonum);
++
++ hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
++ conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
++ conn->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.dst.protonum);
++
++ WRITE_LOCK(&ip_nat_lock);
++ LIST_DELETE(&bysource[hs], &info->bysource);
++ LIST_DELETE(&byipsproto[hp], &info->byipsproto);
++ WRITE_UNLOCK(&ip_nat_lock);
++}
++
++/* We do checksum mangling, so if they were wrong before they're still
++ * wrong. Also works for incomplete packets (eg. ICMP dest
++ * unreachables.) */
++u_int16_t
++ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
++{
++ u_int32_t diffs[] = { oldvalinv, newval };
++ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
++ oldcheck^0xFFFF));
++}
++
++static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
++{
++ return i->protonum == proto;
++}
++
++struct ip_nat_protocol *
++find_nat_proto(u_int16_t protonum)
++{
++ struct ip_nat_protocol *i;
++
++ MUST_BE_READ_LOCKED(&ip_nat_lock);
++ i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
++ if (!i)
++ i = &unknown_nat_protocol;
++ return i;
++}
++
++/* Is this tuple already taken? (not by us) */
++int
++ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack *ignored_conntrack)
++{
++ /* Conntrack tracking doesn't keep track of outgoing tuples; only
++ incoming ones. NAT means they don't have a fixed mapping,
++ so we invert the tuple and look for the incoming reply.
++
++ We could keep a separate hash if this proves too slow. */
++ struct ip_conntrack_tuple reply;
++
++ invert_tuplepr(&reply, tuple);
++ return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
++}
++
++/* Does tuple + the source manip come within the range mr */
++static int
++in_range(const struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_manip *manip,
++ const struct ip_nat_multi_range *mr)
++{
++ struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
++ unsigned int i;
++ struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
++
++ for (i = 0; i < mr->rangesize; i++) {
++ /* If we are allowed to map IPs, then we must be in the
++ range specified, otherwise we must be unchanged. */
++ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
++ if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
++ || (ntohl(newtuple.src.ip)
++ > ntohl(mr->range[i].max_ip)))
++ continue;
++ } else {
++ if (newtuple.src.ip != tuple->src.ip)
++ continue;
++ }
++
++ if ((mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
++ && proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
++ &mr->range[i].min, &mr->range[i].max))
++ return 1;
++ }
++ return 0;
++}
++
++static inline int
++src_cmp(const struct ip_nat_hash *i,
++ const struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_multi_range *mr)
++{
++ return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
++ == tuple->dst.protonum
++ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
++ == tuple->src.ip
++ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
++ == tuple->src.u.all
++ && in_range(tuple,
++ &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.src,
++ mr));
++}
++
++/* Only called for SRC manip */
++static struct ip_conntrack_manip *
++find_appropriate_src(const struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_multi_range *mr)
++{
++ unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
++ struct ip_nat_hash *i;
++
++ MUST_BE_READ_LOCKED(&ip_nat_lock);
++ i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
++ if (i)
++ return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
++ else
++ return NULL;
++}
++
++#ifdef CONFIG_IP_NF_NAT_LOCAL
++/* If it's really a local destination manip, it may need to do a
++ source manip too. */
++static int
++do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
++{
++ struct rtable *rt;
++
++ /* FIXME: IPTOS_TOS(iph->tos) --RR */
++ if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) {
++ DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
++ NIPQUAD(var_ip));
++ return 0;
++ }
++
++ *other_ipp = rt->rt_src;
++ ip_rt_put(rt);
++ return 1;
++}
++#endif
++
++/* Simple way to iterate through all. */
++static inline int fake_cmp(const struct ip_nat_hash *i,
++ u_int32_t src, u_int32_t dst, u_int16_t protonum,
++ unsigned int *score,
++ const struct ip_conntrack *conntrack)
++{
++ /* Compare backwards: we're dealing with OUTGOING tuples, and
++ inside the conntrack is the REPLY tuple. Don't count this
++ conntrack. */
++ if (i->conntrack != conntrack
++ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
++ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
++ && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
++ == protonum))
++ (*score)++;
++ return 0;
++}
++
++static inline unsigned int
++count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
++ const struct ip_conntrack *conntrack)
++{
++ unsigned int score = 0;
++ unsigned int h;
++
++ MUST_BE_READ_LOCKED(&ip_nat_lock);
++ h = hash_by_ipsproto(src, dst, protonum);
++ LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
++ src, dst, protonum, &score, conntrack);
++
++ return score;
++}
++
++/* For [FUTURE] fragmentation handling, we want the least-used
++ src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
++ if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
++ 1-65535, we don't do pro-rata allocation based on ports; we choose
++ the ip with the lowest src-ip/dst-ip/proto usage.
++
++ If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
++ range), we eliminate that and try again. This is not the most
++ efficient approach, but if you're worried about that, don't hand us
++ ranges you don't really have. */
++static struct ip_nat_range *
++find_best_ips_proto(struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_multi_range *mr,
++ const struct ip_conntrack *conntrack,
++ unsigned int hooknum)
++{
++ unsigned int i;
++ struct {
++ const struct ip_nat_range *range;
++ unsigned int score;
++ struct ip_conntrack_tuple tuple;
++ } best = { NULL, 0xFFFFFFFF };
++ u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
++ static unsigned int randomness = 0;
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
++ var_ipp = &tuple->src.ip;
++ saved_ip = tuple->dst.ip;
++ other_ipp = &tuple->dst.ip;
++ } else {
++ var_ipp = &tuple->dst.ip;
++ saved_ip = tuple->src.ip;
++ other_ipp = &tuple->src.ip;
++ }
++ /* Don't do do_extra_mangle unless neccessary (overrides
++ explicit socket bindings, for example) */
++ orig_dstip = tuple->dst.ip;
++
++ IP_NF_ASSERT(mr->rangesize >= 1);
++ for (i = 0; i < mr->rangesize; i++) {
++ /* Host order */
++ u_int32_t minip, maxip, j;
++
++ /* Don't do ranges which are already eliminated. */
++ if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
++ continue;
++ }
++
++ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
++ minip = ntohl(mr->range[i].min_ip);
++ maxip = ntohl(mr->range[i].max_ip);
++ } else
++ minip = maxip = ntohl(*var_ipp);
++
++ randomness++;
++ for (j = 0; j < maxip - minip + 1; j++) {
++ unsigned int score;
++
++ *var_ipp = htonl(minip + (randomness + j)
++ % (maxip - minip + 1));
++
++ /* Reset the other ip in case it was mangled by
++ * do_extra_mangle last time. */
++ *other_ipp = saved_ip;
++
++#ifdef CONFIG_IP_NF_NAT_LOCAL
++ if (hooknum == NF_IP_LOCAL_OUT
++ && *var_ipp != orig_dstip
++ && !do_extra_mangle(*var_ipp, other_ipp)) {
++ DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
++ i, NIPQUAD(*var_ipp));
++ /* Can't route? This whole range part is
++ * probably screwed, but keep trying
++ * anyway. */
++ continue;
++ }
++#endif
++
++ /* Count how many others map onto this. */
++ score = count_maps(tuple->src.ip, tuple->dst.ip,
++ tuple->dst.protonum, conntrack);
++ if (score < best.score) {
++ /* Optimization: doesn't get any better than
++ this. */
++ if (score == 0)
++ return (struct ip_nat_range *)
++ &mr->range[i];
++
++ best.score = score;
++ best.tuple = *tuple;
++ best.range = &mr->range[i];
++ }
++ }
++ }
++ *tuple = best.tuple;
++
++ /* Discard const. */
++ return (struct ip_nat_range *)best.range;
++}
++
++/* Fast version doesn't iterate through hash chains, but only handles
++ common case of single IP address (null NAT, masquerade) */
++static struct ip_nat_range *
++find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_multi_range *mr,
++ const struct ip_conntrack *conntrack,
++ unsigned int hooknum)
++{
++ if (mr->rangesize != 1
++ || (mr->range[0].flags & IP_NAT_RANGE_FULL)
++ || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
++ && mr->range[0].min_ip != mr->range[0].max_ip))
++ return find_best_ips_proto(tuple, mr, conntrack, hooknum);
++
++ if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ tuple->src.ip = mr->range[0].min_ip;
++ else {
++ /* Only do extra mangle when required (breaks
++ socket binding) */
++#ifdef CONFIG_IP_NF_NAT_LOCAL
++ if (tuple->dst.ip != mr->range[0].min_ip
++ && hooknum == NF_IP_LOCAL_OUT
++ && !do_extra_mangle(mr->range[0].min_ip,
++ &tuple->src.ip))
++ return NULL;
++#endif
++ tuple->dst.ip = mr->range[0].min_ip;
++ }
++ }
++
++ /* Discard const. */
++ return (struct ip_nat_range *)&mr->range[0];
++}
++
++static int
++get_unique_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *orig_tuple,
++ const struct ip_nat_multi_range *mrr,
++ struct ip_conntrack *conntrack,
++ unsigned int hooknum)
++{
++ struct ip_nat_protocol *proto
++ = find_nat_proto(orig_tuple->dst.protonum);
++ struct ip_nat_range *rptr;
++ unsigned int i;
++ int ret;
++
++ /* We temporarily use flags for marking full parts, but we
++ always clean up afterwards */
++ struct ip_nat_multi_range *mr = (void *)mrr;
++
++ /* 1) If this srcip/proto/src-proto-part is currently mapped,
++ and that same mapping gives a unique tuple within the given
++ range, use that.
++
++ This is only required for source (ie. NAT/masq) mappings.
++ So far, we don't do local source mappings, so multiple
++ manips not an issue. */
++ if (hooknum == NF_IP_POST_ROUTING) {
++ struct ip_conntrack_manip *manip;
++
++ manip = find_appropriate_src(orig_tuple, mr);
++ if (manip) {
++ /* Apply same source manipulation. */
++ *tuple = ((struct ip_conntrack_tuple)
++ { *manip, orig_tuple->dst });
++ DEBUGP("get_unique_tuple: Found current src map\n");
++ return 1;
++ }
++ }
++
++ /* 2) Select the least-used IP/proto combination in the given
++ range.
++ */
++ *tuple = *orig_tuple;
++ while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
++ != NULL) {
++ DEBUGP("Found best for "); DUMP_TUPLE(tuple);
++ /* 3) The per-protocol part of the manip is made to
++ map into the range to make a unique tuple. */
++
++ /* Only bother mapping if it's not already in range
++ and unique */
++ if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
++ || proto->in_range(tuple, HOOK2MANIP(hooknum),
++ &rptr->min, &rptr->max))
++ && !ip_nat_used_tuple(tuple, conntrack)) {
++ ret = 1;
++ goto clear_fulls;
++ } else {
++ if (proto->unique_tuple(tuple, rptr,
++ HOOK2MANIP(hooknum),
++ conntrack)) {
++ /* Must be unique. */
++ IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
++ conntrack));
++ ret = 1;
++ goto clear_fulls;
++ } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ /* Try implicit source NAT; protocol
++ may be able to play with ports to
++ make it unique. */
++ struct ip_nat_range r
++ = { IP_NAT_RANGE_MAP_IPS,
++ tuple->src.ip, tuple->src.ip,
++ { 0 }, { 0 } };
++ DEBUGP("Trying implicit mapping\n");
++ if (proto->unique_tuple(tuple, &r,
++ IP_NAT_MANIP_SRC,
++ conntrack)) {
++ /* Must be unique. */
++ IP_NF_ASSERT(!ip_nat_used_tuple
++ (tuple, conntrack));
++ ret = 1;
++ goto clear_fulls;
++ }
++ }
++ DEBUGP("Protocol can't get unique tuple %u.\n",
++ hooknum);
++ }
++
++ /* Eliminate that from range, and try again. */
++ rptr->flags |= IP_NAT_RANGE_FULL;
++ *tuple = *orig_tuple;
++ }
++
++ ret = 0;
++
++ clear_fulls:
++ /* Clear full flags. */
++ IP_NF_ASSERT(mr->rangesize >= 1);
++ for (i = 0; i < mr->rangesize; i++)
++ mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
++
++ return ret;
++}
++
++static inline int
++helper_cmp(const struct ip_nat_helper *helper,
++ const struct ip_conntrack_tuple *tuple)
++{
++ return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
++}
++
++/* Where to manip the reply packets (will be reverse manip). */
++static unsigned int opposite_hook[NF_IP_NUMHOOKS]
++= { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
++ [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
++#ifdef CONFIG_IP_NF_NAT_LOCAL
++ [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
++ [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
++#endif
++};
++
++unsigned int
++ip_nat_setup_info(struct ip_conntrack *conntrack,
++ const struct ip_nat_multi_range *mr,
++ unsigned int hooknum)
++{
++ struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
++ struct ip_conntrack_tuple orig_tp;
++ struct ip_nat_info *info = &conntrack->nat.info;
++ int in_hashes = info->initialized;
++
++ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
++ IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
++ || hooknum == NF_IP_POST_ROUTING
++ || hooknum == NF_IP_LOCAL_IN
++ || hooknum == NF_IP_LOCAL_OUT);
++ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ /* What we've got will look like inverse of reply. Normally
++ this is what is in the conntrack, except for prior
++ manipulations (future optimization: if num_manips == 0,
++ orig_tp =
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
++ invert_tuplepr(&orig_tp,
++ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++#if 0
++ {
++ unsigned int i;
++
++ DEBUGP("Hook %u (%s), ", hooknum,
++ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
++ DUMP_TUPLE(&orig_tp);
++ DEBUGP("Range %p: ", mr);
++ for (i = 0; i < mr->rangesize; i++) {
++ DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
++ i,
++ (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
++ ? " MAP_IPS" : "",
++ (mr->range[i].flags
++ & IP_NAT_RANGE_PROTO_SPECIFIED)
++ ? " PROTO_SPECIFIED" : "",
++ (mr->range[i].flags & IP_NAT_RANGE_FULL)
++ ? " FULL" : "",
++ NIPQUAD(mr->range[i].min_ip),
++ NIPQUAD(mr->range[i].max_ip),
++ mr->range[i].min.all,
++ mr->range[i].max.all);
++ }
++ }
++#endif
++
++ do {
++ if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
++ hooknum)) {
++ DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
++ conntrack);
++ return NF_DROP;
++ }
++
++#if 0
++ DEBUGP("Hook %u (%s) %p\n", hooknum,
++ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
++ conntrack);
++ DEBUGP("Original: ");
++ DUMP_TUPLE(&orig_tp);
++ DEBUGP("New: ");
++ DUMP_TUPLE(&new_tuple);
++#endif
++
++ /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
++ the original (A/B/C/D') and the mangled one (E/F/G/H').
++
++ We're only allowed to work with the SRC per-proto
++ part, so we create inverses of both to start, then
++ derive the other fields we need. */
++
++ /* Reply connection: simply invert the new tuple
++ (G/H/E/F') */
++ invert_tuplepr(&reply, &new_tuple);
++
++ /* Alter conntrack table so it recognizes replies.
++ If fail this race (reply tuple now used), repeat. */
++ } while (!ip_conntrack_alter_reply(conntrack, &reply));
++
++ /* FIXME: We can simply used existing conntrack reply tuple
++ here --RR */
++ /* Create inverse of original: C/D/A/B' */
++ invert_tuplepr(&inv_tuple, &orig_tp);
++
++ /* Has source changed?. */
++ if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
++ /* In this direction, a source manip. */
++ info->manips[info->num_manips++] =
++ ((struct ip_nat_info_manip)
++ { IP_CT_DIR_ORIGINAL, hooknum,
++ IP_NAT_MANIP_SRC, new_tuple.src });
++
++ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
++
++ /* In the reverse direction, a destination manip. */
++ info->manips[info->num_manips++] =
++ ((struct ip_nat_info_manip)
++ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
++ IP_NAT_MANIP_DST, orig_tp.src });
++ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
++ }
++
++ /* Has destination changed? */
++ if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
++ /* In this direction, a destination manip */
++ info->manips[info->num_manips++] =
++ ((struct ip_nat_info_manip)
++ { IP_CT_DIR_ORIGINAL, hooknum,
++ IP_NAT_MANIP_DST, reply.src });
++
++ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
++
++ /* In the reverse direction, a source manip. */
++ info->manips[info->num_manips++] =
++ ((struct ip_nat_info_manip)
++ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
++ IP_NAT_MANIP_SRC, inv_tuple.src });
++ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
++ }
++
++ /* If there's a helper, assign it; based on new tuple. */
++ if (!conntrack->master)
++ info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
++ &reply);
++
++ /* It's done. */
++ info->initialized |= (1 << HOOK2MANIP(hooknum));
++
++ if (in_hashes) {
++ IP_NF_ASSERT(info->bysource.conntrack);
++ replace_in_hashes(conntrack, info);
++ } else {
++ place_in_hashes(conntrack, info);
++ }
++
++ return NF_ACCEPT;
++}
++
++void replace_in_hashes(struct ip_conntrack *conntrack,
++ struct ip_nat_info *info)
++{
++ /* Source has changed, so replace in hashes. */
++ unsigned int srchash
++ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.src,
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.protonum);
++ /* We place packet as seen OUTGOUNG in byips_proto hash
++ (ie. reverse dst and src of reply packet. */
++ unsigned int ipsprotohash
++ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.dst.ip,
++ conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.src.ip,
++ conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.dst.protonum);
++
++ IP_NF_ASSERT(info->bysource.conntrack == conntrack);
++ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
++
++ list_del(&info->bysource.list);
++ list_del(&info->byipsproto.list);
++
++ list_prepend(&bysource[srchash], &info->bysource);
++ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
++}
++
++void place_in_hashes(struct ip_conntrack *conntrack,
++ struct ip_nat_info *info)
++{
++ unsigned int srchash
++ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.src,
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.protonum);
++ /* We place packet as seen OUTGOUNG in byips_proto hash
++ (ie. reverse dst and src of reply packet. */
++ unsigned int ipsprotohash
++ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.dst.ip,
++ conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.src.ip,
++ conntrack->tuplehash[IP_CT_DIR_REPLY]
++ .tuple.dst.protonum);
++
++ IP_NF_ASSERT(!info->bysource.conntrack);
++
++ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
++ info->byipsproto.conntrack = conntrack;
++ info->bysource.conntrack = conntrack;
++
++ list_prepend(&bysource[srchash], &info->bysource);
++ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
++}
++
++static void
++manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
++ const struct ip_conntrack_manip *manip,
++ enum ip_nat_manip_type maniptype,
++ __u32 *nfcache)
++{
++ *nfcache |= NFC_ALTERED;
++ find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
++
++ if (maniptype == IP_NAT_MANIP_SRC) {
++ iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
++ iph->check);
++ iph->saddr = manip->ip;
++ } else {
++ iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
++ iph->check);
++ iph->daddr = manip->ip;
++ }
++#if 0
++ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
++ DEBUGP("IP: checksum on packet bad.\n");
++
++ if (proto == IPPROTO_TCP) {
++ void *th = (u_int32_t *)iph + iph->ihl;
++ if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,
++ csum_partial((char *)th, len-4*iph->ihl, 0)))
++ DEBUGP("TCP: checksum on packet bad\n");
++ }
++#endif
++}
++
++static inline int exp_for_packet(struct ip_conntrack_expect *exp,
++ struct sk_buff **pskb)
++{
++ struct ip_conntrack_protocol *proto;
++ int ret = 1;
++
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++ proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
++ if (proto->exp_matches_pkt)
++ ret = proto->exp_matches_pkt(exp, pskb);
++
++ return ret;
++}
++
++/* Do packet manipulations according to binding. */
++unsigned int
++do_bindings(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_nat_info *info,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ unsigned int i;
++ struct ip_nat_helper *helper;
++ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
++ int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
++
++ /* Need nat lock to protect against modification, but neither
++ conntrack (referenced) and helper (deleted with
++ synchronize_bh()) can vanish. */
++ READ_LOCK(&ip_nat_lock);
++ for (i = 0; i < info->num_manips; i++) {
++ /* raw socket (tcpdump) may have clone of incoming
++ skb: don't disturb it --RR */
++ if (skb_cloned(*pskb) && !(*pskb)->sk) {
++ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
++ if (!nskb) {
++ READ_UNLOCK(&ip_nat_lock);
++ return NF_DROP;
++ }
++ kfree_skb(*pskb);
++ *pskb = nskb;
++ }
++
++ if (info->manips[i].direction == dir
++ && info->manips[i].hooknum == hooknum) {
++ DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
++ *pskb,
++ info->manips[i].maniptype == IP_NAT_MANIP_SRC
++ ? "SRC" : "DST",
++ NIPQUAD(info->manips[i].manip.ip),
++ htons(info->manips[i].manip.u.all));
++ manip_pkt((*pskb)->nh.iph->protocol,
++ (*pskb)->nh.iph,
++ (*pskb)->len,
++ &info->manips[i].manip,
++ info->manips[i].maniptype,
++ &(*pskb)->nfcache);
++ }
++ }
++ helper = info->helper;
++ READ_UNLOCK(&ip_nat_lock);
++
++ if (helper) {
++ struct ip_conntrack_expect *exp = NULL;
++ struct list_head *cur_item;
++ int ret = NF_ACCEPT;
++ int helper_called = 0;
++
++ DEBUGP("do_bindings: helper existing for (%p)\n", ct);
++
++ /* Always defragged for helpers */
++ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
++ & htons(IP_MF|IP_OFFSET)));
++
++ /* Have to grab read lock before sibling_list traversal */
++ READ_LOCK(&ip_conntrack_lock);
++ list_for_each_prev(cur_item, &ct->sibling_list) {
++ exp = list_entry(cur_item, struct ip_conntrack_expect,
++ expected_list);
++
++ /* if this expectation is already established, skip */
++ if (exp->sibling)
++ continue;
++
++ if (exp_for_packet(exp, pskb)) {
++ /* FIXME: May be true multiple times in the
++ * case of UDP!! */
++ DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
++ ret = helper->help(ct, exp, info, ctinfo,
++ hooknum, pskb);
++ if (ret != NF_ACCEPT) {
++ READ_UNLOCK(&ip_conntrack_lock);
++ return ret;
++ }
++ helper_called = 1;
++ }
++ }
++ /* Helper might want to manip the packet even when there is no
++ * matching expectation for this packet */
++ if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
++ DEBUGP("calling nat helper for packet without expectation\n");
++ ret = helper->help(ct, NULL, info, ctinfo,
++ hooknum, pskb);
++ if (ret != NF_ACCEPT) {
++ READ_UNLOCK(&ip_conntrack_lock);
++ return ret;
++ }
++ }
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ /* Adjust sequence number only once per packet
++ * (helper is called at all hooks) */
++ if (is_tcp && (hooknum == NF_IP_POST_ROUTING
++ || hooknum == NF_IP_LOCAL_IN)) {
++ DEBUGP("ip_nat_core: adjusting sequence number\n");
++ /* future: put this in a l4-proto specific function,
++ * and call this function here. */
++ ip_nat_seq_adjust(*pskb, ct, ctinfo);
++ }
++
++ return ret;
++
++ } else
++ return NF_ACCEPT;
++
++ /* not reached */
++}
++
++unsigned int
++icmp_reply_translation(struct sk_buff *skb,
++ struct ip_conntrack *conntrack,
++ unsigned int hooknum,
++ int dir)
++{
++ struct iphdr *iph = skb->nh.iph;
++ struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
++ struct iphdr *inner = (struct iphdr *)(hdr + 1);
++ size_t datalen = skb->len - ((void *)inner - (void *)iph);
++ unsigned int i;
++ struct ip_nat_info *info = &conntrack->nat.info;
++
++ IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
++ /* Must be RELATED */
++ IP_NF_ASSERT(skb->nfct
++ - ((struct ip_conntrack *)skb->nfct->master)->infos
++ == IP_CT_RELATED
++ || skb->nfct
++ - ((struct ip_conntrack *)skb->nfct->master)->infos
++ == IP_CT_RELATED+IP_CT_IS_REPLY);
++
++ /* Redirects on non-null nats must be dropped, else they'll
++ start talking to each other without our translation, and be
++ confused... --RR */
++ if (hdr->type == ICMP_REDIRECT) {
++ /* Don't care about races here. */
++ if (info->initialized
++ != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
++ || info->num_manips != 0)
++ return NF_DROP;
++ }
++
++ DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
++ skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
++ /* Note: May not be from a NAT'd host, but probably safest to
++ do translation always as if it came from the host itself
++ (even though a "host unreachable" coming from the host
++ itself is a bit weird).
++
++ More explanation: some people use NAT for anonymizing.
++ Also, CERT recommends dropping all packets from private IP
++ addresses (although ICMP errors from internal links with
++ such addresses are not too uncommon, as Alan Cox points
++ out) */
++
++ READ_LOCK(&ip_nat_lock);
++ for (i = 0; i < info->num_manips; i++) {
++ DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
++ i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
++ "ORIG" : "REPLY", info->manips[i].hooknum);
++
++ if (info->manips[i].direction != dir)
++ continue;
++
++ /* Mapping the inner packet is just like a normal
++ packet, except it was never src/dst reversed, so
++ where we would normally apply a dst manip, we apply
++ a src, and vice versa. */
++ if (info->manips[i].hooknum == hooknum) {
++ DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
++ info->manips[i].maniptype == IP_NAT_MANIP_SRC
++ ? "DST" : "SRC",
++ NIPQUAD(info->manips[i].manip.ip),
++ ntohs(info->manips[i].manip.u.udp.port));
++ manip_pkt(inner->protocol, inner,
++ skb->len - ((void *)inner - (void *)iph),
++ &info->manips[i].manip,
++ !info->manips[i].maniptype,
++ &skb->nfcache);
++ /* Outer packet needs to have IP header NATed like
++ it's a reply. */
++
++ /* Use mapping to map outer packet: 0 give no
++ per-proto mapping */
++ DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
++ info->manips[i].maniptype == IP_NAT_MANIP_SRC
++ ? "SRC" : "DST",
++ NIPQUAD(info->manips[i].manip.ip));
++ manip_pkt(0, iph, skb->len,
++ &info->manips[i].manip,
++ info->manips[i].maniptype,
++ &skb->nfcache);
++ }
++ }
++ READ_UNLOCK(&ip_nat_lock);
++
++ /* Since we mangled inside ICMP packet, recalculate its
++ checksum from scratch. (Hence the handling of incorrect
++ checksums in conntrack, so we don't accidentally fix one.) */
++ hdr->checksum = 0;
++ hdr->checksum = ip_compute_csum((unsigned char *)hdr,
++ sizeof(*hdr) + datalen);
++
++ return NF_ACCEPT;
++}
++
++int __init ip_nat_init(void)
++{
++ size_t i;
++
++ /* Leave them the same for the moment. */
++ ip_nat_htable_size = ip_conntrack_htable_size;
++
++ /* One vmalloc for both hash tables */
++ bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
++ if (!bysource) {
++ return -ENOMEM;
++ }
++ byipsproto = bysource + ip_nat_htable_size;
++
++ /* Sew in builtin protocols. */
++ WRITE_LOCK(&ip_nat_lock);
++ list_append(&protos, &ip_nat_protocol_tcp);
++ list_append(&protos, &ip_nat_protocol_udp);
++ list_append(&protos, &ip_nat_protocol_icmp);
++ WRITE_UNLOCK(&ip_nat_lock);
++
++ for (i = 0; i < ip_nat_htable_size; i++) {
++ INIT_LIST_HEAD(&bysource[i]);
++ INIT_LIST_HEAD(&byipsproto[i]);
++ }
++
++ /* FIXME: Man, this is a hack. <SIGH> */
++ IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
++ ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
++
++ return 0;
++}
++
++/* Clear NAT section of all conntracks, in case we're loaded again. */
++static int clean_nat(const struct ip_conntrack *i, void *data)
++{
++ memset((void *)&i->nat, 0, sizeof(i->nat));
++ return 0;
++}
++
++/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
++void ip_nat_cleanup(void)
++{
++ ip_ct_selective_cleanup(&clean_nat, NULL);
++ ip_conntrack_destroyed = NULL;
++ vfree(bysource);
++}
+diff -uNr linux_org/net/ipv4/netfilter/ip_nat_pptp.c linux/net/ipv4/netfilter/ip_nat_pptp.c
+--- linux_org/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_nat_pptp.c 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,475 @@
++/*
++ * ip_nat_pptp.c - Version 1.5
++ *
++ * NAT support for PPTP (Point to Point Tunneling Protocol).
++ * PPTP is a a protocol for creating virtual private networks.
++ * It is a specification defined by Microsoft and some vendors
++ * working with Microsoft. PPTP is built on top of a modified
++ * version of the Internet Generic Routing Encapsulation Protocol.
++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
++ * PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ * TODO: - Support for multiple calls within one session
++ * (needs netfilter newnat code)
++ * - NAT to a unique tuple, not to TCP source port
++ * (needs netfilter tuple reservation)
++ *
++ * Changes:
++ * 2002-02-10 - Version 1.3
++ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
++ * in local connections (Philip Craig <philipc@snapgear.com>)
++ * - add checks for magicCookie and pptp version
++ * - make argument list of pptp_{out,in}bound_packet() shorter
++ * - move to C99 style initializers
++ * - print version number at module loadtime
++ * 2003-09-22 - Version 1.5
++ * - use SNATed tcp sourceport as callid, since we get called before
++ * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_pptp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++#define IP_NAT_PPTP_VERSION "1.5"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
++
++
++#if 0
++#include "ip_conntrack_pptp_priv.h"
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static unsigned int
++pptp_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_conntrack *master = master_ct(ct);
++ struct ip_nat_multi_range mr;
++ struct ip_ct_pptp_master *ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info;
++ u_int32_t newip, newcid;
++ int ret;
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ DEBUGP("we have a connection!\n");
++
++ LOCK_BH(&ip_pptp_lock);
++ ct_pptp_info = &master->help.ct_pptp_info;
++ nat_pptp_info = &master->nat.help.nat_pptp_info;
++
++ /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
++ * (unmanipulated) values */
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ DEBUGP("completing tuples with NAT info \n");
++ /* we can do this, since we're unconfirmed */
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(ct_pptp_info->pac_call_id)) {
++ /* assume PNS->PAC */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(nat_pptp_info->pns_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(nat_pptp_info->pns_call_id);
++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newcid = htonl(nat_pptp_info->pac_call_id);
++ } else {
++ /* assume PAC->PNS */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(nat_pptp_info->pac_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(nat_pptp_info->pac_call_id);
++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newcid = htonl(nat_pptp_info->pns_call_id);
++ }
++ } else {
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(ct_pptp_info->pac_call_id)) {
++ /* assume PNS->PAC */
++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ newcid = htonl(ct_pptp_info->pns_call_id);
++ }
++ else {
++ /* assume PAC->PNS */
++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ newcid = htonl(ct_pptp_info->pac_call_id);
++ }
++ }
++
++ mr.rangesize = 1;
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++ mr.range[0].min = mr.range[0].max =
++ ((union ip_conntrack_manip_proto ) { newcid });
++ DEBUGP("change ip to %u.%u.%u.%u\n",
++ NIPQUAD(newip));
++ DEBUGP("change key to 0x%x\n", ntohl(newcid));
++ ret = ip_nat_setup_info(ct, &mr, hooknum);
++
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return ret;
++
++}
++
++/* outbound packets == from PNS to PAC */
++static inline unsigned int
++pptp_outbound_pkt(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *exp)
++
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
++ ((void *)tcph + tcph->doff*4);
++
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
++
++ u_int16_t msg, *cid = NULL, new_callid;
++
++ /* FIXME: size checks !!! */
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ new_callid = htons(ct_pptp_info->pns_call_id);
++
++ switch (msg = ntohs(ctlh->messageType)) {
++ case PPTP_OUT_CALL_REQUEST:
++ cid = &pptpReq.ocreq->callID;
++ /* FIXME: ideally we would want to reserve a call ID
++ * here. current netfilter NAT core is not able to do
++ * this :( For now we use TCP source port. This breaks
++ * multiple calls within one control session */
++
++ /* save original call ID in nat_info */
++ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
++
++ /* don't use tcph->source since we are at a DSTmanip
++ * hook (e.g. PREROUTING) and pkt is not mangled yet */
++ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
++
++ /* save new call ID in ct info */
++ ct_pptp_info->pns_call_id = ntohs(new_callid);
++ break;
++ case PPTP_IN_CALL_REPLY:
++ cid = &pptpReq.icreq->callID;
++ break;
++ case PPTP_CALL_CLEAR_REQUEST:
++ cid = &pptpReq.clrreq->callID;
++ break;
++ default:
++ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
++ /* fall through */
++
++ case PPTP_SET_LINK_INFO:
++ /* only need to NAT in case PAC is behind NAT box */
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
++ }
++
++ IP_NF_ASSERT(cid);
++
++ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
++ ntohs(*cid), ntohs(new_callid));
++
++ /* mangle packet */
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
++ sizeof(new_callid), (char *)&new_callid,
++ sizeof(new_callid));
++
++ return NF_ACCEPT;
++}
++
++/* inbound packets == from PAC to PNS */
++static inline unsigned int
++pptp_inbound_pkt(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *oldexp)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
++ ((void *)tcph + tcph->doff*4);
++
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
++
++ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
++ u_int32_t old_dst_ip;
++
++ struct ip_conntrack_tuple t, inv_t;
++ struct ip_conntrack_tuple *orig_t, *reply_t;
++
++ /* FIXME: size checks !!! */
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ new_pcid = htons(nat_pptp_info->pns_call_id);
++
++ switch (msg = ntohs(ctlh->messageType)) {
++ case PPTP_OUT_CALL_REPLY:
++ pcid = &pptpReq.ocack->peersCallID;
++ cid = &pptpReq.ocack->callID;
++ if (!oldexp) {
++ DEBUGP("outcall but no expectation\n");
++ break;
++ }
++ old_dst_ip = oldexp->tuple.dst.ip;
++ t = oldexp->tuple;
++ invert_tuplepr(&inv_t, &t);
++
++ /* save original PAC call ID in nat_info */
++ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
++
++ /* alter expectation */
++ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
++ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
++ /* expectation for PNS->PAC direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
++ t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
++ inv_t.src.ip = reply_t->src.ip;
++ inv_t.dst.ip = reply_t->dst.ip;
++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
++ } else {
++ /* expectation for PAC->PNS direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
++ t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
++ inv_t.src.ip = orig_t->src.ip;
++ inv_t.dst.ip = orig_t->dst.ip;
++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
++ }
++
++ if (!ip_conntrack_change_expect(oldexp, &t)) {
++ DEBUGP("successfully changed expect\n");
++ } else {
++ DEBUGP("can't change expect\n");
++ }
++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
++ break;
++ case PPTP_IN_CALL_CONNECT:
++ pcid = &pptpReq.iccon->peersCallID;
++ if (!oldexp)
++ break;
++ old_dst_ip = oldexp->tuple.dst.ip;
++ t = oldexp->tuple;
++
++ /* alter expectation, no need for callID */
++ if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
++ /* expectation for PNS->PAC direction */
++ t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ } else {
++ /* expectation for PAC->PNS direction */
++ t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ }
++
++ if (!ip_conntrack_change_expect(oldexp, &t)) {
++ DEBUGP("successfully changed expect\n");
++ } else {
++ DEBUGP("can't change expect\n");
++ }
++ break;
++ case PPTP_IN_CALL_REQUEST:
++ /* only need to nat in case PAC is behind NAT box */
++ break;
++ case PPTP_WAN_ERROR_NOTIFY:
++ pcid = &pptpReq.wanerr->peersCallID;
++ break;
++ case PPTP_CALL_DISCONNECT_NOTIFY:
++ pcid = &pptpReq.disc->callID;
++ break;
++
++ default:
++ DEBUGP("unknown inbound packet %s\n",
++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
++ /* fall through */
++
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
++ }
++
++ /* mangle packet */
++ IP_NF_ASSERT(pcid);
++ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
++ ntohs(*pcid), ntohs(new_pcid));
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
++ sizeof(new_pcid), (char *)&new_pcid,
++ sizeof(new_pcid));
++
++ if (new_cid) {
++ IP_NF_ASSERT(cid);
++ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
++ ntohs(*cid), ntohs(new_cid));
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ (void *)cid - (void *)pptph,
++ sizeof(new_cid), (char *)&new_cid,
++ sizeof(new_cid));
++ }
++
++ /* great, at least we don't need to resize packets */
++ return NF_ACCEPT;
++}
++
++
++static unsigned int tcp_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum, struct sk_buff **pskb)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
++ struct pptp_pkt_hdr *pptph;
++
++ int dir;
++
++ DEBUGP("entering\n");
++
++ /* Only mangle things once: DST for original direction
++ and SRC for reply direction. */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
++ && dir == IP_CT_DIR_ORIGINAL)
++ || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
++ && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
++ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
++ return NF_ACCEPT;
++ }
++
++ /* if packet is too small, just skip it */
++ if (datalen < sizeof(struct pptp_pkt_hdr)+
++ sizeof(struct PptpControlHeader)) {
++ DEBUGP("pptp packet too short\n");
++ return NF_ACCEPT;
++ }
++
++ pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
++
++ /* if it's not a control message, we can't handle it */
++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
++ DEBUGP("not a pptp control packet\n");
++ return NF_ACCEPT;
++ }
++
++ LOCK_BH(&ip_pptp_lock);
++
++ if (dir == IP_CT_DIR_ORIGINAL) {
++ /* reuqests sent by client to server (PNS->PAC) */
++ pptp_outbound_pkt(pskb, ct, ctinfo, exp);
++ } else {
++ /* response from the server to the client (PAC->PNS) */
++ pptp_inbound_pkt(pskb, ct, ctinfo, exp);
++ }
++
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return NF_ACCEPT;
++}
++
++/* nat helper struct for control connection */
++static struct ip_nat_helper pptp_tcp_helper = {
++ .list = { NULL, NULL },
++ .name = "pptp",
++ .flags = IP_NAT_HELPER_F_ALWAYS,
++ .me = THIS_MODULE,
++ .tuple = { .src = { .ip = 0,
++ .u = { .tcp = { .port =
++ __constant_htons(PPTP_CONTROL_PORT) }
++ }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = IPPROTO_TCP
++ }
++ },
++
++ .mask = { .src = { .ip = 0,
++ .u = { .tcp = { .port = 0xFFFF } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = 0xFFFF
++ }
++ },
++ .help = tcp_help,
++ .expect = pptp_nat_expected
++};
++
++
++static int __init init(void)
++{
++ DEBUGP("%s: registering NAT helper\n", __FILE__);
++ if (ip_nat_helper_register(&pptp_tcp_helper)) {
++ printk(KERN_ERR "Unable to register NAT application helper "
++ "for pptp\n");
++ return -EIO;
++ }
++
++ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ DEBUGP("cleanup_module\n" );
++ ip_nat_helper_unregister(&pptp_tcp_helper);
++ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
+diff -uNr linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c linux/net/ipv4/netfilter/ip_nat_proto_gre.c
+--- linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_nat_proto_gre.c 2006-10-27 14:11:52.000000000 +0200
+@@ -0,0 +1,225 @@
++/*
++ * ip_nat_proto_gre.c - Version 1.2
++ *
++ * NAT protocol helper module for GRE.
++ *
++ * GRE is a generic encapsulation protocol, which is generally not very
++ * suited for NAT, as it has no protocol-specific part as port numbers.
++ *
++ * It has an optional key field, which may help us distinguishing two
++ * connections between the same two hosts.
++ *
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ *
++ * PPTP is built on top of a modified version of GRE, and has a mandatory
++ * field called "CallID", which serves us for the same purpose as the key
++ * field in plain GRE.
++ *
++ * Documentation about PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_nat_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(x, args...)
++#endif
++
++/* is key in given range between min and max */
++static int
++gre_in_range(const struct ip_conntrack_tuple *tuple,
++ enum ip_nat_manip_type maniptype,
++ const union ip_conntrack_manip_proto *min,
++ const union ip_conntrack_manip_proto *max)
++{
++ u_int32_t key;
++
++ if (maniptype == IP_NAT_MANIP_SRC)
++ key = tuple->src.u.gre.key;
++ else
++ key = tuple->dst.u.gre.key;
++
++ return ntohl(key) >= ntohl(min->gre.key)
++ && ntohl(key) <= ntohl(max->gre.key);
++}
++
++/* generate unique tuple ... */
++static int
++gre_unique_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_range *range,
++ enum ip_nat_manip_type maniptype,
++ const struct ip_conntrack *conntrack)
++{
++ u_int32_t min, i, range_size;
++ u_int32_t key = 0, *keyptr;
++
++ if (maniptype == IP_NAT_MANIP_SRC)
++ keyptr = &tuple->src.u.gre.key;
++ else
++ keyptr = &tuple->dst.u.gre.key;
++
++ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
++
++ switch (tuple->dst.u.gre.version) {
++ case 0:
++ DEBUGP("NATing GRE version 0 (ct=%p)\n",
++ conntrack);
++ min = 1;
++ range_size = 0xffffffff;
++ break;
++ case GRE_VERSION_PPTP:
++ DEBUGP("%p: NATing GRE PPTP\n",
++ conntrack);
++ min = 1;
++ range_size = 0xffff;
++ break;
++ default:
++ printk(KERN_WARNING "nat_gre: unknown GRE version\n");
++ return 0;
++ break;
++ }
++
++ } else {
++ min = ntohl(range->min.gre.key);
++ range_size = ntohl(range->max.gre.key) - min + 1;
++ }
++
++ DEBUGP("min = %u, range_size = %u\n", min, range_size);
++
++ for (i = 0; i < range_size; i++, key++) {
++ *keyptr = htonl(min + key % range_size);
++ if (!ip_nat_used_tuple(tuple, conntrack))
++ return 1;
++ }
++
++ DEBUGP("%p: no NAT mapping\n", conntrack);
++
++ return 0;
++}
++
++/* manipulate a GRE packet according to maniptype */
++static void
++gre_manip_pkt(struct iphdr *iph, size_t len,
++ const struct ip_conntrack_manip *manip,
++ enum ip_nat_manip_type maniptype)
++{
++ struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
++ struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
++
++ /* we only have destination manip of a packet, since 'source key'
++ * is not present in the packet itself */
++ if (maniptype == IP_NAT_MANIP_DST) {
++ /* key manipulation is always dest */
++ switch (greh->version) {
++ case 0:
++ if (!greh->key) {
++ DEBUGP("can't nat GRE w/o key\n");
++ break;
++ }
++ if (greh->csum) {
++ /* FIXME: Never tested this code... */
++ *(gre_csum(greh)) =
++ ip_nat_cheat_check(~*(gre_key(greh)),
++ manip->u.gre.key,
++ *(gre_csum(greh)));
++ }
++ *(gre_key(greh)) = manip->u.gre.key;
++ break;
++ case GRE_VERSION_PPTP:
++ DEBUGP("call_id -> 0x%04x\n",
++ ntohl(manip->u.gre.key));
++ pgreh->call_id = htons(ntohl(manip->u.gre.key));
++ break;
++ default:
++ DEBUGP("can't nat unknown GRE version\n");
++ break;
++ }
++ }
++}
++
++/* print out a nat tuple */
++static unsigned int
++gre_print(char *buffer,
++ const struct ip_conntrack_tuple *match,
++ const struct ip_conntrack_tuple *mask)
++{
++ unsigned int len = 0;
++
++ if (mask->dst.u.gre.version)
++ len += sprintf(buffer + len, "version=%d ",
++ ntohs(match->dst.u.gre.version));
++
++ if (mask->dst.u.gre.protocol)
++ len += sprintf(buffer + len, "protocol=0x%x ",
++ ntohs(match->dst.u.gre.protocol));
++
++ if (mask->src.u.gre.key)
++ len += sprintf(buffer + len, "srckey=0x%x ",
++ ntohl(match->src.u.gre.key));
++
++ if (mask->dst.u.gre.key)
++ len += sprintf(buffer + len, "dstkey=0x%x ",
++ ntohl(match->src.u.gre.key));
++
++ return len;
++}
++
++/* print a range of keys */
++static unsigned int
++gre_print_range(char *buffer, const struct ip_nat_range *range)
++{
++ if (range->min.gre.key != 0
++ || range->max.gre.key != 0xFFFF) {
++ if (range->min.gre.key == range->max.gre.key)
++ return sprintf(buffer, "key 0x%x ",
++ ntohl(range->min.gre.key));
++ else
++ return sprintf(buffer, "keys 0x%u-0x%u ",
++ ntohl(range->min.gre.key),
++ ntohl(range->max.gre.key));
++ } else
++ return 0;
++}
++
++/* nat helper struct */
++static struct ip_nat_protocol gre =
++ { { NULL, NULL }, "GRE", IPPROTO_GRE,
++ gre_manip_pkt,
++ gre_in_range,
++ gre_unique_tuple,
++ gre_print,
++ gre_print_range
++ };
++
++static int __init init(void)
++{
++ if (ip_nat_protocol_register(&gre))
++ return -EIO;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip_nat_protocol_unregister(&gre);
++}
++
++module_init(init);
++module_exit(fini);
diff --git a/packages/linux/linux-mtx-2-2.4.27/defconfig-mtx-2 b/packages/linux/linux-mtx-2-2.4.27/defconfig-mtx-2
index fb8c033e09..55b05b57a2 100644
--- a/packages/linux/linux-mtx-2-2.4.27/defconfig-mtx-2
+++ b/packages/linux/linux-mtx-2-2.4.27/defconfig-mtx-2
@@ -311,13 +311,15 @@ CONFIG_SYN_COOKIES=y
#
# IP: Netfilter Configuration
#
-CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CONNTRACK=m
CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_CT_PROTO_GRE=m
+CONFIG_IP_NF_PPTP=m
CONFIG_IP_NF_AMANDA=m
CONFIG_IP_NF_TFTP=m
CONFIG_IP_NF_IRC=m
CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_LIMIT=m
CONFIG_IP_NF_MATCH_MAC=m
CONFIG_IP_NF_MATCH_PKTTYPE=m
@@ -332,29 +334,31 @@ CONFIG_IP_NF_MATCH_LENGTH=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_MATCH_TCPMSS=m
CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
CONFIG_IP_NF_MATCH_UNCLEAN=m
CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_NAT_AMANDA=m
# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_PROTO_GRE=m
CONFIG_IP_NF_NAT_SNMP_BASIC=m
CONFIG_IP_NF_NAT_IRC=m
CONFIG_IP_NF_NAT_FTP=m
CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
CONFIG_IP_NF_TARGET_TCPMSS=m
CONFIG_IP_NF_ARPTABLES=m
@@ -1212,67 +1216,124 @@ CONFIG_USB_LCD=m
# CONFIG_USB_GADGET is not set
#
-# USB clients (devices, not hosts)
-#
-CONFIG_USBD=m
-# CONFIG_USBD_HIGH_SPEED is not set
-# CONFIG_USBD_NO_SERIAL_NUMBER is not set
-CONFIG_USBD_SERIAL_NUMBER_STR=""
-CONFIG_USBD_MAXPOWER=0
-CONFIG_USBD_PROCFS=y
-CONFIG_USBD_PROCFSM=m
-
-#
-# Network Function
-#
-CONFIG_USBD_NETWORK=m
-CONFIG_USBD_NETWORK_VENDORID=12b9
-CONFIG_USBD_NETWORK_PRODUCTID=f001
-CONFIG_USBD_NETWORK_BCDDEVICE=0100
-CONFIG_USBD_NETWORK_MANUFACTURER="Belcarra"
-## CONFIG_USBD_NETWORK_PRODUCT_NAME="Belcarra BLAN Device"
-## CONFIG_USBD_NETWORK_BLAN=y
-## CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg"
-## CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf"
-# CONFIG_USBD_NETWORK_BLAN_CRC is not set
-# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set
-# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set
-# CONFIG_USBD_NETWORK_BLAN_NOBRIDGE is not set
-CONFIG_USBD_NETWORK_SAFE=y
-CONFIG_USBD_NETWORK_SAFE_NOBRIDGE=y
-# CONFIG_USBD_NETWORK_CDC is not set
-# CONFIG_USBD_NETWORK_BASIC is not set
-# CONFIG_USBD_NETWORK_BASIC2 is not set
-# CONFIG_USBD_NETWORK_START_SINGLE is not set
-# CONFIG_USBD_NETWORK_EP0TEST is not set
-
-#
-# CDC ACM Function
-#
-CONFIG_USBD_ACM=m
-CONFIG_USBD_ACM_VENDORID=12b9
-CONFIG_USBD_ACM_PRODUCTID=f002
-CONFIG_USBD_ACM_BCDDEVICE=0100
-CONFIG_USBD_ACM_MANUFACTURER="Belcarra"
-CONFIG_USBD_ACM_PRODUCT_NAME="Belcarra ACM Device"
-CONFIG_USBD_ACM_DESC="Acm Cfg"
-CONFIG_USBD_ACM_COMM_INTF="Comm Intf"
-CONFIG_USBD_ACM_DATA_INTF="Data Intf"
-# CONFIG_USBD_ACM_TRACE is not set
-
-#
-# Random Mouse Function
-#
-# CONFIG_USBD_MOUSE is not set
-
-#
-# AMD AU1X000 Bus Interface
-#
-CONFIG_USBD_AU1X00_BUS=m
-CONFIG_USBD_AU1X00_SCLOCK=400
-CONFIG_AU1000_USB_DEVICE=y
-CONFIG_AU1X00_USB_DEVICE=y
-# CONFIG_USBD_BI_REGISTER_TRACE is not set
+# On-The-Go and USB Peripheral Support
+#
+CONFIG_OTG=m
+
+#
+# Select Hardware
+#
+
+#
+# DB1550 Development Board
+#
+CONFIG_OTG_DB1550=m
+CONFIG_OTG_AU1X00_SCLOCK=400
+# CONFIG_AU1000_USB_DEVICE is not set
+# CONFIG_AU1X00_USB_DEVICE is not set
+CONFIG_OTG_PLATFORM_USBD=y
+CONFIG_OTG_AU1550=m
+CONFIG_OTG_DB1550_J14=y
+# CONFIG_OTG_DB1550_J15 is not set
+# CONFIG_OTG_PLATFORM_OTG is not set
+CONFIG_OTG_PLATFORM_USBD=y
+# CONFIG_OTG_MAX3353E is not set
+CONFIG_OTG_AU1550_DB1550_TR=m
+
+#
+# AMD AU1X00 Bus Interface
+#
+# CONFIG_OTG_AU1X00 is not set
+
+#
+# General Support Options
+#
+# CONFIG_OTG_HIGH_SPEED is not set
+CONFIG_OTG_TRACE=y
+CONFIG_OTG_PROCFSM=m
+# CONFIG_OTG_NOC99 is not set
+
+#
+# Targeted Peripherals (USB Peripheral Function Drivers)
+#
+
+#
+# USB Peripheral Function Driver - CDC ACM
+#
+CONFIG_OTG_ACM=m
+CONFIG_OTG_ACM_VENDORID=15ec
+CONFIG_OTG_ACM_PRODUCTID=f001
+CONFIG_OTG_ACM_BCDDEVICE=0100
+CONFIG_OTG_ACM_MANUFACTURER="Belcarra"
+CONFIG_OTG_ACM_PRODUCT_NAME="Belcarra ACM Device"
+CONFIG_OTG_ACM_DESC="Acm Cfg"
+CONFIG_OTG_ACM_COMM_INTF="Comm Intf"
+CONFIG_OTG_ACM_DATA_INTF="Data Intf"
+
+#
+# USB Peripheral Function Driver - Random Mouse
+#
+# CONFIG_OTG_MOUSE is not set
+
+#
+# USB Peripheral Function Driver - Network
+#
+CONFIG_OTG_NETWORK=m
+CONFIG_OTG_NETWORK_VENDORID=15ec
+CONFIG_OTG_NETWORK_PRODUCTID=f001
+CONFIG_OTG_NETWORK_BCDDEVICE=0100
+CONFIG_OTG_NETWORK_MANUFACTURER="Belcarra"
+CONFIG_OTG_NETWORK_PRODUCT_NAME="Belcarra BLAN Device"
+CONFIG_OTG_NETWORK_BLAN=y
+# CONFIG_OTG_NETWORK_SAFE is not set
+# CONFIG_OTG_NETWORK_CDC is not set
+# CONFIG_OTG_NETWORK_BASIC is not set
+# CONFIG_OTG_NETWORK_BASIC2 is not set
+# CONFIG_OTG_NETWORK_EEM is not set
+
+#
+# MBLM-BLAN Networking Configuration
+#
+CONFIG_OTG_NETWORK_BLAN_DESC="BLAN Net Cfg"
+CONFIG_OTG_NETWORK_BLAN_INTF="Comm/Data Intf"
+CONFIG_OTG_NETWORK_BLAN_CRC=y
+# CONFIG_OTG_NETWORK_BLAN_PADBEFORE is not set
+# CONFIG_OTG_NETWORK_BLAN_PADAFTER is not set
+# CONFIG_OTG_NETWORK_BLAN_FERMAT is not set
+# CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME is not set
+# CONFIG_OTG_NETWORK_BLAN_HOSTNAME is not set
+CONFIG_OTG_NETWORK_BLAN_NONBRIDGED=y
+# CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK is not set
+CONFIG_OTG_NETWORK_BLAN_PADBYTES=8
+CONFIG_OTG_NETWORK_BLAN_INTERVAL=4
+# CONFIG_OTG_NETWORK_BLAN_IPADDR is not set
+CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG=y
+# CONFIG_OTG_NETWORK_START_SINGLE is not set
+# CONFIG_OTG_NETWORK_EP0TEST is not set
+# CONFIG_OTG_NETWORK_HOTPLUG is not set
+
+#
+# Mass Storage Function
+#
+# CONFIG_OTG_MSC is not set
+
+#
+# Traditional Device Options
+#
+CONFIG_OTG_FW_MN=y
+CONFIG_OTG_TR_AUTO=y
+
+#
+# Host configuration (OTG minihost core and HCD)
+#
+
+#
+# OTG Host Controller Driver (HCD)
+#
+# CONFIG_OTG_HCD is not set
+CONFIG_OTG_ROOTHUB_VENDORID=15ec
+CONFIG_OTG_ROOTHUB_PRODUCTID=f010
+CONFIG_OTG_ROOTHUB_BCDDEVICE=0100
#
# Bluetooth support