summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/usb/gadget_cathy
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/usb/gadget_cathy')
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/Kconfig67
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/Makefile6
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/dummy_hcd.c4
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/epautoconf.c15
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/ether.c646
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/file_storage.c577
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.c10
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/rndis.h6
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/usb_gadget.h8
-rw-r--r--target/linux/realtek/files/drivers/usb/gadget_cathy/usb_ulinker.h49
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 (&eth_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 (&eth_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 (&eth_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