diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/usb/gadget_cathy')
10 files changed, 1211 insertions, 177 deletions
diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/Kconfig b/target/linux/realtek/files/drivers/usb/gadget_cathy/Kconfig index a60157c60..896e01cc0 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/Kconfig +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/Kconfig @@ -54,6 +54,22 @@ config USB_GADGET_DEBUG_FILES here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_VBUS_DRAW + int "Maximum VBUS Power usage (2-500 mA)" + range 2 500 + default 2 + help + Some devices need to draw power from USB when they are + configured, perhaps to operate circuitry or to recharge + batteries. This is in addition to any local power supply, + such as an AC adapter or batteries. + + Enter the maximum power your device draws through USB, in + milliAmperes. The permitted range of values is 2 - 500 mA; + 0 mA would be legal, but can make some hosts misbehave. + + This value will be used except for system-specific gadget + drivers that have more specific information. config USB_GADGET_SELECTED boolean "USB_GADGET_SELECTED" @@ -369,21 +385,10 @@ config USB_ETH_RNDIS XP, you'll need to download drivers from Microsoft's website; a URL is given in comments found in that info file. -config USB_GADGETFS - tristate "Gadget Filesystem (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - This driver provides a filesystem based API that lets user mode - programs implement a single-configuration USB device, including - endpoint I/O and control requests that don't relate to enumeration. - All endpoints, transfer speeds, and transfer types supported by - the hardware are available, through read() and write() calls. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "gadgetfs". - config USB_FILE_STORAGE - tristate "File-backed Storage Gadget" + bool "File-backed Storage Gadget" + depends on USB_ETH && EXPERIMENTAL + default y help The File-backed Storage Gadget acts as a USB Mass Storage disk drive. As its storage repository it can use a regular @@ -403,6 +408,40 @@ config USB_FILE_STORAGE_TEST behavior of USB Mass Storage hosts. Not needed for normal operation. +config USB_GADGETFS + tristate "Gadget Filesystem (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + This driver provides a filesystem based API that lets user mode + programs implement a single-configuration USB device, including + endpoint I/O and control requests that don't relate to enumeration. + All endpoints, transfer speeds, and transfer types supported by + the hardware are available, through read() and write() calls. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "gadgetfs". + +#config USB_FILE_STORAGE +# tristate "File-backed Storage Gadget" +# help +# The File-backed Storage Gadget acts as a USB Mass Storage +# disk drive. As its storage repository it can use a regular +# file or a block device (in much the same way as the "loop" +# device driver), specified as a module parameter. +# +# Say "y" to link the driver statically, or "m" to build a +# dynamically linked module called "g_file_storage". +# +#config USB_FILE_STORAGE_TEST +# bool "File-backed Storage Gadget testing version" +# depends on USB_FILE_STORAGE +# default n +# help +# Say "y" to generate the larger testing version of the +# File-backed Storage Gadget, useful for probing the +# behavior of USB Mass Storage hosts. Not needed for +# normal operation. + config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM support)" help diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/Makefile b/target/linux/realtek/files/drivers/usb/gadget_cathy/Makefile index 13b5584e1..f54560ca0 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/Makefile +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/Makefile @@ -17,14 +17,14 @@ g_ether-objs := ether.o usbstring.o config.o epautoconf.o g_serial-objs := serial.o usbstring.o config.o epautoconf.o g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o gadgetfs-objs := inode.o -g_file_storage-objs := file_storage.o usbstring.o config.o \ - epautoconf.o +#g_file_storage-objs := file_storage.o usbstring.o config.o epautoconf.o +g_file_storage-objs := file_storage.o ifeq ($(CONFIG_USB_ETH_RNDIS),y) g_ether-objs += rndis.o endif -obj-$(CONFIG_USB_OTG_DEVICE_RTL8672) += g_ether.o +#obj-$(CONFIG_USB_OTG_DEVICE_RTL8672) += g_ether.o #obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/dummy_hcd.c b/target/linux/realtek/files/drivers/usb/gadget_cathy/dummy_hcd.c index f1f32d7be..633cbb9df 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/dummy_hcd.c +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/dummy_hcd.c @@ -59,7 +59,11 @@ #include <asm/unaligned.h> +#if defined(CONFIG_USB_UWIFI_HOST) +#include "../core_uWiFi/hcd.h" +#else #include "../core/hcd.h" +#endif #define DRIVER_DESC "USB Host+Gadget Emulator" diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/epautoconf.c b/target/linux/realtek/files/drivers/usb/gadget_cathy/epautoconf.c index 3842ed339..3d483a773 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/epautoconf.c +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/epautoconf.c @@ -32,14 +32,17 @@ #include "gadget_chips.h" +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif /* we must assign addresses for configurable endpoints (like net2280) */ -static __devinitdata unsigned epnum; +static ULINKER_DEVINITDATA unsigned epnum; // #define MANY_ENDPOINTS #ifdef MANY_ENDPOINTS /* more than 15 configurable endpoints */ -static __devinitdata unsigned in_epnum; +static ULINKER_DEVINITDATA unsigned in_epnum; #endif @@ -59,7 +62,7 @@ static __devinitdata unsigned in_epnum; * NOTE: each endpoint is unidirectional, as specified by its USB * descriptor; and isn't specific to a configuration or altsetting. */ -static int __devinit +static int ULINKER_DEVINIT ep_matches ( struct usb_gadget *gadget, struct usb_ep *ep, @@ -186,7 +189,7 @@ ep_matches ( return 1; } -static struct usb_ep * __devinit +static struct usb_ep * ULINKER_DEVINIT find_ep (struct usb_gadget *gadget, const char *name) { struct usb_ep *ep; @@ -228,7 +231,7 @@ find_ep (struct usb_gadget *gadget, const char *name) * * On failure, this returns a null endpoint descriptor. */ -struct usb_ep * __devinit usb_ep_autoconfig ( +struct usb_ep * ULINKER_DEVINIT usb_ep_autoconfig ( struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc ) @@ -295,7 +298,7 @@ struct usb_ep * __devinit usb_ep_autoconfig ( * state such as ep->driver_data and the record of assigned endpoints * used by usb_ep_autoconfig(). */ -void __devinit usb_ep_autoconfig_reset (struct usb_gadget *gadget) +void ULINKER_DEVINIT usb_ep_autoconfig_reset (struct usb_gadget *gadget) { struct usb_ep *ep; diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/ether.c b/target/linux/realtek/files/drivers/usb/gadget_cathy/ether.c index c92d50010..c844945ee 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/ether.c +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/ether.c @@ -61,11 +61,19 @@ #include <asm-mips/rtl865x/platform.h> #define SPEED_UP_TX +#if 1//defined(CONFIG_RTL_ULINKER_BRSC) +#include "linux/ulinker_brsc.h" +#endif + //#define TEST_MODE #ifdef TEST_MODE #include "../net/otg_dev_driver.h" #endif +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif + struct eth_dev * g_eth_dev; #define REG32(reg) (*(volatile unsigned int *)((unsigned int)reg)) /*-------------------------------------------------------------------------*/ @@ -142,6 +150,9 @@ struct eth_dev { spinlock_t req_lock; struct list_head tx_reqs, rx_reqs; +#if ULINKER_BRSC_RECOVER_TX_REQ + struct list_head txed_reqs; +#endif struct net_device *net; struct net_device_stats stats; @@ -208,9 +219,14 @@ struct eth_dev { * the non-RNDIS configuration. */ //cathy, test + +#if 0 #define RNDIS_VENDOR_NUM 0x0BDA//0x0525 /* NetChip */ #define RNDIS_PRODUCT_NUM 0x8672//0xa4a2 /* Ethernet/RNDIS Gadget */ - +#else +#define RNDIS_VENDOR_NUM ULINKER_ETHER_VID +#define RNDIS_PRODUCT_NUM ULINKER_ETHER_PID +#endif /* Some systems will want different product identifers published in the * device descriptor, either numbers or strings or both. These string @@ -351,9 +367,11 @@ static inline int rndis_active(struct eth_dev *dev) #define subset_active(dev) (!is_cdc(dev) && !rndis_active(dev)) #define cdc_active(dev) ( is_cdc(dev) && !rndis_active(dev)) - - +#if defined(CONFIG_RTL_ULINKER_BRSC) +#define DEFAULT_QLEN 4 /* double buffering by default */ +#else #define DEFAULT_QLEN 2 /* double buffering by default */ +#endif /* peak bulk transfer bits-per-second */ //#define HS_BPS (13 * 512 * 8 * 1000 * 8) @@ -1186,6 +1204,19 @@ static void eth_reset_config (struct eth_dev *dev) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); +#if ULINKER_BRSC_RECOVER_TX_REQ //clean txed list + spin_lock(&dev->req_lock); + while (likely (!list_empty (&dev->txed_reqs))) { + req = container_of (dev->txed_reqs.next, + struct usb_request, list); + list_del (&req->list); + + spin_unlock(&dev->req_lock); + //usb_ep_free_request (dev->in_ep, req); + spin_lock(&dev->req_lock); + } + spin_unlock(&dev->req_lock); +#endif } if (dev->out) { usb_ep_disable (dev->out_ep); @@ -1281,6 +1312,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) : (cdc_active(dev) ? "CDC Ethernet" : "CDC Ethernet Subset")); + +{ + extern int rndis_reset; + if (rndis_reset == 1 && number == 1) + rndis_reset = 2; +} + } return result; } @@ -1405,6 +1443,15 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) #endif /* RNDIS */ +#if defined(CONFIG_RTL_ULINKER) +int wall_mount = 1; +enum { + RTL_ETHER_STATE_INIT, + RTL_ETHER_STATE_GET_DEV_DESC, + RTL_ETHER_STATE_SET_CONF +}; +int ether_state = RTL_ETHER_STATE_INIT; +#endif /* * The setup() callback implements all the ep0 functionality that's not * handled lower down. CDC has a number of less-common features: @@ -1439,6 +1486,19 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_DEVICE: value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); +#if defined(CONFIG_RTL_ULINKER) + /* + if wall_mount=1 means usb driver doesn't get any control urb + ie, when ulinker is plugged into a usb adapter, not pc, we need to change ulinker into + ether mode after some seconds. + */ + if (wall_mount) + { + wall_mount = 0; + ether_state = RTL_ETHER_STATE_GET_DEV_DESC; + BDBG_GADGET_MODE_SWITCH("[%s:%d] get dev_desc, set wall_mount=0\n", __FUNCTION__, __LINE__); + } +#endif break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: @@ -1481,6 +1541,13 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); value = eth_set_config (dev, wValue, GFP_ATOMIC); spin_unlock (&dev->lock); +#if defined(CONFIG_RTL_ULINKER) + if ((value == 0) && (ether_state == RTL_ETHER_STATE_GET_DEV_DESC)) + { + BDBG_GADGET_MODE_SWITCH("[%s:%d] set conf\n", __FUNCTION__, __LINE__); + ether_state = RTL_ETHER_STATE_SET_CONF; + } +#endif break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) @@ -1687,7 +1754,7 @@ eth_disconnect (struct usb_gadget *gadget) /* NETWORK DRIVER HOOKUP (to the layer above this driver) */ -static int eth_change_mtu (struct net_device *net, int new_mtu) +static int geth_change_mtu (struct net_device *net, int new_mtu) { struct eth_dev *dev = netdev_priv(net); @@ -1792,6 +1859,173 @@ static void defer_kevent (struct eth_dev *dev, int flag) DEBUG (dev, "kevent %d scheduled\n", flag); } +#if defined(CONFIG_RTL_ULINKER_BRSC) +#define MACADDRLEN 6 + +#if ULINKER_BRSC_COUNTER +struct brsc_counter_s brsc_counter = {0}; +#endif + +char usb_cached = 0; + +struct brsc_cache cached_usb; +struct brsc_cache cached_eth; +struct brsc_cache cached_wlan; + +static struct net_device * eth0_dev = NULL; +spinlock_t brsc_cache_lock = SPIN_LOCK_UNLOCKED; + +#if ULINKER_BRSC_RECOVER_TX_REQ +extern int early_tx_complete (void); +#endif + +inline struct net_device *brsc_get_cached_dev(char from_usb, unsigned char *da) +{ + if (usb_cached == 0) + return NULL; + + if (cached_usb.dev == NULL) { + cached_usb.dev = dev_get_by_name(&init_net, "usb0"); + if (cached_usb.dev == NULL) + return NULL; + } + + BDBG_BRSC("BRSC: da[%02x:%02x:%02x:%02x:%02x:%02x]\n", + da[0], da[1], da[2], da[3], da[4], da[5]); + + if (from_usb == 0) { + if (cached_usb.dev && !memcmp(da, cached_usb.addr, MACADDRLEN)) { + BDBG_BRSC("BRSC: return cached_usb\n"); + return cached_usb.dev; + } + } + else { + unsigned long flags; + spin_lock_irqsave(&brsc_cache_lock, flags); + if (cached_wlan.dev && !memcmp(da, cached_wlan.addr, MACADDRLEN)) { + BDBG_BRSC("BRSC: return cached_wlan\n"); + spin_unlock_irqrestore(&brsc_cache_lock, flags); + return cached_wlan.dev; + } + + if (cached_eth.dev && !memcmp(da, cached_eth.addr, MACADDRLEN)) { + BDBG_BRSC("BRSC: return cached_eth\n"); + spin_unlock_irqrestore(&brsc_cache_lock, flags); + return cached_eth.dev; + } + spin_unlock_irqrestore(&brsc_cache_lock, flags); + } + + return NULL; +} + +inline void brsc_cache_dev(int from, struct net_device *dev, unsigned char *sa) +{ + unsigned long flags; + + if (dev) { + if (from == 1) { + BDBG_BRSC("BRSC: cache %s, %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + + spin_lock_irqsave(&brsc_cache_lock, flags); + cached_wlan.dev = dev; + memcpy(cached_wlan.addr, sa, MACADDRLEN); + spin_unlock_irqrestore(&brsc_cache_lock, flags); + } + else if (from == 2) { + BDBG_BRSC("BRSC: cache %s, %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + + if (eth0_dev == NULL) + eth0_dev = dev_get_by_name(&init_net, "eth0"); + else if (dev == eth0_dev) + printk("[%s:%d] from eth0\n", __FUNCTION__, __LINE__); + + spin_lock_irqsave(&brsc_cache_lock, flags); + cached_eth.dev = dev; + memcpy(cached_eth.addr, sa, MACADDRLEN); + spin_unlock_irqrestore(&brsc_cache_lock, flags); + } + else { + printk("[%s:%d] not handle dev[%s]\n", __FUNCTION__, __LINE__, dev->name); + } + } +} + +#if defined(CONFIG_RTL_ULINKER_BRSC_TASKLET) +#define ULINKER_BRSC_TASKLET 1 +#endif + +#if defined(ULINKER_BRSC_TASKLET) +#include <linux/kfifo.h> + +struct rx_fifo { + struct sk_buff *skb; + struct net_device *outdev; +}; + +struct tasklet_struct usb_rx_tasklet; +static spinlock_t rx_fifo_buffer_lock = SPIN_LOCK_UNLOCKED; +static struct kfifo *rx_fifo_buffer; + +#define QUEUE_MAX (1024) +#define BUFFER_SIZE (8192) //(QUEUE_MAX*sizeof(struct rx_fifo)) +#define ENTRY_SIZE (8) //(sizeof(struct rx_fifo)) + +inline void rx_queue_in(struct sk_buff *pskb, struct net_device *poutdev) +{ + static struct rx_fifo tmp; + unsigned long flags; + + spin_lock_irqsave(rx_fifo_buffer->lock, flags); + + (&tmp)->skb = pskb; + (&tmp)->outdev = poutdev; + if((BUFFER_SIZE - kfifo_len(rx_fifo_buffer)) >= ENTRY_SIZE) + { + __kfifo_put(rx_fifo_buffer, (unsigned char *)(&tmp), ENTRY_SIZE); + } + else { + printk("[%s:%d] queue run out!!!\n", __FUNCTION__, __LINE__); + dev_kfree_skb(pskb); + } + + spin_unlock_irqrestore(rx_fifo_buffer->lock, flags); +} + +inline unsigned int rx_queue_out(struct rx_fifo *tmp) +{ + return kfifo_get(rx_fifo_buffer, (unsigned char *)(tmp), ENTRY_SIZE); +} + +void rx_xmit_kfifo(unsigned long s) +{ + static struct rx_fifo tmp; + while (rx_queue_out(&tmp)) { + (&tmp)->outdev->netdev_ops->ndo_start_xmit((&tmp)->skb,(&tmp)->outdev); + } +} + +inline void init_rx_queue(void) +{ + rx_fifo_buffer = kfifo_alloc(BUFFER_SIZE, GFP_KERNEL, &rx_fifo_buffer_lock); +} + +inline void free_rx_queue(void) +{ +#if 0 + static struct rx_fifo tmp; + while (rx_queue_out(&tmp)) { + dev_kfree_skb((&tmp)->skb); + } +#endif + kfifo_free(rx_fifo_buffer); +} +#endif /* #if defined(ULINKER_BRSC_TASKLET) */ + +#endif /* #if defined(CONFIG_RTL_ULINKER_BRSC) */ + static void rx_complete (struct usb_ep *ep, struct usb_request *req); @@ -1822,6 +2056,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) size += 1000; #endif if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) { + BRSC_COUNTER_UPDATE(rx_alloc_fail); DEBUG (dev, "no rx skb\n"); goto enomem; } @@ -1839,6 +2074,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) retval = usb_ep_queue (dev->out_ep, req, gfp_flags); if (retval == -ENOMEM) { + BRSC_COUNTER_UPDATE(rx_ep_queue_fail); enomem: defer_kevent (dev, WORK_RX_MEMORY); //cathy @@ -1848,14 +2084,23 @@ enomem: return retval; } if (retval) { + BRSC_COUNTER_UPDATE(rx_ep_queue_fail2); DEBUG (dev, "rx submit --> %d\n", retval); dev_kfree_skb_any (skb); spin_lock(&dev->req_lock); list_add (&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); } + +#if ULINKER_BRSC_COUNTER + if (retval == 0) { + BRSC_COUNTER_UPDATE(rx_ep_queue_ok); + } +#endif + return retval; } + static int eth_start_xmit (struct sk_buff *skb, struct net_device *net); #ifdef TEST_MODE extern void memDump (void *start, u32 size, char * strHeader); @@ -1873,6 +2118,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) int rest; #endif #endif + + BRSC_COUNTER_UPDATE(rx_complete_in); + switch (status) { /* normal completion */ @@ -1888,6 +2136,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) dev->stats.rx_errors++; dev->stats.rx_length_errors++; DEBUG (dev, "rx length %d\n", skb->len); + BRSC_COUNTER_UPDATE(rx_complete_err); break; } #endif @@ -2019,6 +2268,76 @@ check_length_again: #endif #ifndef TEST_MODE + #if defined(CONFIG_RTL_ULINKER_BRSC) + { + unsigned char *data = NULL; + struct net_device *cached_dev; + int offset = 0; + + if (skb) + data = skb_mac_header(skb); + + BDBG_BRSC("BRSC: 0x%x, 0x%x\n", skb->data, data); + + BDBG_BRSC("BRSC: data[%02x:%02x:%02x:%02x:%02x:%02x]\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + if (0==(data[0]&0x01)) /* unicast pkt only */ + { + /* shortcut process */ + if ((cached_dev=brsc_get_cached_dev(1, data))!=NULL) { + #if 0 + if (cached_dev->name) { + BDBG_BRSC("BRSC: go short cut[%s]\n", cached_dev->name); + } + else { + BDBG_BRSC("BRSC: go short cut[%s] fail, go normal path\n", "NULL"); + goto NORMAL_PATH; + } + #endif + + offset = skb->data-data; + + BDBG_BRSC("BRSC: offset[%d]\n", offset); + + if (offset > 0) { + skb_push(skb, offset); + BDBG_BRSC("BRSC: skb_push: 0x%x, 0x%x\n", skb->data, data); + } + else if (offset < 0) { + printk("BRSC: %d, %d, go normal path!!!!!!!!!!!!\n", offset, 0-offset); + goto NORMAL_PATH; + } + + skb->dev = cached_dev; + BRSC_COUNTER_UPDATE(rx_complete_sc); + + #if defined(ULINKER_BRSC_TASKLET) + rx_queue_in(skb, cached_dev); + tasklet_schedule(&usb_rx_tasklet); + #else + #if defined(CONFIG_COMPAT_NET_DEV_OPS) + cached_dev->hard_start_xmit(skb, cached_dev); + #else + cached_dev->netdev_ops->ndo_start_xmit(skb,cached_dev); + #endif + #endif + + BDBG_BRSC("BRSC: send by shortcut dev[%s]\n\n", cached_dev->name); + + if (req) + rx_submit(dev, req, GFP_ATOMIC); + + return; + } + } + } + +NORMAL_PATH: + BRSC_COUNTER_UPDATE(rx_complete_normal); + + #endif /* #if defined(CONFIG_RTL_ULINKER_BRSC) */ + status = netif_rx (skb); skb = NULL; #endif @@ -2026,12 +2345,19 @@ check_length_again: /* software-driven interface shutdown */ case -ECONNRESET: // unlink + #if ULINKER_BRSC_COUNTER + BRSC_COUNTER_UPDATE(rx_complete_connreset); + VDEBUG (dev, "rx shutdown, code %d\n", status); + goto quiesce; + #endif case -ESHUTDOWN: // disconnect etc + BRSC_COUNTER_UPDATE(rx_complete_shutdown); VDEBUG (dev, "rx shutdown, code %d\n", status); goto quiesce; /* for hardware automagic (such as pxa) */ case -ECONNABORTED: // endpoint reset + BRSC_COUNTER_UPDATE(rx_complete_connabort); DEBUG (dev, "rx %s reset\n", ep->name); defer_kevent (dev, WORK_RX_MEMORY); quiesce: @@ -2040,10 +2366,12 @@ quiesce: /* data overrun */ case -EOVERFLOW: + BRSC_COUNTER_UPDATE(rx_complete_overflow); dev->stats.rx_over_errors++; // FALLTHROUGH default: + BRSC_COUNTER_UPDATE(rx_complete_other_err); dev->stats.rx_errors++; DEBUG (dev, "rx status %d\n", status); break; @@ -2178,12 +2506,20 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req) dev->stats.tx_bytes += skb->len; } dev->stats.tx_packets++; + BRSC_COUNTER_UPDATE(tx_ok); spin_lock(&dev->req_lock); +#if ULINKER_BRSC_RECOVER_TX_REQ + list_del (&req->list); // remove from transferred list +#endif list_add (&req->list, &dev->tx_reqs); spin_unlock(&dev->req_lock); +#if defined(CONFIG_RTL_ULINKER_BRSC) + dev_kfree_skb_any (skb); +#else //dev_kfree_skb_any (skb);//cathy dev_kfree_skb (skb); +#endif atomic_dec (&dev->tx_qlen); if (netif_carrier_ok (dev->net)) @@ -2239,6 +2575,9 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) #ifdef SPEED_UP_TX struct rndis_packet_msg_type *header=NULL; #endif + + BRSC_COUNTER_UPDATE(tx_in); + /* apply outgoing CDC or RNDIS filters */ if (!eth_is_promisc (dev)) { u8 *dest = skb->data; @@ -2254,6 +2593,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(dev->cdc_filter & type)) { + BRSC_COUNTER_UPDATE(tx_unknown_cdc_filter); dev_kfree_skb_any (skb); return 0; } @@ -2264,8 +2604,32 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) //eason,for usb1.1 fault spin_lock_irqsave(&dev->req_lock, flags); - if (list_empty (&dev->tx_reqs)){ - netif_stop_queue (net); +#if ULINKER_BRSC_RECOVER_TX_REQ + if (list_empty (&dev->tx_reqs)) + { + struct usb_request *preq = NULL; + int i = 0; + + list_for_each_entry(preq, &dev->txed_reqs, list) { + if (early_tx_complete()==11) { + BRSC_COUNTER_UPDATE(tx_req_full_recover); + break; + } + else { + break; + } + i++; + } + } +#endif /* #if ULINKER_BRSC_RECOVER_TX_REQ */ + + if (list_empty (&dev->tx_reqs) +#if 0//defined(CONFIG_RTL_ULINKER_BRSC) + || netif_queue_stopped(net) +#endif + ) { + BRSC_COUNTER_UPDATE(tx_req_full); + netif_stop_queue (net); dev->stats.tx_dropped++; dev_kfree_skb_any (skb); spin_unlock_irqrestore(&dev->req_lock, flags); @@ -2273,6 +2637,9 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) }else{ req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + #if ULINKER_BRSC_RECOVER_TX_REQ + list_add_tail(&req->list, &dev->txed_reqs);// add to transferred list + #endif spin_unlock_irqrestore(&dev->req_lock, flags); } @@ -2312,8 +2679,10 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) struct sk_buff *skb_rndis; skb_rndis = skb_realloc_headroom2 (skb, sizeof (struct rndis_packet_msg_type)); - if (!skb_rndis) + if (!skb_rndis) { + BRSC_COUNTER_UPDATE(tx_realloc_header_fail); goto drop; + } if( skb!=skb_rndis) { //dev_kfree_skb_any (skb); dev_kfree_skb(skb); //cathy test @@ -2338,6 +2707,28 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) offset = (u32)skb->data%4; if( offset ) { skb_new = skb_copy_expand(skb, skb_headroom(skb)+offset, 0, GFP_ATOMIC); + +#if defined(CONFIG_RTL_ULINKER_BRSC) + if (skb_new==NULL) { + offset = 0; + BRSC_COUNTER_UPDATE(tx_skb_expand_full); + goto drop; + } + + dev_kfree_skb(skb); + skb = skb_new; + #ifdef SPEED_UP_TX + if(header==NULL) + req->buf = skb->data; + else + req->buf = skb->data-(sizeof *header); + #else + req->buf = skb->data; + #endif + req->context = skb; + + offset = 0; //for free skb, not skb_new +#else //------ #ifdef SPEED_UP_TX if(header==NULL) #endif @@ -2348,6 +2739,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) #endif req->context = skb_new; dev_kfree_skb(skb); +#endif /* #if defined(CONFIG_RTL_ULINKER_BRSC) */ } else { #ifdef SPEED_UP_TX @@ -2379,10 +2771,18 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) : 0; #endif +#ifdef SUPPORT_MACOS + if (req->length % 512 == 0) { + //printk("[%s:%d] req->length=%d, skb->len=%d\n", __FUNCTION__, __LINE__, req->length, skb->len); + req->length++; + } +#endif + retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { default: DEBUG (dev, "tx queue err %d\n", retval); + BRSC_COUNTER_UPDATE(tx_ep_queue_err); break; case 0: net->trans_start = jiffies; @@ -2399,6 +2799,9 @@ drop: spin_lock_irqsave(&dev->req_lock, flags); if (list_empty (&dev->tx_reqs)) netif_start_queue (net); + #if ULINKER_BRSC_RECOVER_TX_REQ + list_del(&req->list);// remove from transferred list + #endif list_add (&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } @@ -2503,6 +2906,13 @@ static int eth_open (struct net_device *net) { #define USB2_PHY_DELAY __delay(200) struct eth_dev *dev = netdev_priv(net); + +#if defined(ULINKER_BRSC_TASKLET) + spin_lock_init(&brsc_cache_lock); + init_rx_queue(); + tasklet_init(&usb_rx_tasklet, (void *)rx_xmit_kfifo, (unsigned long)net); +#endif + #if 0 u32 tmp = REG32(0xb8003314); //090929 cathy start @@ -2557,9 +2967,18 @@ static int eth_stop (struct net_device *net) { struct eth_dev *dev = netdev_priv(net); +#if defined(CONFIG_RTL_ULINKER) + // for link down rndis on winows + (void) rndis_signal_disconnect (dev->rndis_config); +#else VDEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (net); +#if defined(ULINKER_BRSC_TASKLET) + tasklet_kill(&usb_rx_tasklet); + free_rx_queue(); +#endif + DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", dev->stats.rx_packets, dev->stats.tx_packets, dev->stats.rx_errors, dev->stats.tx_errors @@ -2586,6 +3005,7 @@ static int eth_stop (struct net_device *net) NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } +#endif /* #if defined(CONFIG_RTL_ULINKER) */ return 0; } @@ -2651,7 +3071,7 @@ eth_unbind (struct usb_gadget *gadget) set_gadget_data (gadget, NULL); } -static u8 __devinit nibble (unsigned char c) +static u8 ULINKER_DEVINIT nibble (unsigned char c) { if (likely (isdigit (c))) return c - '0'; @@ -2661,7 +3081,7 @@ static u8 __devinit nibble (unsigned char c) return 0; } -static int __devinit get_ether_addr(const char *str, u8 *dev_addr) +static int ULINKER_DEVINIT get_ether_addr(const char *str, u8 *dev_addr) { if (str) { unsigned i; @@ -2705,7 +3125,46 @@ static int eth_set_host_mac_addr(struct net_device *net, void *addr) return err; } -static int __devinit +#if defined(CONFIG_RTL_ULINKER) && !defined(CONFIG_COMPAT_NET_DEV_OPS) +static void eth_set_rx_mode (struct net_device *dev) +{ + /* Not yet implemented. */ +} + +static void eth_tx_timeout (struct net_device *dev) +{ + printk("Tx Timeout!!! Can't send packet\n"); +} + +static const struct net_device_ops rtl819x_netdev_ops_usb = { + .ndo_open = eth_open, + .ndo_stop = eth_stop, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_set_host_mac_addr, + .ndo_set_multicast_list = eth_set_rx_mode, + .ndo_get_stats = eth_get_stats, + .ndo_do_ioctl = eth_ioctl, +#ifdef TEST_MODE + .ndo_start_xmit = eth_start_xmit2, +#else + .ndo_start_xmit = eth_start_xmit, +#endif + .ndo_tx_timeout = eth_tx_timeout, +#if defined(CP_VLAN_TAG_USED) + .ndo_vlan_rx_register = cp_vlan_rx_register, +#endif + .ndo_change_mtu = geth_change_mtu, +}; + +#if 0 +//cathy, for update host mac (eth mac + 1) + my_eth_mac_addr = net->set_mac_address; + net->set_mac_address = eth_set_host_mac_addr; +#endif + +#endif /* defined(CONFIG_RTL_ULINKER) && !defined(CONFIG_COMPAT_NET_DEV_OPS) */ + +static int ULINKER_DEVINIT eth_bind (struct usb_gadget *gadget) { struct eth_dev *dev; @@ -2714,7 +3173,7 @@ eth_bind (struct usb_gadget *gadget) struct usb_ep *in_ep, *out_ep, *status_ep = NULL; int status = -ENOMEM; int gcnum; - + //REG32(0xb8030804) |= 0x02000000; //cathy, set soft disconnect in reg DCTL /* these flags are only ever cleared; compiler take note */ #ifndef DEV_CONFIG_CDC @@ -2765,13 +3224,13 @@ eth_bind (struct usb_gadget *gadget) gadget->name); return -ENODEV; } -#endif +#endif #if 0 snprintf (manufacturer, sizeof manufacturer, "%s %s/%s", init_utsname()->sysname, init_utsname()->release, gadget->name); #endif - snprintf (manufacturer, sizeof manufacturer, "Realtek Semiconductor Corporation"); + snprintf (manufacturer, sizeof manufacturer, ULINKER_MANUFACTURER); /* If there's an RNDIS configuration, that's what Windows wants to * be using ... so use these product IDs here and in the "linux.inf" * needed to install MSFT drivers. Current Linux kernels will use @@ -2913,6 +3372,9 @@ autoconf_fail: g_eth_dev= net; INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); +#if ULINKER_BRSC_RECOVER_TX_REQ + INIT_LIST_HEAD (&dev->txed_reqs); +#endif /* network device setup */ dev->net = net; @@ -2929,6 +3391,32 @@ autoconf_fail: * The host side address is used with CDC and RNDIS, and commonly * ends up in a persistent config database. */ + +#if defined(CONFIG_RTL_ULINKER) +{ + extern char ulinker_rndis_mac[]; + if (strlen(ulinker_rndis_mac)==12) + { + strcpy(host_addr, ulinker_rndis_mac); + //panic_printk("[%s:%d] host_addr[%s], len[%d]\n", __FUNCTION__, __LINE__, host_addr, strlen(host_addr)); + + #if defined(CONFIG_RTL_ULINKER_BRSC) + get_ether_addr(ulinker_rndis_mac, cached_usb.addr); + cached_usb.dev = dev_get_by_name(&init_net, "usb0"); + #if 0 + printk("[%s:%d] host_addr[%s], len[%d]\n", + __FUNCTION__, __LINE__, ulinker_rndis_mac, strlen(ulinker_rndis_mac)); + printk("--> 1. %02x:%02x:%02x:%02x:%02x:%02x\n", + cached_usb.addr[0], cached_usb.addr[1], cached_usb.addr[2], + cached_usb.addr[3], cached_usb.addr[4], cached_usb.addr[5]); + printk("--> 1. cached_usb.dev[%s], dev[%s]\n", cached_usb.dev->name, net->name); + #endif + usb_cached = 1; + #endif + } +} +#endif + if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); @@ -2953,7 +3441,11 @@ autoconf_fail: } } - net->change_mtu = eth_change_mtu; +#if defined(CONFIG_RTL_ULINKER) && !defined(CONFIG_COMPAT_NET_DEV_OPS) /* bruce, for support newer net_device */ + net->netdev_ops = &rtl819x_netdev_ops_usb; + SET_ETHTOOL_OPS(net, &ops); +#else //--- !defined(CONFIG_RTL_ULINKER) + net->change_mtu = geth_change_mtu; net->get_stats = eth_get_stats; #ifdef TEST_MODE net->hard_start_xmit = eth_start_xmit2; @@ -2970,6 +3462,8 @@ autoconf_fail: // watchdog_timeo, tx_timeout ... // set_multicast_list SET_ETHTOOL_OPS(net, &ops); +#endif /* defined(CONFIG_RTL_ULINKER) */ + //cathy test device_desc.iSerialNumber = STRING_ETHADDR, @@ -3127,22 +3621,132 @@ static void __exit cleanup (void) } module_exit (cleanup); + +#if defined(CONFIG_RTL_ULINKER_BRSC) +static int read_ulinker_brsc_en(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; +#if ULINKER_BRSC_COUNTER + len = sprintf(page, "USB_TX:\n\t" + "tx_in: %lu\n\t" + "from_eth_sc: %lu\n\t" + "from_wlan_sc: %lu\n\t" + "tx_ok: %lu\n\t" + "uno_cdc_filter: %lu\n\t" + "tx_req_full: %lu\n\t" + "realloc_fail: %lu\n\t" + "expand_full: %lu\n\t" + "ep_queue_err: %lu\n\t" + "tx_req_recover: %lu\n\t" + "\n" + "USB_RX:\n\t" + "alloc_fail: %lu\n\t" + "ep_queue_fail: %lu\n\t" + "ep_queue_fail2: %lu\n\t" + "ep_queue_ok: %lu\n\t" + "complete_in: %lu\n\t" + "complete_err: %lu\n\t" + "complete_sc: %lu\n\t" + "complete_normal:%lu\n\t" + "connreset: %lu\n\t" + "shutdown: %lu\n\t" + "connabort: %lu\n\t" + "overflow: %lu\n\t" + "other_err: %lu\n\t" + "\n" + "OTG_INTR:\n\t" + "status_fail: %lu\n\t" + "inepint: %lu\n\t" + "outepintr: %lu\n\t", + brsc_counter.tx_in, + brsc_counter.tx_eth_sc, + brsc_counter.tx_wlan_sc, + brsc_counter.tx_ok, + brsc_counter.tx_unknown_cdc_filter, + brsc_counter.tx_req_full, + brsc_counter.tx_realloc_header_fail, + brsc_counter.tx_skb_expand_full, + brsc_counter.tx_ep_queue_err, + brsc_counter.tx_req_full_recover, + + brsc_counter.rx_alloc_fail, + brsc_counter.rx_ep_queue_fail, + brsc_counter.rx_ep_queue_fail2, + brsc_counter.rx_ep_queue_ok, + brsc_counter.rx_complete_in, + brsc_counter.rx_complete_err, + brsc_counter.rx_complete_sc, + brsc_counter.rx_complete_normal, + brsc_counter.rx_complete_connreset, + brsc_counter.rx_complete_shutdown, + brsc_counter.rx_complete_connabort, + brsc_counter.rx_complete_overflow, + brsc_counter.rx_complete_other_err, + + brsc_counter.otg_status_fail, + brsc_counter.otg_inepint, + brsc_counter.otg_outepintr); +#else + len = sprintf(page, "not enable\n"); +#endif + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len > count) len = count; + if (len < 0) len = 0; + + return len; +} +#endif /* #if defined(CONFIG_RTL_ULINKER_BRSC) */ + + int eth_reg_again(void) { int ret=0; - ret=usb_gadget_register_driver (ð_driver); - if(ret!=0) printk("Ether: gad reg fail \n"); - else printk("Ether: gad reg ok \n"); - return ret; +#if defined(CONFIG_RTL_ULINKER_BRSC) + struct proc_dir_entry *res=NULL; + +#if ULINKER_BRSC_COUNTER + memset(&brsc_counter, 0, sizeof(struct brsc_counter_s)); +#endif + +#if defined(CONFIG_RTL_ULINKER) + wall_mount = 1; + ether_state = RTL_ETHER_STATE_INIT; + + BDBG_GADGET_MODE_SWITCH("[%s:%d] reinit ether gadget, set wall_mount=%d, ether_state=%d\n", + __FUNCTION__, __LINE__, wall_mount, ether_state); +#endif + + res = create_proc_entry("brsc", 0, NULL); + if (res) + { + res->read_proc = read_ulinker_brsc_en; + } + else + printk("create brsc failed!\n"); +#endif + + ret=usb_gadget_register_driver (ð_driver); + if(ret!=0) printk("Ether: gad reg fail \n"); + else printk("Ether: gad reg ok \n"); + return ret; } int eth_unreg_again(void) { int ret; ret=usb_gadget_unregister_driver (ð_driver); - if(ret!=0) printk("Ether: gad unreg fail\n"); - else printk("Ether: gad unreg pass \n"); - return ret; + +#if defined(CONFIG_RTL_ULINKER_BRSC) + remove_proc_entry("brsc", NULL); +#endif + + if(ret!=0) printk("Ether: gad unreg fail\n"); + else printk("Ether: gad unreg pass \n"); + return ret; } diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/file_storage.c b/target/linux/realtek/files/drivers/usb/gadget_cathy/file_storage.c index 8b975d155..fb2f4c5c6 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/file_storage.c +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/file_storage.c @@ -38,16 +38,17 @@ /* * The File-backed Storage Gadget acts as a USB Mass Storage device, - * appearing to the host as a disk drive. In addition to providing an - * example of a genuinely useful gadget driver for a USB device, it also - * illustrates a technique of double-buffering for increased throughput. - * Last but not least, it gives an easy way to probe the behavior of the - * Mass Storage drivers in a USB host. + * appearing to the host as a disk drive or as a CD-ROM drive. In addition + * to providing an example of a genuinely useful gadget driver for a USB + * device, it also illustrates a technique of double-buffering for increased + * throughput. Last but not least, it gives an easy way to probe the + * behavior of the Mass Storage drivers in a USB host. * * Backing storage is provided by a regular file or a block device, specified * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. The gadget will indicate that - * it has removable media if the optional "removable" module parameter is set. + * setting the optional "ro" module parameter. (For CD-ROM emulation, + * access is always read-only.) The gadget will indicate that it has + * removable media if the optional "removable" module parameter is set. * * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected @@ -64,7 +65,12 @@ * The default number of LUNs is taken from the number of "file" elements; * it is 1 if "file" is not given. If "removable" is not set then a backing * file must be specified for each LUN. If it is set, then an unspecified - * or empty backing filename means the LUN's medium is not loaded. + * or empty backing filename means the LUN's medium is not loaded. Ideally + * each LUN would be settable independently as a disk drive or a CD-ROM + * drive, but currently all LUNs have to be the same type. The CD-ROM + * emulation includes a single data track and no audio tracks; hence there + * need be only one backing file per LUN. Note also that the CD-ROM block + * length is set to 512 rather than the more common value 2048. * * Requirements are modest; only a bulk-in and a bulk-out endpoint are * needed (an interrupt-out endpoint is also needed for CBI). The memory @@ -91,6 +97,8 @@ * USB device controller (usually true), * boolean to permit the driver to halt * bulk endpoints + * cdrom Default false, boolean for whether to emulate + * a CD-ROM drive * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; @@ -103,15 +111,16 @@ * PAGE_CACHE_SIZE) * * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", - * "removable", "luns", and "stall" options are available; default values - * are used for everything else. + * "removable", "luns", "stall", and "cdrom" options are available; default + * values are used for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun<n> subdirectory of the * gadget's sysfs directory. If the "removable" option is set, writing to * these files will simulate ejecting/loading the medium (writing an empty * line means eject) and adjusting a write-enable tab. Changes to the ro - * setting are not allowed when the medium is loaded. + * setting are not allowed when the medium is loaded or if CD-ROM emulation + * is being used. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. * The driver's SCSI command interface was based on the "Information @@ -251,19 +260,24 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/suspend.h> +#include <linux/freezer.h> //wei add #include <linux/utsname.h> -#include <linux/usb_ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/ch9.h> //wei add +#include <linux/usb/gadget.h> //wei add +#include <linux/dcache.h> #include "gadget_chips.h" +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif /*-------------------------------------------------------------------------*/ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "20 November 2008" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -276,9 +290,13 @@ MODULE_LICENSE("Dual BSD/GPL"); * * DO NOT REUSE THESE IDs with any other driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ -#define DRIVER_VENDOR_ID 0x0525 // NetChip -#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget - +#if 0 +#define DRIVER_VENDOR_ID 0x0BDA //0x0525 // NetChip +#define DRIVER_PRODUCT_ID 0x8671 //0xa4a5 // Linux-USB File-backed Storage Gadget +#else +#define DRIVER_VENDOR_ID ULINKER_STORAGE_VID +#define DRIVER_PRODUCT_ID ULINKER_STORAGE_PID +#endif /* * This driver assumes self-powered hardware and has no way for users to @@ -287,6 +305,7 @@ MODULE_LICENSE("Dual BSD/GPL"); */ + /*-------------------------------------------------------------------------*/ #define xprintk(f,level,fmt,args...) \ @@ -294,32 +313,43 @@ MODULE_LICENSE("Dual BSD/GPL"); #define yprintk(l,level,fmt,args...) \ dev_printk(level , &(l)->dev , fmt , ## args) +#if 0 +//wei add +#define DEBUG 1 +#define DUMP_MSGS 1 +#define VERBOSE 1 +#endif + #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ + + #if 0 + #define DBG(fsg,fmt,args...) \ xprintk(fsg , KERN_DEBUG , fmt , ## args) -#define LDBG(lun,fmt,args...) \ + #define LDBG(lun,fmt,args...) \ yprintk(lun , KERN_DEBUG , fmt , ## args) -#define MDBG(fmt,args...) \ + #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) + #else + #define DBG(fsg,fmt,args...) printk( fmt , ## args) + #define LDBG(lun,fmt,args...) printk( fmt , ## args) + #define MDBG(fmt,args...) printk( fmt , ## args) + + #endif + #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) -#define LDBG(lun,fmt,args...) \ - do { } while (0) -#define MDBG(fmt,args...) \ - do { } while (0) -#undef VERBOSE -#undef DUMP_MSGS + #define DBG(fsg,fmt,args...) do { } while (0) + #define LDBG(lun,fmt,args...) do { } while (0) + #define MDBG(fmt,args...) do { } while (0) + #undef VERBOSE + #undef DUMP_MSGS #endif /* DEBUG */ #ifdef VERBOSE -#define VDBG DBG +#define VDBG DBG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) -#define VLDBG(lun,fmt,args...) \ - do { } while (0) +#define VDBG(fsg,fmt,args...) do { } while (0) +#define VLDBG(lun,fmt,args...) do { } while (0) #endif /* VERBOSE */ #define ERROR(fsg,fmt,args...) \ @@ -350,12 +380,13 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; int can_stall; + int cdrom; char *transport_parm; char *protocol_parm; @@ -372,8 +403,11 @@ static struct { } mod_data = { // Default values .transport_parm = "BBB", .protocol_parm = "SCSI", - .removable = 0, - .can_stall = 1, +// .removable = 0, + .removable = 1, //wei add + .can_stall = 0, //wei add +// .can_stall = 0, //wei add + .cdrom = 1, .vendor = DRIVER_VENDOR_ID, .product = DRIVER_PRODUCT_ID, .release = 0xffff, // Use controller chip type @@ -397,6 +431,9 @@ MODULE_PARM_DESC(removable, "true to simulate removable media"); module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); +module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); +MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); + /* In the non-TEST version, only the module parameters listed above * are available. */ @@ -426,6 +463,10 @@ MODULE_PARM_DESC(buflen, "I/O buffer size"); /*-------------------------------------------------------------------------*/ +/* SCSI device types */ +#define TYPE_DISK 0x00 +#define TYPE_CDROM 0x05 + /* USB protocol value = the transport method */ #define USB_PR_CBI 0x00 // Control/Bulk/Interrupt #define USB_PR_CB 0x01 // Control/Bulk w/o interrupt @@ -502,6 +543,8 @@ struct interrupt_data { #define SC_READ_12 0xa8 #define SC_READ_CAPACITY 0x25 #define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_READ_HEADER 0x44 +#define SC_READ_TOC 0x43 #define SC_RELEASE 0x17 #define SC_REQUEST_SENSE 0x03 #define SC_RESERVE 0x16 @@ -578,7 +621,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -713,13 +756,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -728,7 +771,7 @@ static void inline set_bulk_out_req_length(struct fsg_dev *fsg, rem = length % fsg->bulk_out_maxpacket; if (rem > 0) length += fsg->bulk_out_maxpacket - rem; - bh->outreq->length = length; + bh->outreq->length = (unsigned)length; } static struct fsg_dev *the_fsg; @@ -752,6 +795,7 @@ static void dump_msg(struct fsg_dev *fsg, const char *label, return; DBG(fsg, "%s, length %u:\n", label, length); +#if 0 start = 0; while (length > 0) { num = min(length, 16u); @@ -759,27 +803,40 @@ static void dump_msg(struct fsg_dev *fsg, const char *label, for (i = 0; i < num; ++i) { if (i == 8) *p++ = ' '; - sprintf(p, " %02x", buf[i]); + //sprintf(p, " %02x", buf[i]); //wei del + printk("%02x ", buf[i] ); p += 3; } *p = 0; printk(KERN_DEBUG "%6x: %s\n", start, line); + //printk( "%6x: %s\n", start, line); //wei add + buf += num; start += num; length -= num; } +#else + + //printk("Addr=%x :", buf); + printk("==> "); + for(i=0;i<length; i++) + printk("%02x ", buf[i]); + printk("\n"); +#endif + + } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) { int i; char cmdbuf[3*MAX_COMMAND_SIZE + 1]; @@ -803,7 +860,9 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) else name = ep->name; DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); + printk("fsg_set_halt\n"); + return usb_ep_set_halt(ep); //wei add +// return 0; //wei add } @@ -811,24 +870,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -858,13 +917,13 @@ device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, /* The next three values can be overridden by module parameters */ - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(0xffff), + .idVendor = cpu_to_le16(DRIVER_VENDOR_ID), + .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID), + .bcdDevice = cpu_to_le16(0xffff), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, @@ -937,7 +996,7 @@ fs_intr_in_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(2), + .wMaxPacketSize = cpu_to_le16(2), .bInterval = 32, // frames -> 32 ms }; @@ -952,8 +1011,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -967,7 +1024,7 @@ dev_qualifier = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, .bNumConfigurations = 1, @@ -980,7 +1037,7 @@ hs_bulk_in_desc = { /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(512), }; static struct usb_endpoint_descriptor @@ -990,7 +1047,7 @@ hs_bulk_out_desc = { /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, // NAK every 1 uframe }; @@ -1001,7 +1058,7 @@ hs_intr_in_desc = { /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(2), + .wMaxPacketSize = cpu_to_le16(2), .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms }; @@ -1016,14 +1073,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1055,22 +1112,18 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ @@ -1109,8 +1162,10 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) fsg->exception_req_tag = fsg->ep0_req_tag; fsg->state = new_state; if (fsg->thread_task) + { printk("=>send_sig_info\n"); send_sig_info(SIGUSR1, SEND_SIG_FORCED, fsg->thread_task); + } } spin_unlock_irqrestore(&fsg->lock, flags); } @@ -1296,6 +1351,7 @@ static int class_setup_req(struct fsg_dev *fsg, struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg->config) @@ -1309,7 +1365,7 @@ static int class_setup_req(struct fsg_dev *fsg, if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0) { + if (w_index != 0 || w_value != 0) { value = -EDOM; break; } @@ -1325,7 +1381,7 @@ static int class_setup_req(struct fsg_dev *fsg, if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0) { + if (w_index != 0 || w_value != 0) { value = -EDOM; break; } @@ -1344,7 +1400,7 @@ static int class_setup_req(struct fsg_dev *fsg, if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0) { + if (w_index != 0 || w_value != 0) { value = -EDOM; break; } @@ -1395,7 +1451,7 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); if (!fsg->gadget->is_dualspeed) @@ -1409,12 +1465,12 @@ static int standard_setup_req(struct fsg_dev *fsg, if (!fsg->gadget->is_dualspeed) break; goto get_config; -#endif + case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED + get_config: -#endif + value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -1515,7 +1571,8 @@ static int fsg_setup(struct usb_gadget *gadget, if (rc >= 0 && rc != DELAYED_STATUS) { rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < w_length; + fsg->ep0req->zero = rc < w_length + && (rc % gadget->ep0->maxpacket) == 0; //wei add, fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -1647,7 +1704,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1886,7 +1944,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2059,24 +2118,34 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) { u8 *buf = (u8 *) bh->buf; +#if defined(CONFIG_RTL_ULINKER) + static char vendor_id[] = ULINKER_STORAGE_VID_STR; + static char product_disk_id[] = ULINKER_STORAGE_PID_DISK_STR; + static char product_cdrom_id[] = ULINKER_STORAGE_PID_CDROM_STR; +#else static char vendor_id[] = "Linux "; - static char product_id[] = "File-Stor Gadget"; + static char product_disk_id[] = "File-Stor Gadget"; + static char product_cdrom_id[] = "File-CD Gadget "; +#endif if (!fsg->curlun) { // Unsupported LUNs are okay fsg->bad_lun_okay = 1; memset(buf, 0, 36); buf[0] = 0x7f; // Unsupported, no device-type + buf[4] = 31; // Additional length return 36; } - memset(buf, 0, 8); // Non-removable, direct-access device + memset(buf, 0, 8); + buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK); if (mod_data.removable) buf[1] = 0x80; buf[2] = 2; // ANSI SCSI level 2 buf[3] = 2; // SCSI-2 INQUIRY data format buf[4] = 31; // Additional length // No special options - sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id, + sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, + (mod_data.cdrom ? product_cdrom_id : product_disk_id), mod_data.release); return 36; } @@ -2155,6 +2224,75 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) } +static void store_cdrom_address(u8 *dest, int msf, u32 addr) +{ + if (msf) { + /* Convert to Minutes-Seconds-Frames */ + addr >>= 2; /* Convert to 2048-byte frames */ + addr += 2*75; /* Lead-in occupies 2 seconds */ + dest[3] = addr % 75; /* Frames */ + addr /= 75; + dest[2] = addr % 60; /* Seconds */ + addr /= 60; + dest[1] = addr; /* Minutes */ + dest[0] = 0; /* Reserved */ + } else { + /* Absolute sector */ + put_be32(dest, addr); + } +} + +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + u32 lba = get_be32(&fsg->cmnd[2]); + u8 *buf = (u8 *) bh->buf; + + if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + memset(buf, 0, 8); + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ + store_cdrom_address(&buf[4], msf, lba); + return 8; +} + + +static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + int start_track = fsg->cmnd[6]; + u8 *buf = (u8 *) bh->buf; + + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ + start_track > 1) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + memset(buf, 0, 20); + buf[1] = (20-2); /* TOC data length */ + buf[2] = 1; /* First track number */ + buf[3] = 1; /* Last track number */ + buf[5] = 0x16; /* Data track, copying allowed */ + buf[6] = 0x01; /* Only track is number 1 */ + store_cdrom_address(&buf[8], msf, 0); + + buf[13] = 0x16; /* Lead-out track is data */ + buf[14] = 0xAA; /* Lead-out track number */ + store_cdrom_address(&buf[16], msf, curlun->num_sectors); + return 20; +} + + static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct lun *curlun = fsg->curlun; @@ -2357,6 +2495,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg) return rc; } +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) +{ + int rc; + + DBG(fsg, "bulk-in set wedge\n"); + rc = usb_ep_set_wedge(fsg->bulk_in); + if (rc == -EAGAIN) + VDBG(fsg, "delayed bulk-in endpoint wedge\n"); + while (rc != 0) { + if (rc != -EAGAIN) { + WARN(fsg, "usb_ep_set_wedge -> %d\n", rc); + rc = 0; + break; + } + + /* Wait for a short time and then try again */ + if (msleep_interruptible(100) != 0) + return -EINTR; + rc = usb_ep_set_wedge(fsg->bulk_in); + } + return rc; +} + static int pad_with_zeros(struct fsg_dev *fsg) { struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; @@ -2370,7 +2531,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2430,7 +2592,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2552,7 +2715,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2580,7 +2744,7 @@ static int send_status(struct fsg_dev *fsg) struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; /* Store and send the Bulk-only CSW */ - csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); + csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); csw->Tag = fsg->tag; csw->Residue = cpu_to_le32(fsg->residue); csw->Status = status; @@ -2771,10 +2935,20 @@ static int do_scsi_command(struct fsg_dev *fsg) dump_cdb(fsg); +#if defined(CONFIG_RTL_ULINKER) +{ + extern int rtl_otg_gadget; + + if (fsg->cmnd[0]==0xe0) /* for mode switch */ + rtl_otg_gadget = 1; +} +#endif + /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } fsg->phase_error = 0; @@ -2864,6 +3038,26 @@ static int do_scsi_command(struct fsg_dev *fsg) reply = do_read_capacity(fsg, bh); break; + case SC_READ_HEADER: + if (!mod_data.cdrom) + goto unknown_cmnd; + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7) | (0x1f<<1), 1, + "READ HEADER")) == 0) + reply = do_read_header(fsg, bh); + break; + + case SC_READ_TOC: + if (!mod_data.cdrom) + goto unknown_cmnd; + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (7<<6) | (1<<1), 1, + "READ TOC")) == 0) + reply = do_read_toc(fsg, bh); + break; + case SC_READ_FORMAT_CAPACITIES: fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, @@ -2949,6 +3143,7 @@ static int do_scsi_command(struct fsg_dev *fsg) // Fall through default: + unknown_cmnd: fsg->data_size_from_cmnd = 0; sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); if ((reply = check_command(fsg, fsg->cmnd_size, @@ -2990,7 +3185,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW valid? */ if (req->actual != USB_BULK_CB_WRAP_LEN || - cbw->Signature != __constant_cpu_to_le32( + cbw->Signature != cpu_to_le32( USB_BULK_CB_SIG)) { DBG(fsg, "invalid CBW: len %u sig 0x%x\n", req->actual, @@ -3048,7 +3243,8 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -3064,7 +3260,8 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } smp_rmb(); @@ -3075,7 +3272,8 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -3278,8 +3476,7 @@ static void handle_exception(struct fsg_dev *fsg) /* Clear the existing signals. Anything but SIGUSR1 is converted * into a high-priority EXIT exception. */ for (;;) { - sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, - &info); + sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, &info); if (!sig) break; if (sig != SIGUSR1) { @@ -3432,11 +3629,21 @@ static int fsg_main_thread(void *fsg_) /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ +#if 0 //wei del siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | sigmask(SIGTERM) | sigmask(SIGKILL) | sigmask(SIGUSR1)); sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL); +#else + allow_signal(SIGINT); + allow_signal(SIGTERM); + allow_signal(SIGKILL); + allow_signal(SIGUSR1); + + /* Allow the thread to be frozen */ + set_freezable(); +#endif /* Arrange for userspace references to be interpreted as kernel * pointers. That way we can pass a kernel pointer to a routine * that expects a __user pointer and it will work okay. */ @@ -3483,11 +3690,12 @@ static int fsg_main_thread(void *fsg_) fsg->thread_task = NULL; spin_unlock_irq(&fsg->lock); - /* In case we are exiting because of a signal, unregister the - * gadget driver and close the backing file. */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) { + /* If we are exiting because of a signal, unregister the + * gadget driver. */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) + { usb_gadget_unregister_driver(&fsg_driver); - close_all_backing_files(fsg); + //close_all_backing_files(fsg); //wei del } /* Let the unbind and cleanup routines know the thread has exited */ @@ -3508,6 +3716,7 @@ static int open_backing_file(struct lun *curlun, const char *filename) struct inode *inode = NULL; loff_t size; loff_t num_sectors; + loff_t min_sectors; /* R/W if we can, R/O if we must */ ro = curlun->ro; @@ -3546,18 +3755,34 @@ static int open_backing_file(struct lun *curlun, const char *filename) ro = 1; size = i_size_read(inode->i_mapping->host); - if (size < 0) { + if (size < 0) + { LINFO(curlun, "unable to find file size: %s\n", filename); rc = (int) size; goto out; } - num_sectors = size >> 9; // File size in 512-byte sectors - if (num_sectors == 0) { + num_sectors = size >> 9; // File size in 512-byte blocks + min_sectors = 1; +#if 0 //wei add + if (mod_data.cdrom) + { + num_sectors &= ~3; // Reduce to a multiple of 2048 + min_sectors = 300*4; // Smallest track is 300 frames + if (num_sectors >= 256*60*75*4) + { + num_sectors = (256*60*75 - 1) * 4; + LINFO(curlun, "file too big: %s\n", filename); + LINFO(curlun, "using only first %d blocks\n", (int) num_sectors); + } + } +#endif +#if 1 //wei add + if (num_sectors < min_sectors) { LINFO(curlun, "file too small: %s\n", filename); rc = -ETOOSMALL; goto out; } - +#endif get_file(filp); curlun->ro = ro; curlun->filp = filp; @@ -3597,6 +3822,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } + static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); @@ -3606,8 +3832,9 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt, - buf, PAGE_SIZE - 1); + //p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt,buf, PAGE_SIZE - 1); //wei add, del + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3756,7 +3983,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } -static int __init check_parameters(struct fsg_dev *fsg) +static int check_parameters(struct fsg_dev *fsg) { int prot; int gcnum; @@ -3767,6 +3994,11 @@ static int __init check_parameters(struct fsg_dev *fsg) mod_data.protocol_type = USB_SC_SCSI; mod_data.protocol_name = "Transparent SCSI"; +#if 1 //wei add + mod_data.file[0]= "/etc/autorun.img"; + mod_data.num_filenames=1; +#endif + if (gadget_is_sh(fsg->gadget)) mod_data.can_stall = 0; @@ -3841,7 +4073,7 @@ static int __init check_parameters(struct fsg_dev *fsg) } -static int __init fsg_bind(struct usb_gadget *gadget) +static int fsg_bind(struct usb_gadget *gadget) { struct fsg_dev *fsg = the_fsg; int rc; @@ -3863,6 +4095,10 @@ static int __init fsg_bind(struct usb_gadget *gadget) dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644; dev_attr_ro.store = store_ro; dev_attr_file.store = store_file; + if (!mod_data.cdrom) { + dev_attr_ro.attr.mode = 0644; + dev_attr_ro.store = store_ro; + } } /* Find out how many LUNs there should be */ @@ -3887,12 +4123,15 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; curlun->ro = mod_data.ro[i]; + if (mod_data.cdrom) + curlun->ro = 1; curlun->dev.release = lun_release; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; dev_set_drvdata(&curlun->dev, fsg); - snprintf(curlun->dev.bus_id, BUS_ID_SIZE, - "%s-lun%d", gadget->dev.bus_id, i); +// snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); //wei add +// snprintf(curlun->dev.name, BUS_ID_SIZE, "%s-lun%d", gadget->dev.name, i); //wei add + dev_set_name(&curlun->dev,"%s-lun%d", dev_name(&gadget->dev), i); if ((rc = device_register(&curlun->dev)) != 0) { INFO(fsg, "failed to register LUN%d: %d\n", i, rc); @@ -3953,7 +4192,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; /* Assume ep0 uses the same maxpacket value for both speeds */ @@ -3963,7 +4202,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif + if (gadget->is_otg) { otg_desc.bmAttributes |= USB_OTG_HNP, @@ -4030,9 +4269,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (backing_file_is_open(curlun)) { p = NULL; if (pathbuf) { - p = d_path(curlun->filp->f_dentry, - curlun->filp->f_vfsmnt, - pathbuf, PATH_MAX); + //p = d_path(curlun->filp->f_dentry,curlun->filp->f_vfsmnt,pathbuf, PATH_MAX); //wei add + p = d_path(&curlun->filp->f_path, pathbuf, PATH_MAX); if (IS_ERR(p)) p = NULL; } @@ -4048,15 +4286,22 @@ static int __init fsg_bind(struct usb_gadget *gadget) mod_data.protocol_name, mod_data.protocol_type); DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", mod_data.vendor, mod_data.product, mod_data.release); - DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", mod_data.removable, mod_data.can_stall, - mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); + mod_data.cdrom, mod_data.buflen); + //DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); //wei del + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); set_bit(REGISTERED, &fsg->atomic_bitflags); /* Tell the thread to start working */ wake_up_process(fsg->thread_task); + + printk("HangUp Res\n"); + extern void HangUpRes(int en); + HangUpRes(1); + + return 0; autoconf_fail: @@ -4066,7 +4311,8 @@ autoconf_fail: out: fsg->state = FSG_STATE_TERMINATED; // The thread is dead fsg_unbind(gadget); - close_all_backing_files(fsg); + //close_all_backing_files(fsg); //wei del + complete(&fsg->thread_notifier); return rc; } @@ -4100,7 +4346,7 @@ static struct usb_gadget_driver fsg_driver = { #endif .function = (char *) longname, .bind = fsg_bind, - .unbind = __exit_p(fsg_unbind), + .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, .suspend = fsg_suspend, @@ -4116,7 +4362,7 @@ static struct usb_gadget_driver fsg_driver = { }; -static int __init fsg_alloc(void) +static int fsg_alloc(void) { struct fsg_dev *fsg; @@ -4132,8 +4378,8 @@ static int __init fsg_alloc(void) return 0; } - -static int __init fsg_init(void) +//============================================================ +static int fsg_init(void) { int rc; struct fsg_dev *fsg; @@ -4145,11 +4391,82 @@ static int __init fsg_init(void) kref_put(&fsg->ref, fsg_release); return rc; } -module_init(fsg_init); +//module_init(fsg_init); +//============================================================= +static void fsg_cleanup(void) +{ + struct fsg_dev *fsg = the_fsg; + + /* Unregister the driver iff the thread hasn't already done so */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) + usb_gadget_unregister_driver(&fsg_driver); + + /* Wait for the thread to finish up */ + wait_for_completion(&fsg->thread_notifier); + + close_all_backing_files(fsg); + kref_put(&fsg->ref, fsg_release); +} +//module_exit(fsg_cleanup); + +#if defined(CONFIG_RTL_ULINKER) +unsigned long fsg_jiffies = 0; +unsigned long rst_jiffies = 0; +#endif -static void __exit fsg_cleanup(void) +//================================================================ +#if defined(CONFIG_USB_ETH_RNDIS) +int fsg_reg_again(void) +#else +int eth_reg_again(void) +#endif { +#if 0 + int ret=0; + ret=usb_gadget_register_driver (&fsg_driver); + if(ret!=0) printk("Storage: gad reg fail \n"); + else printk("Storage: gad reg ok \n"); + return ret; +#else + + int rc=0; + struct fsg_dev *fsg; + +#if defined(CONFIG_RTL_ULINKER) + rst_jiffies = 0; + fsg_jiffies = jiffies; +#endif + + printk("storage: register\n"); + if ((rc = fsg_alloc()) != 0) + return rc; + + printk("storage: alloc ok, dev=%x\n", the_fsg); + fsg = the_fsg; + + printk("storage: driver=%x\n ", fsg_driver); + + if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) + kref_put(&fsg->ref, fsg_release); + return rc; +#endif +} + +#if defined(CONFIG_USB_ETH_RNDIS) +int fsg_unreg_again(void) +#else +int eth_unreg_again(void) +#endif +{ +#if 0 + int ret; + ret=usb_gadget_unregister_driver (&fsg_driver); + if(ret!=0) printk("Storage: gad unreg fail\n"); + else printk("Storage: gad unreg pass \n"); + return ret; +#else + struct fsg_dev *fsg = the_fsg; /* Unregister the driver iff the thread hasn't already done so */ @@ -4161,5 +4478,7 @@ static void __exit fsg_cleanup(void) close_all_backing_files(fsg); kref_put(&fsg->ref, fsg_release); +#endif } -module_exit(fsg_cleanup); + + diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.c b/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.c index e0ecd9d9e..e0d36c070 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.c +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.c @@ -44,6 +44,9 @@ #include "rndis.h" +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif /* The driver for your USB chip needs to support ep0 OUT to work with * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). @@ -949,6 +952,11 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) rndis_per_dev_params [configNr].ack ( rndis_per_dev_params [configNr].dev); +{ + extern int rndis_reset; + rndis_reset = 1; +} + return 0; } @@ -1398,7 +1406,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -int __devinit rndis_init (void) +int ULINKER_DEVINIT rndis_init (void) { u8 i; diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.h b/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.h index c61bd2fb6..98934ed39 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.h +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.h @@ -19,6 +19,10 @@ #include "ndis.h" +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif + #define RNDIS_MAXIMUM_FRAME_SIZE 1518 #define RNDIS_MAX_TOTAL_SIZE 1558 @@ -264,7 +268,7 @@ int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); extern void rndis_set_host_mac (int configNr, const u8 *addr); -int __devinit rndis_init (void); +int ULINKER_DEVINIT rndis_init (void); void rndis_exit (void); #endif /* _LINUX_RNDIS_H */ diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_gadget.h b/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_gadget.h index 5321e1a82..bb97800f5 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_gadget.h +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_gadget.h @@ -22,6 +22,10 @@ #include "usb_ch9.h" //#include "../otg/lm.h" +#if 1//defined(CONFIG_RTL_ULINKER) +#include "usb_ulinker.h" +#endif + //struct usb_ep; /** * struct usb_ep - device side representation of USB endpoint @@ -892,9 +896,9 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, /* utility wrapping a simple endpoint selection policy */ #if 0 extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, - struct usb_endpoint_descriptor *) __devinit; + struct usb_endpoint_descriptor *) ULINKER_DEVINIT; -extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; +extern void usb_ep_autoconfig_reset (struct usb_gadget *) ULINKER_DEVINIT; #endif //#endif /* __KERNEL__ */ diff --git a/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_ulinker.h b/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_ulinker.h index 16fa3fc10..96536a6f8 100644 --- a/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_ulinker.h +++ b/target/linux/realtek/files/drivers/usb/gadget_cathy/usb_ulinker.h @@ -1,6 +1,55 @@ #ifndef __LINUX_USB_ULINKER_H #define __LINUX_USB_ULINKER_H +#include "linux/autoconf.h" + +#ifndef CONFIG_RTL_ULINKER_CUSTOMIZATION +#define ULINKER_ETHER_VID 0x0BDA +#define ULINKER_ETHER_PID 0x8196 +#define ULINKER_MANUFACTURER "Realtek Semicoonductor Corp." + +#define ULINKER_WINTOOLS_GUID "1CACC490-055C-4035-A026-1DAB0BDA8196" +#define ULINKER_WINTOOLS_DISPLAY_NAME "Realtek RTL8196EU Universal Linker" +#define ULINKER_WINTOOLS_CONTACT "nicfae@realtek.com.tw" +#define ULINKER_WINTOOLS_DISPLAY_VERSION "v1.0.0.0" +#define ULINKER_WINTOOLS_HELP_LINK "http://www.realtek.com.tw" +#define ULINKER_WINTOOLS_PUBLISHER ULINKER_MANUFACTURER +#define ULINKER_WINTOOLS_TARGET_DIR ULINKER_WINTOOLS_DISPLAY_NAME +#else +#define ULINKER_ETHER_VID CONFIG_RTL_ULINKER_VID +#define ULINKER_ETHER_PID CONFIG_RTL_ULINKER_PID +#define ULINKER_STORAGE_VID CONFIG_RTL_ULINKER_VID_S +#define ULINKER_STORAGE_PID CONFIG_RTL_ULINKER_PID_S +#define ULINKER_MANUFACTURER CONFIG_RTL_ULINKER_MANUFACTURE + +#define ULINKER_WINTOOLS_GUID CONFIG_RTL_ULINKER_WINTOOLS_GUID +#define ULINKER_WINTOOLS_DISPLAY_NAME CONFIG_RTL_ULINKER_WINTOOLS_DISPLAY_NAME +#define ULINKER_WINTOOLS_CONTACT CONFIG_RTL_ULINKER_WINTOOLS_CONTACT +#define ULINKER_WINTOOLS_DISPLAY_VERSION CONFIG_RTL_ULINKER_WINTOOLS_DISPLAY_VERSION +#define ULINKER_WINTOOLS_HELP_LINK CONFIG_RTL_ULINKER_WINTOOLS_HELP_LINK +#define ULINKER_WINTOOLS_PUBLISHER ULINKER_MANUFACTURER +#define ULINKER_WINTOOLS_TARGET_DIR ULINKER_WINTOOLS_DISPLAY_NAME +#endif + +//------------------------------------------------ +// if you don't have a specific PID for storage, don't change following define of storage mode. +// +// begin: don't change +#ifndef ULINKER_STORAGE_VID +#define ULINKER_STORAGE_VID 0x0BDA +#define ULINKER_STORAGE_PID 0x8197 +#endif + +#define ULINKER_STORAGE_VID_STR "USB Ether " +#define ULINKER_STORAGE_PID_DISK_STR "Driver DISC" +#define ULINKER_STORAGE_PID_CDROM_STR "Driver CDROM" + +#define ULINKER_WINTOOLS_DRIVER_PATH "Driver" +// end: don't change +//------------------------------------------------ + + +//---------------------------------------------------------------------- #if defined(CONFIG_RTL_ULINKER) #define ULINKER_DEVINIT |
