summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/usb')
-rw-r--r--ANDROID_3.4.5/drivers/usb/core/driver.c4
-rw-r--r--ANDROID_3.4.5/drivers/usb/core/generic.c2
-rw-r--r--ANDROID_3.4.5/drivers/usb/core/hcd.c14
-rw-r--r--ANDROID_3.4.5/drivers/usb/core/hub.c63
-rw-r--r--ANDROID_3.4.5/drivers/usb/core/usb.c47
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/Kconfig15
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/Makefile3
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/android.c128
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/composite.c5
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c37
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c10
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/f_adb.c3
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c7
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c22
-rwxr-xr-xANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c322
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c7
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h3
-rwxr-xr-xANDROID_3.4.5/drivers/usb/gadget/rawbulk.c1272
-rwxr-xr-xANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c1372
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/rndis.c4
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/storage_common.c38
-rw-r--r--ANDROID_3.4.5/drivers/usb/gadget/u_ether.c16
-rwxr-xr-xANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c4699
-rwxr-xr-xANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h801
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/Kconfig15
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c51
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci-hub.c337
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci-pci.c29
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci-q.c7
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci-sched.c7
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/ehci.h23
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/pci-quirks.c9
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c9
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/uhci-hub.c11
-rw-r--r--ANDROID_3.4.5/drivers/usb/host/uhci-pci.c26
-rw-r--r--ANDROID_3.4.5/drivers/usb/serial/Makefile1
-rw-r--r--ANDROID_3.4.5/drivers/usb/serial/option.c68
-rw-r--r--ANDROID_3.4.5/drivers/usb/serial/usb-serial.c12
-rwxr-xr-xANDROID_3.4.5/drivers/usb/serial/via_option.c1218
-rwxr-xr-xANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h88
-rwxr-xr-xANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c1013
-rw-r--r--ANDROID_3.4.5/drivers/usb/storage/usb.c2
42 files changed, 11742 insertions, 78 deletions
diff --git a/ANDROID_3.4.5/drivers/usb/core/driver.c b/ANDROID_3.4.5/drivers/usb/core/driver.c
index 9a56635d..b3df4e9a 100644
--- a/ANDROID_3.4.5/drivers/usb/core/driver.c
+++ b/ANDROID_3.4.5/drivers/usb/core/driver.c
@@ -1269,6 +1269,10 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ if (!(&udev->dev))
+ printk("(NULL device *): %s: status %d\n", __func__, status);
+ else
+ printk("%s%s : %s: status %d\n",dev_driver_string(&udev->dev), dev_name(&udev->dev), __func__, status);
if (!status)
udev->reset_resume = 0;
return status;
diff --git a/ANDROID_3.4.5/drivers/usb/core/generic.c b/ANDROID_3.4.5/drivers/usb/core/generic.c
index 69ecd3c9..ec4bfde3 100644
--- a/ANDROID_3.4.5/drivers/usb/core/generic.c
+++ b/ANDROID_3.4.5/drivers/usb/core/generic.c
@@ -20,6 +20,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "usb.h"
+extern int usb_power_insuf_skip=0; //read from uboot,default is false;
static inline const char *plural(int n)
{
@@ -97,6 +98,7 @@ int usb_choose_configuration(struct usb_device *udev)
*/
/* Rule out configs that draw too much bus current */
+ if(!usb_power_insuf_skip)
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
insufficient_power++;
continue;
diff --git a/ANDROID_3.4.5/drivers/usb/core/hcd.c b/ANDROID_3.4.5/drivers/usb/core/hcd.c
index 140d3e11..8318901f 100644
--- a/ANDROID_3.4.5/drivers/usb/core/hcd.c
+++ b/ANDROID_3.4.5/drivers/usb/core/hcd.c
@@ -2384,6 +2384,8 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
* buffers of consistent memory, register the bus, request the IRQ line,
* and call the driver's reset() and start() routines.
*/
+extern char enable_ehci_wake;
+
int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
@@ -2437,7 +2439,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
* but drivers can override it in reset() if needed, along with
* recording the overall controller's system wakeup capability.
*/
- device_set_wakeup_capable(&rhdev->dev, 1);
+ if (enable_ehci_wake) {
+ device_init_wakeup(&rhdev->dev, 1);
+ }
+
+ //device_set_wakeup_capable(&rhdev->dev, 1);
/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
* registered. But since the controller can die at any time,
@@ -2494,7 +2500,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
* they only forward requests from the root hub. Therefore
* controllers should always be enabled for remote wakeup.
*/
- device_wakeup_enable(hcd->self.controller);
+
+ if (enable_ehci_wake) {
+ device_wakeup_enable(hcd->self.controller);
+ }
+
return retval;
error_create_attr_group:
diff --git a/ANDROID_3.4.5/drivers/usb/core/hub.c b/ANDROID_3.4.5/drivers/usb/core/hub.c
index 6241b717..d6dab03a 100644
--- a/ANDROID_3.4.5/drivers/usb/core/hub.c
+++ b/ANDROID_3.4.5/drivers/usb/core/hub.c
@@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
#define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 100
-
+unsigned int usb_storage_id = 0;
static int usb_reset_and_verify_device(struct usb_device *udev);
@@ -592,6 +592,8 @@ EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
/* If do_delay is false, return the number of milliseconds the caller
* needs to delay.
*/
+/*CharlesTu,2012.09.14,improve resume time*/
+unsigned char usb_resume_flag=0;
static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
{
int port1;
@@ -617,7 +619,9 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
/* Wait at least 100 msec for power to become stable */
delay = max(pgood_delay, (unsigned) 100);
if (do_delay)
- msleep(delay);
+ if (!usb_resume_flag) {
+ msleep(delay);
+ }
return delay;
}
@@ -839,12 +843,17 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
/* Clear status-change flags; we'll debounce later */
if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ if (!usb_resume_flag) {
need_debounce_delay = true;
+ }
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
- need_debounce_delay = true;
+
+ if (!usb_resume_flag) {
+ need_debounce_delay = true;
+ }
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
}
@@ -1530,6 +1539,9 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
* USB_STATE_NOTATTACHED then all of udev's descendants' states are also set
* to USB_STATE_NOTATTACHED.
*/
+
+extern char enable_ehci_wake;
+
void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state)
{
@@ -1564,8 +1576,11 @@ void usb_set_device_state(struct usb_device *udev,
} else
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
- if (wakeup >= 0)
+ if (wakeup >= 0) {
device_set_wakeup_capable(&udev->dev, wakeup);
+ if (enable_ehci_wake)
+ device_wakeup_enable(&udev->dev);//gri
+ }
}
EXPORT_SYMBOL_GPL(usb_set_device_state);
@@ -1668,6 +1683,14 @@ void usb_disconnect(struct usb_device **pdev)
struct usb_device *udev = *pdev;
int i;
+ int wmt_usb_patch = 0;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub)
+ && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00)))
+ wmt_usb_patch = 1;
+
+
/* mark the device as inactive, so any further urb submissions for
* this device (and any of its children) will fail immediately.
* this quiesces everything except pending urbs.
@@ -1714,6 +1737,9 @@ void usb_disconnect(struct usb_device **pdev)
hub_free_dev(udev);
put_device(&udev->dev);
+
+ if (wmt_usb_patch)
+ *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x2);
}
#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
@@ -1974,6 +2000,14 @@ int usb_new_device(struct usb_device *udev)
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
usb_mark_last_busy(udev);
pm_runtime_put_sync_autosuspend(&udev->dev);
+
+ {
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub)
+ && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00)))
+ *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x1);
+ }
return err;
fail:
@@ -2219,7 +2253,7 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
if (!warm) {
struct usb_hcd *hcd;
/* TRSTRCY = 10 ms; plus some extra */
- msleep(10 + 40);
+ msleep(10); /*CharlesTu,2012.09.14,improve resume time*/
update_devnum(udev, 0);
hcd = bus_to_hcd(udev->bus);
if (hcd->driver->reset_device) {
@@ -2808,9 +2842,10 @@ static int hub_resume(struct usb_interface *intf)
static int hub_reset_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
-
+ usb_resume_flag = 1;
dev_dbg(&intf->dev, "%s\n", __func__);
hub_activate(hub, HUB_RESET_RESUME);
+ usb_resume_flag = 0;
return 0;
}
@@ -3588,7 +3623,7 @@ static void hub_events(void)
u16 hubchange;
u16 portstatus;
u16 portchange;
- int i, ret;
+ int i, ret,j = 0;
int connect_change, wakeup_change;
/*
@@ -3663,8 +3698,18 @@ static void hub_events(void)
hub->error = 0;
}
- /* deal with port status changes */
- for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+ /* deal with other port status changes */
+
+ //for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+ for (j = 1; j <= hub->descriptor->bNbrPorts; j++) {
+ i = j;
+ if (hub->descriptor->bNbrPorts > 2 ) {
+ if (usb_storage_id)
+ i = (j + usb_storage_id -2 ) % hub->descriptor->bNbrPorts + 1 ;
+
+ };
+
+
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits);
diff --git a/ANDROID_3.4.5/drivers/usb/core/usb.c b/ANDROID_3.4.5/drivers/usb/core/usb.c
index c74ba7bb..0fc63407 100644
--- a/ANDROID_3.4.5/drivers/usb/core/usb.c
+++ b/ANDROID_3.4.5/drivers/usb/core/usb.c
@@ -1000,12 +1000,59 @@ static void usb_debugfs_cleanup(void)
debugfs_remove(usb_debug_root);
}
+unsigned char usb_sus = 0;
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
/*
* Init
*/
+
+extern char enable_uhci0_wake;
+extern char enable_uhci1_wake;
+extern char enable_ehci_wake ;
+
+char enable_ehci_disc_wakeup = 0;
+
static int __init usb_init(void)
{
+
int retval;
+
+ char usb_env_pmc_name[] = "wmt.pmc.param";
+ char usb_env_pmc_val[120] = "0";
+ int varpmclen = 120;
+ unsigned int usb_pmc_param[7];
+
+ if(wmt_getsyspara(usb_env_pmc_name, usb_env_pmc_val, &varpmclen) == 0) {
+ sscanf(usb_env_pmc_val,"%X:%X:%X:%X:%X:%X:%X", &usb_pmc_param[0],&usb_pmc_param[1],
+ &usb_pmc_param[2],&usb_pmc_param[3],&usb_pmc_param[4],&usb_pmc_param[5],&usb_pmc_param[6]);
+ printk("*** uhci_hcd_init usb_param[0] =%x ,usb_param[1]=%x ,usb_param[2]=%x ,usb_param[3]=%x ,usb_param[4]=%x, usb_param[5]=%x, usb_param[6]=%x\n"
+ ,usb_pmc_param[0],usb_pmc_param[1],usb_pmc_param[2],usb_pmc_param[3],usb_pmc_param[4]
+ ,usb_pmc_param[5],usb_pmc_param[6]);
+ if (usb_pmc_param[0]) {
+ if(usb_pmc_param[1] & 0x00100000) {
+ enable_ehci_wake = 1;
+ //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id);
+ } else {
+ enable_ehci_wake = 0;// default port B
+ }
+ if (usb_pmc_param[5] & 0x1)
+ enable_uhci0_wake = 1;
+ else
+ enable_uhci0_wake = 0;
+ if (usb_pmc_param[5] & 0x2)
+ enable_uhci1_wake = 1;
+ else
+ enable_uhci1_wake = 0;
+ if (usb_pmc_param[6] & 0x1)
+ enable_ehci_disc_wakeup = 1;
+ } else {
+ enable_ehci_wake = 0;
+ enable_uhci1_wake = 0;
+ enable_uhci0_wake = 0;
+ }
+ }
+
if (nousb) {
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig
index a04b3f57..21a5f4cd 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig
+++ b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig
@@ -135,6 +135,17 @@ choice
# Integrated controllers
#
+config USB_GADGET_WMT
+ tristate "GADGET WMT"
+ select USB_GADGET_SELECTED
+ select USB_GADGET_DUALSPEED
+# default USB_GADGET
+
+config USB_WMT
+ tristate "USB WMT"
+ depends on USB_GADGET_WMT
+# default USB_GADGET
+
config USB_AT91
tristate "Atmel AT91 USB Device Port"
depends on ARCH_AT91
@@ -540,8 +551,8 @@ config USB_GADGET_SUPERSPEED
# USB Gadget Drivers
#
choice
- tristate "USB Gadget Drivers"
- default USB_ETH
+ boolean "USB Gadget Drivers"
+ default USB_G_ANDROID
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller
driver through the abstract "gadget" API. Some other operating
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Makefile b/ANDROID_3.4.5/drivers/usb/gadget/Makefile
index b91866a6..8df55f44 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/Makefile
+++ b/ANDROID_3.4.5/drivers/usb/gadget/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
+obj-$(CONFIG_USB_WMT) += udc_wmt.o
#
# USB gadget drivers
@@ -73,3 +74,5 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
obj-$(CONFIG_USB_G_ANDROID) += g_android.o
+obj-y += rawbulk.o
+obj-y += rawbulk_transfer.o
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/android.c b/ANDROID_3.4.5/drivers/usb/gadget/android.c
index 4e73bf1a..c5ce536a 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/android.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/android.c
@@ -28,6 +28,8 @@
#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
+#include <linux/power/wmt_battery.h>
+
#include "gadget_chips.h"
/*
@@ -54,6 +56,7 @@
#include "f_rndis.c"
#include "rndis.c"
#include "u_ether.c"
+#include "f_rawbulk.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -62,6 +65,9 @@ MODULE_VERSION("1.0");
static const char longname[] = "Gadget Android";
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+extern int wmt_setsyspara(char *varname, char *varval);
+
/* Default vendor and product IDs, overridden by userspace */
#define VENDOR_ID 0x18D1
#define PRODUCT_ID 0x0001
@@ -215,6 +221,7 @@ static void android_disable(struct android_dev *dev)
/* Cancel pending control requests */
usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
usb_remove_config(cdev, &android_config_driver);
+ usb_ep_autoconfig_reset(cdev->gadget);
}
}
@@ -917,6 +924,86 @@ static struct android_usb_function accessory_function = {
.bind_config = accessory_function_bind_config,
.ctrlrequest = accessory_function_ctrlrequest,
};
+#define CONFIG_USB_ANDROID_RAWBULK 1
+
+/* VIA Rawbulk functions */
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+static int rawbulk_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ return 0;
+}
+
+static void rawbulk_function_cleanup(struct android_usb_function *f)
+{
+ ;
+}
+
+static int rawbulk_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ char *i = f->name + strlen("via_");
+ if (!strncmp(i, "modem", 5))
+ return rawbulk_bind_config(c, RAWBULK_TID_MODEM);
+ else if (!strncmp(i, "ets", 3))
+ return rawbulk_bind_config(c, RAWBULK_TID_ETS);
+ else if (!strncmp(i, "atc", 3))
+ return rawbulk_bind_config(c, RAWBULK_TID_AT);
+ else if (!strncmp(i, "pcv", 3))
+ return rawbulk_bind_config(c, RAWBULK_TID_PCV);
+ else if (!strncmp(i, "gps", 3))
+ return rawbulk_bind_config(c, RAWBULK_TID_GPS);
+ return -EINVAL;
+}
+
+static int rawbulk_function_modem_ctrlrequest(struct android_usb_function *f,
+ struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *c)
+{
+ if ((c->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE &&
+ (c->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
+ struct rawbulk_function *fn = rawbulk_lookup_function(RAWBULK_TID_MODEM);
+ return rawbulk_function_setup(&fn->function, c);
+ }
+ return -1;
+}
+
+static struct android_usb_function rawbulk_modem_function = {
+ .name = "via_modem",
+ .init = rawbulk_function_init,
+ .cleanup = rawbulk_function_cleanup,
+ .bind_config = rawbulk_function_bind_config,
+ .ctrlrequest = rawbulk_function_modem_ctrlrequest,
+};
+
+static struct android_usb_function rawbulk_ets_function = {
+ .name = "via_ets",
+ .init = rawbulk_function_init,
+ .cleanup = rawbulk_function_cleanup,
+ .bind_config = rawbulk_function_bind_config,
+};
+
+static struct android_usb_function rawbulk_atc_function = {
+ .name = "via_atc",
+ .init = rawbulk_function_init,
+ .cleanup = rawbulk_function_cleanup,
+ .bind_config = rawbulk_function_bind_config,
+};
+
+static struct android_usb_function rawbulk_pcv_function = {
+ .name = "via_pcv",
+ .init = rawbulk_function_init,
+ .cleanup = rawbulk_function_cleanup,
+ .bind_config = rawbulk_function_bind_config,
+};
+
+static struct android_usb_function rawbulk_gps_function = {
+ .name = "via_gps",
+ .init = rawbulk_function_init,
+ .cleanup = rawbulk_function_cleanup,
+ .bind_config = rawbulk_function_bind_config,
+};
+#endif /* CONFIG_USB_ANDROID_RAWBULK */
static int audio_source_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
@@ -990,6 +1077,11 @@ static struct android_usb_function *supported_functions[] = {
&mass_storage_function,
&accessory_function,
&audio_source_function,
+ &rawbulk_modem_function,
+ &rawbulk_ets_function,
+ &rawbulk_atc_function,
+ &rawbulk_pcv_function,
+ &rawbulk_gps_function,
NULL
};
@@ -1356,6 +1448,23 @@ static void android_unbind_config(struct usb_configuration *c)
android_unbind_enabled_functions(dev, c);
}
+unsigned char buf_android_serialno[32];
+
+int get_android_serialno(void)
+{
+ int varlen =127;
+ int retval;
+ memset(buf_android_serialno,0,sizeof(buf_android_serialno));
+ retval = wmt_getsyspara("androidboot.serialno", buf_android_serialno, &varlen);
+ if(!retval)
+ {
+ printk("androidboot.serialno=%s\n",buf_android_serialno);
+ return 0x0;
+ }else{
+ printk("uboot variant androidboot.serialno do not exit\n");
+ return -1;
+ }
+}
static int android_bind(struct usb_composite_dev *cdev)
{
@@ -1391,7 +1500,15 @@ static int android_bind(struct usb_composite_dev *cdev)
/* Default strings - should be updated by userspace */
strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1);
strncpy(product_string, "Android", sizeof(product_string) - 1);
- strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1);
+
+ get_android_serialno();
+ if(strlen(buf_android_serialno)==0){
+ strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1);
+ printk("buf_android_serialno is null\n");
+ }else{
+ strncpy(serial_string, buf_android_serialno, sizeof(serial_string) - 1);
+ printk("buf_android_serialno:%s\n",buf_android_serialno);
+ }
id = usb_string_id(cdev);
if (id < 0)
@@ -1467,6 +1584,9 @@ android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
if (!dev->connected) {
dev->connected = 1;
schedule_work(&dev->work);
+#if defined(CONFIG_BATTERY_WMT)
+ wmt_do_pc_connected();
+#endif
} else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
cdev->config) {
schedule_work(&dev->work);
@@ -1518,6 +1638,12 @@ static int android_create_device(struct android_dev *dev)
return 0;
}
+/* provide usb connected state for charger */
+int wmt_is_pc_connected(void)
+{
+ return _android_dev ? _android_dev->connected : 0;
+}
+EXPORT_SYMBOL(wmt_is_pc_connected);
static int __init init(void)
{
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/composite.c b/ANDROID_3.4.5/drivers/usb/gadget/composite.c
index 8f82fc0e..6cfe5f24 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/composite.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/composite.c
@@ -798,6 +798,7 @@ static int unbind_config(struct usb_composite_dev *cdev,
return 0;
}
+extern void wmt_cleanup_done_thread(int number);
/**
* usb_remove_config() - remove a configuration from a device.
* @cdev: wraps the USB gadget
@@ -811,16 +812,14 @@ int usb_remove_config(struct usb_composite_dev *cdev,
struct usb_configuration *config)
{
unsigned long flags;
-
+ //wmt_cleanup_done_thread(1);
spin_lock_irqsave(&cdev->lock, flags);
-
if (cdev->config == config)
reset_config(cdev);
list_del(&config->list);
spin_unlock_irqrestore(&cdev->lock, flags);
-
return unbind_config(cdev, config);
}
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c
index 51f3d42f..fc5eb804 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c
@@ -280,6 +280,43 @@ struct usb_ep *usb_ep_autoconfig_ss(
if (ep && ep_matches(gadget, ep, desc, ep_comp))
goto found_ep;
+ } else if (gadget_is_wmt (gadget)) {
+ //printk(KERN_INFO "usb_ep_autoconfig find wmt_gadget \n");
+ if (USB_ENDPOINT_XFER_INT == type) {
+ /* single buffering is enough */
+ //printk(KERN_INFO "usb_ep_autoconfig try to find ep3in-int \n");
+ ep = find_ep (gadget, "ep3in-int");
+ if (ep && ep_matches (gadget, ep, desc, ep_comp)){
+ //printk(KERN_INFO "usb_ep_autoconfig found ep3in-int \n");
+ goto found_ep;
+ }
+ } else if (USB_ENDPOINT_XFER_BULK == type
+ && (USB_DIR_IN & desc->bEndpointAddress)) {
+ /* DMA may be available */
+ //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n");
+ ep = find_ep (gadget, "ep1in-bulk");
+ if (ep && ep_matches (gadget, ep, desc, ep_comp)){
+ //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n");
+ goto found_ep;
+ }
+ } else if (USB_ENDPOINT_XFER_BULK == type) {
+ /* DMA may be available */
+ //printk(KERN_INFO "usb_ep_autoconfig try to find ep2out-bulk \n");
+ ep = find_ep (gadget, "ep2out-bulk");
+ if (ep && ep_matches (gadget, ep, desc, ep_comp)){
+ //printk(KERN_INFO "usb_ep_autoconfig found ep2out-bulk \n");
+ goto found_ep;
+ }
+ } else if (USB_ENDPOINT_XFER_ISOC == type
+ && (USB_DIR_IN & desc->bEndpointAddress)) {
+ /* DMA may be available */
+ //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n");
+ ep = find_ep (gadget, "ep4in-iso");
+ if (ep && ep_matches (gadget, ep, desc, ep_comp)){
+ //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n");
+ goto found_ep;
+ }
+ }
} else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c
index a244265c..bfb3a777 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c
@@ -502,6 +502,7 @@ static int create_bulk_endpoints(struct acc_dev *dev,
ep->driver_data = dev; /* claim the endpoint */
dev->ep_in = ep;
+#if 0
ep = usb_ep_autoconfig(cdev->gadget, out_desc);
if (!ep) {
DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
@@ -510,6 +511,7 @@ static int create_bulk_endpoints(struct acc_dev *dev,
DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name);
ep->driver_data = dev; /* claim the endpoint */
dev->ep_out = ep;
+#endif
ep = usb_ep_autoconfig(cdev->gadget, out_desc);
if (!ep) {
@@ -568,6 +570,10 @@ static ssize_t acc_read(struct file *fp, char __user *buf,
ret = wait_event_interruptible(dev->read_wq, dev->online);
if (ret < 0) {
r = ret;
+ if (r == -ERESTARTSYS){
+ r = -EIO;
+ }
+
goto done;
}
@@ -588,6 +594,10 @@ requeue_req:
ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
if (ret < 0) {
r = ret;
+ if (r == -ERESTARTSYS){
+ r = -EIO;
+ }
+
usb_ep_dequeue(dev->ep_out, req);
goto done;
}
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c
index 1629ffb5..0eea2191 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c
@@ -502,7 +502,8 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f)
dev->error = 1;
wake_up(&dev->read_wq);
-
+ extern void wmt_cleanup_done_thread(int number);
+ wmt_cleanup_done_thread(1);
adb_request_free(dev->rx_req, dev->ep_out);
while ((req = adb_req_get(dev, &dev->tx_idle)))
adb_request_free(req, dev->ep_in);
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c
index cb8c162c..68c3d9f6 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c
@@ -2691,6 +2691,8 @@ static int fsg_main_thread(void *common_)
static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+static DEVICE_ATTR(cdrom, 0644, fsg_show_cdrom, fsg_store_cdrom);
+
/****************************** FSG COMMON ******************************/
@@ -2815,7 +2817,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
rc = device_create_file(&curlun->dev, &dev_attr_nofua);
if (rc)
goto error_luns;
-
+ rc = device_create_file(&curlun->dev, &dev_attr_cdrom);
+ if (rc)
+ goto error_luns;
if (lcfg->filename) {
rc = fsg_lun_open(curlun, lcfg->filename);
if (rc)
@@ -2947,6 +2951,7 @@ static void fsg_common_release(struct kref *ref)
device_remove_file(&lun->dev, &dev_attr_nofua);
device_remove_file(&lun->dev, &dev_attr_ro);
device_remove_file(&lun->dev, &dev_attr_file);
+ device_remove_file(&lun->dev, &dev_attr_cdrom);
fsg_lun_close(lun);
device_unregister(&lun->dev);
}
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c
index 1638977a..6279bfb0 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c
@@ -410,6 +410,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
ep->driver_data = dev; /* claim the endpoint */
dev->ep_out = ep;
+#if 0
ep = usb_ep_autoconfig(cdev->gadget, out_desc);
if (!ep) {
DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
@@ -418,6 +419,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name);
ep->driver_data = dev; /* claim the endpoint */
dev->ep_out = ep;
+#endif
ep = usb_ep_autoconfig(cdev->gadget, intr_desc);
if (!ep) {
@@ -478,6 +480,10 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
dev->state != STATE_OFFLINE);
if (ret < 0) {
r = ret;
+ if (r == -ERESTARTSYS){
+ r = -EIO;
+ }
+
goto done;
}
spin_lock_irq(&dev->lock);
@@ -506,7 +512,11 @@ requeue_req:
/* wait for a request to complete */
ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
if (ret < 0) {
- r = ret;
+ r = ret;
+ if (r == -ERESTARTSYS){
+ r = -EIO;
+ }
+
usb_ep_dequeue(dev->ep_out, req);
goto done;
}
@@ -1121,7 +1131,8 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
struct mtp_dev *dev = func_to_mtp(f);
struct usb_request *req;
int i;
-
+ extern void wmt_cleanup_done_thread(int number);
+ wmt_cleanup_done_thread(1);
while ((req = mtp_req_get(dev, &dev->tx_idle)))
mtp_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
@@ -1175,21 +1186,22 @@ static int mtp_function_set_alt(struct usb_function *f,
return 0;
}
+
static void mtp_function_disable(struct usb_function *f)
{
struct mtp_dev *dev = func_to_mtp(f);
struct usb_composite_dev *cdev = dev->cdev;
- DBG(cdev, "mtp_function_disable\n");
+ printk("mtp_function_disable\n");
dev->state = STATE_OFFLINE;
usb_ep_disable(dev->ep_in);
usb_ep_disable(dev->ep_out);
usb_ep_disable(dev->ep_intr);
-
+// wmt_cleanup_done_thread(1);
/* readers may be blocked waiting for us to go online */
wake_up(&dev->read_wq);
- VDBG(cdev, "%s disabled\n", dev->function.name);
+ printk("%s disabled\n", dev->function.name);
}
static int mtp_bind_config(struct usb_configuration *c, bool ptp_config)
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c
new file mode 100755
index 00000000..92bce0fb
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c
@@ -0,0 +1,322 @@
+/*
+ * Rawbulk Gadget Function Driver from VIA Telecom
+ *
+ * Copyright (C) 2011 VIA Telecom, Inc.
+ * Author: Karfield Chen (kfchen@via-telecom.com)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>"
+#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget"
+#define DRIVER_VERSION "1.0.1"
+#define DRIVER_NAME "usb_rawbulk"
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/rawbulk.h>
+struct usb_composite_dev * wmt_cdev;
+#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function)
+
+static void simple_setup_complete(struct usb_ep *ep,
+ struct usb_request *req) {
+ ;//DO NOTHING
+}
+
+unsigned int dump_mask = 0;
+static int rawbulk_function_setup(struct usb_function *f, const struct
+ usb_ctrlrequest *ctrl) {
+ int rc;
+ struct rawbulk_function *fn = function_to_rawbulk(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+
+ if (rawbulk_transfer_state(fn->transfer_id) < 0)
+ return -EOPNOTSUPP;
+
+ if (dump_mask & (1 << RAWBULK_TID_MODEM))
+ printk(KERN_DEBUG "DUMP ctrl: bRequestType = %02X, bRequest = %02X, " \
+ "wValue = %04X, wIndex = %04X, wLength = %d\n",
+ ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
+ ctrl->wLength);
+
+ if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x02) {
+ /* Query CD109 Status */
+ if (rawbulk_check_enable(fn))
+ goto forwarding;
+ *(unsigned char *)req->buf = 0x02; /* Test!!! */
+ req->length = 1;
+ req->complete = simple_setup_complete;
+ req->zero = 0;
+ return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ } else if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0x01) {
+ /* Set/Clear DTR */
+ if (rawbulk_check_enable(fn))
+ goto forwarding;
+ req->zero = 0;
+ return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ } else if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x04) {
+ /* Request CBP Product Name */
+ req->length = sprintf(req->buf, "CBP_KUNLUN");
+ req->zero = 0;
+ return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ }
+
+ return -EOPNOTSUPP;
+forwarding:
+ rc = rawbulk_forward_ctrlrequest(ctrl);
+ if (rc < 0) {
+ printk(KERN_DEBUG "rawbulk forwarding failed %d\n", rc);
+ return rc;
+ }
+ return 256 + 999;//USB_GADGET_DELAYED_STATUS;
+}
+
+static void rawbulk_auto_reconnect(int transfer_id) {
+ int rc;
+ struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id);
+ if (!fn || fn->autoreconn == 0)
+ return;
+
+ if (rawbulk_check_enable(fn) && fn->activated) {
+ printk(KERN_DEBUG "start %s again automatically.\n", fn->longname);
+ rc = rawbulk_start_transactions(transfer_id, fn->nups,
+ fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable);
+ if (rc < 0) {
+ rawbulk_disable_function(fn);
+ rawbulk_tty_start_io(fn);
+ }
+ }
+}
+
+static struct usb_ep *match_ep(struct usb_configuration *c,
+ struct rawbulk_function *fn, int in) {
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep;
+ struct usb_endpoint_descriptor *desc =
+ (struct usb_endpoint_descriptor *)(in? fn->fs_descs[BULKIN_DESC]:
+ fn->fs_descs[BULKOUT_DESC]);
+ return usb_ep_autoconfig(gadget, desc);
+}
+
+static int rawbulk_function_bind(struct usb_configuration *c, struct
+ usb_function *f) {
+ int rc, ifnum;
+ struct rawbulk_function *fn = function_to_rawbulk(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep_out, *ep_in;
+
+ rc = usb_interface_id(c, f);
+ if (rc < 0)
+ return rc;
+ ifnum = rc;
+
+ fn->interface.bInterfaceNumber = cpu_to_le16(ifnum);
+
+
+
+ usb_ep_autoconfig_reset(c->cdev->gadget); //added by griffen
+
+
+ if (!(ep_out = match_ep(c, fn, 0))) {
+ printk(KERN_DEBUG "unfortunately, we could not find endpoint(OUT) for %s",
+ fn->longname);
+ return -ENOMEM;
+ }
+
+ if (!(ep_in = match_ep(c, fn, 1))) {
+ printk(KERN_DEBUG "unfortunately, we could not find endpoint(IN) for %s",
+ fn->longname);
+ return -ENOMEM;
+ }
+
+ ep_out->driver_data = fn;
+ ep_in->driver_data = fn;
+ fn->bulk_out = ep_out;
+ fn->bulk_in = ep_in;
+
+ f->descriptors = usb_copy_descriptors(fn->fs_descs);
+ if (unlikely(!f->descriptors))
+ return -ENOMEM;
+
+ if (gadget_is_dualspeed(gadget)) {
+ fn->hs_bulkin_endpoint.bEndpointAddress =
+ fn->fs_bulkin_endpoint.bEndpointAddress;
+ fn->hs_bulkout_endpoint.bEndpointAddress =
+ fn->fs_bulkout_endpoint.bEndpointAddress;
+ f->hs_descriptors = usb_copy_descriptors(fn->hs_descs);
+ if (unlikely(!f->hs_descriptors)) {
+ usb_free_descriptors(f->descriptors);
+ return -ENOMEM;
+ }
+ }
+
+ fn->cdev = c->cdev;
+ fn->activated = 0;
+
+ /*
+ rc = rawbulk_register_tty(fn);
+ if (rc < 0)
+ printk(KERN_ERR "failed to register tty for %s\n", fn->longname);
+ */
+
+ return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in,
+ rawbulk_auto_reconnect);
+}
+
+static void rawbulk_function_unbind(struct usb_configuration *c, struct
+ usb_function *f) {
+ struct rawbulk_function *fn = function_to_rawbulk(f);
+
+ printk(KERN_DEBUG "%s - unbind %s.\n", __func__, fn->longname);
+ //rawbulk_unregister_tty(fn);
+ rawbulk_unbind_function(fn->transfer_id);
+}
+
+static void do_activate(struct work_struct *data) {
+ struct rawbulk_function *fn = container_of(data, struct rawbulk_function,
+ activator);
+ int rc;
+ printk(KERN_DEBUG "%s rawbulk %s channel (enabled? %s).\n",
+ fn->activated? "activte": "detach", fn->shortname,
+ rawbulk_check_enable(fn)? "yes": "no");
+ if (fn->activated) { /* enumerated */
+ int ret;
+ ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_out);
+ if (ret)
+ return ;
+
+ /* enabled endpoints */
+ rc = usb_ep_enable(fn->bulk_out);
+ if (rc < 0) {
+ printk(KERN_ERR "failed to enable rawbulk %s %d\n",
+ fn->bulk_out->name, rc);
+ return;
+ }
+
+
+ ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_in);
+ if (ret)
+ return ;
+
+ rc = usb_ep_enable(fn->bulk_in);
+ if (rc < 0) {
+ printk(KERN_ERR "failed to enable rawbulk %s %d\n",
+ fn->bulk_in->name, rc);
+ usb_ep_disable(fn->bulk_out);
+ return;
+ }
+
+ /* start rawbulk if enabled */
+ if (rawbulk_check_enable(fn)) {
+ wake_lock(&fn->keep_awake);
+ rc = rawbulk_start_transactions(fn->transfer_id, fn->nups,
+ fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable);
+ if (rc < 0)
+ rawbulk_disable_function(fn);
+ }
+
+ /* start tty io */
+ rc = rawbulk_tty_alloc_request(fn);
+ if (rc < 0)
+ return;
+ if (!rawbulk_check_enable(fn))
+ rawbulk_tty_start_io(fn);
+ } else { /* disconnect */
+ if (rawbulk_check_enable(fn)) {
+ if (fn->transfer_id == RAWBULK_TID_MODEM) {
+ /* this in interrupt, but DTR need be set firstly then clear it
+ * */
+ //control_dtr(0);
+ }
+ rawbulk_stop_transactions(fn->transfer_id);
+ /* keep the enable state, so we can enable again in next time */
+ //set_enable_state(fn, 0);
+ wake_unlock(&fn->keep_awake);
+ } else
+ rawbulk_tty_stop_io(fn);
+
+ rawbulk_tty_free_request(fn);
+
+ usb_ep_disable(fn->bulk_out);
+ usb_ep_disable(fn->bulk_in);
+
+ fn->bulk_out->driver_data = NULL;
+ fn->bulk_in->driver_data = NULL;
+ }
+}
+
+static int rawbulk_function_setalt(struct usb_function *f, unsigned intf,
+ unsigned alt) {
+ struct rawbulk_function *fn = function_to_rawbulk(f);
+ fn->activated = 1;
+ schedule_work(&fn->activator);
+ return 0;
+}
+
+static void rawbulk_function_disable(struct usb_function *f) {
+ struct rawbulk_function *fn = function_to_rawbulk(f);
+ fn->activated = 0;
+ schedule_work(&fn->activator);
+}
+
+static int rawbulk_bind_config(struct usb_configuration *c, int transfer_id) {
+ int rc;
+ struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id);
+
+ printk(KERN_DEBUG "add %s to config.\n", fn->longname);
+
+ if (!fn)
+ return -ENOMEM;
+
+ if (fn->string_defs[0].id == 0) {
+ rc = usb_string_id(c->cdev);
+ if (rc < 0)
+ return rc;
+ fn->string_defs[0].id = rc;
+ fn->interface.iInterface = rc;
+ }
+ wmt_cdev = c->cdev;
+
+ fn->function.name = fn->longname;
+ fn->function.setup = rawbulk_function_setup;
+ fn->function.bind = rawbulk_function_bind;
+ fn->function.unbind = rawbulk_function_unbind;
+ fn->function.set_alt = rawbulk_function_setalt;
+ fn->function.disable = rawbulk_function_disable;
+
+ INIT_WORK(&fn->activator, do_activate);
+
+ rc = usb_add_function(c, &fn->function);
+ if (rc < 0)
+ printk(KERN_DEBUG "%s - failed to config %d.\n", __func__, rc);
+
+ return rc;
+}
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c
index 3a6e5587..5a4fdbc7 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c
@@ -458,7 +458,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
status, req->actual, req->length);
// spin_unlock(&dev->lock);
}
-
+extern bool get_rndis_initialized(void);
static int
rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
@@ -469,7 +469,8 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
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(!get_rndis_initialized())
+ return;
/* composite driver infrastructure handles everything except
* CDC class messages; interface activation uses set_alt().
*/
@@ -614,7 +615,7 @@ static void rndis_disable(struct usb_function *f)
if (!rndis->notify->driver_data)
return;
- DBG(cdev, "rndis deactivated\n");
+ printk("rndis deactivated\n");
rndis_uninit(rndis->config);
gether_disconnect(&rndis->port);
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h
index a8855d0b..30fad3e8 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h
+++ b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h
@@ -26,6 +26,7 @@
* do that for you.
*/
#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name))
+#define gadget_is_wmt(g) (!strcmp("wmotgdev", (g)->name))
#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name))
#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name))
#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x31;
else if (gadget_is_dwc3(gadget))
return 0x32;
+ else if (gadget_is_wmt(gadget))
+ return 0x33;
return -ENOENT;
}
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c
new file mode 100755
index 00000000..5c027da4
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c
@@ -0,0 +1,1272 @@
+/*
+ * Rawbulk Gadget Function Driver from VIA Telecom
+ *
+ * Copyright (C) 2011 VIA Telecom, Inc.
+ * Author: Karfield Chen (kfchen@via-telecom.com)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>"
+#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget"
+#define DRIVER_VERSION "1.0.1"
+#define DRIVER_NAME "usb_rawbulk"
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/rawbulk.h>
+
+#ifdef DEBUG
+#define ldbg(f, a...) printk(KERN_DEBUG "%s - " f "\n", __func__, ##a)
+#else
+#define ldbg(...) {}
+#endif
+
+/* sysfs attr idx assignment */
+enum _attr_idx {
+ ATTR_ENABLE = 0, /** enable switch for Rawbulk */
+#ifdef SUPPORT_LEGACY_CONTROL
+ ATTR_ENABLE_C, /** enable switch too, but for legacy */
+#endif
+ ATTR_AUTORECONN, /** enable to rebind cp when it reconnect */
+ ATTR_STATISTICS, /** Rawbulk summary/statistics for one pipe */
+ ATTR_NUPS, /** upstream transfers count */
+ ATTR_NDOWNS, /** downstram transfers count */
+ ATTR_UPSIZE, /** upstream buffer for each transaction */
+ ATTR_DOWNSIZE, /** downstram buffer for each transaction */
+ ATTR_SPLIT, /** split option for downstream */
+ ATTR_PUSHABLE, /** set to use push-way for upstream */
+ ATTR_DTR, /** DTR control, only for Data-Call port */
+};
+
+/* USB gadget framework is not strong enough, and not be compatiable with some
+ * controller, such as musb.
+ * in musb driver, the usb_request's member list is used internally, but in some
+ * applications it used in function driver too. to avoid this, here we
+ * re-wrap the usb_request */
+struct usb_request_wrapper {
+ struct list_head list;
+ struct usb_request *request;
+ int length;
+ struct rawbulk_function *fn;
+ char buffer[0];
+};
+
+static struct usb_request_wrapper *get_wrapper(struct usb_request *req) {
+ if (!req->buf)
+ return NULL;
+ return container_of(req->buf, struct usb_request_wrapper, buffer);
+}
+
+/* Internal TTY functions/data */
+static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct
+ *tty);
+static void rawbulk_tty_deactivate(struct tty_port *port);
+static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct
+ *tty);
+static void rawbulk_tty_cleanup(struct tty_struct *tty);
+static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip);
+static void rawbulk_tty_hangup(struct tty_struct *tty);
+static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip);
+static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count);
+static int rawbulk_tty_write_room(struct tty_struct *tty);
+static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty);
+static void rawbulk_tty_throttle(struct tty_struct *tty);
+static void rawbulk_tty_unthrottle(struct tty_struct *tty);
+static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios
+ *old);
+static int rawbulk_tty_tiocmget(struct tty_struct *tty);
+static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set,
+ unsigned int clear);
+
+static struct tty_port_operations rawbulk_tty_port_ops = {
+ .activate = rawbulk_tty_activate,
+ .shutdown = rawbulk_tty_deactivate,
+};
+
+static struct tty_operations rawbulk_tty_ops = {
+ .open = rawbulk_tty_open,
+ .close = rawbulk_tty_close,
+ .write = rawbulk_tty_write,
+ .hangup = rawbulk_tty_hangup,
+ .write_room = rawbulk_tty_write_room,
+ .set_termios = rawbulk_tty_set_termios,
+ .throttle = rawbulk_tty_throttle,
+ .unthrottle = rawbulk_tty_unthrottle,
+ .chars_in_buffer = rawbulk_tty_chars_in_buffer,
+ .tiocmget = rawbulk_tty_tiocmget,
+ .tiocmset = rawbulk_tty_tiocmset,
+ .cleanup = rawbulk_tty_cleanup,
+ .install = rawbulk_tty_install,
+};
+
+struct tty_driver *rawbulk_tty_driver;
+
+struct rawbulk_function *prealloced_functions[_MAX_TID] = { NULL };
+struct rawbulk_function *rawbulk_lookup_function(int transfer_id) {
+ if (transfer_id >= 0 && transfer_id < _MAX_TID)
+ return prealloced_functions[transfer_id];
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rawbulk_lookup_function);
+
+static struct rawbulk_function *lookup_by_tty_minor(int minor) {
+ int n;
+ struct rawbulk_function *fn;
+ for (n = 0; n < _MAX_TID; n ++) {
+ fn = prealloced_functions[n];
+ if (fn->tty_minor == minor)
+ return fn;
+ }
+ return NULL;
+}
+
+static inline int check_enable_state(struct rawbulk_function *fn) {
+ int enab;
+ unsigned long flags;
+ spin_lock_irqsave(&fn->lock, flags);
+ enab = fn->enable? 1: 0;
+ spin_unlock_irqrestore(&fn->lock, flags);
+ return enab;
+}
+
+int rawbulk_check_enable(struct rawbulk_function *fn) {
+ return check_enable_state(fn);
+}
+EXPORT_SYMBOL_GPL(rawbulk_check_enable);
+
+static inline int check_tty_opened(struct rawbulk_function *fn) {
+ int opened;
+ unsigned long flags;
+ spin_lock_irqsave(&fn->lock, flags);
+ opened = fn->tty_opened? 1: 0;
+ spin_unlock_irqrestore(&fn->lock, flags);
+ return opened;
+}
+
+static inline void set_enable_state(struct rawbulk_function *fn, int enab) {
+ unsigned long flags;
+ spin_lock_irqsave(&fn->lock, flags);
+ fn->enable = !!enab;
+ spin_unlock_irqrestore(&fn->lock, flags);
+}
+
+void rawbulk_disable_function(struct rawbulk_function *fn) {
+ set_enable_state(fn, 0);
+}
+EXPORT_SYMBOL_GPL(rawbulk_disable_function);
+
+static inline void set_tty_opened(struct rawbulk_function *fn, int opened) {
+ unsigned long flags;
+ spin_lock_irqsave(&fn->lock, flags);
+ fn->tty_opened = !!opened;
+ spin_unlock_irqrestore(&fn->lock, flags);
+}
+
+#define port_to_rawbulk(p) container_of(p, struct rawbulk_function, port)
+#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function)
+
+static struct usb_request_wrapper *get_req(struct list_head *head, spinlock_t
+ *lock) {
+ unsigned long flags;
+ struct usb_request_wrapper *req = NULL;
+ spin_lock_irqsave(lock, flags);
+ if (!list_empty(head)) {
+ req = list_first_entry(head, struct usb_request_wrapper, list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(lock, flags);
+ return req;
+}
+
+static void put_req(struct usb_request_wrapper *req, struct list_head *head,
+ spinlock_t *lock) {
+ unsigned long flags;
+ spin_lock_irqsave(lock, flags);
+ list_add_tail(&req->list, head);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void move_req(struct usb_request_wrapper *req, struct list_head *head,
+ spinlock_t *lock) {
+ unsigned long flags;
+ spin_lock_irqsave(lock, flags);
+ list_move_tail(&req->list, head);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void insert_req(struct usb_request_wrapper *req, struct list_head *head,
+ spinlock_t *lock) {
+ unsigned long flags;
+ spin_lock_irqsave(lock, flags);
+ list_add(&req->list, head);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static int control_dtr(int set) {
+ struct usb_ctrlrequest ctrl = {
+ .bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR, //0x40
+ .bRequest = 0x01,
+ .wLength = 0,
+ .wIndex = 0,
+ };
+
+ ctrl.wValue = cpu_to_le16(!!set);
+ return rawbulk_forward_ctrlrequest(&ctrl);
+}
+
+static void init_endpoint_desc(struct usb_endpoint_descriptor *epdesc, int in,
+ int maxpacksize) {
+ struct usb_endpoint_descriptor template = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ };
+
+ *epdesc = template;
+ if (in)
+ epdesc->bEndpointAddress = USB_DIR_IN;
+ else
+ epdesc->bEndpointAddress = USB_DIR_OUT;
+ epdesc->wMaxPacketSize = cpu_to_le16(maxpacksize);
+}
+
+static void init_interface_desc(struct usb_interface_descriptor *ifdesc) {
+ struct usb_interface_descriptor template = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xff,//USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff,
+ .iInterface = 0,
+ };
+
+ *ifdesc = template;
+}
+
+static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute
+ *attr, char *buf);
+static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count);
+
+static inline void add_device_attr(struct rawbulk_function *fn, int n, const char
+ *name, int mode) {
+ if (n < MAX_ATTRIBUTES) {
+ fn->attr[n].attr.name = name;
+ fn->attr[n].attr.mode = mode;
+ fn->attr[n].show = rawbulk_attr_show;
+ fn->attr[n].store = rawbulk_attr_store;
+ }
+}
+
+static int which_attr(struct rawbulk_function *fn, struct device_attribute
+ *attr) {
+ int n;
+ for (n = 0; n < fn->max_attrs; n ++) {
+ if (attr == &fn->attr[n])
+ return n;
+ }
+ return -1;
+}
+
+static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ int n;
+ int idx;
+ int enab;
+ struct rawbulk_function *fn;
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ fn = rawbulk_lookup_function(n);
+ if (fn->dev == dev) {
+ idx = which_attr(fn, attr);
+ break;
+ }
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (!strcmp(attr->attr.name, fn->shortname)) {
+ idx = ATTR_ENABLE_C;
+ break;
+ }
+#endif
+ }
+
+ if (n == _MAX_TID)
+ return 0;
+
+ enab = check_enable_state(fn);
+ switch (idx) {
+ case ATTR_ENABLE:
+ return sprintf(buf, "%d", enab);
+#ifdef SUPPORT_LEGACY_CONTROL
+ case ATTR_ENABLE_C:
+ return sprintf(buf, "%s", enab? "gadget": "tty");
+#endif
+ case ATTR_AUTORECONN:
+ return sprintf(buf, "%d", fn->autoreconn);
+ case ATTR_STATISTICS:
+ return rawbulk_transfer_statistics(fn->transfer_id, buf);
+ case ATTR_NUPS:
+ return sprintf(buf, "%d", enab? fn->nups: -1);
+ case ATTR_NDOWNS:
+ return sprintf(buf, "%d", enab? fn->ndowns: -1);
+ case ATTR_UPSIZE:
+ return sprintf(buf, "%d", enab? fn->upsz: -1);
+ case ATTR_DOWNSIZE:
+ return sprintf(buf, "%d", enab? fn->downsz: -1);
+ case ATTR_SPLIT:
+ return sprintf(buf, "%d", enab? fn->splitsz: -1);
+ case ATTR_PUSHABLE:
+ return sprintf(buf, "%d", fn->pushable);
+ default:
+ break;
+ }
+ return 0;
+}
+
+static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count) {
+ int n;
+ int rc = 0;
+ int idx = -1;
+ int nups;
+ int ndowns;
+ int upsz;
+ int downsz;
+ int splitsz;
+ int pushable;
+ struct rawbulk_function *fn;
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ fn = rawbulk_lookup_function(n);
+ if (fn->dev == dev) {
+ idx = which_attr(fn, attr);
+ break;
+ }
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (!strcmp(attr->attr.name, fn->shortname)) {
+ idx = ATTR_ENABLE_C;
+ break;
+ }
+#endif
+ }
+
+ if (idx < 0) {
+ printk(KERN_ERR "sorry, I cannot find rawbulk fn '%s'\n", attr->attr.name);
+ goto exit;
+ }
+
+ nups = fn->nups;
+ ndowns = fn->ndowns;
+ upsz = fn->upsz;
+ downsz = fn->downsz;
+ splitsz = fn->splitsz;
+ pushable = fn->pushable;
+
+ /* find out which attr(file) we write */
+
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (idx <= ATTR_ENABLE_C)
+#else
+ if (idx == ATTR_ENABLE)
+#endif
+ {
+ int enable;
+ if (idx == ATTR_ENABLE) {
+ enable = simple_strtoul(buf, NULL, 10);
+#ifdef SUPPORT_LEGACY_CONTROL
+ } else if (idx == ATTR_ENABLE_C) {
+ if (!strncmp(buf, "tty", 3))
+ enable = 0;
+ else if (!strncmp(buf, "gadget", 6))
+ enable = 1;
+ else {
+ printk(KERN_ERR "invalid option(%s) for bypass, try again...\n", buf);
+ goto exit;
+ }
+#endif /* SUPPORT_LEGACY_CONTROL */
+ } else
+ goto exit;
+
+ if (check_enable_state(fn) != (!!enable)) {
+ set_enable_state(fn, enable);
+ if (!!enable && fn->activated) {
+ printk(KERN_DEBUG "enable rawbulk %s channel, been activated? %s\n",
+ fn->shortname, fn->activated? "yes": "no");
+ if (fn->transfer_id == RAWBULK_TID_MODEM) {
+ /* clear DTR to endup last session between AP and CP */
+ control_dtr(1);
+ msleep(10);
+ control_dtr(0);
+ }
+
+ /* Stop TTY i/o */
+ rawbulk_tty_stop_io(fn);
+
+ /* Start rawbulk transfer */
+ wake_lock(&fn->keep_awake);
+ rc = rawbulk_start_transactions(fn->transfer_id, nups,
+ ndowns, upsz, downsz, splitsz, pushable);
+ if (rc < 0) {
+ set_enable_state(fn, !enable);
+ rawbulk_tty_start_io(fn);
+ }
+ } else {
+ /* Stop rawbulk transfer */
+ printk(KERN_DEBUG "disable rawbulk %s channel, been activated? %s\n",
+ fn->shortname, fn->activated? "yes": "no");
+ rawbulk_stop_transactions(fn->transfer_id);
+ if (fn->transfer_id == RAWBULK_TID_MODEM) {
+ /* clear DTR automatically when disable modem rawbulk */
+ control_dtr(1);
+ msleep(10);
+ control_dtr(0);
+ }
+ wake_unlock(&fn->keep_awake);
+
+ /* Start TTY i/o */
+ rawbulk_tty_start_io(fn);
+ }
+ }
+ } else if (idx == ATTR_DTR) {
+ if (fn->transfer_id == RAWBULK_TID_MODEM) {
+ if (check_enable_state(fn))
+ control_dtr(simple_strtoul(buf, NULL, 10));
+ }
+ } else if (idx == ATTR_AUTORECONN) {
+ fn->autoreconn = !!simple_strtoul(buf, NULL, 10);
+ } else {
+ int val = simple_strtoul(buf, NULL, 10);
+ switch (idx) {
+ case ATTR_NUPS: nups = val; break;
+ case ATTR_NDOWNS: ndowns = val; break;
+ case ATTR_UPSIZE: upsz = val; break;
+ case ATTR_DOWNSIZE: downsz = val; break;
+ case ATTR_SPLIT: splitsz = val; break;
+ case ATTR_PUSHABLE:
+ pushable = !!val;
+ fn->pushable = pushable;
+ break;
+ default: goto exit;
+ }
+
+ if (!check_enable_state(fn))
+ goto exit;
+
+ if (!fn->activated)
+ goto exit;
+
+ rawbulk_stop_transactions(fn->transfer_id);
+ rc = rawbulk_start_transactions(fn->transfer_id, nups, ndowns, upsz,
+ downsz, splitsz, pushable);
+ if (rc >= 0) {
+ fn->nups = nups;
+ fn->ndowns = ndowns;
+ fn->upsz = upsz;
+ fn->downsz = downsz;
+ fn->splitsz = splitsz;
+ fn->pushable = pushable;
+ } else {
+ rawbulk_stop_transactions(fn->transfer_id);
+ wake_unlock(&fn->keep_awake);
+ set_enable_state(fn, 0);
+ }
+ }
+
+exit:
+ return count;
+}
+
+static int rawbulk_create_files(struct rawbulk_function *fn) {
+ int n, rc;
+ for (n = 0; n < fn->max_attrs; n ++){
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (n == ATTR_ENABLE_C)
+ continue;
+#endif
+ rc = device_create_file(fn->dev, &fn->attr[n]);
+ if (rc < 0) {
+ while (--n >= 0) {
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (n == ATTR_ENABLE_C)
+ continue;
+#endif
+ device_remove_file(fn->dev, &fn->attr[n]);
+ }
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static void rawbulk_remove_files(struct rawbulk_function *fn) {
+ int n = fn->max_attrs;
+ while (--n >= 0) {
+#ifdef SUPPORT_LEGACY_CONTROL
+ if (n == ATTR_ENABLE_C)
+ continue;
+#endif
+ device_remove_file(fn->dev, &fn->attr[n]);
+ }
+}
+
+#define RAWBULK_TTY_MINORS 255
+static int tty_minors[RAWBULK_TTY_MINORS] = { 0 };
+static int alloc_tty_minor(struct rawbulk_function *fn) {
+ int n;
+ if (check_tty_opened(fn))
+ printk(KERN_WARNING "ttyRB%d has opened yet %s has been disconnected\n",
+ fn->tty_minor, fn->longname);
+ for (n = 0; n < RAWBULK_TTY_MINORS; n ++) {
+ if (tty_minors[n] == 0) {
+ tty_minors[n] = fn->transfer_id + 0x8000;
+ return n;
+ }
+ }
+ return -ENODEV;
+}
+
+static void free_tty_minor(struct rawbulk_function *fn) {
+ int n;
+ struct tty_struct **ttys = rawbulk_tty_driver->ttys;
+ if (!check_tty_opened(fn))
+ tty_minors[fn->tty_minor] = 0;
+ /* Clear the closed tty minors of this port */
+ for (n = 0; n < RAWBULK_TTY_MINORS; n ++) {
+ if ((tty_minors[n] == fn->transfer_id + 0x8000) && ttys[n]) {
+ struct tty_struct *tty = ttys[n];
+ if (tty->count > 0)
+ continue; /* Keep the minor while tty is being used */
+ if (test_bit(TTY_CLOSING, &tty->flags)) {
+ /* FIXME: Cannot close the tty_struct! */
+ printk(KERN_DEBUG "cannot recycle the minor %d because " \
+ "the TTY_CLOSING flags is still on\n", n);
+ continue;
+ }
+ tty_minors[n] = 0;
+ }
+ }
+}
+
+int rawbulk_register_tty(struct rawbulk_function *fn) {
+ struct device *dev;
+
+ spin_lock_init(&fn->tx_lock);
+ spin_lock_init(&fn->rx_lock);
+ INIT_LIST_HEAD(&fn->tx_free);
+ INIT_LIST_HEAD(&fn->rx_free);
+ INIT_LIST_HEAD(&fn->tx_inproc);
+ INIT_LIST_HEAD(&fn->rx_inproc);
+ INIT_LIST_HEAD(&fn->rx_throttled);
+
+ fn->tty_minor = alloc_tty_minor(fn);
+ if (fn->tty_minor < 0)
+ return -ENODEV;
+ fn->tty_opened = 0;
+ fn->last_pushed = 0;
+ tty_port_init(&fn->port);
+ fn->port.ops = &rawbulk_tty_port_ops;
+
+ /* Bring up the tty device */
+ dev = tty_register_device(rawbulk_tty_driver, fn->tty_minor, fn->dev);
+ if (IS_ERR(dev))
+ printk(KERN_ERR "Failed to attach ttyRB%d to %s device.\n",
+ fn->tty_minor, fn->longname);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rawbulk_register_tty);
+
+void rawbulk_unregister_tty(struct rawbulk_function *fn) {
+ tty_unregister_device(rawbulk_tty_driver, fn->tty_minor);
+ free_tty_minor(fn);
+}
+EXPORT_SYMBOL_GPL(rawbulk_unregister_tty);
+
+/******************************************************************************/
+
+/* Call this after all request has detached! */
+void rawbulk_tty_free_request(struct rawbulk_function *fn) {
+ struct usb_request_wrapper *req;
+
+ while ((req = get_req(&fn->rx_free, &fn->rx_lock))) {
+ usb_ep_free_request(fn->bulk_out, req->request);
+ kfree(req);
+ }
+
+ while ((req = get_req(&fn->tx_free, &fn->tx_lock))) {
+ usb_ep_free_request(fn->bulk_in, req->request);
+ kfree(req);
+ }
+}
+EXPORT_SYMBOL_GPL(rawbulk_tty_free_request);
+
+static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req);
+static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req);
+
+int rawbulk_tty_alloc_request(struct rawbulk_function *fn) {
+ int n;
+ struct usb_request_wrapper *req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fn->lock, flags);
+ if (!fn->bulk_out || !fn->bulk_in) {
+ spin_unlock_irqrestore(&fn->lock, flags);
+ return -ENODEV;
+ }
+ spin_unlock_irqrestore(&fn->lock, flags);
+
+ /* Allocate and init rx request */
+ for (n = 0; n < MAX_TTY_RX; n ++) {
+ req = kmalloc(sizeof(struct usb_request_wrapper) +
+ MAX_TTY_RX_PACKAGE, GFP_KERNEL);
+ if (!req)
+ break;
+
+ req->request = usb_ep_alloc_request(fn->bulk_out, GFP_KERNEL);
+ if (!req->request) {
+ kfree(req);
+ break;
+ }
+
+ req->fn = fn;
+ INIT_LIST_HEAD(&req->list);
+ req->length = MAX_TTY_RX_PACKAGE;
+ req->request->buf = req->buffer;
+ req->request->length = MAX_TTY_RX_PACKAGE;
+ req->request->complete = rawbulk_tty_rx_complete;
+ put_req(req, &fn->rx_free, &fn->rx_lock);
+ }
+
+ if (n < MAX_TTY_RX) {
+ /* free allocated request */
+ rawbulk_tty_free_request(fn);
+ return -ENOMEM;
+ }
+
+ /* Allocate and init tx request */
+ for (n = 0; n < MAX_TTY_TX; n ++) {
+ req = kmalloc(sizeof(struct usb_request_wrapper) +
+ MAX_TTY_TX_PACKAGE, GFP_KERNEL);
+ if (!req)
+ break;
+
+ req->request = usb_ep_alloc_request(fn->bulk_in, GFP_KERNEL);
+ if (!req->request) {
+ kfree(req);
+ break;
+ }
+
+ req->fn = fn;
+ INIT_LIST_HEAD(&req->list);
+ req->length = MAX_TTY_TX_PACKAGE;
+ req->request->zero = 0;
+ req->request->buf = req->buffer;
+ req->request->complete = rawbulk_tty_tx_complete;
+ put_req(req, &fn->tx_free, &fn->tx_lock);
+ }
+
+ if (n < MAX_TTY_TX) {
+ /* free allocated request */
+ rawbulk_tty_free_request(fn);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rawbulk_tty_alloc_request);
+
+int rawbulk_tty_stop_io(struct rawbulk_function *fn) {
+ struct usb_request_wrapper *req;
+
+ if (!check_tty_opened(fn))
+ return -ENODEV;
+
+ while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) {
+ if (req->request->status == -EINPROGRESS) {
+ put_req(req, &fn->rx_inproc, &fn->rx_lock);
+ usb_ep_dequeue(fn->bulk_out, req->request);
+ }
+ }
+
+ while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) {
+ if (req->request->status == -EINPROGRESS) {
+ put_req(req, &fn->tx_inproc, &fn->tx_lock);
+ usb_ep_dequeue(fn->bulk_in, req->request);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rawbulk_tty_stop_io);
+
+int rawbulk_tty_start_io(struct rawbulk_function *fn) {
+ int ret;
+ struct usb_request_wrapper *req;
+
+ if (!check_tty_opened(fn))
+ return -ENODEV;
+
+ while ((req = get_req(&fn->rx_free, &fn->rx_lock))) {
+ put_req(req, &fn->rx_inproc, &fn->rx_lock);
+ ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC);
+ if (ret < 0) {
+ move_req(req, &fn->rx_free, &fn->rx_lock);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rawbulk_tty_start_io);
+
+/* Complete the data send stage */
+static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req) {
+ struct usb_request_wrapper *r = get_wrapper(req);
+ struct rawbulk_function *fn = r->fn;
+
+ move_req(r, &fn->tx_free, &fn->tx_lock);
+}
+
+static void rawbulk_tty_push_data(struct rawbulk_function *fn) {
+ struct usb_request_wrapper *r;
+ struct tty_struct *tty;
+
+ tty = tty_port_tty_get(&fn->port);
+ tty->minimum_to_wake = 1; /* wakeup to read even pushed only once */
+ /* walk the throttled list, push all the data to TTY */
+ while ((r = get_req(&fn->rx_throttled, &fn->rx_lock))) {
+ char *sbuf;
+ int push_count;
+ struct usb_request *req = r->request;
+
+ if (req->status < 0) {
+ put_req(r, &fn->rx_free, &fn->rx_lock);
+ continue;
+ }
+ sbuf = req->buf + fn->last_pushed;
+ push_count = req->actual - fn->last_pushed;
+ if (push_count) {
+ int count = tty_insert_flip_string(tty, sbuf, push_count);
+ if (count < push_count) {
+ /* We met throttled again */
+ fn->last_pushed += count;
+ if (count)
+ tty_flip_buffer_push(tty);
+ insert_req(r, &fn->rx_throttled, &fn->rx_lock);
+ break;
+ }
+ tty_flip_buffer_push(tty);
+ fn->last_pushed = 0;
+ }
+ put_req(r, &fn->rx_free, &fn->rx_lock);
+ }
+ tty_kref_put(tty);
+}
+
+/* Recieve data from host */
+static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req) {
+ int ret;
+ struct usb_request_wrapper *r = get_wrapper(req);
+ struct rawbulk_function *fn = r->fn;
+ struct tty_struct *tty = fn->tty;
+
+ if (req->status < 0 || !check_tty_opened(fn)) {
+ move_req(r, &fn->rx_free, &fn->rx_lock);
+ return;
+ }
+
+ if (test_bit(TTY_THROTTLED, &tty->flags)) {
+ /* Give up to resubmitted the request */
+ move_req(r, &fn->rx_free, &fn->rx_lock);
+ return;
+ } else {
+ /* Move the request to the throttled queue */
+ move_req(r, &fn->rx_throttled, &fn->rx_lock);
+ /* Start to push data */
+ rawbulk_tty_push_data(fn);
+ }
+
+ /* Re-queue the request again */
+ while ((r = get_req(&fn->rx_free, &fn->rx_lock))) {
+ put_req(r, &fn->rx_inproc, &fn->rx_lock);
+ ret = usb_ep_queue(fn->bulk_out, r->request, GFP_ATOMIC);
+ if (ret < 0) {
+ move_req(r, &fn->rx_free, &fn->rx_lock);
+ break;
+ }
+ }
+}
+
+/* Start to queue request on BULK OUT endpoint, when tty is try to open */
+static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct
+ *tty) {
+ struct rawbulk_function *fn = port_to_rawbulk(port);
+ /* Low latency for tty */
+ tty->low_latency = 1;
+ tty->termios->c_cc[VMIN] = 1;
+ return rawbulk_tty_start_io(fn);
+}
+
+static void rawbulk_tty_deactivate(struct tty_port *port) {
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = port_to_rawbulk(port);
+
+ /* This is a little different from stop_io */
+ while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) {
+ put_req(req, &fn->rx_inproc, &fn->rx_lock);
+ usb_ep_dequeue(fn->bulk_out, req->request);
+ }
+
+ while ((req = get_req(&fn->rx_throttled, &fn->rx_lock)))
+ put_req(req, &fn->rx_free, &fn->rx_lock);
+
+ while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) {
+ put_req(req, &fn->tx_inproc, &fn->tx_lock);
+ usb_ep_dequeue(fn->bulk_in, req->request);
+ }
+}
+
+static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count) {
+ int ret;
+ int submitted = 0;
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = tty->driver_data;
+
+ if (check_enable_state(fn))
+ return -EBUSY;
+
+ /* Get new request(s) that freed, fill it, queue it to the endpoint */
+ while ((req = get_req(&fn->tx_free, &fn->tx_lock))) {
+ int length = count - submitted;
+ if (length <= 0) {
+ put_req(req, &fn->tx_free, &fn->tx_lock);
+ break;
+ }
+ if (length > MAX_TTY_TX_PACKAGE)
+ length = MAX_TTY_TX_PACKAGE;
+ memcpy(req->buffer, buf + submitted, length);
+ req->request->length = length;
+ put_req(req, &fn->tx_inproc, &fn->tx_lock);
+ ret = usb_ep_queue(fn->bulk_in, req->request, GFP_ATOMIC);
+ if (ret < 0) {
+ move_req(req, &fn->tx_free, &fn->tx_lock);
+ return ret;
+ }
+ submitted += length;
+ }
+
+ return submitted;
+}
+
+static int rawbulk_tty_write_room(struct tty_struct *tty) {
+ int room = 0;
+ unsigned long flags;
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = tty->driver_data;
+
+ if (check_enable_state(fn))
+ return 0;
+
+ spin_lock_irqsave(&fn->tx_lock, flags);
+ list_for_each_entry(req, &fn->tx_free, list)
+ room += req->length;
+ spin_unlock_irqrestore(&fn->tx_lock, flags);
+
+ return room;
+}
+
+static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty) {
+ int chars = 0;
+ unsigned long flags;
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = tty->driver_data;
+
+ if (check_enable_state(fn))
+ return 0;
+
+ spin_lock_irqsave(&fn->rx_lock, flags);
+ list_for_each_entry(req, &fn->rx_throttled, list) {
+ if (req->request->status < 0)
+ continue;
+ chars += req->request->actual;
+ }
+ chars -= fn->last_pushed;
+ spin_unlock_irqrestore(&fn->rx_lock, flags);
+
+ return chars;
+}
+
+static void rawbulk_tty_throttle(struct tty_struct *tty) {
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = tty->driver_data;
+
+ /* Stop the processing requests */
+ while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) {
+ if (req->request->status == -EINPROGRESS) {
+ put_req(req, &fn->rx_inproc, &fn->rx_lock);
+ usb_ep_dequeue(fn->bulk_out, req->request);
+ }
+ }
+}
+
+static void rawbulk_tty_unthrottle(struct tty_struct *tty) {
+ int ret;
+ struct usb_request_wrapper *req;
+ struct rawbulk_function *fn = tty->driver_data;
+
+ /* Try to push the throttled requests' data to TTY */
+ rawbulk_tty_push_data(fn);
+
+ /* Restart the free requests */
+ while ((req = get_req(&fn->rx_free, &fn->rx_lock))) {
+ put_req(req, &fn->rx_inproc, &fn->rx_lock);
+ ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC);
+ if (ret < 0) {
+ move_req(req, &fn->rx_free, &fn->rx_lock);
+ break;
+ }
+ }
+}
+
+static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios
+ *old) {
+ //struct rawbulk_function *fn = tty->driver_data;
+}
+
+static int rawbulk_tty_tiocmget(struct tty_struct *tty) {
+ //struct rawbulk_function *fn = tty->driver_data;
+ return 0;
+}
+
+static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set,
+ unsigned int clear) {
+ //struct rawbulk_function *fn = tty->driver_data;
+ return 0;
+}
+
+static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct
+ *tty) {
+ int ret = 0;
+ struct rawbulk_function *fn = lookup_by_tty_minor(tty->index);
+
+ if (!fn)
+ return -ENODEV;
+
+ ret = tty_init_termios(tty);
+ if (ret < 0)
+ return ret;
+
+ tty->driver_data = fn;
+ fn->tty = tty;
+
+ /* Final install (we use the default method) */
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[tty->index] = tty;
+ return ret;
+}
+
+static void rawbulk_tty_cleanup(struct tty_struct *tty) {
+ struct rawbulk_function *fn = lookup_by_tty_minor(tty->index);
+ tty->driver_data = NULL;
+ if (fn)
+ fn->tty = NULL;
+}
+
+static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip) {
+ int ret;
+ struct rawbulk_function *fn = lookup_by_tty_minor(tty->index);
+
+ if (!fn)
+ return -ENODEV;
+
+ tty->driver_data = fn;
+ fn->tty = tty;
+
+ if (check_enable_state(fn))
+ return -EBUSY;
+
+ if (check_tty_opened(fn))
+ return -EBUSY;
+
+ set_tty_opened(fn, 1);
+
+ ret = tty_port_open(&fn->port, tty, flip);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static void rawbulk_tty_hangup(struct tty_struct *tty) {
+ struct rawbulk_function *fn = tty->driver_data;
+ if (!fn)
+ return;
+ tty_port_hangup(&fn->port);
+}
+
+static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip) {
+ struct rawbulk_function *fn = tty->driver_data;
+ if (!fn)
+ return;
+ set_tty_opened(fn, 0);
+ tty_port_close(&fn->port, tty, flip);
+}
+
+static __init int rawbulk_tty_init(void) {
+ int ret;
+ struct tty_driver *drv = alloc_tty_driver(_MAX_TID);
+ if (!drv)
+ return -ENOMEM;
+
+ drv->owner = THIS_MODULE;
+ drv->driver_name = "rawbulkport";
+ drv->name = "ttyRB";//prefix
+ drv->type = TTY_DRIVER_TYPE_SERIAL;
+ drv->subtype = SERIAL_TYPE_NORMAL;
+ drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ drv->init_termios = tty_std_termios;
+ drv->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ drv->init_termios.c_lflag = 0;
+ drv->init_termios.c_ispeed = 9600;
+ drv->init_termios.c_ospeed = 9600;
+
+ tty_set_operations(drv, &rawbulk_tty_ops);
+
+ ret = tty_register_driver(drv);
+ if (ret < 0) {
+ put_tty_driver(drv);
+ } else
+ rawbulk_tty_driver = drv;
+ return ret;
+}
+
+/******************************************************************************/
+static struct class *rawbulk_class;
+
+static struct _function_init_stuff {
+ const char *longname;
+ const char *shortname;
+ const char *iString;
+ unsigned int ep_maxpkg;
+ unsigned int nups;
+ unsigned int ndowns;
+ unsigned int upsz;
+ unsigned int downsz;
+ unsigned int splitsz;
+ bool autoreconn;
+ bool pushable;
+} _init_params[] = {
+ {"rawbulk-modem", "data", "Modem Port", 64, 16, 16, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false },
+ {"rawbulk-ets", "ets", "ETS Port", 512, 4, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false },
+ {"rawbulk-at", "atc", "AT Channel", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false },
+ {"rawbulk-pcv", "pcv", "PCM Voice", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false },
+ {"rawbulk-gps", "gps", "LBS GPS Port", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false },
+ { }, /* End of configurations */
+};
+
+static __init struct rawbulk_function *rawbulk_alloc_function(int transfer_id) {
+ int rc;
+ struct rawbulk_function *fn;
+ struct _function_init_stuff *_init = &_init_params[transfer_id];
+
+ if (transfer_id == _MAX_TID)
+ return NULL;
+
+ fn = kzalloc(sizeof *fn, GFP_KERNEL);
+ if (IS_ERR(fn))
+ return NULL;
+
+ /* init default features of rawbulk functions */
+ fn->longname = _init->longname;
+ fn->shortname = _init->shortname;
+ fn->string_defs[0].s = _init->iString;
+ fn->nups = _init->nups;
+ fn->ndowns = _init->ndowns;
+ fn->upsz = _init->upsz;
+ fn->downsz = _init->downsz;
+ fn->splitsz = _init->splitsz;
+ fn->autoreconn = _init->autoreconn;
+ fn->pushable = _init->pushable;
+
+ fn->tty_minor = -1;
+ /* init descriptors */
+ init_interface_desc(&fn->interface);
+ init_endpoint_desc(&fn->fs_bulkin_endpoint, 1, _init->ep_maxpkg);
+ init_endpoint_desc(&fn->hs_bulkin_endpoint, 1, _init->ep_maxpkg);
+ init_endpoint_desc(&fn->fs_bulkout_endpoint, 0, _init->ep_maxpkg);
+ init_endpoint_desc(&fn->hs_bulkout_endpoint, 0, _init->ep_maxpkg);
+
+ fn->fs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface;
+ fn->fs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkin_endpoint;
+ fn->fs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkout_endpoint;
+
+ fn->hs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface;
+ fn->hs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkin_endpoint;
+ fn->hs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkout_endpoint;
+
+ fn->string_table.language = 0x0409;
+ fn->string_table.strings = fn->string_defs;
+ fn->strings[0] = &fn->string_table;
+ fn->strings[1] = NULL;
+
+ fn->transfer_id = transfer_id;
+
+ /* init function callbacks */
+ fn->function.strings = fn->strings;
+ fn->function.descriptors = fn->fs_descs;
+ fn->function.hs_descriptors = fn->hs_descs;
+
+ /* init device attributes */
+ add_device_attr(fn, ATTR_ENABLE, "enable", 0755);
+#ifdef SUPPORT_LEGACY_CONTROL
+ add_device_attr(fn, ATTR_ENABLE_C, fn->shortname, 0755);
+#endif
+ add_device_attr(fn, ATTR_AUTORECONN, "autoreconn", 0755);
+ add_device_attr(fn, ATTR_STATISTICS, "statistics", 0644);
+ add_device_attr(fn, ATTR_NUPS, "nups", 0755);
+ add_device_attr(fn, ATTR_NDOWNS, "ndowns", 0755);
+ add_device_attr(fn, ATTR_UPSIZE, "ups_size", 0755);
+ add_device_attr(fn, ATTR_DOWNSIZE, "downs_size", 0755);
+ add_device_attr(fn, ATTR_SPLIT, "split_size", 0755);
+ add_device_attr(fn, ATTR_PUSHABLE, "pushable", 0755);
+
+ fn->max_attrs = ATTR_PUSHABLE + 1;
+
+ if (transfer_id == RAWBULK_TID_MODEM) {
+ // printk(" kevin chagnge dtr for 200 for cts, disable usb est bypass \n");
+ add_device_attr(fn, ATTR_DTR, "dtr", 0200);
+ fn->max_attrs ++;
+ }
+
+ fn->dev = device_create(rawbulk_class, NULL, MKDEV(0,
+ fn->transfer_id), NULL, fn->shortname);
+ if (IS_ERR(fn->dev)) {
+ kfree(fn);
+ return NULL;
+ }
+
+ rc = rawbulk_create_files(fn);
+ if (rc < 0) {
+ device_destroy(rawbulk_class, fn->dev->devt);
+ kfree(fn);
+ return NULL;
+ }
+
+ spin_lock_init(&fn->lock);
+ wake_lock_init(&fn->keep_awake, WAKE_LOCK_SUSPEND, fn->longname);
+ return fn;
+}
+
+static void rawbulk_destory_function(struct rawbulk_function *fn) {
+ if (!fn)
+ return;
+ wake_lock_destroy(&fn->keep_awake);
+ rawbulk_remove_files(fn);
+ device_destroy(rawbulk_class, fn->dev->devt);
+ kfree(fn);
+}
+
+#ifdef SUPPORT_LEGACY_CONTROL
+static struct attribute *legacy_sysfs[_MAX_TID + 1] = { NULL };
+static struct attribute_group legacy_sysfs_group = {
+ .attrs = legacy_sysfs,
+};
+struct kobject *legacy_sysfs_stuff;
+#endif /* SUPPORT_LEGACY_CONTROL */
+
+static int __init init(void) {
+ int n;
+ int rc = 0;
+
+ printk(KERN_INFO "rawbulk functions init.\n");
+
+ rawbulk_class = class_create(THIS_MODULE, "usb_rawbulk");
+ if (IS_ERR(rawbulk_class))
+ return PTR_ERR(rawbulk_class);
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ struct rawbulk_function *fn = rawbulk_alloc_function(n);
+ if (IS_ERR(fn)) {
+ while (n --)
+ rawbulk_destory_function(prealloced_functions[n]);
+ rc = PTR_ERR(fn);
+ break;
+ }
+ prealloced_functions[n] = fn;
+#ifdef SUPPORT_LEGACY_CONTROL
+ legacy_sysfs[n] = &fn->attr[ATTR_ENABLE_C].attr;
+#endif
+ }
+
+ if (rc < 0) {
+ class_destroy(rawbulk_class);
+ return rc;
+ }
+
+#ifdef SUPPORT_LEGACY_CONTROL
+ /* make compatiable with old bypass sysfs access */
+ legacy_sysfs_stuff = kobject_create_and_add("usb_bypass", NULL);
+ if (legacy_sysfs_stuff) {
+ rc = sysfs_create_group(legacy_sysfs_stuff, &legacy_sysfs_group);
+ if (rc < 0)
+ printk(KERN_ERR "failed to create legacy bypass sys-stuff, but continue...\n");
+ }
+#endif /* SUPPORT_LEGACY_CONTROL */
+
+ rc = rawbulk_tty_init();
+ if (rc < 0) {
+ printk(KERN_ERR "failed to init rawbulk tty driver.\n");
+ return rc;
+ }
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ struct rawbulk_function *fn = prealloced_functions[n];
+ rc = rawbulk_register_tty(fn);
+ if (rc < 0) {
+ printk(KERN_ERR "fatal error: we cannot create ttyRB%d for %s\n",
+ n, fn->longname);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+module_init(init);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c
new file mode 100755
index 00000000..70ec5be1
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c
@@ -0,0 +1,1372 @@
+/*
+ * Rawbulk Driver from VIA Telecom
+ *
+ * Copyright (C) 2011 VIA Telecom, Inc.
+ * Author: Karfield Chen (kfchen@via-telecom.com)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+/*
+ * Rawbulk is transfer performer between CBP host driver and Gadget driver
+ *
+ * 1 rawbulk transfer can be consist by serval upstream and/or downstream
+ * transactions.
+ *
+ * upstream: CBP Driver ---> Gadget IN
+ * downstream: Gadget OUT ---> CBP Driver
+ *
+ * upstream flowchart:
+ *
+ * -x-> usb_submit_urb -> complete -> usb_ep_queue -> complete -,
+ * | |
+ * `----------------------(control)----------------------------'
+ *
+ * downstream flowchart:
+ *
+ * -x-> usb_ep_queue -> complete -> usb_submit_urb -> complete -,
+ * | |
+ * `----------------------(control)----------------------------'
+ *
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>"
+#define DRIVER_DESC "Rawbulk Driver - perform bypass for Kunlun"
+#define DRIVER_VERSION "1.0.3"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/usb/rawbulk.h>
+#include <linux/moduleparam.h>
+
+#ifdef VERBOSE_DEBUG
+#define ldbg(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args)
+#define tdbg(t, fmt, args...) \
+ printk(KERN_DEBUG "Rawbulk %s: " fmt "\n", t->name, ##args)
+#else
+#define ldbg(args...)
+#define tdbg(args...)
+#endif
+
+#define lerr(fmt, args...) \
+ printk(KERN_ERR "%s: " fmt "\n", __func__, ##args)
+#define terr(t, fmt, args...) \
+ printk(KERN_ERR "Rawbulk [%s]:" fmt "\n", t->name, ##args)
+
+#define FREE_STALLED 1
+#define FREE_IDLED 2
+#define FREE_RETRIVING 4
+#define FREE_ALL (FREE_STALLED | FREE_IDLED | FREE_RETRIVING)
+
+#define STOP_UPSTREAM 0x1
+#define STOP_DOWNSTREAM 0x2
+
+struct rawbulk_transfer {
+ enum transfer_id id;
+ spinlock_t lock;
+ int control;
+ struct usb_anchor submitted;
+ struct usb_function *function;
+ struct usb_interface *interface;
+ struct mutex mutex; /* protection for API calling */
+ rawbulk_autoreconn_callback_t autoreconn;
+ rawbulk_intercept_t inceptor;
+ spinlock_t suspend_lock;
+ int suspended;
+ struct {
+ int ntrans;
+ struct list_head transactions;
+ struct usb_ep *ep;
+ struct usb_host_endpoint *host_ep;
+ } upstream, downstream;
+};
+
+static inline int get_epnum(struct usb_host_endpoint *ep) {
+ return (int)(ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+}
+
+static inline int get_maxpacksize(struct usb_host_endpoint *ep) {
+ return (int)(le16_to_cpu(ep->desc.wMaxPacketSize));
+}
+
+
+#define MAX_RESPONSE 32
+struct rawbulk_transfer_model {
+ struct usb_device *udev;
+ struct usb_composite_dev *cdev;
+ char ctrl_response[MAX_RESPONSE];
+ struct usb_ctrlrequest forward_dr;
+ struct urb *forwarding_urb;
+ struct rawbulk_transfer transfer[_MAX_TID];
+};
+static struct rawbulk_transfer_model *rawbulk;
+
+static struct rawbulk_transfer *id_to_transfer(int transfer_id) {
+ if (transfer_id < 0 || transfer_id >= _MAX_TID)
+ return NULL;
+ return &rawbulk->transfer[transfer_id];
+}
+
+/*
+ * upstream
+ */
+
+#define UPSTREAM_STAT_FREE 0
+#define UPSTREAM_STAT_RETRIEVING 1
+#define UPSTREAM_STAT_UPLOADING 2
+
+struct upstream_transaction {
+ int state;
+ int stalled;
+ char name[32];
+ struct list_head tlist;
+ struct delayed_work delayed;
+ struct rawbulk_transfer *transfer;
+ struct usb_request *req;
+ struct urb *urb;
+ int buffer_length;
+ unsigned char *buffer;
+};
+
+static void upstream_delayed_work(struct work_struct *work);
+static struct upstream_transaction *
+alloc_upstream_transaction(struct rawbulk_transfer *transfer, int bufsz, int pushable)
+{
+ struct upstream_transaction *t;
+
+ if (bufsz < get_maxpacksize(transfer->upstream.host_ep))
+ return NULL;
+ if (bufsz < PAGE_SIZE || bufsz % PAGE_SIZE != 0)
+ return NULL;
+
+ t = kzalloc(sizeof *t, GFP_KERNEL);
+ if (!t)
+ return NULL;
+
+ t->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(bufsz));
+ if (!t->buffer) {
+ kfree(t);
+ return NULL;
+ }
+
+ t->buffer_length = bufsz;
+
+ t->req = usb_ep_alloc_request(transfer->upstream.ep, GFP_KERNEL);
+ if (!t->req)
+ goto failto_alloc_usb_request;
+
+ if (!pushable) {
+ t->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!t->urb)
+ goto failto_alloc_urb;
+ }
+
+ t->name[0] = 0;
+ sprintf(t->name, "U%d (H:ep%din, G:%s)", transfer->upstream.ntrans,
+ get_epnum(transfer->upstream.host_ep),
+ transfer->upstream.ep->name);
+
+ INIT_LIST_HEAD(&t->tlist);
+ list_add_tail(&t->tlist, &transfer->upstream.transactions);
+ transfer->upstream.ntrans ++;
+ t->transfer = transfer;
+
+ INIT_DELAYED_WORK(&t->delayed, upstream_delayed_work);
+ t->state = UPSTREAM_STAT_FREE;
+ return t;
+
+failto_alloc_urb:
+ usb_ep_free_request(transfer->upstream.ep, t->req);
+failto_alloc_usb_request:
+ free_page((unsigned long)t->buffer);
+ kfree(t);
+ return NULL;
+}
+
+static void free_upstream_transaction(struct rawbulk_transfer *transfer, int option) {
+ struct list_head *p, *n;
+ list_for_each_safe(p, n, &transfer->upstream.transactions) {
+ struct upstream_transaction *t = list_entry(p, struct
+ upstream_transaction, tlist);
+
+ if ((option & FREE_RETRIVING) &&
+ (t->state == UPSTREAM_STAT_RETRIEVING)) {
+ if (t->urb) usb_unlink_urb(t->urb);
+ goto free;
+ }
+
+ if ((option & FREE_STALLED) && t->stalled)
+ goto free;
+
+ if ((option & FREE_IDLED) && (t->state == UPSTREAM_STAT_FREE))
+ goto free;
+
+ continue;
+free:
+ list_del(p);
+ if (t->urb)
+ usb_free_urb(t->urb);
+ usb_ep_free_request(transfer->upstream.ep, t->req);
+ free_page((unsigned long)t->buffer);
+ kfree(t);
+
+ transfer->upstream.ntrans --;
+ }
+}
+
+static void upstream_second_stage(struct urb *urb);
+static void upstream_final_stage(struct usb_ep *ep, struct usb_request
+ *req);
+
+static int start_upstream(struct upstream_transaction *t, gfp_t mem_flags) {
+ int rc;
+ unsigned long flags;
+ struct rawbulk_transfer *transfer = t->transfer;
+
+ spin_lock_irqsave(&transfer->lock, flags);
+ if (transfer->control & STOP_UPSTREAM) {
+ spin_unlock_irqrestore(&transfer->lock, flags);
+ cancel_delayed_work(&t->delayed);
+ t->state = UPSTREAM_STAT_FREE;
+ t->stalled = 1;
+ return -EPIPE;
+ }
+ spin_unlock_irqrestore(&transfer->lock, flags);
+
+ t->stalled = 0;
+ t->state = UPSTREAM_STAT_FREE;
+
+ usb_fill_bulk_urb(t->urb, rawbulk->udev,
+ usb_rcvbulkpipe(rawbulk->udev,
+ get_epnum(transfer->upstream.host_ep)),
+ t->buffer, t->buffer_length,
+ upstream_second_stage, t);
+ usb_anchor_urb(t->urb, &transfer->submitted);
+
+ rc = usb_submit_urb(t->urb, mem_flags);
+ usb_mark_last_busy(rawbulk->udev);
+ if (rc < 0) {
+ terr(t, "fail to submit urb %d", rc);
+ /* FIXME: if we met the host is suspending yet, we may add re-submit
+ * this urb in a ashman thread. so what is a ashman? this can deal any
+ * error that occur in this driver, and maintain the driver's health, I
+ * will complete this code in future, here we just stall the transaction
+ */
+ t->stalled = 1;
+ usb_unanchor_urb(t->urb);
+ }
+
+ t->state = UPSTREAM_STAT_RETRIEVING;
+ return rc;
+}
+
+static void upstream_delayed_work(struct work_struct *work) {
+ int rc;
+ int stop;
+ unsigned long flags;
+ struct delayed_work *dw = container_of(work, struct delayed_work, work);
+ struct upstream_transaction *t = container_of (work, struct
+ upstream_transaction, delayed.work);
+ struct rawbulk_transfer *transfer = t->transfer;
+
+ spin_lock_irqsave(&transfer->lock, flags);
+ stop = !!(transfer->control & STOP_UPSTREAM);
+ spin_unlock_irqrestore(&transfer->lock, flags);
+
+ rc = start_upstream(t, GFP_ATOMIC);
+ if (rc < 0 && !stop)
+ schedule_delayed_work(dw, HZ);
+}
+
+static unsigned int dump_mask = 0;
+module_param(dump_mask, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_mask, "Set data dump mask for each transfers");
+
+static inline void dump_data(struct rawbulk_transfer *trans,
+ const char *str, const unsigned char *data, int size) {
+ int i;
+ int no_chars = 0;
+
+ if (!(dump_mask & (1 << trans->id)))
+ return;
+
+ printk(KERN_DEBUG "DUMP tid = %d, %s: len = %d, chars = \"",
+ trans->id, str, size);
+ for (i = 0; i < size; ++i) {
+ char c = data[i];
+ if (c > 0x20 && c < 0x7e) {
+ printk("%c", c);
+ } else {
+ printk(".");
+ no_chars ++;
+ }
+ }
+ printk("\", data = ");
+ for (i = 0; i < size; ++i) {
+ printk("%.2x ", data[i]);
+ if (i > 7)
+ break;
+ }
+ if (size < 8) {
+ printk("\n");
+ return;
+ } else if (i < size - 8) {
+ printk("... ");
+ i = size - 8;
+ }
+ for (; i < size; ++i)
+ printk("%.2x ", data[i]);
+ printk("\n");
+}
+
+static void upstream_second_stage(struct urb *urb) {
+ int rc;
+ struct upstream_transaction *t = urb->context;
+ struct rawbulk_transfer *transfer = t->transfer;
+ struct usb_request *req = t->req;
+
+ if (urb->status < 0) {
+ if (urb->status == -ECONNRESET) {
+ terr(t, "usb-device connection reset!");
+ return;
+ }
+ printk("WTF?! %s failed %d\n", __func__, urb->status);
+ /* start again atomatically */
+ rc = start_upstream(t, GFP_ATOMIC);
+#if 0
+ if (rc < 0)
+ schedule_delayed_work(&t->delayed, HZ);
+#endif
+ return;
+ }
+
+ dump_data(transfer, "upstream", t->buffer, urb->actual_length);
+ /* allow zero-length package to pass
+ if (!urb->actual_length) {
+ terr(t, "urb actual_length 0");
+ start_upstream(t, GFP_ATOMIC);
+ return;
+ }
+ */
+
+ req->status = 0;
+ req->context = t;
+ req->buf = urb->transfer_buffer;
+ req->length = urb->actual_length;
+ req->complete = upstream_final_stage;
+ if (urb->actual_length == 0)
+ req->zero = 1;
+ else
+ req->zero = 0;
+
+ t->state = UPSTREAM_STAT_UPLOADING;
+ rc = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC);
+ if (rc < 0) {
+ terr(t, "fail to queue request, %d", rc);
+ t->stalled = 1;
+ t->state = UPSTREAM_STAT_FREE;
+ }
+}
+
+static void upstream_final_stage(struct usb_ep *ep,
+ struct usb_request *req) {
+ struct upstream_transaction *t = req->context;
+
+ t->state = UPSTREAM_STAT_FREE;
+
+ if (req->status < 0) {
+ if (req->status != -ECONNRESET)
+ terr(t, "req status %d", req->status);
+ if (req->status == -ESHUTDOWN) {
+ t->stalled = 1;
+ return;
+ }
+ }
+
+ if (!req->actual)
+ terr(t, "req actual 0");
+
+ if (t->urb)
+ start_upstream(t, GFP_ATOMIC);
+}
+
+static void stop_upstream(struct upstream_transaction *t) {
+ struct rawbulk_transfer *transfer = t->transfer;
+ if (t->state == UPSTREAM_STAT_RETRIEVING) {
+ cancel_delayed_work(&t->delayed);
+ if (t->urb)
+ usb_unlink_urb(t->urb);
+ } else if (t->state == UPSTREAM_STAT_UPLOADING) {
+ usb_ep_dequeue(transfer->upstream.ep, t->req);
+ }
+ t->stalled = 1;
+ t->state = UPSTREAM_STAT_FREE;
+}
+
+int rawbulk_push_upstream_buffer(int transfer_id, const void *buffer,
+ unsigned int length) {
+ int ret = -ENOENT;
+ struct upstream_transaction *t;
+ struct rawbulk_transfer *transfer;
+ struct usb_request *req;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ /* search for free transfer */
+ mutex_lock(&transfer->mutex);
+ list_for_each_entry(t, &transfer->upstream.transactions, tlist) {
+ if (t && t->state != UPSTREAM_STAT_UPLOADING) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&transfer->mutex);
+ if (ret < 0) {
+ terr(t, "no entry for transfer %d while pushing!\n", transfer_id);
+ return ret;
+ }
+ req = t->req;
+ if (!req)
+ return -EINVAL;
+
+ /* copy the buffer */
+ memcpy(t->buffer, buffer, length);
+ dump_data(transfer, "pushing up", t->buffer, length);
+
+ req->status = 0;
+ req->length = length;
+ req->buf = t->buffer;
+ req->complete = upstream_final_stage;
+ req->zero = (length > 0)? 0: 1;
+
+ t->state = UPSTREAM_STAT_UPLOADING;
+ ret = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ terr(t, "fail to queue request, %d", ret);
+ t->stalled = 1;
+ t->state = UPSTREAM_STAT_FREE;
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rawbulk_push_upstream_buffer);
+
+/*
+ * downstream
+ */
+
+#define MAX_SPLIT_LIMITED 64
+
+#define DOWNSTREAM_STAT_FREE 0
+#define DOWNSTREAM_STAT_RETRIEVING 1
+#define DOWNSTREAM_STAT_DOWNLOADING 2
+
+struct downstream_transaction {
+ int state;
+ int stalled;
+ char name[32];
+ struct list_head tlist;
+ struct rawbulk_transfer *transfer;
+ struct usb_request *req;
+ int nurb;
+ struct urb *urb[MAX_SPLIT_LIMITED];
+ int urb_length;
+ int buffer_length;
+ unsigned char buffer[0];
+};
+
+static void downstream_second_stage(struct usb_ep *ep,
+ struct usb_request *req);
+static void downstream_final_stage(struct urb *urb);
+
+static struct downstream_transaction *alloc_downstream_transaction(
+ struct rawbulk_transfer *transfer, int bufsz, int urbsz) {
+ int n = 0;
+ struct downstream_transaction *t;
+ int maxurbs = bufsz / urbsz;
+
+ if (urbsz < get_maxpacksize(transfer->downstream.host_ep))
+ return NULL;
+
+ if (maxurbs > MAX_SPLIT_LIMITED)
+ return NULL;
+
+ t = kzalloc(sizeof *t + bufsz * sizeof(unsigned char), GFP_KERNEL);
+ if (!t)
+ return NULL;
+
+ t->buffer_length = bufsz;
+ t->urb_length = urbsz;
+
+ t->req = usb_ep_alloc_request(transfer->downstream.ep, GFP_KERNEL);
+ if (!t->req)
+ goto failto_alloc_usb_request;
+
+ for (n = 0; n < maxurbs; n ++) {
+ t->urb[n] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!t->urb[n])
+ goto failto_alloc_urb;
+ }
+ t->nurb = 0;
+
+ t->name[0] = 0;
+ sprintf(t->name, "D%d (G:%s, H:ep%dout)", transfer->downstream.ntrans,
+ transfer->downstream.ep->name,
+ get_epnum(transfer->downstream.host_ep));
+
+ INIT_LIST_HEAD(&t->tlist);
+ list_add_tail(&t->tlist, &transfer->downstream.transactions);
+ transfer->downstream.ntrans ++;
+ t->transfer = transfer;
+
+ t->state = DOWNSTREAM_STAT_FREE;
+ return t;
+
+failto_alloc_urb:
+ while (n --)
+ usb_free_urb(t->urb[n]);
+ usb_ep_free_request(transfer->downstream.ep, t->req);
+failto_alloc_usb_request:
+ kfree(t);
+ return NULL;
+}
+
+static void free_downstream_transaction(struct rawbulk_transfer *transfer, int option) {
+ int i;
+ int maxurbs;
+ struct list_head *p, *n;
+ list_for_each_safe(p, n, &transfer->downstream.transactions) {
+ struct downstream_transaction *t = list_entry(p, struct
+ downstream_transaction, tlist);
+
+ if ((option & FREE_STALLED) && t->stalled)
+ goto free;
+
+ if ((option & FREE_IDLED) && (t->state == DOWNSTREAM_STAT_FREE))
+ goto free;
+
+ if ((option & FREE_RETRIVING) &&
+ (t->state == DOWNSTREAM_STAT_RETRIEVING)) {
+ usb_ep_dequeue(transfer->downstream.ep, t->req);
+ goto free;
+ }
+
+ continue;
+free:
+ list_del(p);
+ maxurbs = t->buffer_length / t->urb_length;
+ for (i = 0; i < maxurbs; i ++)
+ usb_free_urb(t->urb[i]);
+ usb_ep_free_request(transfer->downstream.ep, t->req);
+ kfree(t);
+
+ transfer->downstream.ntrans --;
+ }
+}
+
+static int start_downstream(struct downstream_transaction *t) {
+ int rc;
+ unsigned long flags;
+ struct rawbulk_transfer *transfer = t->transfer;
+ struct usb_request *req = t->req;
+
+ spin_lock_irqsave(&transfer->lock, flags);
+ if (transfer->control & STOP_DOWNSTREAM) {
+ spin_unlock_irqrestore(&transfer->lock, flags);
+ t->state = DOWNSTREAM_STAT_FREE;
+ t->stalled = 1;
+ return -EPIPE;
+ }
+ spin_unlock_irqrestore(&transfer->lock, flags);
+
+ t->stalled = 0;
+ t->state = DOWNSTREAM_STAT_FREE;
+
+ req->buf = t->buffer;
+ req->length = t->buffer_length;
+ req->complete = downstream_second_stage;
+
+ rc = usb_ep_queue(transfer->downstream.ep, req, GFP_ATOMIC);
+ if (rc < 0) {
+ terr(t, "fail to queue request, %d", rc);
+ t->stalled = 1;
+ return rc;
+ }
+
+ t->state = DOWNSTREAM_STAT_RETRIEVING;
+ return 0;
+}
+
+static void downstream_second_stage(struct usb_ep *ep,
+ struct usb_request *req) {
+ int n = 0;
+ void *next_buf = req->buf;
+ int data_length = req->actual;
+ struct downstream_transaction *t = container_of(req->buf,
+ struct downstream_transaction, buffer);
+ struct rawbulk_transfer *transfer = t->transfer;
+
+ if (req->status) {
+ if (req->status != -ECONNRESET)
+ terr(t, "req status %d", req->status);
+ if (req->status == -ESHUTDOWN ||req->status == -ECONNRESET )
+ t->stalled = 1;
+ else
+ start_downstream(t);
+ return;
+ }
+
+ dump_data(transfer, "downstream", t->buffer, req->actual);
+ /*
+ if (!data_length) {
+ terr(t, "req actual 0");
+ start_downstream(t);
+ return;
+ }
+ */
+
+ /* split recieved data into servral urb size less than maxpacket of cbp
+ * endpoint */
+ do {
+ int rc;
+ struct urb *urb = t->urb[n];
+ int tsize = (data_length > t->urb_length)? t->urb_length:
+ data_length;
+
+ urb->status = 0;
+ usb_fill_bulk_urb(urb, rawbulk->udev,
+ usb_sndbulkpipe(rawbulk->udev,
+ get_epnum(transfer->downstream.host_ep)),
+ next_buf, tsize, downstream_final_stage, t);
+ usb_anchor_urb(urb, &transfer->submitted);
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ usb_mark_last_busy(rawbulk->udev);
+ if (rc < 0) {
+ terr(t, "fail to submit urb %d, n %d", rc, n);
+ usb_unanchor_urb(urb);
+ break;
+ }
+
+ data_length -= tsize;
+ next_buf += tsize;
+ n ++;
+ } while (data_length > 0);
+
+ t->nurb = n;
+ t->state = DOWNSTREAM_STAT_DOWNLOADING;
+}
+
+static void downstream_final_stage(struct urb *urb) {
+ int n;
+ int actual_total = 0;
+ struct downstream_transaction *t = urb->context;
+
+ if (urb->status < 0) {
+ printk("WTF?! - %s failed %d\n", __func__, urb->status);
+ }
+
+ /* check the condition, re-queue usb_request on gadget ep again if possible */
+ for (n = 0; n < t->nurb; n ++) {
+ int status = t->urb[n]->status;
+
+ if (status == -EINPROGRESS)
+ return;
+
+ if (!status)
+ actual_total += t->urb[n]->actual_length;
+ }
+
+ if (actual_total < t->req->actual) {
+ terr(t, "requested %d actual %d", t->req->actual, actual_total);
+ t->stalled = 1;
+ return;
+ }
+
+ /* completely transfered over, we can start next transfer now */
+ start_downstream(t);
+}
+
+static void stop_downstream(struct downstream_transaction *t) {
+ int n;
+ struct rawbulk_transfer *transfer = t->transfer;
+ int maxurbs = t->buffer_length / t->urb_length;
+
+ if (t->state == DOWNSTREAM_STAT_RETRIEVING) {
+ usb_ep_dequeue(transfer->downstream.ep, t->req);
+ } else if (t->state == DOWNSTREAM_STAT_DOWNLOADING) {
+ for (n = 0; n < maxurbs; n ++)
+ usb_unlink_urb(t->urb[n]);
+ }
+
+ t->stalled = 1;
+}
+
+/*
+ * Ctrlrequest forwarding
+ */
+
+static void response_complete(struct usb_ep *ep, struct usb_request *req) {
+ if (req->status < 0)
+ ldbg("feedback error %d\n", req->status);
+}
+
+static void forward_ctrl_complete(struct urb *urb) {
+ struct usb_composite_dev *cdev = urb->context;
+ if (!cdev)
+ return;
+
+ if (urb->status >= 0) {
+ struct usb_request *req = cdev->req;
+ if (urb->pipe & USB_DIR_IN) {
+ memcpy(req->buf, urb->transfer_buffer, urb->actual_length);
+ req->zero = 0;
+ req->length = urb->actual_length;
+ req->complete = response_complete;
+ ldbg("cp echo: len %d data[0] %02x", req->length, *((char *)req->buf));
+ usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ } else /* Finish the status stage */
+ usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ }
+}
+
+int rawbulk_forward_ctrlrequest(const struct usb_ctrlrequest *ctrl) {
+ struct usb_device *dev;
+ struct urb *urb;
+
+ ldbg("req_type %02x req %02x value %04x index %04x len %d",
+ ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
+ ctrl->wLength);
+
+ dev = rawbulk->udev;
+ if (!dev) {
+ return -ENODEV;
+ }
+
+ rawbulk->forward_dr.bRequestType = ctrl->bRequestType;
+ rawbulk->forward_dr.bRequest = ctrl->bRequest;
+ rawbulk->forward_dr.wValue = ctrl->wValue;
+ //rawbulk->forward_dr.wIndex = ctrl->wIndex;
+ rawbulk->forward_dr.wIndex = 0;//MODEM DATA PORT
+ rawbulk->forward_dr.wLength = ctrl->wLength;
+
+ if (!rawbulk->forwarding_urb) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+ rawbulk->forwarding_urb = urb;
+ } else
+ urb = rawbulk->forwarding_urb;
+
+ if (ctrl->bRequestType & USB_DIR_IN)
+ usb_fill_control_urb(urb, dev,
+ usb_rcvctrlpipe(dev, 0),
+ (unsigned char *)&rawbulk->forward_dr,
+ rawbulk->ctrl_response,
+ __le16_to_cpu(ctrl->wLength),
+ forward_ctrl_complete,
+ rawbulk->cdev);
+ else
+ usb_fill_control_urb(urb, dev,
+ usb_sndctrlpipe(dev, 0),
+ (unsigned char *)&rawbulk->forward_dr,
+ NULL, 0,
+ forward_ctrl_complete,
+ rawbulk->cdev);
+
+ return usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_forward_ctrlrequest);
+
+int rawbulk_start_transactions(int transfer_id, int nups, int ndowns, int upsz,
+ int downsz, int splitsz, int pushable) {
+ int n;
+ int rc;
+ unsigned long flags = 0;
+ int suspended;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ if (!rawbulk->cdev || !rawbulk->udev)
+ return -ENODEV;
+
+ if (!transfer->function || !transfer->interface)
+ return -ENODEV;
+
+ ldbg("start transactions on id %d, nups %d ndowns %d upsz %d downsz %d split %d pushable %d\n",
+ transfer_id, nups, ndowns, upsz, downsz, splitsz, pushable);
+
+ mutex_lock(&transfer->mutex);
+
+ /* stop host transfer 1stly */
+ if (transfer->inceptor)
+ transfer->inceptor(transfer->interface, pushable?
+ (RAWBULK_INCEPT_FLAG_ENABLE | RAWBULK_INCEPT_FLAG_PUSH_WAY):
+ RAWBULK_INCEPT_FLAG_ENABLE);
+
+ /* Make upstream buffer larger than the pusher */
+ if (pushable && (upsz < 4096))
+ upsz = 4096;
+
+ for (n = 0; n < nups; n ++) {
+ upstream = alloc_upstream_transaction(transfer, upsz, pushable);
+ if (!upstream) {
+ rc = -ENOMEM;
+ ldbg("fail to allocate upstream transaction n %d", n);
+ goto failto_alloc_upstream;
+ }
+ }
+
+ for (n = 0; n < ndowns; n ++) {
+ downstream = alloc_downstream_transaction(transfer, downsz, splitsz);
+ if (!downstream) {
+ rc = -ENOMEM;
+ ldbg("fail to allocate downstream transaction n %d", n);
+ goto failto_alloc_downstream;
+ }
+ }
+
+ spin_lock_irqsave(&transfer->suspend_lock, flags);
+ suspended = transfer->suspended;
+ spin_unlock_irqrestore(&transfer->suspend_lock, flags);
+
+ if (suspended) {
+ ldbg("interface %d is sleeping", transfer_id);
+ mutex_unlock(&transfer->mutex);
+ return 0;
+ }
+
+ transfer->control &= ~STOP_UPSTREAM;
+ if (!pushable) {
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) {
+ if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) {
+ rc = start_upstream(upstream, GFP_KERNEL);
+ if (rc < 0) {
+ ldbg("fail to start upstream %s rc %d\n", upstream->name, rc);
+ goto failto_start_upstream;
+ }
+ }
+ }
+ }
+
+ transfer->control &= ~STOP_DOWNSTREAM;
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) {
+ if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) {
+ rc = start_downstream(downstream);
+ if (rc < 0) {
+ ldbg("fail to start downstream %s rc %d\n", downstream->name, rc);
+ goto failto_start_downstream;
+ }
+ }
+ }
+
+ mutex_unlock(&transfer->mutex);
+ return 0;
+
+failto_start_downstream:
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist)
+ stop_downstream(downstream);
+failto_start_upstream:
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist)
+ stop_upstream(upstream);
+failto_alloc_downstream:
+ free_downstream_transaction(transfer, FREE_ALL);
+failto_alloc_upstream:
+ free_upstream_transaction(transfer, FREE_ALL);
+ /* recover host transfer */
+ if (transfer->inceptor)
+ transfer->inceptor(transfer->interface, 0);
+ mutex_unlock(&transfer->mutex);
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_start_transactions);
+
+void rawbulk_stop_transactions(int transfer_id) {
+ unsigned long flags;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return;
+
+ mutex_lock(&transfer->mutex);
+ spin_lock_irqsave(&transfer->lock, flags);
+ transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM);
+ spin_unlock_irqrestore(&transfer->lock, flags);
+
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist)
+ stop_upstream(upstream);
+ free_upstream_transaction(transfer, FREE_ALL);
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist)
+ stop_downstream(downstream);
+ free_downstream_transaction(transfer, FREE_ALL);
+ if (transfer->inceptor)
+ transfer->inceptor(transfer->interface, 0);
+ mutex_unlock(&transfer->mutex);
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_stop_transactions);
+
+int rawbulk_halt_transactions(int transfer_id) {
+ unsigned long flags;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ spin_lock_irqsave(&transfer->lock, flags);
+ transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM);
+ spin_unlock_irqrestore(&transfer->lock, flags);
+
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist)
+ stop_upstream(upstream);
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist)
+ stop_downstream(downstream);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_halt_transactions);
+
+int rawbulk_resume_transactions(int transfer_id) {
+ int rc;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ if (!rawbulk->cdev || !rawbulk->udev)
+ return -ENODEV;
+
+ if (!transfer->function || !transfer->interface)
+ return -ENODEV;
+
+ transfer->control &= ~STOP_UPSTREAM;
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) {
+ if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) {
+ rc = start_upstream(upstream, GFP_KERNEL);
+ if (rc < 0) {
+ ldbg("fail to start upstream %s rc %d", upstream->name, rc);
+ goto failto_start_upstream;
+ }
+ }
+ }
+
+ transfer->control &= ~STOP_DOWNSTREAM;
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) {
+ if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) {
+ rc = start_downstream(downstream);
+ if (rc < 0) {
+ ldbg("fail to start downstream %s rc %d", downstream->name, rc);
+ goto failto_start_downstream;
+ }
+ }
+ }
+ return 0;
+
+failto_start_downstream:
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist)
+ stop_downstream(downstream);
+failto_start_upstream:
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist)
+ stop_upstream(upstream);
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_resume_transactions);
+
+int rawbulk_transfer_state(int transfer_id) {
+ int stalled = 1;
+ int count = 0;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -EINVAL;
+
+ if (!rawbulk->udev || !rawbulk->cdev)
+ return -ENODEV;
+
+ if (!transfer->interface || !transfer->function)
+ return -EIO;
+
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) {
+ if (!upstream->stalled)
+ stalled = 0;
+ count ++;
+ }
+
+ if (stalled || count == 0)
+ return -EACCES;
+
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) {
+ if (!downstream->stalled)
+ stalled = 0;
+ count ++;
+ }
+ if (stalled || count == 0)
+ return -EACCES;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_transfer_state);
+
+static char *state2string(int state, int upstream) {
+ if (upstream) {
+ switch (state) {
+ case UPSTREAM_STAT_FREE:
+ return "FREE";
+ case UPSTREAM_STAT_RETRIEVING:
+ return "RETRIEVING";
+ case UPSTREAM_STAT_UPLOADING:
+ return "UPLOADING";
+ default:
+ return "UNKNOW";
+ }
+ } else {
+ switch (state) {
+ case DOWNSTREAM_STAT_FREE:
+ return "FREE";
+ case DOWNSTREAM_STAT_RETRIEVING:
+ return "RETRIEVING";
+ case DOWNSTREAM_STAT_DOWNLOADING:
+ return "DOWNLOADING";
+ default:
+ return "UNKNOW";
+ }
+ }
+}
+
+int rawbulk_transfer_statistics(int transfer_id, char *buf) {
+ char *pbuf = buf;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return sprintf(pbuf, "-ENODEV, id %d\n", transfer_id);
+
+ pbuf += sprintf(pbuf, "rawbulk statistics:\n");
+ if (rawbulk->udev)
+ pbuf += sprintf(pbuf, " host device: %d-%d\n", rawbulk->udev->bus->busnum,
+ rawbulk->udev->devnum);
+ else
+ pbuf += sprintf(pbuf, " host device: -ENODEV\n");
+ if (rawbulk->cdev && rawbulk->cdev->config)
+ pbuf += sprintf(pbuf, " gadget device: %s\n",
+ rawbulk->cdev->config->label);
+ else
+ pbuf += sprintf(pbuf, " gadget device: -ENODEV\n");
+ pbuf += sprintf(pbuf, " upstreams (total %d transactions)\n",
+ transfer->upstream.ntrans);
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) {
+ pbuf += sprintf(pbuf, " %s state: %s", upstream->name,
+ state2string(upstream->state, 1));
+ pbuf += sprintf(pbuf, ", maxbuf: %d bytes", upstream->buffer_length);
+ if (upstream->stalled)
+ pbuf += sprintf(pbuf, " (stalled!)");
+ pbuf += sprintf(pbuf, "\n");
+ }
+ pbuf += sprintf(pbuf, " downstreams (total %d transactions)\n",
+ transfer->downstream.ntrans);
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) {
+ pbuf += sprintf(pbuf, " %s state: %s", downstream->name,
+ state2string(downstream->state, 0));
+ pbuf += sprintf(pbuf, ", maxbuf: %d bytes", downstream->buffer_length);
+ if (downstream->state == DOWNSTREAM_STAT_DOWNLOADING)
+ pbuf += sprintf(pbuf, ", spliting: %d urbs(%d bytes)", downstream->nurb,
+ downstream->urb_length);
+ if (downstream->stalled)
+ pbuf += sprintf(pbuf, " (stalled!)");
+ pbuf += sprintf(pbuf, "\n");
+ }
+ pbuf += sprintf(pbuf, "\n");
+ return (int)(pbuf - buf);
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_transfer_statistics);
+
+int rawbulk_bind_function(int transfer_id, struct usb_function *function, struct
+ usb_ep *bulk_out, struct usb_ep *bulk_in,
+ rawbulk_autoreconn_callback_t autoreconn_callback) {
+ struct rawbulk_transfer *transfer;
+
+ if (!function || !bulk_out || !bulk_in)
+ return -EINVAL;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ transfer->downstream.ep = bulk_out;
+ transfer->upstream.ep = bulk_in;
+ transfer->function = function;
+ rawbulk->cdev = function->config->cdev;
+
+ transfer->autoreconn = autoreconn_callback;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_bind_function);
+
+void rawbulk_unbind_function(int transfer_id) {
+ int n;
+ int no_functions = 1;
+ struct rawbulk_transfer *transfer;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return;
+
+ rawbulk_stop_transactions(transfer_id);
+ transfer->downstream.ep = NULL;
+ transfer->upstream.ep = NULL;
+ transfer->function = NULL;
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ if (!!rawbulk->transfer[n].function)
+ no_functions = 0;
+ }
+
+ if (no_functions)
+ rawbulk->cdev = NULL;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_unbind_function);
+
+int rawbulk_bind_host_interface(struct usb_interface *interface,
+ rawbulk_intercept_t inceptor) {
+ int n;
+ int transfer_id;
+ struct rawbulk_transfer *transfer;
+ struct usb_device *udev;
+
+ if (!interface || !inceptor)
+ return -EINVAL;
+
+ transfer_id = interface->cur_altsetting->desc.bInterfaceNumber;
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -ENODEV;
+
+ udev = interface_to_usbdev(interface);
+ if (!udev)
+ return -ENODEV;
+
+ if (!rawbulk->udev) {
+ rawbulk->udev = udev;
+ }
+
+ /* search host bulk ep for up/downstreams */
+ for (n = 0; n < interface->cur_altsetting->desc.bNumEndpoints; n++) {
+ struct usb_host_endpoint *endpoint =
+ &interface->cur_altsetting->endpoint[n];
+ if (usb_endpoint_is_bulk_out(&endpoint->desc))
+ transfer->upstream.host_ep = endpoint;
+ if (usb_endpoint_is_bulk_in(&endpoint->desc))
+ transfer->downstream.host_ep = endpoint;
+ }
+
+ if (!transfer->upstream.host_ep || !transfer->downstream.host_ep) {
+ lerr("endpoints do not match bulk pair that needed\n");
+ return -EINVAL;
+ }
+
+ transfer->interface = interface;
+ transfer->inceptor = inceptor;
+
+ if (transfer->autoreconn)
+ transfer->autoreconn(transfer->id);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_bind_host_interface);
+
+void rawbulk_unbind_host_interface(struct usb_interface *interface) {
+ int n;
+ int no_interfaces = 1;
+ struct rawbulk_transfer *transfer;
+ int transfer_id = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return;
+
+ rawbulk_stop_transactions(transfer_id);
+ transfer->upstream.host_ep = NULL;
+ transfer->downstream.host_ep = NULL;
+ transfer->interface = NULL;
+ transfer->inceptor = NULL;
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ if(!!rawbulk->transfer[n].interface)
+ no_interfaces = 0;
+ }
+
+ if (no_interfaces) {
+ usb_kill_urb(rawbulk->forwarding_urb);
+ usb_free_urb(rawbulk->forwarding_urb);
+ rawbulk->forwarding_urb = NULL;
+ rawbulk->udev = NULL;
+ }
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_unbind_host_interface);
+
+int rawbulk_suspend_host_interface(int transfer_id, pm_message_t message) {
+ unsigned long flags = 0;
+ struct rawbulk_transfer *transfer;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -EINVAL;
+
+ spin_lock_irqsave(&transfer->suspend_lock, flags);
+ transfer->suspended = 1;
+ spin_unlock_irqrestore(&transfer->suspend_lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_suspend_host_interface);
+
+int rawbulk_resume_host_interface(int transfer_id) {
+ int rc;
+ unsigned long flags = 0;
+ struct rawbulk_transfer *transfer;
+ struct upstream_transaction *upstream;
+ struct downstream_transaction *downstream;
+
+ transfer = id_to_transfer(transfer_id);
+ if (!transfer)
+ return -EINVAL;
+
+ spin_lock_irqsave(&transfer->suspend_lock, flags);
+ transfer->suspended = 0;
+ spin_unlock_irqrestore(&transfer->suspend_lock, flags);
+
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) {
+ if (upstream->stalled) {
+ transfer->control &= ~STOP_UPSTREAM;
+ /* restart transaction again */
+ ldbg("restart upstream: %s", upstream->name);
+ stop_upstream(upstream);
+ rc = start_upstream(upstream, GFP_KERNEL);
+ if (rc < 0) {
+ ldbg("fail to start upstream %s rc %d", upstream->name, rc);
+ goto failto_start_upstream;
+ }
+ }
+ }
+
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) {
+ if (downstream->stalled) {
+ transfer->control &= ~STOP_DOWNSTREAM;
+ ldbg("restart downstream: %s", downstream->name);
+ stop_downstream(downstream);
+ rc = start_downstream(downstream);
+ if (rc < 0) {
+ ldbg("fail to start downstream %s rc %d", downstream->name, rc);
+ goto failto_start_downstream;
+ }
+ }
+ }
+
+ return 0;
+failto_start_downstream:
+ list_for_each_entry(downstream, &transfer->downstream.transactions, tlist)
+ stop_downstream(downstream);
+failto_start_upstream:
+ list_for_each_entry(upstream, &transfer->upstream.transactions, tlist)
+ stop_upstream(upstream);
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(rawbulk_resume_host_interface);
+
+static __init int rawbulk_init(void) {
+ int n;
+
+ rawbulk = kzalloc(sizeof *rawbulk, GFP_KERNEL);
+ if (!rawbulk)
+ return -ENOMEM;
+
+ for (n = 0; n < _MAX_TID; n ++) {
+ struct rawbulk_transfer *t = &rawbulk->transfer[n];
+
+ t->id = n;
+ INIT_LIST_HEAD(&t->upstream.transactions);
+ INIT_LIST_HEAD(&t->downstream.transactions);
+
+ mutex_init(&t->mutex);
+ spin_lock_init(&t->lock);
+ spin_lock_init(&t->suspend_lock);
+ t->suspended = 0;
+ t->control = STOP_UPSTREAM | STOP_DOWNSTREAM;
+
+ init_usb_anchor(&t->submitted);
+ }
+
+ return 0;
+}
+
+fs_initcall (rawbulk_init);
+
+static __exit void rawbulk_exit(void) {
+ int n;
+ for (n = 0; n < _MAX_TID; n ++)
+ rawbulk_stop_transactions(n);
+
+ if (rawbulk->forwarding_urb) {
+ usb_kill_urb(rawbulk->forwarding_urb);
+ usb_free_urb(rawbulk->forwarding_urb);
+ rawbulk->forwarding_urb = NULL;
+ }
+
+ kfree(rawbulk);
+}
+
+module_exit (rawbulk_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c
index 0cb21218..953439d4 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c
@@ -1203,3 +1203,7 @@ void rndis_exit(void)
}
#endif
}
+bool get_rndis_initialized(void)
+{
+ return rndis_initialized;
+} \ No newline at end of file
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c
index 8081ca3a..88e9c0ef 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c
@@ -813,6 +813,14 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
return rc;
}
+static ssize_t fsg_show_cdrom(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fsg_lun *curlun = fsg_lun_from_dev(dev);
+
+ return sprintf(buf, "%d\n", curlun->cdrom);
+}
+
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -898,3 +906,33 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
up_write(filesem);
return (rc < 0 ? rc : count);
}
+
+static ssize_t fsg_store_cdrom(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t rc;
+ struct fsg_lun *curlun = fsg_lun_from_dev(dev);
+ struct rw_semaphore *filesem = dev_get_drvdata(dev);
+ unsigned cdrom;
+
+ rc = kstrtouint(buf, 2, &cdrom);
+ if (rc)
+ return rc;
+
+ /*
+ * Allow the write-enable status to change only while the
+ * backing file is closed.
+ */
+ down_read(filesem);
+ if (fsg_lun_is_open(curlun)) {
+ LDBG(curlun, "read-only status change prevented\n");
+ rc = -EBUSY;
+ } else {
+ curlun->cdrom = cdrom;
+ LDBG(curlun, "cdrom status set to %d\n", curlun->cdrom);
+ rc = count;
+ }
+ up_read(filesem);
+ return rc;
+}
+
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c
index c8702c8e..59ac7227 100644
--- a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c
+++ b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c
@@ -457,7 +457,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
{
struct sk_buff *skb = req->context;
struct eth_dev *dev = ep->driver_data;
-
+ unsigned long flags;
switch (req->status) {
default:
dev->net->stats.tx_errors++;
@@ -471,9 +471,11 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
}
dev->net->stats.tx_packets++;
- spin_lock(&dev->req_lock);
+ //spin_lock(&dev->req_lock);
+ spin_lock_irqsave(&dev->req_lock, flags);
list_add(&req->list, &dev->tx_reqs);
- spin_unlock(&dev->req_lock);
+ //spin_unlock(&dev->req_lock);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
dev_kfree_skb_any(skb);
atomic_dec(&dev->tx_qlen);
@@ -703,7 +705,7 @@ module_param(dev_addr, charp, S_IRUGO);
MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
/* this address is invisible to ifconfig */
-static char *host_addr;
+static char *host_addr="02:50:e6:a8:b8:63";
module_param(host_addr, charp, S_IRUGO);
MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
@@ -938,7 +940,7 @@ fail0:
return ERR_PTR(result);
return dev->net;
}
-
+extern void wmt_cleanup_done_thread(int number);
/**
* gether_disconnect - notify network layer that USB link is inactive
* @link: the USB link, on which gether_connect() was called
@@ -955,7 +957,7 @@ void gether_disconnect(struct gether *link)
{
struct eth_dev *dev = link->ioport;
struct usb_request *req;
-
+ unsigned long flags;
WARN_ON(!dev);
if (!dev)
return;
@@ -970,6 +972,7 @@ void gether_disconnect(struct gether *link)
* and forget about the endpoints.
*/
usb_ep_disable(link->in_ep);
+ wmt_cleanup_done_thread(1);
spin_lock(&dev->req_lock);
while (!list_empty(&dev->tx_reqs)) {
req = container_of(dev->tx_reqs.next,
@@ -985,6 +988,7 @@ void gether_disconnect(struct gether *link)
link->in_ep->desc = NULL;
usb_ep_disable(link->out_ep);
+ wmt_cleanup_done_thread(1);
spin_lock(&dev->req_lock);
while (!list_empty(&dev->rx_reqs)) {
req = container_of(dev->rx_reqs.next,
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c
new file mode 100755
index 00000000..c239e3d8
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c
@@ -0,0 +1,4699 @@
+/*
+ * wmt_udc.c -- for WonderMedia Technology udc
+ *
+ * Copyright (C) 2007 VIA Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+#undef VERBOSE
+
+#include <generated/autoconf.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/suspend.h>
+
+
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/mach-types.h>
+#include <linux/usb/composite.h>
+
+#include "udc_wmt.h"
+
+#define USE_BULK3_TO_INTERRUPT //gri
+
+//#define FULL_SPEED_ONLY
+/*#define HW_BUG_HIGH_SPEED_PHY*/
+#undef USB_TRACE
+
+/* bulk DMA seems to be behaving for both IN and OUT */
+#define USE_DMA
+
+/*#define DEBUG_UDC_ISR_TIMER*/
+#undef DEBUG_UDC_ISR_TIMER
+
+/*#define RNDIS_INFO_DEBUG_BULK_OUT*/
+#undef RNDIS_INFO_DEBUG_BULK_OUT
+
+/*#define RNDIS_INFO_DEBUG_BULK_IN*/
+#undef RNDIS_INFO_DEBUG_BULK_IN
+
+/*#define MSC_COMPLIANCE_TEST*/
+#undef MSC_COMPLIANCE_TEST
+
+/*#define UDC_A1_SELF_POWER_ENABLE*/
+
+/*-----------------------------------------------------------------------------*/
+
+#define DRIVER_DESC "VIA UDC driver"
+#define DRIVER_VERSION "3 December 2007"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+static unsigned fifo_mode;
+
+static unsigned fiq_using = 0;
+
+/* "modprobe vt8500_udc fifo_mode=42", or else as a kernel
+ * boot parameter "vt8500_udc:fifo_mode=42"
+ */
+
+module_param(fifo_mode, uint, 0);
+MODULE_PARM_DESC(fifo_mode, "endpoint setup (0 == default)");
+
+static bool use_dma = 1;
+
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable DMA");
+
+static const char driver_name[] = "wmotgdev";/*"wmt_udc";*/
+static const char driver_desc[] = DRIVER_DESC;
+
+static DEFINE_SEMAPHORE(wmt_udc_sem);
+static int f_ep3_used = 0;
+
+static struct vt8500_udc *udc;
+static struct device *pDMADescLI, *pDMADescSI;
+static struct device *pDMADescLO, *pDMADescSO;
+
+static struct device *pDMADescL2I, *pDMADescS2I;
+
+dma_addr_t UdcPdmaPhyAddrLI, UdcPdmaPhyAddrSI;
+static UINT UdcPdmaVirAddrLI, UdcPdmaVirAddrSI;
+dma_addr_t UdcPdmaPhyAddrLO, UdcPdmaPhyAddrSO;
+static UINT UdcPdmaVirAddrLO, UdcPdmaVirAddrSO;
+
+dma_addr_t UdcPdmaPhyAddrL2I, UdcPdmaPhyAddrS2I;
+static UINT UdcPdmaVirAddrL2I, UdcPdmaVirAddrS2I;
+
+dma_addr_t UdcRndisEp1PhyAddr, UdcRndisEp2PhyAddr, UdcRndisEp3PhyAddr;
+static UINT UdcRndisEp1VirAddr, UdcRndisEp2VirAddr, UdcRndisEp3VirAddr;
+
+#ifdef OTGIP
+static struct USB_GLOBAL_REG *pGlobalReg;
+#endif
+/*static struct UDC_REGISTER *udc_reg;*/
+
+static volatile struct UDC_REGISTER *pDevReg;
+static volatile struct UDC_DMA_REG *pUdcDmaReg;
+
+PSETUPCOMMAND pSetupCommand;
+UCHAR *pSetupCommandBuf;
+UCHAR *SetupBuf;
+UCHAR *IntBuf;
+
+UCHAR ControlState; /* the state the control pipe*/
+UCHAR USBState;
+UCHAR TestMode;
+
+/* Basic Define*/
+//#define REG32 *(volatile unsigned int *)
+//#define REG_GET32(addr) (REG32(addr)) /* Read 32 bits Register */
+
+static unsigned long irq_flags;//gri
+
+volatile unsigned char *pUSBMiscControlRegister5;
+
+unsigned int interrupt_transfer_size;
+
+static void wmt_pdma_reset(void);
+static void wmt_pdma0_reset(void);
+static void wmt_pdma1_reset(void);
+
+#ifdef USE_BULK3_TO_INTERRUPT
+static void wmt_pdma2_reset(void);
+#endif
+
+/* 1 : storage */
+static unsigned int gadget_connect=0;
+//static unsigned int first_mount=0;
+
+
+struct work_struct online_thread;
+struct work_struct offline_thread;
+struct work_struct done_thread;
+struct work_struct chkiso_thread;
+
+
+
+struct list_head done_main_list;
+spinlock_t gri_lock;
+static unsigned long gri_flags;//gri
+
+static unsigned int b_pullup=0;
+
+void run_chkiso (struct work_struct *work);
+
+static inline unsigned int wmt_ost_counter(void)
+{
+ OSTC_VAL |= OSTC_RDREQ;
+ while (OSTA_VAL & OSTA_RCA)
+ ;
+
+ return (u32)OSCR_VAL;
+}
+
+static inline void wmt_ost2_set_match(u32 new_match)
+{
+ /* check if can write OS Timer2 match register nows */
+ while (OSTA_VAL & OSTA_MWA2)
+ ;
+
+ OSM2_VAL = new_match;
+}
+
+void wmt_enable_fiq(unsigned int how_many_us)
+{
+ unsigned int cnt = 0;
+
+ cnt = wmt_ost_counter();
+ cnt += (3*how_many_us);
+ wmt_ost2_set_match(cnt);
+ OSTI_VAL |= OSTI_E2;
+}
+
+void wmt_disable_fiq(void)
+{
+ OSTI_VAL &= ~OSTI_E2;
+}
+
+static irqreturn_t
+test_fiq_handler(int irq, void *_udc)//, struct pt_regs *r)
+{
+ OSTS_VAL = OSTI_E2;
+
+ //printk("i am test_fiq_handler\n");
+
+ run_chkiso(NULL);
+ return IRQ_HANDLED;
+}
+
+void initial_test_fiq(void)
+{
+ //int ret = -1;
+ int status = -ENODEV;
+
+ printk("\n\n\ninitial_test_fiq\n\n");
+ // set fiq
+
+ OSTS_VAL = OSTI_E2;
+ OSTI_VAL &= ~OSTI_E2;
+#if 0
+ fhandler.fiq = test_fiq_handler;
+ fhandler.resume = test_fiq_resume;
+ ret = fiq_wmt_register_handler(&fhandler);
+ if (ret) {
+ pr_err("%s: could not install fiq handler ( %d )\n", __func__, ret);
+ return;
+ }
+
+ //use OST2 to test
+
+ enable_fiq(70);
+#else
+ status = request_irq(IRQ_OST2, test_fiq_handler,
+// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc);
+// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);
+ (IRQF_DISABLED), driver_name, udc);//gri
+ if (status != 0) {
+ ERR("**** can't get irq %d, err %d\n",
+ IRQ_OST2, status);
+ } else
+ INFO("**** wmt_udc_probe - request_irq(0x%02X) pass!\n", IRQ_OST2);
+#endif
+}
+
+/**
+ *
+ * Run these two functions to execute shell script to mount / umount storage
+ *
+ */
+#if 0
+static int run_online(void)
+{
+ kobject_uevent(&udc->dev->kobj, 2);
+ return 0;
+}
+#endif
+void wmt_cleanup_done_thread(int number);
+static void run_offline (struct work_struct *work)
+{
+ if ((udc->driver) && b_pullup){
+// printk(KERN_INFO "disconnect\n"); //gri
+ udc->driver->disconnect(&udc->gadget);
+ }
+// return 0;
+}
+
+static void run_done (struct work_struct *work)
+{
+ struct vt8500_req * req;
+
+ spin_lock_irqsave(&gri_lock, gri_flags);
+// printk(KERN_INFO "d1\n"); //gri
+ while (!list_empty(&done_main_list)){
+// printk(KERN_INFO "d3\n"); //gri
+ req = list_entry(done_main_list.next, struct vt8500_req, mem_list);
+ list_del_init(&req->mem_list);
+ spin_unlock_irqrestore(&gri_lock, gri_flags);
+ req->req.complete(&req->ep->ep, &req->req);
+ spin_lock_irqsave(&gri_lock, gri_flags);
+ }
+// printk(KERN_INFO "d2\n"); //gri
+ spin_unlock_irqrestore(&gri_lock, gri_flags);
+// return 0;
+}
+
+void dma_irq(u8 addr);
+void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req);
+void iso_prepare_0byte(void);
+void run_chkiso (struct work_struct *work)
+{
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ if (!fiq_using) {
+ //printk("iso fail\n");
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ return;
+ }
+
+ //do {
+ //schedule();
+ if (pDevReg->Bulk3DesStatus & BULKXFER_XACTERR) {
+ {
+ struct vt8500_ep *ep;
+ struct vt8500_req *req;
+ /*u32 temp32;*/
+ /*u32 i;*/
+
+ ep = &udc->ep[4];
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ //printk("iso h q\n");
+ next_in_dma(ep, req);
+ } else {
+ //printk("no q\n");
+ wmt_disable_fiq();
+ fiq_using = 0;
+ wmt_pdma2_reset();
+ iso_prepare_0byte();
+ }
+ }
+ //printk("iso hit\n");
+ //break;
+ } else {
+ wmt_enable_fiq(300);
+ //printk("iso hit miss\n");
+ }
+ //} while (1);
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+}
+
+enum schedule_work_action
+{
+ action_done, action_off_line, action_chkiso
+};
+
+static void run_script(enum schedule_work_action dwAction)
+{
+
+ if (dwAction == action_done){//8
+ schedule_work(&done_thread);
+ }else if (dwAction == action_off_line){//7
+ schedule_work(&offline_thread);
+ }else if (dwAction == action_chkiso){//7
+ schedule_work(&chkiso_thread);
+ }else {
+ }
+
+}
+
+
+void udc_device_dump_register(void)
+{
+ volatile unsigned int address;
+ volatile unsigned char temp8;
+ int i;
+
+ for (i = 0x20; i <= 0x3F; i++) { /*0x20~0x3F (0x3F-0x20 + 1) /4 = 8 DWORD*/
+ address = (USB_UDC_REG_BASE + i);
+ temp8 = REG_GET8(address);
+
+ INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8);
+ }
+
+ for (i = 0x308; i <= 0x30D; i++) { /*0x308~0x30D*/
+ address = (USB_UDC_REG_BASE + i);
+ temp8 = REG_GET8(address);
+
+ INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8);
+ }
+
+ for (i = 0x310; i <= 0x317; i++) { /*0x310~0x317*/
+ address = (USB_UDC_REG_BASE + i);
+ temp8 = REG_GET8(address);
+
+ INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8);
+ }
+
+ INFO("[UDC Device] Dump Reigster PASS!\n");
+
+} /*void udc_device_dump_register(void)*/
+
+void udc_bulk_dma_dump_register(void)
+{
+ volatile unsigned int temp32;
+ int i;
+
+ for (i = 0; i <= 0x10; i++) { /*0x100 ~ 0x113 (0x113 - 0x100 + 1) = 0x14 /4 = 5*/
+ temp32 = REG_GET32(USB_UDC_DMA_REG_BASE + i*4);
+ INFO("[UDC Bulk DMA] Offset[0x%8.8X] = 0x%8.8X \n", (USB_UDC_DMA_REG_BASE + i*4), temp32);
+ }
+ INFO("[UDC Bulk DMAD] Dump Reigster PASS!\n");
+
+} /*void udc_bulk_dma_dump_register(void)*/
+
+void wmt_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp)
+{
+ struct vt8500_ep *ep;
+ /*u32 epn_rxtx = 0;*/
+ /*U8 temp_adr;*/
+
+ VDBG("wmt_ep_setup_csr()\n");
+
+ /* OUT endpoints first, then IN*/
+
+ ep = &udc->ep[addr & 0x7f];
+
+ VDBG("wmt_ep_setup()\n");
+
+ /* OUT endpoints first, then IN*/
+ ep = &udc->ep[addr & 0x7f];
+
+ if (type == USB_ENDPOINT_XFER_CONTROL) {
+ /*pDevReg->ControlEpControl;*/
+ pDevReg->ControlEpReserved = 0;
+ pDevReg->ControlEpMaxLen = (maxp & 0xFF);
+ pDevReg->ControlEpEpNum = 0;
+ } else if (type == USB_ENDPOINT_XFER_BULK) {
+ if (addr & USB_DIR_IN) {
+ /*pDevReg->Bulk1EpControl;*/
+ pDevReg->Bulk1EpOutEpNum = (addr & 0x7f) << 4;
+ pDevReg->Bulk1EpMaxLen = (maxp & 0xFF);
+ pDevReg->Bulk1EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8));
+ } else {
+ /*pDevReg->Bulk2EpControl;*/
+ pDevReg->Bulk2EpOutEpNum = (addr & 0x7f) << 4;
+ pDevReg->Bulk2EpMaxLen = (maxp & 0xFF);
+ pDevReg->Bulk2EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8));
+ }
+ } else if (type == USB_ENDPOINT_XFER_INT) {
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4;
+ pDevReg->Bulk3EpMaxLen = (maxp & 0xFF);
+ pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8));
+
+ pDevReg->InterruptReserved = (0x85 & 0x7f) << 4;
+ pDevReg->InterruptEpMaxLen = (8 & 0xFF); /* Interrupt maximum transfer length - 2E*/
+ pDevReg->InterruptEpEpNum = (((0x85 & 0x7f) << 4) | ((8 & 0x700) >> 8));
+#else
+ /*pDevReg->InterruptEpControl; // Interrupt endpoint control - 2C*/
+ /* Interrupt endpoint reserved byte - 2D*/
+ pDevReg->InterruptReserved = (addr & 0x7f) << 4;
+ pDevReg->InterruptEpMaxLen = (maxp & 0xFF); /* Interrupt maximum transfer length - 2E*/
+ pDevReg->InterruptEpEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8));
+#endif
+ } else if (type == USB_ENDPOINT_XFER_ISOC) {
+ pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4;
+ pDevReg->Bulk3EpMaxLen = (maxp & 0xFF);
+ pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8));
+ }
+
+ /*Setting address pointer ...*/
+ wmb();
+ VDBG("wmt_ep_setup_csr() - %s addr %02x maxp %d\n",
+ name, addr, maxp);
+
+ ep->toggle_bit = 0;
+ ep->ep.maxpacket = maxp;
+} /*tatic void wmt_ep_setup_csr()*/
+
+static int wmt_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep);
+ struct vt8500_udc *udc;
+
+ u16 maxp;
+
+ DBG("wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL);
+ printk(KERN_INFO "gri wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL);
+
+ /* catch various bogus parameters*/
+ if (!_ep || !desc || (ep->desc && ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC))
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || ep->bEndpointAddress != desc->bEndpointAddress
+ || ep->maxpacket < usb_endpoint_maxp(desc)) {
+ VDBG("ep->bEndpointAddress = 0x%08X\n", ep->bEndpointAddress);
+ VDBG("desc->bEndpointAddres = 0x%08X\n", desc->bEndpointAddress);
+ VDBG("ep->maxpacket =0x%08X\n", ep->maxpacket);
+ VDBG("desc->wMaxPacketSize =0x%08X\n", desc->wMaxPacketSize);
+ VDBG("_ep =0x%08X\n", (unsigned int)_ep);
+ VDBG("desc =0x%08X\n", (unsigned int)desc);
+ VDBG("ep->desc =0x%08X\n", (unsigned int)ep->desc);
+
+ /*DBG("%s, bad ep or descriptor\n", __FUNCTION__);*/
+ return -EINVAL;
+ }
+
+ maxp = usb_endpoint_maxp(desc);
+
+ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK)
+ && (usb_endpoint_maxp(desc) > ep->maxpacket
+ || !desc->wMaxPacketSize)) {
+ DBG("[wmt_ep_enable]bad %s maxpacket\n", _ep->name);
+ return -ERANGE;
+ }
+
+#if 1
+ if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC
+ && desc->bInterval != 1)) {
+ /* hardware wants period = 1; USB allows 2^(Interval-1) */
+ DBG("%s, unsupported ISO period %dms\n", _ep->name,
+ 1 << (desc->bInterval - 1));
+ return -EDOM;
+ }
+
+#if 0
+ /* xfer types must match, except that interrupt ~= bulk*/
+ if (ep->bmAttributes != desc->bmAttributes
+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+ DBG("[wmt_ep_enable], %s type mismatch\n", _ep->name);
+ printk("[wmt_ep_enable], %s type mismatch\n", _ep->name);
+ return -EINVAL;
+ }
+#endif
+#endif
+
+ udc = ep->udc;
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+
+ ep->desc = desc;
+ ep->irqs = 0;
+ ep->stopped = 0;
+ ep->ep.maxpacket = maxp;
+
+ ep->has_dma = 1;
+ ep->ackwait = 0;
+
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64);
+ wmb();
+ pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA;
+ break;
+
+ case 1:/*Bulk In*/
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, maxp);
+ wmb();
+ pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA;
+ break;
+
+ case 2:/*Bulk Out*/
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, maxp);
+ wmb();
+ pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA;
+ break;
+
+ case 3:/*Interrupt In*/
+#ifdef USE_BULK3_TO_INTERRUPT
+ if (f_ep3_used == 4)
+ return -ERANGE;
+ f_ep3_used = 3;
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp);
+ wmb();
+ pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA;
+#else
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp);
+ wmb();
+ pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA;
+#endif
+ break;
+
+ case 4:/*iso in*/
+ if (f_ep3_used == 3)
+ return -ERANGE;
+ f_ep3_used = 4;
+ wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISOC, 384);
+ wmb();
+
+ wmt_pdma2_reset();
+ iso_prepare_0byte();
+
+ pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA;
+ break;
+
+ }
+ wmb();
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ VDBG("%s enabled\n", _ep->name);
+// printk(KERN_INFO "gri enabled %s\n", ep ? ep->ep.name : NULL);
+
+ return 0;
+} /*static int wmt_ep_enable()*/
+
+static void nuke(struct vt8500_ep *, int status);
+
+static int wmt_ep_disable(struct usb_ep *_ep)
+{
+ struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep);
+// unsigned long flags;
+
+ DBG("wmt_ep_disable() %s\n", ep ? ep->ep.name : NULL);
+
+ if (!_ep || !ep->desc) {
+ DBG("[wmt_ep_disable], %s not enabled\n",
+ _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ep->udc->lock, irq_flags);
+ ep->desc = 0;
+ nuke(ep, -ESHUTDOWN);
+ ep->ep.maxpacket = ep->maxpacket;
+ ep->has_dma = 0;
+
+ del_timer(&ep->timer);
+
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ pDevReg->ControlEpControl &= 0xFC;
+ break;
+
+ case 1:/*Bulk In*/
+ pDevReg->Bulk1EpControl &= 0xFC;
+ break;
+
+ case 2:/*Bulk Out*/
+ pDevReg->Bulk2EpControl &= 0xFC;
+ break;
+
+ case 3:/*Interrupt In*/
+#ifdef USE_BULK3_TO_INTERRUPT
+ if (f_ep3_used == 3)
+ f_ep3_used = 0;
+ pDevReg->Bulk3EpControl &= 0xFC;
+#else
+ pDevReg->InterruptEpControl &= 0xFC;
+#endif
+ break;
+
+ case 4:/*Iso In*/
+ if (f_ep3_used == 4)
+ f_ep3_used = 0;
+ pDevReg->Bulk3EpControl &= 0xFC;
+ fiq_using = 0;
+ break;
+ }
+ wmb();
+ spin_unlock_irqrestore(&ep->udc->lock, irq_flags);
+
+ VDBG("%s disabled\n", _ep->name);
+ return 0;
+} /*static int wmt_ep_disable()*/
+
+
+static struct usb_request *
+wmt_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct vt8500_req *req;
+ struct vt8500_ep *ep = NULL;
+
+// DBG("gri wmt_alloc_request() %s\n", ep->name);
+
+ ep = container_of(_ep, struct vt8500_ep, ep);
+// printk(KERN_INFO "gri wmt_alloc_request() %s\n", ep->name);
+// if ((ep->bEndpointAddress & 0x7F) > 4)
+// return NULL;
+
+
+ /*if(ep->bEndpointAddress == 3)*/
+ /* INFO("wmt_alloc_request() %s\n", ep->name);*/
+
+ req = kmalloc(sizeof *req, gfp_flags);
+ if (req) {
+ memset(req, 0, sizeof *req);
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+ }
+ return &req->req;/*struct usb_request for file_storage.o*/
+} /*wmt_alloc_request()*/
+
+static void
+wmt_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct vt8500_req *req = container_of(_req, struct vt8500_req, req);
+ struct vt8500_ep *ep = NULL;
+
+ DBG("wmt_free_request() %s\n", ep->name);
+ ep = container_of(_ep, struct vt8500_ep, ep);
+
+ /*if(ep->bEndpointAddress == 3)*/
+ /* INFO("wmt_free_request() %s\n", ep->name);*/
+
+ if (_req)
+ kfree(req);
+} /*wmt_free_request()*/
+
+/*EP0 - Control 256 bytes*/
+/*EP2,3 Bulk In/Out 16384 bytes (16K)*/
+/*file_storeage.c - req->buf*/
+/*struct usb_request req;*/
+static void wmt_pdma_init(struct device *dev);
+
+
+static void ep0_status(struct vt8500_udc *udc)
+{
+ struct vt8500_ep *ep;
+
+ ep = &udc->ep[0];
+
+ if (udc->ep0_in) { /*OUT STATUS*/
+ if (udc->ep0_status_0_byte == 1) {
+ udc->ep0_status_0_byte = 0;
+
+ /* the data phase is OUT*/
+
+ if (ep->toggle_bit)
+ pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA1;
+ else
+ pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA0;
+
+ pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC;
+ wmb();
+ pDevReg->ControlDesStatus = CTRLXFER_ACTIVE;
+ ControlState = CONTROLSTATE_STATUS;
+ } /*if(udc->ep0_status_0_byte == 1)*/
+ } else { /*IN STATUS*/
+ if (udc->ep0_status_0_byte == 1) {
+ udc->ep0_status_0_byte = 0;
+
+ if (ep->toggle_bit)
+ pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1;
+ else
+ pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA0;
+
+ pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; /* zero length*/
+ pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC;
+ wmb();
+ pDevReg->ControlDesStatus = CTRLXFER_ACTIVE;
+ ControlState = CONTROLSTATE_STATUS;
+ } /*if(udc->ep0_status_0_byte == 1)*/
+ }
+
+} /*static void ep0_status(struct vt8500_udc *udc)*/
+
+
+static void
+done(struct vt8500_ep *ep, struct vt8500_req *req, int status)
+{
+ unsigned stopped = ep->stopped;
+
+ DBG("done() %s\n", ep ? ep->ep.name : NULL);
+
+ list_del_init(&req->queue);
+
+ /*#define EINPROGRESS 115*/ /* Operation now in progress */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else {
+ if (status != 0)
+ status = req->req.status;
+ }
+
+ DBG("complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback*/
+ ep->stopped = 1;
+
+ spin_unlock_irqrestore(&ep->udc->lock, irq_flags);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock_irqsave(&ep->udc->lock, irq_flags);
+
+ if ((ep->bEndpointAddress & 0x7F) == 0)/*Control*/
+ {
+ if (req->req.actual != 0) {
+ ep->udc->ep0_status_0_byte = 1;
+ }
+ }
+#if 0
+ else
+ printk("**done() %s\n", ep ? ep->ep.name : NULL);
+#endif
+
+ ep->stopped = stopped;
+
+} /*done(struct vt8500_ep *ep, struct vt8500_req *req, int status)*/
+
+static u32 dma_src_len(struct vt8500_ep *ep, struct vt8500_req *req)
+{
+ /*dma_addr_t end;*/
+ /*U32 ep_trans_len;*/
+ unsigned start = 0 , end = 0;
+ u32 temp32 = 0;
+
+ start = req->req.length;
+
+ if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control In*/
+ end = (pDevReg->ControlDesTbytes & 0x7F);
+ temp32 = (ep->ep_fifo_length - end);
+ return temp32;
+ } else if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/
+ end = (pDevReg->Bulk1DesTbytes2 & 0x03) << 16;
+ end |= pDevReg->Bulk1DesTbytes1 << 8;
+ end |= pDevReg->Bulk1DesTbytes0;
+ } else if ((ep->bEndpointAddress & 0x7F) == 3)/*Interrupt In*/
+ {
+#ifdef USE_BULK3_TO_INTERRUPT
+ end = (pDevReg->Bulk3DesTbytes2 & 0x03) << 16;
+ end |= pDevReg->Bulk3DesTbytes1 << 8;
+ end |= pDevReg->Bulk3DesTbytes0;
+#else
+ start = req->dma_bytes;
+ end = (pDevReg->InterruptDes >> 4);
+#endif
+ } else if ((ep->bEndpointAddress & 0x7F) == 4)/*Iso In*/
+ {
+ end = 0;
+ }
+
+ temp32 = (start - end);
+ return temp32;
+} /*static u32 dma_src_len()*/
+
+static u32 dma_dest_len(struct vt8500_ep *ep, struct vt8500_req *req)
+{
+ /*dma_addr_t end;*/
+ unsigned start = 0 , end = 0;
+ u32 temp32 = 0;
+
+ start = req->req.length;
+
+ if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control Out*/
+ end = (pDevReg->ControlDesTbytes & 0x7F);
+ temp32 = (ep->ep_fifo_length - end);
+ return temp32;
+ } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/
+ end = (pDevReg->Bulk2DesTbytes2 & 0x03) << 16;
+ end |= pDevReg->Bulk2DesTbytes1 << 8;
+ end |= pDevReg->Bulk2DesTbytes0;
+ }
+
+ temp32 = (start - end);
+ return temp32;
+} /*static u32 dma_dest_len()*/
+
+/* Each USB transfer request using DMA maps to one or more DMA transfers.
+ * When DMA completion isn't request completion, the UDC continues with
+ * the next DMA transfer for that USB transfer.
+ */
+
+static void wmt_udc_pdma_des_prepare(unsigned int size, unsigned int dma_phy
+ , unsigned char des_type, unsigned char channel, int is_bulk)
+{
+ unsigned int res_size = size;
+ volatile unsigned int trans_dma_phy = dma_phy, des_phy_addr = 0, des_vir_addr = 0;
+ unsigned int cut_size = 0x40;
+
+ switch (des_type) {
+ case DESCRIPTOT_TYPE_SHORT:
+ {
+ struct _UDC_PDMA_DESC_S *pDMADescS;
+
+ if (channel == TRANS_OUT) {
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrSO;
+ des_vir_addr = UdcPdmaVirAddrSO;
+ pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff;
+ } else if (channel == TRANS_IN) {
+ if (is_bulk) {
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrSI;
+ des_vir_addr = UdcPdmaVirAddrSI;
+ pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff;
+ }
+ else {
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrS2I;
+ des_vir_addr = UdcPdmaVirAddrS2I;
+ pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff;
+ }
+ } else
+ DBG("!! wrong channel %d\n", channel);
+
+ while (res_size) {
+ pDMADescS = (struct _UDC_PDMA_DESC_S *) des_vir_addr;
+
+ pDMADescS->Data_Addr = trans_dma_phy;
+ pDMADescS->D_Word0_Bits.Format = 0;
+
+// if (res_size <= 65535) {
+ if (res_size <= 32767) {
+ pDMADescS->D_Word0_Bits.i = 1;
+ pDMADescS->D_Word0_Bits.End = 1;
+ pDMADescS->D_Word0_Bits.ReqCount = res_size;
+
+ res_size -= res_size;
+ } else {
+ pDMADescS->D_Word0_Bits.i = 0;
+ pDMADescS->D_Word0_Bits.End = 0;
+ pDMADescS->D_Word0_Bits.ReqCount = 0x8000 - cut_size;
+
+ res_size -= 0x8000;
+ des_vir_addr += (unsigned int)DES_S_SIZE;
+ trans_dma_phy += (unsigned int)0x8000;
+ }
+ }
+ break;
+ }
+
+ case DESCRIPTOT_TYPE_LONG:
+ {
+ struct _UDC_PDMA_DESC_L *pDMADescL;
+
+ if (channel == TRANS_OUT) {
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrLO;
+ des_vir_addr = UdcPdmaVirAddrLO;
+ pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff;
+
+// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X",
+// pUdcDmaReg->DMA_Descriptor_Point1); //gri
+
+// printk(KERN_INFO "des_vir_addr=0x%08X",
+// des_vir_addr); //gri
+
+ } else if (channel == TRANS_IN) {
+ if (is_bulk){
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrLI;
+ des_vir_addr = UdcPdmaVirAddrLI;
+ pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff;
+
+ // printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X",
+ // pUdcDmaReg->DMA_Descriptor_Point0); //gri
+
+// printk(KERN_INFO "des_vir_addr=0x%08X",
+// des_vir_addr); //gri
+ }
+ else {
+ des_phy_addr = (unsigned int) UdcPdmaPhyAddrL2I;
+ des_vir_addr = UdcPdmaVirAddrL2I;
+ pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr);
+ cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff;
+
+// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point2=0x%08X",
+// pUdcDmaReg->DMA_Descriptor_Point2); //gri
+
+// printk(KERN_INFO "des_vir_addr 2 =0x%08X",
+// des_vir_addr); //gri
+ }
+
+ } else
+ DBG("!! wrong channel %d\n", channel);
+
+ memset((void *)des_vir_addr, 0, 0x100);
+
+ while (res_size) {
+ pDMADescL = (struct _UDC_PDMA_DESC_L *) des_vir_addr;
+
+ pDMADescL->Data_Addr = trans_dma_phy;
+ pDMADescL->D_Word0_Bits.Format = 1;
+
+// if (res_size <= 65535) {
+ if (res_size <= 32767) {
+ pDMADescL->D_Word0_Bits.i = 1;
+ pDMADescL->D_Word0_Bits.End = 1;
+ pDMADescL->Branch_addr = 0;
+ pDMADescL->D_Word0_Bits.ReqCount = res_size;
+
+ res_size -= res_size;
+ } else {
+ pDMADescL->D_Word0_Bits.i = 0;
+ pDMADescL->D_Word0_Bits.End = 0;
+ pDMADescL->Branch_addr = des_vir_addr + (unsigned int)DES_L_SIZE;
+ pDMADescL->D_Word0_Bits.ReqCount = 0x8000 - cut_size;
+
+ res_size -= 0x8000;
+ des_vir_addr += (unsigned int)DES_L_SIZE;
+ trans_dma_phy += (unsigned int)0x8000;
+ }
+ }
+
+#if 0
+ if (channel == TRANS_IN) {
+ if (!is_bulk) {
+ printk(KERN_INFO "pDMADescL(0x%08X)\n",
+ des_vir_addr); //gri
+ printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri
+ printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri
+ printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri
+ }
+ else {
+ printk(KERN_INFO "pDMADescL(0x%08X)\n",
+ des_vir_addr); //gri
+ printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri
+ printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri
+ printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri
+ }
+ }
+#endif
+
+ break;
+ }
+
+ case DESCRIPTOT_TYPE_MIX:
+ break;
+ default:
+ break;
+ }
+
+ //wmb();
+} /*wmt_udc_pdma_des_prepare*/
+
+void iso_prepare_0byte(void)
+{
+ unsigned char ubulk3tmp;
+
+ ubulk3tmp = pDevReg->Bulk3EpControl;
+ pDevReg->Bulk3EpControl = EP_DMALIGHTRESET;
+ while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET)
+ ;
+
+ pDevReg->Bulk3DesStatus = 0;
+ pDevReg->Bulk3DesTbytes2 = 0;
+ pDevReg->Bulk3DesTbytes1 = 0;
+ pDevReg->Bulk3DesTbytes0 = 0;
+
+ pDevReg->Bulk3EpControl = ubulk3tmp;
+
+ /* set endpoint data toggle*/
+ pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN);
+ //wmb();
+ pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE;
+
+}
+void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req)
+{
+ u32 temp32;
+ u32 dma_ccr = 0;
+ unsigned int length;
+ u32 dcmd;
+ u32 buf;
+ int is_in, i;
+ u8 *pctrlbuf;
+#ifndef USE_BULK3_TO_INTERRUPT
+ u8 *pintbuf;
+#endif
+
+// printk(KERN_INFO "next_in_dma s\n"); //gri
+
+ dcmd = length = req->req.length - req->req.actual;/*wmt_ep_queue() : req->req.actual = 0*/
+ buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC);
+
+ is_in = 1;/*ep->bEndpointAddress & USB_DIR_IN;*/
+
+ DBG("next_in_dma() %s\n", ep ? ep->ep.name : NULL);
+
+#ifdef RNDIS_INFO_DEBUG_BULK_IN
+ if ((ep->bEndpointAddress & 0x7F) == 1)
+ INFO("next_in_dma() %s\n", ep ? ep->ep.name : NULL);
+#endif
+
+ if (((ep->bEndpointAddress & 0x7F) == 1) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) {
+ unsigned int dma_length = 65536;
+
+printk(KERN_INFO "rndis xxxxx %d\n",req->req.length);
+
+ if (ep->rndis_buffer_alloc == 0) {
+
+ ep->rndis_buffer_address = (unsigned int)UdcRndisEp1VirAddr;
+ ep->rndis_dma_phy_address = (u32)UdcRndisEp1PhyAddr;
+ ep->rndis_buffer_length = dma_length;
+ ep->rndis_buffer_alloc = 1;
+ }
+ ep->rndis = 1;
+
+ }
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ if (((ep->bEndpointAddress & 0x7F) == 3) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) {
+ unsigned int dma_length = 65536;
+
+//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length);
+ if (ep->rndis_buffer_alloc == 0) {
+
+ ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr;
+ ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr;
+ ep->rndis_buffer_length = dma_length;
+ ep->rndis_buffer_alloc = 1;
+ }
+ ep->rndis = 1;
+
+ }
+#endif
+
+ if (((ep->bEndpointAddress & 0x7F) == 4) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) {
+ unsigned int dma_length = 65536;
+
+//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length);
+ if (ep->rndis_buffer_alloc == 0) {
+
+ ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr;
+ ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr;
+ ep->rndis_buffer_length = dma_length;
+ ep->rndis_buffer_alloc = 1;
+ }
+ ep->rndis = 1;
+
+ }
+
+ if (((ep->bEndpointAddress & 0x7F) == 1) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) {
+ //void *retval;
+ //dma_addr_t dma;
+
+printk(KERN_INFO "rndis ooooobb %d\n",req->req.length);
+ }
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ if (((ep->bEndpointAddress & 0x7F) == 3) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) {
+ //void *retval;
+ //dma_addr_t dma;
+
+//printk(KERN_INFO "rndis 3 ooooobb %d\n",req->req.length);
+ }
+#endif
+
+ if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control*/
+ ep->ep_fifo_length = 0;
+
+ if (length >= 64)
+ length = 64;
+
+ ep->ep_fifo_length = length;
+ pctrlbuf = (u8 *)(req->req.buf + req->req.actual);
+
+ for (i = 0; i < length; i++)
+ SetupBuf[i] = pctrlbuf[i];
+
+ if (ep->toggle_bit)
+ pDevReg->ControlDesTbytes = length | CTRLXFER_DATA1;
+ else
+ pDevReg->ControlDesTbytes = length | CTRLXFER_DATA0;
+
+ pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC;
+ wmb();
+ pDevReg->ControlDesStatus = CTRLXFER_ACTIVE;
+ ControlState = CONTROLSTATE_DATA;
+
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+ } else if (((ep->bEndpointAddress & 0x7F) == 1)) {/*Bulk In*/
+ ep->stall_more_processing = 0;
+
+// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri
+
+ if (dcmd > UBE_MAX_DMA)
+ dcmd = UBE_MAX_DMA;
+
+ if (pDevReg->Bulk1EpControl & EP_STALL) {
+ ep->stall_more_processing = 1;
+ ep->temp_dcmd = dcmd;
+ }
+
+ if (ep->rndis == 1) {
+ memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length);
+ wmt_udc_pdma_des_prepare(dcmd,
+ ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC),
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 1);
+ } else
+ wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 1);
+
+ if (pDevReg->Bulk1EpControl & EP_STALL)
+ ep->temp_bulk_dma_addr = buf;
+
+ if (pDevReg->Bulk1EpControl & EP_STALL)
+ ep->temp_dma_ccr = dma_ccr;
+
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk1DesTbytes2 |= (dcmd >> 16) & 0x3;
+ pDevReg->Bulk1DesTbytes1 = (dcmd >> 8) & 0xFF;
+ pDevReg->Bulk1DesTbytes0 = dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (is_in) {
+ if (ep->toggle_bit)
+ pDevReg->Bulk1DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/
+ else
+ pDevReg->Bulk1DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/
+
+ pDevReg->Bulk1DesStatus = (BULKXFER_IOC | BULKXFER_IN);
+ } /*if(is_in)*/
+
+ if (pDevReg->Bulk1EpControl & EP_STALL)
+ ep->ep_stall_toggle_bit = ep->toggle_bit;
+
+
+ /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/
+ if (req->req.length > ep->maxpacket) {
+ /*ex : 512 /64 = 8 8 % 2 = 0*/
+ temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket;
+ ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2);
+ } else {
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+ }
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ if (!is_in)
+ dma_ccr |= DMA_TRANS_OUT_DIR;
+
+ if (dcmd) /* PDMA can not support 0 byte transfer*/
+ pUdcDmaReg->DMA_Context_Control0 = dma_ccr;
+
+ wmb();
+ pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE;
+ } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/
+#ifdef USE_BULK3_TO_INTERRUPT
+ ep->stall_more_processing = 0;
+
+// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri
+
+ if (dcmd > UBE_MAX_DMA)
+ dcmd = UBE_MAX_DMA;
+
+ if (pDevReg->Bulk3EpControl & EP_STALL) {
+ ep->stall_more_processing = 1;
+ ep->temp_dcmd = dcmd;
+ }
+
+ if (ep->rndis == 1) {
+ memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length);
+ wmt_udc_pdma_des_prepare(dcmd,
+ ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC),
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+ } else
+ wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->temp_bulk_dma_addr = buf;
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->temp_dma_ccr = dma_ccr;
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (is_in) {
+ if (ep->toggle_bit)
+ pDevReg->Bulk3DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/
+ else
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/
+
+ pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN);
+ } /*if(is_in)*/
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->ep_stall_toggle_bit = ep->toggle_bit;
+
+
+ /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/
+ if (req->req.length > ep->maxpacket) {
+ /*ex : 512 /64 = 8 8 % 2 = 0*/
+ temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket;
+ ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2);
+ } else {
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+ }
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ //dma_ccr = DMA_RUN;
+ if (!is_in)
+ dma_ccr |= DMA_TRANS_OUT_DIR;
+
+ wmb();
+ if (dcmd) /* PDMA can not support 0 byte transfer*/
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr;
+
+ dma_ccr |= DMA_RUN;
+
+ wmb();
+ if (dcmd) /* PDMA can not support 0 byte transfer*/
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr;
+
+ wmb();
+ pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE;
+#else
+
+//printk(KERN_INFO "udc interrupt\n");
+
+ if (dcmd > INT_FIFO_SIZE)
+ dcmd = INT_FIFO_SIZE;
+ interrupt_transfer_size = dcmd;
+
+ pintbuf = (u8 *)(req->req.buf);/* + req->req.actual);*/
+
+ for (i = req->req.actual; i < (req->req.actual + dcmd); i++)
+ IntBuf[(i-req->req.actual)] = pintbuf[i];
+
+ pDevReg->InterruptDes = 0x00;
+ pDevReg->InterruptDes = (dcmd << 4);
+
+ if (ep->toggle_bit)
+ pDevReg->InterruptDes |= INTXFER_DATA1;
+ else
+ pDevReg->InterruptDes &= 0xF7;
+
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ pDevReg->InterruptDes |= INTXFER_IOC;
+ wmb();
+ pDevReg->InterruptDes |= INTXFER_ACTIVE;
+#endif
+ } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/
+
+ unsigned char tmp;
+
+ tmp = pDevReg->Bulk3EpControl;
+
+ pDevReg->Bulk3EpControl = EP_DMALIGHTRESET;
+ while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET)
+ ;
+
+ pDevReg->Bulk3EpControl = tmp;
+
+ wmt_pdma2_reset();
+
+ ep->stall_more_processing = 0;
+
+ //printk(KERN_INFO "next_in_dma 4 %d %d %d\n", length, req->req.length,req->req.actual); //gri
+ //printk(KERN_INFO "next_in_dma 4\n"); //gri
+
+ if (dcmd > UBE_MAX_DMA)
+ dcmd = UBE_MAX_DMA;
+
+ if (pDevReg->Bulk3EpControl & EP_STALL) {
+ ep->stall_more_processing = 1;
+ ep->temp_dcmd = dcmd;
+ }
+
+ if (ep->rndis == 1) {
+ memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length);
+ wmt_udc_pdma_des_prepare(dcmd,
+ ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC),
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+ } else
+ wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->temp_bulk_dma_addr = buf;
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->temp_dma_ccr = dma_ccr;
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (is_in) {
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/
+
+ pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN);
+ } /*if(is_in)*/
+
+ if (pDevReg->Bulk3EpControl & EP_STALL)
+ ep->ep_stall_toggle_bit = ep->toggle_bit;
+
+
+ /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/
+ ep->toggle_bit = 0;
+
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ //dma_ccr = DMA_RUN;
+ if (!is_in)
+ dma_ccr |= DMA_TRANS_OUT_DIR;
+
+// wmb();
+ if (dcmd) /* PDMA can not support 0 byte transfer*/
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr;
+
+ dma_ccr |= DMA_RUN;
+
+// wmb();
+ if (dcmd) /* PDMA can not support 0 byte transfer*/
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr;
+
+// wmb();
+
+ pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE;
+ fiq_using = 1;
+
+ wmt_enable_fiq(300);
+ //run_script(action_chkiso);
+ }
+
+ DBG("req->req.dma 0x%08X \n", req->req.dma);
+
+#ifdef MSC_COMPLIANCE_TEST
+ INFO("req->req.dma 0x%08X \n", req->req.dma);
+#endif
+
+ req->dma_bytes = dcmd;//length;
+
+#if 0
+ if (((ep->bEndpointAddress & 0x7F) == 3) || ((ep->bEndpointAddress & 0x7F) == 4)) {
+ printk(KERN_INFO "next_in_dma 3 e\n"); //gri
+ printk(KERN_INFO "Bulk3EpInEpNum =0x%2.2x\n", pDevReg->Bulk3EpInEpNum); //gri
+ printk(KERN_INFO "Bulk3EpMaxLen =0x%2.2x\n", pDevReg->Bulk3EpMaxLen); //gri
+ printk(KERN_INFO "Bulk3EpOutEpNum =0x%2.2x\n", pDevReg->Bulk3EpOutEpNum); //gri
+ printk(KERN_INFO "Bulk3EpControl =0x%2.2x\n", pDevReg->Bulk3EpControl); //gri
+
+ printk(KERN_INFO "Bulk3DesTbytes2 =0x%2.2x\n", pDevReg->Bulk3DesTbytes2); //gri
+ printk(KERN_INFO "Bulk3DesTbytes1 =0x%2.2x\n", pDevReg->Bulk3DesTbytes1); //gri
+ printk(KERN_INFO "Bulk3DesTbytes0 =0x%2.2x\n", pDevReg->Bulk3DesTbytes0); //gri
+ printk(KERN_INFO "Bulk3DesStatus =0x%2.2x\n", pDevReg->Bulk3DesStatus); //gri
+
+ printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point2); //gri
+ printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes2); //gri
+ printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr2); //gri
+ printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr2); //gri
+ printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr2); //gri
+ printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control2); //gri
+
+ }
+ else if ((ep->bEndpointAddress & 0x7F) == 1) {
+ printk(KERN_INFO "next_in_dma 1 e\n"); //gri
+ printk(KERN_INFO "Bulk1EpInEpNum =0x%2.2x\n", pDevReg->Bulk1EpInEpNum); //gri
+ printk(KERN_INFO "Bulk1EpMaxLen =0x%2.2x\n", pDevReg->Bulk1EpMaxLen); //gri
+ printk(KERN_INFO "Bulk1EpOutEpNum =0x%2.2x\n", pDevReg->Bulk1EpOutEpNum); //gri
+ printk(KERN_INFO "Bulk1EpControl =0x%2.2x\n", pDevReg->Bulk1EpControl); //gri
+
+ printk(KERN_INFO "Bulk1DesTbytes2 =0x%2.2x\n", pDevReg->Bulk1DesTbytes2); //gri
+ printk(KERN_INFO "Bulk1DesTbytes1 =0x%2.2x\n", pDevReg->Bulk1DesTbytes1); //gri
+ printk(KERN_INFO "Bulk1DesTbytes0 =0x%2.2x\n", pDevReg->Bulk1DesTbytes0); //gri
+ printk(KERN_INFO "Bulk1DesStatus =0x%2.2x\n", pDevReg->Bulk1DesStatus); //gri
+
+ printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point0); //gri
+ printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes0); //gri
+ printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr0); //gri
+ printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr0); //gri
+ printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr0); //gri
+ printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control0); //gri
+ }
+#endif
+
+} /*static void next_in_dma()*/
+
+static void finish_in_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status)
+{
+// printk(KERN_INFO "finish_in_dma()s\n"); //gri
+
+ DBG("finish_in_dma() %s\n", ep ? ep->ep.name : NULL);
+
+ if (status == 0) { /* Normal complete!*/
+#ifdef USE_BULK3_TO_INTERRUPT
+ req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/
+#else
+// if ((ep->bEndpointAddress & 0x7F) == 3)
+// req->req.actual += interrupt_transfer_size;
+// else
+ if ((ep->bEndpointAddress & 0x7F) != 3)
+ req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/
+#endif
+
+ /* return if this request needs to send data or zlp*/
+ if (req->req.actual < req->req.length)
+ return;
+
+ if (req->req.zero
+ && req->dma_bytes != 0
+ && (req->req.actual % ep->maxpacket) == 0)
+ return;
+
+ } else
+ req->req.actual += dma_src_len(ep, req);
+
+#ifdef RNDIS_INFO_DEBUG_BULK_IN
+ if ((ep->bEndpointAddress & 0x7F) == 1)
+ INFO("finish_in_dma()e %s req->req.actual(0x%08X) req->req.length(0x%08X)\n",
+ ep ? ep->ep.name : NULL, req->req.actual, req->req.length);
+#endif
+
+ done(ep, req, status);
+
+//printk(KERN_INFO "finish_in_dma() %s req->req.actual(0x%08X) req->req.length(0x%08X)\n",
+//ep ? ep->ep.name : NULL, req->req.actual, req->req.length); //gri
+
+
+} /*static void finish_in_dma()*/
+
+static void next_out_dma(struct vt8500_ep *ep, struct vt8500_req *req)
+{
+ /*unsigned packets;*/
+ u32 dma_ccr = 0;
+ u32 dcmd;
+ u32 buf;
+ int is_in;
+
+// printk(KERN_INFO "next_out_dma s\n"); //gri
+
+ is_in = 0;/*ep->bEndpointAddress & USB_DIR_IN;*/
+
+#ifdef RNDIS_INFO_DEBUG_BULK_OUT
+ if (ep->bEndpointAddress == 2)
+ INFO("next_out_dma() %s\n", ep ? ep->ep.name : NULL);
+#endif
+
+ DBG("next_out_dma() %s\n", ep ? ep->ep.name : NULL);
+
+ dcmd = req->dma_bytes = req->req.length - req->req.actual;
+ buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC);
+
+ if ((ep->bEndpointAddress == 2) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) {
+ unsigned int dma_length = 65536;
+
+printk(KERN_INFO "rndis ooooo %d\n",req->req.length);
+ if (ep->rndis_buffer_alloc == 0) {
+
+ ep->rndis_buffer_address = (unsigned int)UdcRndisEp2VirAddr;
+ ep->rndis_dma_phy_address = (u32)UdcRndisEp2PhyAddr;
+ ep->rndis_buffer_length = dma_length;
+ ep->rndis_buffer_alloc = 1;
+ }
+ ep->rndis = 1;
+ }
+ if ((ep->bEndpointAddress == 2) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) {
+// void *retval;
+// dma_addr_t dma;
+
+printk(KERN_INFO "rndis ooooobb %d\n",req->req.length);
+#if 0
+ dma_free_coherent (ep->udc->dev,
+ ep->rndis_buffer_length,
+ (void *)ep->rndis_buffer_address, (dma_addr_t)ep->rndis_dma_phy_address);
+
+ retval = dma_alloc_coherent(ep->udc->dev,
+ req->req.length, &dma, GFP_ATOMIC);
+
+ ep->rndis_buffer_address = (unsigned int)retval;
+ ep->rndis_dma_phy_address = (u32)dma;
+ ep->rndis_buffer_length = req->req.length;
+ ep->rndis = 1;
+#endif
+ }
+
+ if (ep->bEndpointAddress == 0) {/*Control*/
+ ep->ep_fifo_length = 0;
+
+ if (dcmd >= 64)
+ dcmd = 64;
+
+ ep->ep_fifo_length = dcmd;
+
+ if (ep->toggle_bit)
+ pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA1;
+ else
+ pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA0;
+
+ pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC;
+ wmb();
+ pDevReg->ControlDesStatus = CTRLXFER_ACTIVE;
+ ControlState = CONTROLSTATE_DATA;
+
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/
+ ep->stall_more_processing = 0;
+
+// printk(KERN_INFO "next_out_dma %d %d %d\n", req->dma_bytes, req->req.length,req->req.actual); //gri
+
+ /*if(req->dma_bytes == 64)*/
+ ep->udc->cbw_virtual_address = (((u32)req->req.buf + req->req.actual) & 0xFFFFFFFC);
+
+ if (dcmd > UBE_MAX_DMA)
+ dcmd = UBE_MAX_DMA;
+
+ if (pDevReg->Bulk2EpControl & EP_STALL) {
+ ep->stall_more_processing = 1;
+ ep->temp_dcmd = dcmd;
+ }
+ /* Set Address*/
+ if (ep->rndis == 1)
+ wmt_udc_pdma_des_prepare(dcmd,
+ ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC),
+ DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1);
+ else
+ wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1);
+
+ if (pDevReg->Bulk2EpControl & EP_STALL)
+ ep->temp_bulk_dma_addr = buf;
+
+ if (pDevReg->Bulk2EpControl & EP_STALL)
+ ep->temp_dma_ccr = dma_ccr;
+
+ /* DMA Global Controller Reg*/
+ /* DMA Controller Enable +*/
+ /* DMA Global Interrupt Enable(if any TC, error, or abort status in any channels occurs)*/
+
+ pDevReg->Bulk2DesStatus = 0x00;
+ pDevReg->Bulk2DesTbytes2 |= (dcmd >> 16) & 0x3;
+ pDevReg->Bulk2DesTbytes1 = (dcmd >> 8) & 0xFF;
+ pDevReg->Bulk2DesTbytes0 = dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (ep->toggle_bit)
+ pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1;
+ else
+ pDevReg->Bulk2DesTbytes2 &= 0x3F;/*BULKXFER_DATA0;*/
+
+ pDevReg->Bulk2DesStatus = BULKXFER_IOC;/*| BULKXFER_IN;*/
+
+ if (pDevReg->Bulk2EpControl & EP_STALL)
+ ep->ep_stall_toggle_bit = ep->toggle_bit;
+
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ if (!is_in)
+ dma_ccr |= DMA_TRANS_OUT_DIR;
+
+ wmb();
+ pUdcDmaReg->DMA_Context_Control1 = dma_ccr;
+ wmb();
+ pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE;
+ /*udc_device_dump_register();*/
+ }
+
+ VDBG("req->req.dma 0x%08X \n", req->req.dma);
+
+//printk(KERN_INFO "next_out_dma e\n"); //gri
+
+} /*static void next_out_dma()*/
+
+static void
+finish_out_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status)
+{
+ u16 count;
+ u8 temp8;
+ u32 temp32;
+ /*u8 bulk_dma_csr;*/
+
+// printk(KERN_INFO "finish_out_dma s\n"); //gri
+
+ DBG("finish_out_dma() %s\n", ep ? ep->ep.name : NULL);
+
+ count = dma_dest_len(ep, req);
+
+ if (ep->bEndpointAddress == 0) {/*Control*/
+ u8 *pctrlbuf;
+ int i;
+
+ pctrlbuf = (u8 *)(req->req.buf + req->req.actual);
+ for (i = 0; i < count; i++)
+ pctrlbuf[i] = SetupBuf[i];
+
+ /*INFO("finish_out_dma() %s\n", ep ? ep->ep.name : NULL);*/
+ /*dump_bulk_buffer((req->req.buf + req->req.actual), count);*/
+ }
+
+ count += req->req.actual;
+
+ if (count <= req->req.length)
+ req->req.actual = count;
+
+ if (ep->bEndpointAddress == 0) {/*Control*/
+ if (req->req.actual < req->req.length) {
+ temp8 = pDevReg->ControlDesStatus;
+
+ if ((temp8 & CTRLXFER_SHORTPKT) == 0)
+ return; /*Continue...*/
+ }
+ } else if (ep->bEndpointAddress == 2) {
+
+ if (pDevReg->Bulk2DesTbytes2 & 0x80)
+ ep->toggle_bit= 1;
+ else
+ ep->toggle_bit= 0;
+
+// while((pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0xf) &&
+// (pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0x5));
+
+// printk(KERN_INFO "finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n",
+// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);//gri
+ // INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n",
+ // ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);
+
+
+ {
+ {
+ unsigned int gri_t_d;
+ unsigned int gri_count=0;
+ unsigned int dma_count;
+ do{
+ gri_t_d=pUdcDmaReg->DMA_ISR ;
+ gri_t_d &= 0x2;
+ gri_count++;
+ if (gri_count & 0x10){
+ gri_count=0;
+// printk(KERN_INFO "pUdcDmaReg->DMA_Context_Control1 0x%08x\n", &(pUdcDmaReg->DMA_Context_Control1));
+ printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1);
+ dma_count = req->req.length - pUdcDmaReg->DMA_Residual_Bytes1_Bits.ResidualBytes;
+// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count);
+ if (pUdcDmaReg->DMA_Context_Control1_Bis.Run == 0)
+ break;
+ if ((count == dma_count) || (count == 0)){
+// printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1);
+// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count);
+// while(1);
+ pUdcDmaReg->DMA_Context_Control1_Bis.Run = 0;
+ break;
+ }
+ }
+ }while(!gri_t_d);
+ }
+ }
+
+
+ if (req->req.actual < req->req.length) {
+ DBG("finish_out_dma() req->actual < req->req.length\n");
+ temp8 = pDevReg->Bulk2DesStatus;
+
+ if ((temp8 & BULKXFER_SHORTPKT) == 0)
+ return; /*Continue...*/
+ else { /*Short Package.*/
+ pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET;
+ wmb();
+
+ while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET)
+ ;
+ pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA;
+ wmb();
+ }
+ }
+ }
+ /* rx completion*/
+ /*UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);*/
+
+//#ifdef RNDIS_INFO_DEBUG_BULK_OUT
+// if (ep->bEndpointAddress == 2)
+// INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n",
+// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);
+//#endif
+
+ /*dump_bulk_buffer(req->req.buf, req->req.actual);*/
+
+ if ((ep->bEndpointAddress == 2) && (ep->rndis == 1)) {
+ memcpy((void *)((u32)req->req.buf), (void *)((u32)ep->rndis_buffer_address), req->req.actual);
+
+ #ifdef RNDIS_INFO_DEBUG_BULK_OUT
+ /*if ((req->req.actual % 4 == 3))// && (b_message == 0))*/
+ /*dump_bulk_buffer(req->req.buf, req->req.actual);*/
+ #endif
+#if 0
+ if ((req->req.length == 1600) || (req->req.length == 2048)) {/*F.S. [1600] : H.S. [2048]*/
+ /*ex : 512 /64 = 8 8 % 2 = 0*/
+ temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket;
+ ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2);
+ } else
+ INFO("Different Length for Bulk Out (%08d) Toggle Bit would Error\n"
+ , req->req.length);
+#else
+#if 0
+ if (req->req.length > ep->maxpacket) {
+ /*ex : 512 /64 = 8 8 % 2 = 0*/
+ temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket;
+ ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2);
+ } else {
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+ }
+#endif
+
+#endif
+ } else {
+#if 1
+ if (ep->bEndpointAddress == 0){
+ /*GigaHsu-B 2008.5.15 : Add this caculate toggle from next_out_dma() :
+ fixed sideshow gadget issue.*/
+ if (req->req.length > ep->maxpacket) {
+ /*ex : 512 /64 = 8 8 % 2 = 0*/
+ temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket;
+ ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2);
+ } else {
+ if (ep->toggle_bit == 0)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+ }
+ }
+#endif
+
+ /*GigaHsu-E 2008.5.15*/
+ }
+
+ done(ep, req, status);
+
+//printk(KERN_INFO "finish_out_dma e\n"); //gri
+
+} /*finish_out_dma()*/
+
+void dma_irq(u8 addr)
+{
+ struct vt8500_ep *ep;
+ struct vt8500_req *req;
+ /*u32 temp32;*/
+ /*u32 i;*/
+
+ ep = &udc->ep[addr & 0x7f];
+
+ if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/
+
+ /* IN dma: tx to host*/
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ finish_in_dma(ep, req, 0);
+ }
+
+ while (pDevReg->Bulk1EpControl & EP_COMPLETEINT)
+ ;
+
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ next_in_dma(ep, req);
+ }
+ } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/
+
+ /* OUT dma: rx from host*/
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ finish_out_dma(ep, req, 0);
+ }
+
+ while (pDevReg->Bulk2EpControl & EP_COMPLETEINT)
+ ;
+
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ next_out_dma(ep, req);
+ }
+ } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ /* IN dma: tx to host*/
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ finish_in_dma(ep, req, 0);
+ }
+
+ while (pDevReg->Bulk3EpControl & EP_COMPLETEINT)
+ ;
+
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ next_in_dma(ep, req);
+ }
+#else
+ /* IN dma: tx to host*/
+ while (pDevReg->InterruptEpControl & EP_COMPLETEINT)
+ ;
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ req->req.actual += dma_src_len(ep, req);
+ if (req->req.actual < req->req.length)
+ next_in_dma(ep, req);
+ else
+ finish_in_dma(ep, req, 0);
+ }
+
+// if (!list_empty(&ep->queue)) {
+// req = container_of(ep->queue.next, struct vt8500_req, queue);
+// next_in_dma(ep, req);
+// }
+#endif
+ } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/
+
+ /* IN dma: tx to host*/
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ finish_in_dma(ep, req, 0);
+ }
+ }
+
+} /*static void dma_irq()*/
+
+
+static void pullup_enable(struct vt8500_udc *udc)
+{
+ INFO("gri pullup_enable()\n");
+ b_pullup = 1;
+ /*Enable port control's FSM to enable 1.5k pull-up on D+.*/
+ //pDevReg->PhyMisc &= 0x0F;/*Hardware auto-mode*/
+ pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/
+ wmb();
+ /*pDevReg->PhyMisc |= 0x50;*/
+
+} /*static void pullup_enable()*/
+
+
+
+/*-------------------------------------------------------------------------*/
+/*file_storage.c ep0_queue() - control*/
+/*file_storage.c start_transfer() - bulk*/
+static int
+wmt_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep);
+ struct vt8500_req *req = container_of(_req, struct vt8500_req, req);
+ /*struct vt8500_udc *udc;*/
+// unsigned long flags;
+ unsigned char empty_data = 0;
+
+ DBG("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL);
+// INFO("gri wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL);
+
+// if ((ep->bEndpointAddress & 0x7F) > 4)
+// return -EINVAL;
+
+#ifdef RNDIS_INFO_DEBUG_BULK_OUT
+ if ((ep->bEndpointAddress == 3))/* || ((ep->bEndpointAddress & 0x7F) == 2))*/
+ INFO("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL);
+#endif
+
+ /* catch various bogus parameters*/
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+ DBG("[wmt_ep_queue], bad params\n");
+ return -EINVAL;
+ }
+ if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
+ DBG("[wmt_ep_queue], bad ep\n");
+ return -EINVAL;
+ }
+
+//#ifdef RNDIS_INFO_DEBUG_BULK_OUT
+// if ((ep->bEndpointAddress == 2))/* || ((ep->bEndpointAddress & 0x7F) == 1))*/
+// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n",
+// ep->ep.name, _req, _req->length, _req->buf);
+//#endif
+
+//#ifdef MSC_COMPLIANCE_TEST
+// if ((ep->bEndpointAddress & 0x7F) == 1)
+// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n",
+// ep->ep.name, _req, _req->length, _req->buf);
+//#endif
+
+ DBG("wmt_ep_queue() %s queue req %p, len %d buf %p\n",
+ ep->ep.name, _req, _req->length, _req->buf);
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+
+ /* maybe kickstart non-iso i/o queues*/
+
+ if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) {
+ int is_in;
+
+ if (ep->bEndpointAddress == 0) {
+ if (!udc->ep0_pending || !list_empty(&ep->queue)) {
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ return -EL2HLT;
+ }
+
+ /* empty DATA stage?*/
+ is_in = udc->ep0_in;
+
+ if (!req->req.length) { /*status 0 bytes*/
+
+ udc->ep0_status_0_byte = 1;
+ ep0_status(udc);
+
+ /* cleanup*/
+ udc->ep0_pending = 0;
+ done(ep, req, 0);
+ empty_data = 1;
+ }
+
+ if (req->req.length) {
+ udc->bulk_out_dma_write_error = 0;
+ (is_in ? next_in_dma : next_out_dma)(ep, req);
+ }
+ } else {
+ is_in = ep->bEndpointAddress & USB_DIR_IN;
+
+ if (req != 0){
+ list_add_tail(&req->queue, &ep->queue);
+ empty_data = 1;
+ }
+// else
+// {
+// printk(KERN_INFO "xxx %x %x\n",req,empty_data); //gri
+// }
+ /*if (!ep->has_dma)*/
+ /* use_ep(ep, UDC_EP_SEL);*/
+ /* if ISO: SOF IRQs must be enabled/disabled!*/
+ if (((ep->bEndpointAddress & 0x7F) != 4) || (!fiq_using))
+ (is_in ? next_in_dma : next_out_dma)(ep, req);
+#if 0
+ else
+ printk("gri w_e_q() 01 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using);
+#endif
+ }
+ }
+ /* irq handler advances the queue*/
+#if 0
+ if ((ep->bEndpointAddress & 0x7F) == 4)
+ printk("gri w_e_q() 02 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using);
+#endif
+
+ if ((req != 0) && (empty_data == 0))
+ list_add_tail(&req->queue, &ep->queue);
+
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+
+ return 0;
+} /*wmt_ep_queue()*/
+
+void ep1_cancel_tx(struct vt8500_ep *ep)
+{
+ unsigned char btmp;
+ unsigned char bctrl0;
+
+ bctrl0 = pDevReg->Bulk1EpControl & 0xE3;
+ pDevReg->Bulk1DesStatus &= 0xF0;
+
+ ep->stall_more_processing = 0;
+
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk1DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk1DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk1DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ btmp = pDevReg->Bulk1DesTbytes2 & 0x40;
+
+ if (btmp)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ if (ep->toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk1DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk1DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk1DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ wmb();
+ pDevReg->Bulk1EpControl |= EP_DMALIGHTRESET;
+ wmb();
+ while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET);
+ pDevReg->Bulk1EpControl = bctrl0;
+
+ wmt_pdma0_reset();
+ wmb();
+}
+
+void ep2_cancel_tx(struct vt8500_ep *ep)
+{
+ unsigned char btmp;
+ unsigned char bctrl0;
+
+ bctrl0 = pDevReg->Bulk2EpControl & 0xE3;
+ pDevReg->Bulk2DesStatus &= 0xF0;
+
+ ep->stall_more_processing = 0;
+
+ pDevReg->Bulk2DesStatus = 0x00;
+ pDevReg->Bulk2DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk2DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk2DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ btmp = pDevReg->Bulk2DesTbytes2 & 0x80;
+
+ if (btmp)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ if (ep->toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk2DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk2DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk2DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ wmb();
+ pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET;
+ wmb();
+ while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET);
+ pDevReg->Bulk2EpControl = bctrl0;
+
+ wmt_pdma1_reset();
+ wmb();
+}
+
+void ep3_cancel_tx(struct vt8500_ep *ep)
+{
+#ifdef USE_BULK3_TO_INTERRUPT
+ unsigned char btmp;
+ unsigned char bctrl0;
+
+ bctrl0 = pDevReg->Bulk3EpControl & 0xE3;
+ pDevReg->Bulk3DesStatus &= 0xF0;
+
+ ep->stall_more_processing = 0;
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ btmp = pDevReg->Bulk3DesTbytes2 & 0x40;
+
+ if (btmp)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ if (ep->toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk3DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk3DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ wmb();
+ pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET;
+ wmb();
+ while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET);
+ pDevReg->Bulk3EpControl = bctrl0;
+
+ wmt_pdma2_reset();
+ wmb();
+#else
+ unsigned char tmp0, tmp1, tmp2, tmp3;
+
+ pDevReg->InterruptDes = 0x00;
+ wmb();
+ tmp0 = InterruptEpControl;
+ tmp1 = InterruptReserved;
+ tmp2 = InterruptEpMaxLen;
+ tmp3 = InterruptEpEpNum;
+ InterruptEpControl |= EP_DMALIGHTRESET;
+ wmb();
+ while (pDevReg->InterruptEpControl & EP_DMALIGHTRESET);
+ InterruptEpControl = tmp0;
+ InterruptReserved = tmp1;
+ InterruptEpMaxLen = tmp2;
+ InterruptEpEpNum = tmp3;
+ wmb();
+#endif
+}
+
+void ep4_cancel_tx(struct vt8500_ep *ep)
+{
+
+ unsigned char btmp;
+ unsigned char bctrl0;
+
+ fiq_using = 0;
+
+ bctrl0 = pDevReg->Bulk3EpControl & 0xE3;
+ pDevReg->Bulk3DesStatus &= 0xF0;
+
+ ep->stall_more_processing = 0;
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ btmp = pDevReg->Bulk3DesTbytes2 & 0x40;
+
+ if (btmp)
+ ep->toggle_bit = 1;
+ else
+ ep->toggle_bit = 0;
+
+ if (ep->toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk3DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk3DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ wmb();
+ pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET;
+ wmb();
+ while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET);
+ pDevReg->Bulk3EpControl = bctrl0;
+
+ wmt_pdma2_reset();
+ wmb();
+}
+
+static int wmt_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep);
+ struct vt8500_req *req;
+ int is_in;
+// unsigned long flags;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, irq_flags);
+
+ DBG("wmt_ep_dequeue() %s\n", ep ? ep->ep.name : NULL);
+ /* make sure it's actually queued on this endpoint*/
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ spin_unlock_irqrestore(&ep->udc->lock, irq_flags);
+ return -EINVAL;
+ }
+
+
+ if (((ep->bEndpointAddress & 0x7F) != 0) && ep->queue.next == &req->queue) {
+
+ if (ep->bEndpointAddress == 1){
+ ep1_cancel_tx(ep);
+ }
+ else if (ep->bEndpointAddress == 2){
+ ep2_cancel_tx(ep);
+ }
+ else if (ep->bEndpointAddress == 3){
+ ep3_cancel_tx(ep);
+ }
+ else if (ep->bEndpointAddress == 4){
+ ep4_cancel_tx(ep);
+ }
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ is_in = ep->bEndpointAddress & USB_DIR_IN;
+ (is_in ? next_in_dma : next_out_dma)(ep, req);
+ }
+
+ spin_unlock_irqrestore(&ep->udc->lock, irq_flags);
+
+ return 0;
+} /*static int wmt_ep_dequeue()*/
+
+/*-------------------------------------------------------------------------*/
+
+static int wmt_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep);
+// unsigned long flags;
+ int status = -EOPNOTSUPP;
+
+ spin_lock_irqsave(&ep->udc->lock, irq_flags);
+
+ ep->toggle_bit = 0; /*patch CLEAR_FEATURE ENDPOINT_HALT*/
+ DBG("wmt_ep_set_halt() %s\n", ep ? ep->ep.name : NULL);
+
+ if (value) {
+ u8 temp32bytes[31];
+
+ memset(temp32bytes, 0, 31);
+ temp32bytes[0] = 0xEF;
+ temp32bytes[1] = 0xBE;
+ temp32bytes[2] = 0xAD;
+ temp32bytes[3] = 0xDE;
+
+ /*usb_ep_set_halt() - value == 1 stall*/
+
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ pDevReg->ControlEpControl |= EP_STALL;
+ break;
+
+ case 1:/*Bulk In*/
+ pDevReg->Bulk1EpControl |= EP_STALL;
+ break;
+
+ case 2:/*Bulk Out*/
+ pDevReg->Bulk2EpControl |= EP_STALL;
+ break;
+
+ case 3:/*Interrupt In*/
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl |= EP_STALL;
+#else
+ pDevReg->InterruptEpControl |= EP_STALL;
+#endif
+ break;
+
+ case 4:/*Iso In*/
+ pDevReg->Bulk3EpControl |= EP_STALL;
+ break;
+ }
+
+ ep->stall = 1;
+ /*DBG("wmt_ep_set_halt(1) HALT CSR(0x%08X)\n", *ep->reg_control_status);*/
+ status = 0;
+
+ if (memcmp(temp32bytes, (void *)ep->udc->cbw_virtual_address, 4) == 0)
+ udc->file_storage_set_halt = 1; /*forbid to CLEAR FEATURE*/
+ } else {/*usb_ep_clear_halt - value == 0 reset*/
+
+ /**ep->reg_control_status &= 0xFFFFFFFB;*/
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ pDevReg->ControlEpControl &= 0xF7;
+ break;
+
+ case 1:/*Bulk In*/
+ pDevReg->Bulk1EpControl &= 0xF7;
+ break;
+
+ case 2:/*Bulk Out*/
+ pDevReg->Bulk2EpControl &= 0xF7;
+ break;
+
+ case 3:/*Interrupt In*/
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl &= 0xF7;
+#else
+ pDevReg->InterruptEpControl &= 0xF7;
+#endif
+ break;
+
+ case 4:/*Iso In*/
+ pDevReg->Bulk3EpControl &= 0xF7;
+ break;
+ }
+
+ ep->stall = 0;
+ status = 0;
+ udc->file_storage_set_halt = 0;
+ }
+
+ VDBG("%s %s halt stat %d\n", ep->ep.name,
+ value ? "set" : "clear", status);
+ wmb();
+ spin_unlock_irqrestore(&ep->udc->lock, irq_flags);
+
+ return status;
+} /*static int wmt_ep_set_halt()*/
+
+static struct usb_ep_ops wmt_ep_ops = {
+ .enable = wmt_ep_enable,
+ .disable = wmt_ep_disable,
+
+ .alloc_request = wmt_alloc_request,
+ .free_request = wmt_free_request,
+
+// .alloc_buffer = wmt_alloc_buffer,
+// .free_buffer = wmt_free_buffer,
+
+ .queue = wmt_ep_queue,
+ .dequeue = wmt_ep_dequeue,
+
+ .set_halt = wmt_ep_set_halt,
+
+ /* fifo_status ... report bytes in fifo*/
+ /* fifo_flush ... flush fifo*/
+};
+
+#if 0
+static void
+wmt_udc_csr(struct vt8500_udc *udc)
+{
+ /* abolish any previous hardware state*/
+
+ DBG("wmt_udc_csr()\n");
+
+ if (udc->gadget.speed == USB_SPEED_FULL) {
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64);
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64);
+ } else if (udc->gadget.speed == USB_SPEED_HIGH) {
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512);
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512);
+ } else if (udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512);
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512);
+ }
+ //wmt_ep_setup_csr("ep3in""-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8);
+#ifdef USE_BULK3_TO_INTERRUPT
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28);
+#else
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8);
+#endif
+} /*wmt_udc_csr(void)*/
+#endif
+
+static int wmt_get_frame(struct usb_gadget *gadget)
+{
+ DBG("wmt_get_frame()\n");
+ return 0;
+}
+
+static int wmt_wakeup(struct usb_gadget *gadget)
+{
+ /*struct vt8500_udc *udc;*/
+ /*unsigned long flags;*/
+ int retval = 0;
+ DBG("wmt_wakeup()\n");
+/*
+ udc = container_of(gadget, struct vt8500_udc, gadget);
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ if (udc->devstat & UDC_SUS) {
+ // NOTE: OTG spec erratum says that OTG devices may
+ // issue wakeups without host enable.
+ //
+ if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) {
+ DBG("remote wakeup...\n");
+ UDC_SYSCON2_REG = UDC_RMT_WKP;
+ retval = 0;
+ }
+
+ // NOTE: non-OTG systems may use SRP TOO...
+ } else if (!(udc->devstat & UDC_ATT)) {
+ if (udc->transceiver)
+ retval = otg_start_srp(udc->transceiver->otg);
+ }
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+*/
+ return retval;
+}
+
+static int
+wmt_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ DBG("wmt_set_selfpowered()\n");
+/* struct vt8500_udc *udc;
+ unsigned long flags;
+ u16 syscon1;
+
+ udc = container_of(gadget, struct vt8500_udc, gadget);
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ syscon1 = UDC_SYSCON1_REG;
+ if (is_selfpowered)
+ syscon1 |= UDC_SELF_PWR;
+ else
+ syscon1 &= ~UDC_SELF_PWR;
+ UDC_SYSCON1_REG = syscon1;
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+*/
+ return 0;
+}
+
+
+void reset_ep(void)
+{
+#if 1
+ wmt_disable_fiq();
+ fiq_using = 0;
+
+ pDevReg->Bulk1EpControl = EP_DMALIGHTRESET;
+ while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET)
+ ;
+
+ pDevReg->Bulk2EpControl = EP_DMALIGHTRESET;
+ while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET)
+ ;
+
+ pDevReg->Bulk3EpControl = EP_DMALIGHTRESET;
+ while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET)
+ ;
+#else
+ pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+
+ pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+
+ pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+#endif
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk2DesStatus = 0x00;
+ pDevReg->Bulk3DesStatus = 0x00;
+
+ pDevReg->Bulk1DesTbytes0 = 0;
+ pDevReg->Bulk1DesTbytes1 = 0;
+ pDevReg->Bulk1DesTbytes2 = 0;
+
+ pDevReg->Bulk2DesTbytes0 = 0;
+ pDevReg->Bulk2DesTbytes1 = 0;
+ pDevReg->Bulk2DesTbytes2 = 0;
+
+ pDevReg->Bulk3DesTbytes0 = 0;
+ pDevReg->Bulk3DesTbytes1 = 0;
+ pDevReg->Bulk3DesTbytes2 = 0;
+
+ /* enable DMA and run the control endpoint*/
+ wmb();
+
+ pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA;
+#if 0
+ /* enable DMA and run the bulk endpoint*/
+ pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA;
+ pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA;
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA;
+#else
+ pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA;
+#endif
+#endif
+ /* enable DMA and run the interrupt endpoint*/
+ /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/
+ /* run the USB controller*/
+ pDevReg->MiscControl3 = 0x3d;
+ wmb();
+ pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/
+ pDevReg->CommandStatus = USBREG_RUNCONTROLLER;
+ wmb();
+ ControlState = CONTROLSTATE_SETUP;
+ USBState = USBSTATE_DEFAULT;
+ TestMode = 0;
+
+ /*status = wmt_udc_setup(odev, xceiv);*/
+ wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64);
+#if 1
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64);
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64);
+#if 0
+#ifdef USE_BULK3_TO_INTERRUPT
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28);
+#else
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8);
+#endif
+#endif
+#endif
+}
+
+void reset_udc(void)
+{
+/* if (!((*(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254))&0x00000080))*/
+/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) |= 0x00000080;*/ /*DPM needed*/
+
+pDevReg->CommandStatus |= USBREG_RESETCONTROLLER;
+ wmb();
+
+ if ((*(volatile unsigned char *)(USB_IP_BASE + 0x249))&0x04) {
+ *(volatile unsigned char*)(USB_IP_BASE + 0x249)&= ~0x04;
+ mdelay(1);
+ }
+
+ pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0);
+ *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/
+ /* reset Bulk descriptor control*/
+ wmb();
+
+ f_ep3_used = 0;
+ reset_ep();
+
+ pDevReg->SelfPowerConnect |= 0x10;//Neil
+ wmb();
+ /* enable all interrupt*/
+#ifdef FULL_SPEED_ONLY
+ pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/
+#else
+ pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/
+#endif
+ wmb();
+ /* set IOC on the Setup decscriptor to accept the Setup request*/
+ pDevReg->ControlDesControl = CTRLXFER_IOC;
+/*Neil_080731*/
+/* pullup_disable here and enable in /arch/arm/kernel/apm.c:395
+ apm_ioctl() to patch issue signal fail when resume when recive*/
+/* set_configuration time out.*/
+/* pullup_enable(udc);//usb_gadget_probe_driver()*/
+ wmb();
+ wmt_pdma_reset();
+
+// pullup_enable(udc);
+// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/
+/* pullup_disable(udc);*/
+/*Neil_080731*/
+
+}
+
+
+/*
+static int can_pullup(struct vt8500_udc *udc)
+{
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+*/
+static void pullup_disable(struct vt8500_udc *udc)
+{
+ INFO("pullup_disable()\n");
+ /*Hold port control's FSM from enter device mode.*/
+ //pDevReg->PhyMisc &= 0x0F;
+ //pDevReg->PhyMisc |= 0x10;
+ pDevReg->FunctionPatchEn &= (~0x20); /* HW attach process evaluation enable bit*/
+ wmb();
+ gadget_connect=0;
+
+ f_ep3_used = 0;
+ reset_ep();
+ wmt_pdma_reset();
+
+
+} /*static void pullup_disable()*/
+
+/*
+ * Called by whatever detects VBUS sessions: external transceiver
+ * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
+ */
+static int wmt_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ DBG("wmt_vbus_session()\n");
+ return 0;
+}
+
+static int wmt_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ DBG("wmt_vbus_draw()\n");
+ return -EOPNOTSUPP;
+}
+
+static int wmt_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct vt8500_udc *udc;
+// unsigned long flags;
+
+ DBG("wmt_pullup()\n");
+
+ udc = container_of(gadget, struct vt8500_udc, gadget);
+ down(&wmt_udc_sem);
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ udc->softconnect = (is_on != 0);
+// if (can_pullup(udc))
+
+ if (udc->softconnect)
+ pullup_enable(udc);
+ else {
+ pullup_disable(udc);
+ //run_script(action_off_line);
+ }
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ up(&wmt_udc_sem);
+
+ return 0;
+}
+
+void get_udc_sem (void)
+{
+ down(&wmt_udc_sem);
+}
+
+void release_udc_sem (void)
+{
+ up(&wmt_udc_sem);
+}
+
+static int wmt_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int wmt_udc_stop(struct usb_gadget_driver *driver);
+
+static struct usb_gadget_ops wmt_gadget_ops = {
+ .get_frame = wmt_get_frame,
+ .wakeup = wmt_wakeup,
+ .set_selfpowered = wmt_set_selfpowered,
+ .vbus_session = wmt_vbus_session,
+ .vbus_draw = wmt_vbus_draw,
+ .pullup = wmt_pullup,
+ .start = wmt_udc_start,
+ .stop = wmt_udc_stop,
+};
+
+/* dequeue ALL requests; caller holds udc->lock */
+static void nuke(struct vt8500_ep *ep, int status)
+{
+ struct vt8500_req *req;
+
+ DBG("nuke()\n");
+ ep->stopped = 1;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct vt8500_req, queue);
+ done(ep, req, status);
+ }
+} /*void nuke()*/
+
+/* caller holds udc->lock */
+static void udc_quiesce(struct vt8500_udc *udc)
+{
+ struct vt8500_ep *ep;
+ DBG("udc_quiesce()\n");
+
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->ep[0], -ESHUTDOWN);
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list)
+ nuke(ep, -ESHUTDOWN);
+} /*void udc_quiesce()*/
+
+/*
+static void update_otg(struct vt8500_udc *udc)
+{
+ u16 devstat;
+
+ if (!udc->gadget.is_otg)
+ return;
+
+ if (OTG_CTRL_REG & OTG_ID)
+ devstat = UDC_DEVSTAT_REG;
+ else
+ devstat = 0;
+
+ udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE);
+ udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT);
+ udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT);
+
+ // Enable HNP early, avoiding races on suspend irq path.
+ // ASSUMES OTG state machine B_BUS_REQ input is true.
+ //
+ if (udc->gadget.b_hnp_enable)
+ OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ)
+ & ~OTG_PULLUP;
+
+}//static void update_otg()
+*/
+
+
+/* define the prepare result codes*/
+#define RESPOK 0
+#define RESPFAIL 1
+u16 Control_Length; /* the length of transfer for current control transfer*/
+u16 Configure_Length;
+
+
+/*UDC_IS_SETUP_INT*/
+static void udc_control_prepare_data_resp(void)/*(struct vt8500_udc *udc, u32 udc_irq_src)*/
+{
+ struct vt8500_ep *ep0 = &udc->ep[0];
+ struct vt8500_req *req = 0;
+ /*UCHAR Result = RESPFAIL;*/
+ /*unsigned char CurXferLength = 0;*/
+ /*unsigned char Control_Length = 0;*/
+ int i;
+ u8 test_mode_enable = 0;
+
+ Configure_Length = 0;
+
+ /*ep0->irqs++;*/
+ DBG("ep0_irq()\n");
+ ep0->toggle_bit = 1;
+
+ if (!list_empty(&ep0->queue))
+ req = container_of(ep0->queue.next, struct vt8500_req, queue);
+
+ /* SETUP starts all control transfers*/
+ {
+ union u {
+ u8 bytes[8];
+ struct usb_ctrlrequest r;
+ } u;
+ int status = -EINVAL;
+ struct vt8500_ep *ep = &udc->ep[0];
+ int ep0_status_phase_0_byte = 0;
+
+ nuke(ep0, 0);
+ /* read the (latest) SETUP message*/
+ for (i = 0; i <= 7; i++)
+ u.bytes[i] = pSetupCommandBuf[i];
+
+ le32_to_cpus(&u.r.wValue);
+ le32_to_cpus(&u.r.wIndex);
+ le32_to_cpus(&u.r.wLength);
+
+ /* Delegate almost all control requests to the gadget driver,*/
+ /* except for a handful of ch9 status/feature requests that*/
+ /* hardware doesn't autodecode _and_ the gadget API hides.*/
+ /**/
+ udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0;
+ udc->ep0_set_config = 0;
+ udc->ep0_pending = 1;
+ udc->ep0_in_status = 0;
+
+ ep0->stopped = 0;
+ ep0->ackwait = 0;
+
+ if ((u.r.bRequestType & USB_RECIP_OTHER) == USB_RECIP_OTHER) {/*USB_RECIP_OTHER(0x03)*/
+ status = 0;
+
+ /*INFO("ep0_irq() setup command[0]=(0x%08X)\n",u.dword[0]);*/
+ /*INFO("ep0_irq() setup command[1]=(0x%08X)\n",u.dword[1]);*/
+ /*INFO("ep0_irq() address(%08X)", udc_reg->AddressControl);*/
+ goto delegate;
+ }
+
+ switch (u.r.bRequest) {
+ case USB_REQ_SET_CONFIGURATION:
+ /* udc needs to know when ep != 0 is valid*/
+ /*SETUP 00.09 v0001 i0000 l0000*/
+ if (u.r.bRequestType != USB_RECIP_DEVICE)/*USB_RECIP_DEVICE(0x00)*/
+ goto delegate;
+ if (u.r.wLength != 0)
+ goto do_stall;
+ udc->ep0_set_config = 1;
+ udc->ep0_reset_config = (u.r.wValue == 0);
+ VDBG("set config %d\n", u.r.wValue);
+
+ if (u.r.wValue == 0)
+ USBState = USBSTATE_ADDRESS;
+ else
+ USBState = USBSTATE_CONFIGED;
+ /* update udc NOW since gadget driver may start*/
+ /* queueing requests immediately; clear config*/
+ /* later if it fails the request.*/
+ /**/
+
+ udc->ep[0].toggle_bit = 0;
+ udc->ep[1].toggle_bit = 0;
+ udc->ep[2].toggle_bit = 0;
+ udc->ep[3].toggle_bit = 0;
+ udc->ep[4].toggle_bit = 0;
+ udc->ep[5].toggle_bit = 0;//gri
+ udc->ep[6].toggle_bit = 0;//gri
+
+
+ status = 0;
+ goto delegate;
+
+ /* Giga Hsu : 2007.6.6 This would cause set interface status 0
+ return to fast and cause bulk endpoint in out error*/
+ case USB_REQ_SET_INTERFACE:
+
+ VDBG("set interface %d\n", u.r.wValue);
+ status = 0;
+
+ udc->ep[0].toggle_bit = 0;
+ udc->ep[1].toggle_bit = 0;
+ udc->ep[2].toggle_bit = 0;
+ udc->ep[3].toggle_bit = 0;
+ udc->ep[4].toggle_bit = 0;
+ udc->ep[5].toggle_bit = 0;//gri
+ udc->ep[6].toggle_bit = 0;//gri
+
+ goto delegate;
+ /*break;*/
+
+ case USB_REQ_CLEAR_FEATURE:
+ /* clear endpoint halt*/
+
+ if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+ goto delegate;
+
+ if (u.r.wValue != USB_ENDPOINT_HALT
+ || u.r.wLength != 0)
+ goto do_stall;
+
+ ep = &udc->ep[u.r.wIndex & 0xf];
+
+ if (ep != ep0) {
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc)
+ goto do_stall;
+
+ if (udc->file_storage_set_halt == 0) {
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ pDevReg->ControlEpControl &= 0xF7;
+ break;
+
+ case 1:/*Bulk In*/
+
+ pDevReg->Bulk1EpControl &= 0xF7;
+ #ifdef MSC_COMPLIANCE_TEST
+ udc_bulk_dma_dump_register();
+ udc_device_dump_register();
+ #endif
+ if (ep->stall_more_processing == 1) {
+ u32 dma_ccr = 0;
+
+ ep->stall_more_processing = 0;
+ wmt_pdma0_reset();
+ wmt_udc_pdma_des_prepare(ep->temp_dcmd,
+ ep->temp_bulk_dma_addr,
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 1);
+
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk1DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk1DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk1DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (ep->ep_stall_toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk1DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk1DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk1DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ wmb();
+ pUdcDmaReg->DMA_Context_Control0 = dma_ccr; //neil
+ wmb();
+ pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE;
+ }
+ break;
+
+ case 2:/*Bulk Out*/
+ pDevReg->Bulk2EpControl &= 0xF7;
+
+ if (ep->stall_more_processing == 1) {
+ u32 dma_ccr = 0;
+ ep->stall_more_processing = 0;
+ wmt_pdma1_reset();
+ // wmt_pdma_reset();
+ wmt_udc_pdma_des_prepare(ep->temp_dcmd,
+ ep->temp_bulk_dma_addr,
+ DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1);
+ /* DMA Global Controller Reg*/
+ /* DMA Controller Enable +*/
+ /* DMA Global Interrupt Enable(if any TC, error,
+ or abort status in any channels occurs)*/
+
+ pDevReg->Bulk2DesStatus = 0x00;
+ pDevReg->Bulk2DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk2DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk2DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ if (ep->ep_stall_toggle_bit)
+ pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1;
+ else
+ pDevReg->Bulk2DesTbytes2 &= 0x3F;
+
+ pDevReg->Bulk2DesStatus = BULKXFER_IOC;
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+
+ /*udc_bulk_dma_dump_register();*/
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ dma_ccr |= DMA_TRANS_OUT_DIR;
+ wmb();
+ pUdcDmaReg->DMA_Context_Control1 = dma_ccr;
+ wmb();
+ pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE;
+ }
+ break;
+
+ case 3:/*Interrupt In*/
+#ifdef USE_BULK3_TO_INTERRUPT
+/*Bulk In*/
+
+ pDevReg->Bulk3EpControl &= 0xF7;
+ #ifdef MSC_COMPLIANCE_TEST
+ udc_bulk_dma_dump_register();
+ udc_device_dump_register();
+ #endif
+ if (ep->stall_more_processing == 1) {
+ u32 dma_ccr = 0;
+
+ ep->stall_more_processing = 0;
+ wmt_pdma2_reset();
+ wmt_udc_pdma_des_prepare(ep->temp_dcmd,
+ ep->temp_bulk_dma_addr,
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (ep->ep_stall_toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk3DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk3DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ wmb();
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil
+ wmb();
+ pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE;
+ }
+
+#else
+/*Interrupt In*/
+ pDevReg->InterruptEpControl &= 0xF7;
+#endif
+ break;
+
+ case 4:/*Iso In*/
+
+ pDevReg->Bulk3EpControl &= 0xF7;
+ #ifdef MSC_COMPLIANCE_TEST
+ udc_bulk_dma_dump_register();
+ udc_device_dump_register();
+ #endif
+ if (ep->stall_more_processing == 1) {
+ u32 dma_ccr = 0;
+
+ ep->stall_more_processing = 0;
+ wmt_pdma2_reset();
+ wmt_udc_pdma_des_prepare(ep->temp_dcmd,
+ ep->temp_bulk_dma_addr,
+ DESCRIPTOT_TYPE_LONG, TRANS_IN, 0);
+
+ pDevReg->Bulk3DesStatus = 0x00;
+ pDevReg->Bulk3DesTbytes2 |=
+ (ep->temp_dcmd >> 16) & 0x3;
+ pDevReg->Bulk3DesTbytes1 =
+ (ep->temp_dcmd >> 8) & 0xFF;
+ pDevReg->Bulk3DesTbytes0 =
+ ep->temp_dcmd & 0xFF;
+
+ /* set endpoint data toggle*/
+ if (ep->ep_stall_toggle_bit) {
+ /* BULKXFER_DATA1;*/
+ pDevReg->Bulk3DesTbytes2 |= 0x40;
+ } else {
+ /*(~BULKXFER_DATA1);*/
+ pDevReg->Bulk3DesTbytes2 &= 0xBF;
+ }
+
+ pDevReg->Bulk3DesStatus =
+ (BULKXFER_IOC | BULKXFER_IN);
+
+ /* DMA Channel Control Reg*/
+ /* Software Request + Channel Enable*/
+ dma_ccr = 0;
+ dma_ccr = DMA_RUN;
+ wmb();
+ pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil
+ wmb();
+ pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE;
+ }
+
+ break;
+
+ }
+
+ ep->stall = 0;
+ ep->stopped = 0;
+ /**ep->reg_irp_descriptor = ep->temp_irp_descriptor;*/
+ }
+ } /*if (ep != ep0)*/
+
+ ep0_status_phase_0_byte = 1;
+ VDBG("%s halt cleared by host\n", ep->name);
+ /*goto ep0out_status_stage;*/
+ status = 0;
+ udc->ep0_pending = 0;
+ /*break;*/
+ goto delegate;
+
+ case USB_REQ_SET_FEATURE:
+ /* set endpoint halt*/
+
+ if ((u.r.wValue == USB_DEVICE_TEST_MODE)) {/*(USBState == USBSTATE_DEFAULT) &&*/
+ TestMode = (UCHAR)(u.r.wIndex >> 8);
+ test_mode_enable = 1;
+ INFO("USB_REQ_SET_FEATURE - TestMode (0x%02X)\n", TestMode);
+
+ /*ControlState = CONTROLSTATE_STATUS;*/
+ ep0_status_phase_0_byte = 1;
+ status = 0;
+ break;
+ }
+
+ if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+ goto delegate;
+
+ if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0)
+ goto do_stall;
+
+ ep = &udc->ep[u.r.wIndex & 0xf];
+
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc)
+ goto do_stall;
+
+ wmb();
+ switch ((ep->bEndpointAddress & 0x7F)) {
+ case 0:/*Control In/Out*/
+ pDevReg->ControlEpControl |= EP_STALL;
+ break;
+
+ case 1:/*Bulk In*/
+ pDevReg->Bulk1EpControl |= EP_STALL;
+ break;
+
+ case 2:/*Bulk Out*/
+ pDevReg->Bulk2EpControl |= EP_STALL;
+ break;
+
+ case 3:
+#ifdef USE_BULK3_TO_INTERRUPT
+ /*Bulk Out*/
+ pDevReg->Bulk3EpControl |= EP_STALL;
+#else
+ /*Interrupt In*/
+ pDevReg->InterruptEpControl |= EP_STALL;
+#endif
+ break;
+
+ case 4:
+ /*Bulk Out*/
+ pDevReg->Bulk3EpControl |= EP_STALL;
+ break;
+ }
+ wmb();
+ ep->stall = 1;
+ ep->stopped = 1;
+
+ ep0_status_phase_0_byte = 1;
+ /*use_ep(ep, 0);*/
+ /* can't halt if fifo isn't empty...*/
+ /*UDC_CTRL_REG = UDC_CLR_EP;*/
+ /*UDC_CTRL_REG = UDC_SET_HALT;*/
+ VDBG("%s halted by host\n", ep->name);
+ /*ep0out_status_stage:*/
+ status = 0;
+
+ udc->ep0_pending = 0;
+ /*break;*/
+ goto delegate;
+
+ case USB_REQ_GET_STATUS:
+ /* return interface status. if we were pedantic,*/
+ /* we'd detect non-existent interfaces, and stall.*/
+ /**/
+
+ if (u.r.bRequestType == (USB_DIR_IN|USB_RECIP_ENDPOINT)) {
+ ep = &udc->ep[u.r.wIndex & 0xf];
+
+ if (ep->stall == 1) {
+ udc->ep0_in_status = 0x01;
+
+ /*GgiaHsu-B 2007.08.10 : patch HW Bug :
+ MSC Compliance Test : Error Recovery Items.*/
+ ep = &udc->ep[3];
+ if ((udc->file_storage_set_halt == 1) && (ep->stall == 1))
+ ep->stall = 1;
+ /*GgiaHsu-E 2007.08.10 :
+ --------------------------------------------*/
+
+ ep = &udc->ep[0];
+ ep->stall = 0;
+ } else
+ udc->ep0_in_status = 0x00;
+
+ VDBG("GET_STATUS, interface wIndex(0x%02X) ep0_in_status(0x%04X)\n"
+ , u.r.wIndex, udc->ep0_in_status);
+ } else
+ udc->ep0_in_status = 0x00;
+
+ /* return two zero bytes*/
+ status = 0;
+
+ /* next, status stage*/
+ goto delegate;
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ if (u.r.bRequestType == USB_RECIP_DEVICE) { /*USB_RECIP_DEVICE(0x00)*/
+ if (USBState == USBSTATE_DEFAULT) {
+ if (u.r.wValue != 0)
+ USBState = USBSTATE_ADDRESS;
+ } else if (USBState == USBSTATE_ADDRESS) {
+ if (u.r.wValue == 0)
+ USBState = USBSTATE_DEFAULT;
+ }
+
+ pDevReg->DeviceAddr |= (DEVADDR_ADDRCHANGE | u.r.wValue);
+ VDBG("USB_REQ_SET_ADDRESS 0x%03d\n", u.r.wValue);
+ ControlState = CONTROLSTATE_STATUS;
+ ep0_status_phase_0_byte = 1;
+ status = 0;
+ }
+ break;
+
+ case USB_BULK_RESET_REQUEST:
+
+ VDBG("USB_BULK_RESET_REQUEST\n");
+ udc->file_storage_set_halt = 0;
+
+ udc->ep[0].toggle_bit = 0;
+ udc->ep[1].toggle_bit = 0;
+ udc->ep[2].toggle_bit = 0;
+ udc->ep[3].toggle_bit = 0;
+ udc->ep[4].toggle_bit = 0;
+ udc->ep[5].toggle_bit = 0;//gri
+ udc->ep[6].toggle_bit = 0;//gri
+
+ status = 0;
+
+ goto delegate;
+ /*break;*/
+
+ default:
+delegate:
+ VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+ u.r.bRequestType, u.r.bRequest,
+ u.r.wValue, u.r.wIndex, u.r.wLength);
+ /*
+ // The gadget driver may return an error here,
+ // causing an immediate protocol stall.
+ //
+ // Else it must issue a response, either queueing a
+ // response buffer for the DATA stage, or halting ep0
+ // (causing a protocol stall, not a real halt). A
+ // zero length buffer means no DATA stage.
+ //
+ // It's fine to issue that response after the setup()
+ // call returns, and this IRQ was handled.
+ //
+ */
+ udc->ep0_setup = 1;
+
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ /*usb gadget driver prepare setup data phase(control in)*/
+ status = udc->driver->setup(&udc->gadget, &u.r); /*usb_gadget_driver->setup()*/
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ udc->ep0_setup = 0;
+ } /*switch (u.r.bRequest)*/
+
+ if (ep0_status_phase_0_byte == 1) {/* && (udc->ep[0].stall==0))*/
+ udc->ep0_status_0_byte = 1;
+ if (test_mode_enable == 1)
+ ep0_status(udc);
+ }
+
+ if (status < 0) {
+do_stall:
+ /* ep = &udc->ep[0];*/
+ /**ep->reg_control_status |= UDC_EP0_STALL;*/
+ /* fail in the command parsing*/
+ pDevReg->ControlEpControl |= EP_STALL; /* stall the pipe*/
+ wmb();
+ ControlState = CONTROLSTATE_SETUP; /* go back to setup state*/
+
+ ep->stall = 1;
+ DBG("Setup Command STALL : req %02x.%02x protocol STALL; stat %d\n",
+ u.r.bRequestType, u.r.bRequest, status);
+
+ udc->ep0_pending = 0;
+ } /*if (status < 0)*/
+ } /*if (udc_irq_src & UDC_IS_SETUP_INT)*/
+} /*udc_control_prepare_data_resp()*/
+
+#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT)
+
+static void devstate_irq(struct vt8500_udc *udc, u32 port0_status)
+{
+ udc->usb_connect = 0;
+
+ if (pDevReg->IntEnable & INTENABLE_DEVICERESET) {
+ /*vt3357 hw issue : clear all device register.*/
+ /*payload & address needs re-set again...*/
+ pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT;
+ VDBG("devstate_irq() - Global Reset...\n");
+//printk("[devstate_irq]0xd8009834 = 0x%8.8x\n",*(volatile unsigned int *)(USB_IP_BASE+0x2034));
+
+ if (udc->driver) {
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+// ppudc = udc;
+// run_script(action_off_line);
+// udc->driver->disconnect(&udc->gadget);
+ }
+
+ udc->ep0_set_config = 0;
+ pDevReg->Bulk1DesStatus = 0;
+
+ udc->ep[0].toggle_bit = 0;
+ udc->ep[1].toggle_bit = 0;
+ udc->ep[2].toggle_bit = 0;
+ udc->ep[3].toggle_bit = 0;
+ udc->ep[4].toggle_bit = 0;
+ udc->ep[5].toggle_bit = 0;//gri
+ udc->ep[6].toggle_bit = 0;//gri
+
+
+ udc->ep[0].rndis = 0;
+ udc->ep[1].rndis = 0;
+ udc->ep[2].rndis = 0;
+ udc->ep[3].rndis = 0;
+ udc->ep[4].rndis = 0;
+ udc->ep[5].rndis = 0;//gri
+ udc->ep[6].rndis = 0;//gri
+
+ udc->file_storage_set_halt = 0;
+ udc->bulk_out_dma_write_error = 0;
+
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ wmt_pdma_reset();
+
+ gadget_connect=0;
+ /*vt8500_usb_device_reg_dump();*/
+
+ } /*if (pDevReg->IntEnable & INTENABLE_DEVICERESET)*/
+
+ if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT) {
+ VDBG("devstate_irq() - Global Suspend...\n");
+ pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT;
+
+
+
+ } /*if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT)*/
+
+ if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT) {
+ pDevReg->IntEnable |= INTENABLE_RESUMEDETECT;
+ VDBG("devstate_irq() - Global Resume...\n");
+
+ } /*if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT)*/
+
+/*#ifdef UDC_A1_SELF_POWER_ENABLE*/
+ /* USB Bus Connection Change*/
+ /* clear connection change event*/
+ if (pDevReg->PortControl & PORTCTRL_SELFPOWER)/* Device port control register - 22)*/
+ if (pDevReg->PortControl & PORTCTRL_CONNECTCHANGE)/* Device port control register - 22)*/
+ pDevReg->PortControl |= PORTCTRL_CONNECTCHANGE;/* 0x02 // connection change bit*/
+
+/*#endif*/
+
+ if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) {
+ udc->gadget.speed = USB_SPEED_FULL;
+ udc->usb_connect = 1;
+ /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/
+ /*after host controller connected.*/
+ VDBG("devstate_irq() - full speed host connect...\n");
+ } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/
+
+ if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) {
+ udc->gadget.speed = USB_SPEED_HIGH;
+ udc->usb_connect = 1;
+ /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/
+ /*after host controller connected.*/
+ VDBG("devstate_irq() - high speed host connect...\n");
+ } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/
+
+} /*static void devstate_irq()*/
+
+void USB_ControlXferComplete(void)
+{
+ struct vt8500_ep *ep;
+ struct vt8500_req *req;
+
+ ep = &udc->ep[0];
+ /* when ever a setup received, the Control state will reset*/
+ /* check for the valid bit of the contol descriptor*/
+ /*DBG("USB_ControlXferComplete()\n");*/
+ if (pDevReg->ControlDesControl & CTRLXFER_CMDVALID) {
+ ep->toggle_bit = 1;
+ if (udc->usb_connect == 0) {
+ if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) {
+ udc->gadget.speed = USB_SPEED_FULL;
+ udc->usb_connect = 1;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/
+ /*after host controller connected.*/
+ //wmt_udc_csr(udc);
+ VDBG("devstate_irq() - full speed host connect...\n");
+ USBState = USBSTATE_DEFAULT;
+ } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/
+
+ if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) {
+ udc->gadget.speed = USB_SPEED_HIGH;
+ udc->usb_connect = 1;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/
+ /*after host controller connected.*/
+ //wmt_udc_csr(udc);
+ VDBG("devstate_irq() - high speed host connect...\n");
+ USBState = USBSTATE_DEFAULT;
+ } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/
+ }
+ /* HP11_Begin*/
+ /* clear the command valid bit*/
+ /* pDevReg->ControlDesControl |= CTRLXFER_CMDVALID;*/
+ /* always clear control stall when SETUP received*/
+ pDevReg->ControlEpControl &= 0x17; /* clear the stall*/
+ wmb();
+ ControlState = CONTROLSTATE_DATA;
+ udc_control_prepare_data_resp(); /*processing SETUP command ...*/
+ pDevReg->ControlDesControl &= 0xEF;/*(~CTRLXFER_CMDVALID);*/
+ wmb();
+ /*HP11_End*/
+ return;
+ }
+
+ if (udc->ep0_in) {
+ /* IN dma: tx to host*/
+ if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ VDBG("dma_irq : finish_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL);
+ finish_in_dma(ep, req, 0);
+ }
+
+ while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/
+ ;
+ if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ VDBG("dma_irq : next_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL);
+ next_in_dma(ep, req);
+ }
+ } else {/*ep0 out*/
+ /* OUT dma: rx from host*/
+ if (!list_empty(&ep->queue)) {
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ finish_out_dma(ep, req, 0);
+ }
+
+ while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/
+ ;
+ if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/
+ req = container_of(ep->queue.next, struct vt8500_req, queue);
+ next_out_dma(ep, req);
+ }
+ }
+
+} /*void USB_ControlXferComplete(void)*/
+static irqreturn_t
+wmt_udc_dma_irq(int irq, void *_udc)//, struct pt_regs *r)
+{
+ irqreturn_t status = IRQ_NONE;
+ u32 bulk_dma_csr;
+
+ bulk_dma_csr = pUdcDmaReg->DMA_ISR;
+ /*printk("[udc_dma_isr]dma int_sts = 0x%8.8x\n",pUdcDmaReg->DMA_ISR);*/
+
+ if (bulk_dma_csr & DMA_INTERRUPT_STATUS0) {
+ /* printk("[udc_dma_isr]channel0 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control0);*/
+ pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS0;
+ status = IRQ_HANDLED;
+ }
+
+ if (bulk_dma_csr & DMA_INTERRUPT_STATUS1) {
+ /* printk("[udc_dma_isr]channel1 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control1);*/
+ pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS1;
+ status = IRQ_HANDLED;
+ }
+
+ if (bulk_dma_csr & DMA_INTERRUPT_STATUS2) {
+ /* printk("[udc_dma_isr]channel2 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control2);*/
+ pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS2;
+ //printk("iso dma hit\n");
+ dma_irq(0x84);
+ status = IRQ_HANDLED;
+ }
+ return status;
+}
+
+static irqreturn_t
+wmt_udc_irq(int irq, void *_udc)//, struct pt_regs *r)
+{
+ struct vt8500_udc *udc = _udc;
+ u32 udc_irq_src;
+ irqreturn_t status = IRQ_NONE;
+// unsigned long flags;
+#ifdef OTGIP
+ u32 global_irq_src;
+#endif
+ /*u32 i;*/
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+
+ DBG("wmt_udc_irq()\n");
+
+#ifdef OTGIP
+ /*Global Interrupt Status*/
+ global_irq_src = pGlobalReg->UHDC_Interrupt_Status;
+
+ if (global_irq_src & UHDC_INT_UDC) {/*UDC Core + UDC DMA1 + UDC DMA2 */
+ if (global_irq_src & UHDC_INT_UDC_CORE) {/*UDC Core*/
+#endif
+ /*connection interrupt*/
+ if (pDevReg->SelfPowerConnect & 0x02) {
+ //struct usb_gadget_driver *driver = udc->driver;
+
+ if (pDevReg->SelfPowerConnect & 0x01) //connect
+ {
+// wmt_pdma_reset();
+reset_udc();
+//pullup_enable(udc);
+ }
+ else {//disconnct
+// spin_unlock_irqrestore(&udc->lock, irq_flags);
+// if (udc->driver)
+// udc->driver->disconnect(&udc->gadget);
+// ppudc = udc;
+ printk(KERN_INFO "disconnect 1\n"); //gri
+ run_script(action_off_line);
+ gadget_connect=0;
+
+// pullup_disable(udc);
+
+ }
+
+ status = IRQ_HANDLED;
+ pDevReg->SelfPowerConnect |= 0x02;
+ }
+ wmb();
+ /* Device Global Interrupt Pending Status*/
+ udc_irq_src = pDevReg->CommandStatus;
+
+ /* Device state change (usb ch9 stuff)*/
+ if (udc_irq_src & USBREG_BUSACTINT) {/* the bus activity interrupt occured*/
+ /*caused by Port 0 Statsu Change*/
+ devstate_irq(_udc, udc_irq_src);
+ status = IRQ_HANDLED;
+ pDevReg->CommandStatus |= USBREG_BUSACTINT;
+ wmb();
+ }
+
+ if (udc_irq_src & USBREG_BABBLEINT) {/* the Babble interrupt ocuured*/
+ /* check for Control endpoint for BABBLE error*/
+ if (pDevReg->ControlEpControl & EP_BABBLE) {
+ /* the Control endpoint is encounted the babble error*/
+ /* stall the endpoint and clear the babble condition*/
+ pDevReg->ControlEpControl |= (EP_BABBLE + EP_STALL);
+ INFO("vt8430_udc_irq() - EP0 Babble Detect!\n");
+ udc->ep[0].stopped = 1;
+ udc->ep[0].stall = 1;
+ }
+
+ if (pDevReg->Bulk1EpControl & EP_BABBLE) {
+ /* the Bulk endpoint is encounted the babble error*/
+ /* stall the endpoint and clear the babble condition*/
+ pDevReg->Bulk1EpControl |= (EP_BABBLE + EP_STALL);
+ INFO("vt8430_udc_irq() - EP1 Babble Detect!\n");
+ udc->ep[1].stopped = 1;
+ udc->ep[1].stall = 1;
+ }
+
+ if (pDevReg->Bulk2EpControl & EP_BABBLE) {
+ /* the Bulk endpoint is encounted the babble error*/
+ /* stall the endpoint and clear the babble condition*/
+ pDevReg->Bulk2EpControl |= (EP_BABBLE + EP_STALL);
+ INFO("vt8430_udc_irq() - EP2 Babble Detect!\n");
+ udc->ep[2].stopped = 1;
+ udc->ep[2].stall = 1;
+ }
+
+ if (pDevReg->Bulk3EpControl & EP_BABBLE) {
+ /* the Bulk endpoint is encounted the babble error*/
+ /* stall the endpoint and clear the babble condition*/
+ pDevReg->Bulk3EpControl |= (EP_BABBLE + EP_STALL);
+ INFO("vt8430_udc_irq() - EP3 Babble Detect!\n");
+ udc->ep[3].stopped = 1;
+ udc->ep[3].stall = 1;
+ }
+ wmb();
+ status = IRQ_HANDLED;
+ }
+
+ if (udc_irq_src & USBREG_COMPLETEINT) {/* the complete inerrupt occured*/
+ if (pDevReg->ControlEpControl & EP_COMPLETEINT) {
+ /* the control transfer complete event*/
+ pDevReg->ControlEpControl |= EP_COMPLETEINT; /* clear the event*/
+ wmb();
+ USB_ControlXferComplete();
+#if 0
+ gadget_connect=1;
+#endif
+
+ }
+
+ if (pDevReg->Bulk1EpControl & EP_COMPLETEINT) {
+ /* the bulk transfer complete event*/
+ pDevReg->Bulk1EpControl |= EP_COMPLETEINT;
+ wmb();
+ /*DBG("USB_Bulk 1 DMA()\n");*/
+ dma_irq(0x81);
+#if 1
+ gadget_connect=1;
+#endif
+ }
+
+ if (pDevReg->Bulk2EpControl & EP_COMPLETEINT) {
+ /* the bulk transfer complete event*/
+ pDevReg->Bulk2EpControl |= EP_COMPLETEINT;
+ wmb();
+ /*DBG("USB_Bulk 2 DMA()\n");*/
+ dma_irq(2);
+#if 1
+ gadget_connect=1;
+#endif
+ }
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ if (pDevReg->Bulk3EpControl & EP_COMPLETEINT) {
+ /* the bulk transfer complete event*/
+ pDevReg->Bulk3EpControl |= EP_COMPLETEINT;
+ wmb();
+ /*DBG("USB_Bulk 3 DMA()\n");*/
+ dma_irq(0x83);
+#if 1
+ gadget_connect=1;
+#endif
+ }
+#else
+ if (pDevReg->InterruptEpControl & EP_COMPLETEINT) {
+ /* the bulk transfer complete event*/
+ pDevReg->InterruptEpControl |= EP_COMPLETEINT;
+ /*DBG("USB_INT 3 DMA()\n");*/
+ if (f_ep3_used == 3)
+ dma_irq(0x83);
+#if 1
+ gadget_connect=1;
+#endif
+ }
+#endif
+ status = IRQ_HANDLED;
+ }
+
+ if (udc->ep0_status_0_byte == 1)/* && (udc_ep[0].stall==0))*/
+ ep0_status(udc);
+
+ if (ControlState == CONTROLSTATE_STATUS) {
+ /* checking for test mode*/
+ if (TestMode != 0x00) {
+#if 0
+ pDevReg->CommandStatus &= 0x1F;
+ wmb();
+ pDevReg->CommandStatus |= USBREG_RESETCONTROLLER;
+ while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER)
+ ;
+ /* HW attach process evaluation enable bit*/
+#if 0
+ pDevReg->FunctionPatchEn |= 0x20;
+ /* Device port control register - 22*/
+ pDevReg->PortControl |= PORTCTRL_SELFPOWER;
+ wmb();
+#else
+ pullup_enable(udc);
+ pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/
+ wmb();
+ //msleep(1000);
+#endif
+#endif
+ wmb();
+ udelay(1000);
+ /*GigaHsu 2008.1.26 : Don't set RUN bit while TestMode enable*/
+ /* setting the test mode*/
+ switch (TestMode) {
+ case UDC_TEST_MODE_NOT_ENABLED:/*0*/
+ INFO("UDC_TEST_MODE_NOT_ENABLED (0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_J_STATE:/*1*/
+ pDevReg->CommandStatus = USBREG_TEST_J;
+ INFO("UDC_TEST_J_STATE wIndex(0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_K_STATE:/*2*/
+ pDevReg->CommandStatus = USBREG_TEST_K;
+ INFO("UDC_TEST_K_STATE wIndex(0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_SE0_NAK:/*3*/
+ pDevReg->CommandStatus = USBREG_SE0_NAK;
+ INFO("UDC_TEST_SE0_NAK wIndex(0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_PACKET:/*4*/
+ pDevReg->CommandStatus = USBREG_TESTPACKET;
+ INFO("UDC_TEST_PACKET wIndex(0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_FRORCE_ENABLE:/*5*/
+ pDevReg->CommandStatus = USBREG_FORCEENABLE;
+ INFO("UDC_TEST_FRORCE_ENABLE wIndex(0x%02X)\n", TestMode);
+ break;
+
+ case UDC_TEST_EYE_PATTERN:/*6*/
+ pDevReg->CommandStatus = USBREG_TESTEYE;
+ INFO("UDC_TEST_EYE_PATTERN wIndex(0x%02X)\n", TestMode);
+ break;
+ } /*switch(TestMode)*/
+
+ INFO("UDC - CommandStatus(0x%02X)\n", pDevReg->CommandStatus);
+ /* stop the 8051*/
+ /*ChipTopRegister.Config |= CT_STOP8051;*/
+ }
+ ControlState = CONTROLSTATE_SETUP; /* go back SETUP state*/
+ }
+#ifdef OTGIP
+ }
+
+ global_irq_src = pGlobalReg->UHDC_Interrupt_Status;
+ if (global_irq_src & UHDC_INT_UDC_DMA1)/*UDC Bulk DMA 1*/
+ status = wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r);
+
+// if (global_irq_src & UHDC_INT_UDC_DMA2)/*UDC Bulk DMA 1*/
+// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r);
+
+// if (global_irq_src & UHDC_INT_UDC_DMA3)/*UDC Bulk DMA 1*/
+// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r);
+
+ }
+#endif
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ //printk("udc s =0x%x\n",pGlobalReg->UHDC_Interrupt_Status);
+
+ return status;
+} /*wmt_udc_irq()*/
+
+/* workaround for seemingly-lost IRQs for RX ACKs... */
+#define PIO_OUT_TIMEOUT (jiffies + HZ/3)
+
+#ifdef DEBUG_UDC_ISR_TIMER
+static void wmt_udc_softirq(unsigned long _udc)
+{
+ struct vt8500_udc *udc = (void *) _udc;
+ /*unsigned long flags;*/
+ struct pt_regs r;
+
+ INFO("wmt_udc_softirq()\n");
+ wmt_udc_irq(UDC_IRQ_USB, udc, &r);
+ mod_timer(&udc->timer, PIO_OUT_TIMEOUT);
+
+}
+#endif
+
+static void __init wmt_ep_setup(char *name, u8 addr, u8 type, unsigned maxp);
+
+static int wmt_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+
+{
+ int status = -ENODEV;
+ struct vt8500_ep *ep;
+// unsigned long flags;
+
+ DBG("wmt_udc_start()\n");
+
+ /* basic sanity tests */
+ if (!udc)
+ return -ENODEV;
+ if (!driver
+ /* FIXME if otg, check: driver->is_otg*/
+ || driver->max_speed < USB_SPEED_FULL
+ || !bind
+// || !driver->unbind
+ || !driver->setup){
+// printk(KERN_INFO "gri usb_gadget_probe_driver f2\n");
+// printk(KERN_INFO "gri driver=%x driver->speed=%x driver->bind=%x driver->unbind=%x driver->setup=%x\n",
+// (unsigned int)driver,(unsigned int)driver->speed,(unsigned int)driver->bind,(unsigned int)driver->unbind,(unsigned int)driver->setup);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ if (udc->driver) {
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ return -EBUSY;
+ }
+
+ /* reset state */
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ ep->irqs = 0;
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+ continue;
+ /*use_ep(ep, 0);*/
+ /*UDC_CTRL_REG = UDC_SET_HALT;*/
+ }
+ udc->ep0_pending = 0;
+ udc->ep0_status_0_byte = 0;
+ udc->ep[0].irqs = 0;
+ udc->softconnect = 1;
+ udc->file_storage_set_halt = 0;
+ /* hook up the driver */
+ driver->driver.bus = 0;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+
+ status = bind(&udc->gadget);
+ spin_lock_irqsave(&udc->lock, irq_flags);
+printk(KERN_INFO "bind to %s --> %d\n", driver->driver.name, status);
+
+ if (status) {
+ /* %s -> g_file_storage*/
+ DBG("bind to %s --> %d\n", driver->driver.name, status);
+// printk(KERN_INFO "gri usb_gadget_probe_driver %d\n", status);
+ udc->gadget.dev.driver = 0;
+ udc->driver = 0;
+ goto done;
+ }
+
+ DBG("bound to driver %s\n", driver->driver.name);/*udc: bound to driver g_file_storage*/
+ pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0);
+
+ *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/
+ wmb();
+#if 0
+ /* reset Bulk descriptor control*/
+ pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk1EpControl & EP_ACTIVE)
+ ; /* wait the DMA stopped*/
+
+ pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk2EpControl & EP_ACTIVE)
+ ; /* wait the DMA stopped*/
+
+ pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/
+ while (pDevReg->Bulk3EpControl & EP_ACTIVE)
+ ; /* wait the DMA stopped*/
+
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk2DesStatus = 0x00;
+ pDevReg->Bulk3DesStatus = 0x00;
+
+ pDevReg->Bulk1DesTbytes0 = 0;
+ pDevReg->Bulk1DesTbytes1 = 0;
+ pDevReg->Bulk1DesTbytes2 = 0;
+
+ pDevReg->Bulk2DesTbytes0 = 0;
+ pDevReg->Bulk2DesTbytes1 = 0;
+ pDevReg->Bulk2DesTbytes2 = 0;
+
+ pDevReg->Bulk3DesTbytes0 = 0;
+ pDevReg->Bulk3DesTbytes1 = 0;
+ pDevReg->Bulk3DesTbytes2 = 0;
+
+ /* enable DMA and run the control endpoint*/
+ pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA;
+ /* enable DMA and run the bulk endpoint*/
+ pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA;
+ pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA;
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA;
+#else
+ pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA;
+#endif
+#endif
+ /* enable DMA and run the interrupt endpoint*/
+ /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/
+ /* run the USB controller*/
+ pDevReg->MiscControl3 = 0x3d;
+
+
+ pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/
+ wmb();
+ pDevReg->CommandStatus = USBREG_RUNCONTROLLER;
+ wmb();
+
+ ControlState = CONTROLSTATE_SETUP;
+ USBState = USBSTATE_DEFAULT;
+ TestMode = 0;
+
+ wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64);
+#if 0
+ wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512);
+ wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512);
+#ifdef USE_BULK3_TO_INTERRUPT
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28);
+#else
+ wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8);
+#endif
+ wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISO, 384);
+#endif
+
+ /* enable all interrupt*/
+#ifdef FULL_SPEED_ONLY
+ pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/
+#else
+ pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/
+#endif
+ /* set IOC on the Setup decscriptor to accept the Setup request*/
+ pDevReg->ControlDesControl = CTRLXFER_IOC;
+ wmt_pdma_reset();/*NeilChen*/
+
+// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/
+
+#ifdef DEBUG_UDC_ISR_TIMER
+ init_timer(&udc->timer);
+ udc->timer.function = wmt_udc_softirq;
+ udc->timer.data = (unsigned long) udc;
+ add_timer(&udc->timer);
+#endif
+
+done:
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+ return status;
+} /*int wmt_udc_start ()*/
+
+static int wmt_udc_stop(struct usb_gadget_driver *driver)
+{
+// unsigned long flags;
+ int status = -ENODEV;
+
+ if (!udc)
+ return -ENODEV;
+ if (!driver || driver != udc->driver)
+ return -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, irq_flags);
+ udc_quiesce(udc);
+ spin_unlock_irqrestore(&udc->lock, irq_flags);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = 0;
+ udc->driver = 0;
+
+ pDevReg->IntEnable &= 0x8F;/*INTENABLE_ALL(0x70)*/
+ /* set IOC on the Setup decscriptor to accept the Setup request*/
+ pDevReg->ControlDesControl &= 0x7F;/*CTRLXFER_IOC;*/
+
+ if (udc->transceiver)
+ (void) otg_set_peripheral(udc->transceiver->otg, NULL);
+ else {
+ pullup_disable(udc);
+// pDevReg->FunctionPatchEn &= ~0x20;
+ }
+
+ if (TestMode != 0x00) {
+ pDevReg->CommandStatus &= 0x1F;
+
+ pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0);
+ *pUSBMiscControlRegister5 = 0x00;/* USB PHY in power down & USB in reset*/
+
+ INFO("usb_gadget_unregister_driver() RESET_UDC OK!\n");
+ TestMode = 0;
+ }
+
+ DBG("unregistered driver '%s'\n", driver->driver.name);
+ return status;
+} /*int wmt_udc_stop ()*/
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_vt8500_PROC
+
+#include <linux/seq_file.h>
+
+static const char proc_filename[] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void proc_ep_show(struct seq_file *s, struct vt8500_ep *ep)
+{
+
+} /*proc_ep_show()*/
+
+
+static char *trx_mode(unsigned m)
+{
+ switch (m) {
+ case 3:
+ case 0: return "6wire";
+ case 1: return "4wire";
+ case 2: return "3wire";
+ default: return "unknown";
+ }
+}
+
+static int proc_udc_show(struct seq_file *s, void *_)
+{
+ return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_udc_show, 0);
+}
+
+static struct file_operations proc_ops = {
+ .open = proc_udc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void create_proc_file(void)
+{
+ struct proc_dir_entry *pde;
+
+ pde = create_proc_entry(proc_filename, 0, NULL);
+ if (pde)
+ pde->proc_fops = &proc_ops;
+}
+
+static void remove_proc_file(void)
+{
+ remove_proc_entry(proc_filename, 0);
+}
+
+#else
+
+static inline void create_proc_file(void) {}
+static inline void remove_proc_file(void) {}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* Before this controller can enumerate, we need to pick an endpoint
+ * configuration, or "fifo_mode" That involves allocating 2KB of packet
+ * buffer space among the endpoints we'll be operating.
+ */
+static void __init
+wmt_ep_setup(char *name, u8 addr, u8 type,
+ unsigned maxp)
+{
+ struct vt8500_ep *ep;
+
+ VDBG("wmt_ep_setup()\n");
+
+ /* OUT endpoints first, then IN*/
+ ep = &udc->ep[addr & 0x7f];
+
+ VDBG("wmt_ep_setup() - %s addr %02x maxp %d\n",
+ name, addr, maxp);
+
+ strlcpy(ep->name, name, sizeof ep->name);
+ INIT_LIST_HEAD(&ep->queue);
+ ep->bEndpointAddress = addr;
+ ep->bmAttributes = type;
+ ep->double_buf = 0;/*dbuf;*/
+ ep->udc = udc;
+ ep->toggle_bit = 0;
+ ep->ep.name = ep->name;
+ ep->ep.ops = &wmt_ep_ops;/*struct usb_ep_ops*/
+ ep->ep.maxpacket = ep->maxpacket = maxp;
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+
+ /*return buf;*/
+} /*wmt_ep_setup()*/
+
+static void wmt_udc_release(struct device *dev)
+{
+ DBG("wmt_udc_release()\n");
+ complete(udc->done);
+ kfree(udc);
+ udc = 0;
+} /*wmt_udc_release()*/
+
+static int __init
+wmt_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
+{
+ DBG("wmt_udc_setup()\n");
+ udc = kmalloc(sizeof *udc, GFP_KERNEL);
+
+ if (!udc)
+ return -ENOMEM;
+
+ memset(udc, 0, sizeof *udc);
+ spin_lock_init(&udc->lock);
+
+ spin_lock_init(&gri_lock);
+
+ sema_init(&wmt_udc_sem, 1);
+
+ udc->gadget.ops = &wmt_gadget_ops;
+ udc->gadget.ep0 = &udc->ep[0].ep;
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ /*INIT_LIST_HEAD(&udc->iso);*/
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.name = driver_name;
+
+ device_initialize(&udc->gadget.dev);
+ //strcpy(udc->gadget.dev.bus_id, "gadget");
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.release = wmt_udc_release;
+ udc->transceiver = NULL;
+ /* ep0 is special; put it right after the SETUP buffer*/
+ wmt_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64);
+
+ list_del_init(&udc->ep[0].ep.ep_list);
+
+#if 1
+#if 1
+#define VT8430_BULK_EP(name, addr) \
+ wmt_ep_setup(name "-bulk", addr, \
+ USB_ENDPOINT_XFER_BULK, 512);
+
+/*usb_ch9.h*/
+/*#define USB_DIR_OUT 0 *//* to device */
+/*#define USB_DIR_IN 0x80 *//* to host */
+#define VT8430_INT_EP(name, addr, maxp) \
+ wmt_ep_setup(name "-int", addr, \
+ USB_ENDPOINT_XFER_INT, maxp);
+
+#define VT8430_ISO_EP(name, addr, maxp) \
+ wmt_ep_setup(name "-iso", addr, \
+ USB_ENDPOINT_XFER_ISOC, maxp);
+#endif
+
+ VT8430_BULK_EP("ep1in", USB_DIR_IN | 1);
+ VT8430_BULK_EP("ep2out", USB_DIR_OUT | 2);
+#ifdef USE_BULK3_TO_INTERRUPT
+ VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 512);
+#else
+ VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 8);
+#endif
+ VT8430_ISO_EP("ep4in", USB_DIR_IN | 4, 512);
+#endif
+ udc->ep[0].rndis_buffer_alloc = 0;
+ udc->ep[1].rndis_buffer_alloc = 0;
+ udc->ep[2].rndis_buffer_alloc = 0;
+ udc->ep[3].rndis_buffer_alloc = 0;
+ udc->ep[4].rndis_buffer_alloc = 0;
+ udc->ep[5].rndis_buffer_alloc = 0;//gri
+ udc->ep[6].rndis_buffer_alloc = 0;//gri
+
+ /*INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);*/
+ return 0;
+} /*wmt_udc_setup()*/
+
+static void wmt_pdma_reset(void)
+{
+
+ if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable)
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+
+ pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1;
+ wmb();
+ while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/
+ ;
+
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1;
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1;
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1;
+
+ pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0;
+ pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1;
+ pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0;
+ wmb();
+ /*descriptor initial*/
+
+} /*wmt_pdma_init*/
+
+static void wmt_pdma0_reset(void)
+{
+
+ if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable)
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+
+ pUdcDmaReg->DMA_Global_Bits.SoftwareReset0 = 1;
+ wmb();
+ while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset0)/*wait reset complete*/
+ ;
+
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1;
+
+ pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0;
+ wmb();
+ /*descriptor initial*/
+
+} /*wmt_pdma_init*/
+
+
+static void wmt_pdma1_reset(void)
+{
+
+ if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable)
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+
+ pUdcDmaReg->DMA_Global_Bits.SoftwareReset1 = 1;
+ wmb();
+ while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset1)/*wait reset complete*/
+ ;
+
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1;
+
+ pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1;
+ wmb();
+ /*descriptor initial*/
+
+} /*wmt_pdma_init*/
+
+#ifdef USE_BULK3_TO_INTERRUPT
+static void wmt_pdma2_reset(void)
+{
+
+ if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable)
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+
+ pUdcDmaReg->DMA_Global_Bits.SoftwareReset2 = 1;
+ wmb();
+ while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset2)/*wait reset complete*/
+ ;
+
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1;
+
+ pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0;
+ wmb();
+ /*descriptor initial*/
+
+} /*wmt_pdma_init*/
+#endif
+
+
+/*static void wmt_pdma_init(struct device *dev)*/
+static void wmt_pdma_init(struct device *dev)
+{
+ UdcRndisEp1VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp1PhyAddr), GFP_KERNEL|GFP_ATOMIC);
+ UdcRndisEp2VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp2PhyAddr), GFP_KERNEL|GFP_ATOMIC);
+ UdcRndisEp3VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp3PhyAddr), GFP_KERNEL|GFP_ATOMIC);
+
+ UdcPdmaVirAddrLI = (unsigned int) dma_alloc_coherent(pDMADescLI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLI), GFP_KERNEL|GFP_ATOMIC);
+ UdcPdmaVirAddrSI = (unsigned int) dma_alloc_coherent(pDMADescSI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSI), GFP_KERNEL|GFP_ATOMIC);
+ UdcPdmaVirAddrLO = (unsigned int) dma_alloc_coherent(pDMADescLO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLO), GFP_KERNEL|GFP_ATOMIC);
+ UdcPdmaVirAddrSO = (unsigned int) dma_alloc_coherent(pDMADescSO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSO), GFP_KERNEL|GFP_ATOMIC);
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ UdcPdmaVirAddrL2I = (unsigned int) dma_alloc_coherent(pDMADescL2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrL2I), GFP_KERNEL|GFP_ATOMIC);
+ UdcPdmaVirAddrS2I = (unsigned int) dma_alloc_coherent(pDMADescS2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrS2I), GFP_KERNEL|GFP_ATOMIC);
+#endif
+
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+ pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1;
+ wmb();
+ while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/
+ ;
+ pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1;
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1;
+
+ pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0;
+ pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1;
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1;
+ pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0;
+#endif
+ wmb();
+
+} /*wmt_pdma_init*/
+
+/*static int __init wmt_udc_probe(struct device *dev)*/
+static int __init wmt_udc_probe(struct platform_device *pdev)
+{
+/* struct platform_device *odev = to_platform_device(dev);*/
+ struct device *dev = &pdev->dev;
+ int status = -ENODEV;
+ struct usb_phy *xceiv = 0;
+
+ DBG("wmt_udc_probe()\n");
+
+ /*UDC Register Space 0x400~0x7EF*/
+
+ INIT_LIST_HEAD (&done_main_list);
+
+ b_pullup = 0;
+
+ pDevReg = (struct UDC_REGISTER *)USB_UDC_REG_BASE;
+ pUdcDmaReg = (struct UDC_DMA_REG *)USB_UDC_DMA_REG_BASE;
+ pSetupCommand = (PSETUPCOMMAND)(USB_UDC_REG_BASE + 0x300);
+ pSetupCommandBuf = (unsigned char *)(USB_UDC_REG_BASE + 0x300);
+ SetupBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x340);
+ IntBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x40);
+ pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0);
+
+#ifdef OTGIP
+ /*UHDC Global Register Space 0x7F0~0x7F7*/
+ pGlobalReg = (struct USB_GLOBAL_REG *) USB_GLOBAL_REG_BASE;
+#endif
+
+ *pUSBMiscControlRegister5 = 0x01;
+ pDevReg->CommandStatus &= 0x1F;
+ pDevReg->CommandStatus |= USBREG_RESETCONTROLLER;
+ wmb();
+ while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER)
+ ;
+
+ wmt_pdma_init(dev);
+
+ pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/
+ wmb();
+ while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+ pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/
+ wmb();
+ while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+ pDevReg->Bulk1DesStatus = 0x00;
+ pDevReg->Bulk2DesStatus = 0x00;
+
+ pDevReg->Bulk1DesTbytes0 = 0;
+ pDevReg->Bulk1DesTbytes1 = 0;
+ pDevReg->Bulk1DesTbytes2 = 0;
+
+ pDevReg->Bulk2DesTbytes0 = 0;
+ pDevReg->Bulk2DesTbytes1 = 0;
+ pDevReg->Bulk2DesTbytes2 = 0;
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/
+ wmb();
+ while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/
+ ;
+ pDevReg->Bulk3DesStatus = 0x00;
+
+ pDevReg->Bulk3DesTbytes0 = 0;
+ pDevReg->Bulk3DesTbytes1 = 0;
+ pDevReg->Bulk3DesTbytes2 = 0;
+#endif
+
+ /* enable DMA and run the control endpoint*/
+ wmb();
+ pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA;
+ /* enable DMA and run the bulk endpoint*/
+ pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA;
+ pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA;
+
+#ifdef USE_BULK3_TO_INTERRUPT
+ pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA;
+#else
+ pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA;
+#endif
+ wmb();
+ /* enable DMA and run the interrupt endpoint*/
+ /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/
+ /* run the USB controller*/
+ pDevReg->MiscControl3 = 0x3d;
+
+ /* HW attach process evaluation enable bit For WM3426 and after project*/
+ /*pDevReg->FunctionPatchEn |= 0x20;*/
+#ifdef HW_BUG_HIGH_SPEED_PHY
+ pDevReg->MiscControl0 &= ~0x80;
+#endif
+ pDevReg->MiscControl0 |= 0x02;
+ wmb();
+ pDevReg->CommandStatus = USBREG_RUNCONTROLLER;
+
+ ControlState = CONTROLSTATE_SETUP;
+ USBState = USBSTATE_DEFAULT;
+ TestMode = 0;
+
+ status = wmt_udc_setup(pdev, xceiv);
+ if (status)
+ goto cleanup0;
+
+ xceiv = 0;
+
+ /*udc->chip_version = tmp8;*/
+ /* "udc" is now valid*/
+ pullup_disable(udc);
+
+ udc->gadget.is_otg = 0;/*(config->otg != 0);*/
+ udc->dev = dev;
+ udc->gadget.max_speed = USB_SPEED_HIGH;;
+ udc->ep0_status_0_byte = 0;
+ udc->usb_connect = 0;
+ /* USB general purpose IRQ: ep0, state changes, dma, etc*/
+ status = request_irq(UDC_IRQ_USB, wmt_udc_irq,
+// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc);
+// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);
+ (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);//gri
+ pDevReg->SelfPowerConnect |= 0x10;//Neil
+
+#ifndef OTGIP
+ status = request_irq(UDC_IRQ_DMA, wmt_udc_dma_irq,
+// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc);
+// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);
+ (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);
+#endif
+ /*SA_SAMPLE_RANDOM, driver_name, udc);*/
+ if (status != 0) {
+ ERR("can't get irq %d, err %d\n",
+ UDC_IRQ_USB, status);
+ goto cleanup1;
+ } else
+ INFO("wmt_udc_probe - request_irq(0x%02X) pass!\n", UDC_IRQ_USB);
+
+ create_proc_file();
+ status = device_add(&udc->gadget.dev);
+ if (status)
+ goto cleanup4;
+
+ status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ initial_test_fiq();
+ if (!status)
+ return 0;
+
+cleanup4:
+ remove_proc_file();
+
+/*cleanup2:*/
+ free_irq(UDC_IRQ_USB, udc);
+ INFO("wmt_udc_probe - free_irq(0x%02X)?\n", UDC_IRQ_USB);
+cleanup1:
+ kfree(udc);
+ udc = 0;
+
+cleanup0:
+ if (xceiv)
+ usb_put_transceiver(xceiv);
+ /*release_mem_region(odev->resource[0].start,*/
+ /* odev->resource[0].end - odev->resource[0].start + 1);*/
+ return status;
+
+} /*wmt_udc_probe()*/
+
+static int __exit wmt_udc_remove(struct platform_device *pdev)
+{
+ /*struct platform_device *odev = to_platform_device(dev);*/
+ DECLARE_COMPLETION(done);
+ DBG("wmt_udc_remove()\n");
+
+ if (!udc)
+ return -ENODEV;
+
+ udc->done = &done;
+
+ pullup_disable(udc);
+ if (udc->transceiver) {
+ usb_put_transceiver(udc->transceiver);
+ udc->transceiver = 0;
+ }
+ /*UDC_SYSCON1_REG = 0;*/
+
+ remove_proc_file();
+
+ free_irq(UDC_IRQ_USB, udc);
+
+ device_unregister(&udc->gadget.dev);
+ wait_for_completion(&done);
+
+ return 0;
+} /*wmt_udc_remove()*/
+
+/* suspend/resume/wakeup from sysfs (echo > power/state) */
+
+static int
+wmt_udc_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+
+
+ if (event == PM_SUSPEND_PREPARE) {
+ if (udc->driver){
+ run_script(action_off_line);
+ }
+ gadget_connect=0;
+ down(&wmt_udc_sem);
+ pullup_disable(udc);
+ up(&wmt_udc_sem);
+ }
+ else if (event == PM_POST_SUSPEND) {
+
+ down(&wmt_udc_sem);
+ pullup_enable(udc);
+ up(&wmt_udc_sem);
+
+ wmt_wakeup(&udc->gadget);
+ }
+
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block wmt_udc_pm_notifier = {
+ .notifier_call = wmt_udc_pm_notify,
+};
+
+
+
+
+static int wmt_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ DBG("wmt_udc_suspend()\n");
+ printk(KERN_INFO "wmt_udc_suspend\n"); //gri
+#if 0
+ if (udc->driver){
+ run_script(action_off_line);
+ }
+ gadget_connect=0;
+ run_script(action_mount);
+#endif
+ pDevReg->CommandStatus &= 0x1F;
+
+ pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0);
+ /**pUSBMiscControlRegister5 = 0x02;// USB PHY in power down & USB in reset*/
+ *pUSBMiscControlRegister5 = 0x00;/*USB in reset*/
+ wmb();
+
+ TestMode = 0;
+#if 0
+ down(&wmt_udc_sem);
+ pullup_disable(udc);
+ up(&wmt_udc_sem);
+#endif
+
+/* if ((state == 3) && (level == 3))*/
+/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) &= ~0x00000080;*/ /*DPM needed*/
+ *(volatile unsigned char*)(USB_IP_BASE + 0x249) |= 0x04;
+
+ return 0;
+
+} /*wmt_udc_suspend()*/
+
+static int wmt_udc_resume(struct platform_device *pdev)
+{
+#if 0
+ DBG("wmt_udc_resume()\n");
+ printk(KERN_INFO "wmt_udc_resume\n"); //gri
+ down(&wmt_udc_sem);
+ reset_udc();
+ pullup_enable(udc);
+ up(&wmt_udc_sem);
+
+ return wmt_wakeup(&udc->gadget);
+#endif
+ reset_udc();
+ return 0;
+
+} /*wmt_udc_resume()*/
+
+/*-------------------------------------------------------------------------*/
+
+static struct platform_driver udc_driver = {
+ .driver.name = (char *) driver_name,
+ .probe = wmt_udc_probe,
+ .remove = __exit_p(wmt_udc_remove),
+ .suspend = wmt_udc_suspend,
+ .resume = wmt_udc_resume,
+};
+
+static struct resource wmt_udc_resources[] = {
+ [0] = {
+ .start = (USB_IP_BASE + 0x2000),
+ .end = (USB_IP_BASE + 0x2400),
+ .flags = IORESOURCE_MEM,
+ },
+};
+static u64 wmt_udc_dma_mask = 0xFFFFF000;
+
+static struct platform_device wmt_udc_device = {
+ .name = (char *) driver_name,
+ .id = 0,
+ .dev = {
+ .dma_mask = &wmt_udc_dma_mask,
+ .coherent_dma_mask = ~0,
+ },
+ .num_resources = ARRAY_SIZE(wmt_udc_resources),
+ .resource = wmt_udc_resources,
+};
+
+void wmt_cleanup_done_thread(int number)
+{
+ unsigned long flags;
+ struct usb_composite_dev *cdev = get_gadget_data(&(udc->gadget));
+#if 1
+ if(number == 1)
+ {
+ if(in_interrupt())
+ return;
+ if(spin_is_locked(&cdev->lock)){
+ //local_irq_save(flags);
+ spin_unlock(&cdev->lock);
+ //local_irq_enable();
+ //schedule_work(&done_thread);
+ flush_work_sync(&done_thread);
+ //local_irq_restore(flags);
+ spin_lock(&cdev->lock);
+ }else{
+ flush_work_sync(&done_thread);
+ }
+ //wmt_ep_disable(&udc->ep[0]);
+ spin_lock_irqsave(&udc->lock, flags);
+ nuke(&udc->ep[0],ESHUTDOWN);
+ spin_unlock_irqrestore(&udc->lock, flags);
+ }else if(number == 2)
+ {
+ }else{
+ //flush_work_sync(&mount_thread);
+ printk("erro parameter:%s\n",__func__);
+ }
+#endif
+}
+EXPORT_SYMBOL(wmt_cleanup_done_thread);
+
+static int __init udc_init(void)
+{
+ INFO("%s, version: " DRIVER_VERSION
+ "%s\n", driver_desc,
+ use_dma ? " (dma)" : "");
+
+ DBG("udc_init()\n");
+
+//INIT_WORK(&online_thread, run_online);
+INIT_WORK(&offline_thread, run_offline);
+INIT_WORK(&done_thread, run_done);
+INIT_WORK(&chkiso_thread, run_chkiso);
+
+platform_device_register(&wmt_udc_device);
+
+ register_pm_notifier(&wmt_udc_pm_notifier);
+
+ return platform_driver_register(&udc_driver);
+} /*udc_init()*/
+
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ DBG("udc_exit()\n");
+ //driver_unregister(&udc_driver);
+ platform_driver_unregister(&udc_driver);
+ platform_device_unregister(&wmt_udc_device);
+} /*udc_exit()*/
+
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h
new file mode 100755
index 00000000..c566f3cd
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h
@@ -0,0 +1,801 @@
+/*
+ * wmt_udc.c -- for WonderMedia Technology udc
+ *
+ * Copyright (C) 2007 VIA Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_GADGET_VT8500_H
+#define __LINUX_USB_GADGET_VT8500_H
+
+#include <linux/types.h>
+/*#include <stdio.h>*/
+/*#include <stdlib.h>*/
+/*#include <string.h>*/
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#define OTGIP
+
+#define UINT volatile unsigned int
+#define USHORT volatile unsigned short
+#define UCHAR volatile unsigned char
+#define ULL volatile unsigned long long
+
+#define UDC_IRQ_USB IRQ_UHDC
+
+#ifndef OTGIP
+#define UDC_IRQ_DMA 2
+#endif
+/*#define DWORD volatile unsigned long*/
+/*#define WORD volatile unsigned short*/
+/*#define BYTE volatile unsigned char*/
+#define USB_IP_BASE USB20_HOST_DEVICE_CFG_BASE_ADDR
+/*UDC Register Space 0x400~0x7EF*/
+#define USB_UDC_REG_BASE (USB_IP_BASE + 0x400)
+/*Bulk Endpoint DMA Register Space 0x100*/
+#define USB_UDC_DMA_REG_BASE (USB_IP_BASE + 0x500)
+#ifdef OTGIP
+/*UHDC Global Register Space 0x7F0~0x7F7*/
+#define USB_GLOBAL_REG_BASE (USB_IP_BASE + 0x7f0)
+#endif
+
+#define UDC_REG(offset) REG32_PTR(USB_UDC_REG_BASE + offset)
+
+#define OTG_HOST_MEM_BASE 0x01400000/*20MB*/
+
+#define USB_EP0_CTRL_DMA_BASE OTG_HOST_MEM_BASE /*64 bytes*/
+#define USB_EP1_BULK_IN_DMA_BASE 0x01400040/*OTG_HOST_MEM_BASE + 64 */ /*64B +64KB*/
+#define USB_EP2_BULK_OUT_DMA_BASE 0x01410040/*OTG_HOST_MEM_BASE + 65536*/ /* ~ END*/
+#define USB_DOWNLOAD_KERNEL_RAM_ADDR USB_EP2_BULK_OUT_DMA_BASE
+
+/* Basic Define*/
+#define REG32 *(volatile unsigned int *)
+#define REG16 *(volatile unsigned short *)
+#define REG8 *(volatile unsigned char *)
+
+#define REG_GET32(addr) ( REG32(addr) ) /* Read 32 bits Register */
+#define REG_GET16(addr) ( REG16(addr) ) /* Read 16 bits Register */
+#define REG_GET8(addr) ( REG8(addr) ) /* Read 8 bits Register */
+
+#define REG_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Register */
+#define REG_SET16(addr, val) ( REG16(addr) = (val) ) /* Write 16 bits Register */
+#define REG_SET8(addr, val) ( REG8(addr) = (val) ) /* Write 8 bits Register */
+
+#define MEM_GET32(addr) ( REG32(addr) ) /* Read 32 bits Memory */
+#define MEM_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Memory */
+
+/*#define USB_TIMEOUT 0x100*/ /*256*/
+/*#define USB_TEST_SUCCESS 1*/
+/*#define USB_TEST_FAIL 0*/
+
+/* define the state of the USB device*/
+#define USBSTATE_ATTACHED 0x00 /* device attached to host*/
+#define USBSTATE_POWERED 0x01 /* device obtain power*/
+#define USBSTATE_DEFAULT 0x02 /* default working state*/
+#define USBSTATE_ADDRESS 0x04 /* device has get the address*/
+#define USBSTATE_CONFIGED 0x10 /* deivce has set the configuration*/
+#define USBSTATE_SUSPEND 0x20 /* No bus activity device goes to suspend */
+
+#define UDC_TEST_J_STATE 1
+#define UDC_TEST_K_STATE 2
+#define UDC_TEST_SE0_NAK 3
+#define UDC_TEST_PACKET 4
+#define UDC_TEST_FRORCE_ENABLE 5
+#define UDC_TEST_EYE_PATTERN 6
+#define UDC_TEST_MODE_NOT_ENABLED 0
+
+/*Define the USB register bit value*/
+/* USB device commmand/status register - 20*/
+#define USBREG_RUNCONTROLLER 0x01 /* set the controller run*/
+#define USBREG_RESETCONTROLLER 0x02 /* reset the device contrller*/
+#define USBREG_COMPLETEINT 0x04 /* the completion interrupt*/
+#define USBREG_BABBLEINT 0x08 /* the babble interrupt*/
+#define USBREG_BUSACTINT 0x10 /* the bus activity interrupt*/
+#define USBREG_TEST_J 0x20 /* set test J state*/
+#define USBREG_TEST_K 0x40 /* set test k state*/
+#define USBREG_SE0_NAK 0x60 /* set test SE0 and NAK*/
+#define USBREG_TESTPACKET 0x80 /* set device sending test packet*/
+#define USBREG_FORCEENABLE 0xA0 /* force port enable*/
+#define USBREG_TESTEYE 0xC0 /* Send test eye pattern packet*/
+
+/* The device address register - 21*/
+#define DEVADDR_ADDRCHANGE 0x80 /* the address change bit for device address register*/
+
+/* Device port control register - 22*/
+#define PORTCTRL_CONNECTSTATUS 0x01 /* current connection status*/
+#define PORTCTRL_CONNECTCHANGE 0x02 /* connection change bit*/
+#define PORTCTRL_SELFPOWER 0x04 /* the device is in the self power configuration*/
+#define PORTCTRL_FORCERESUME 0x08 /* force deivce to wake the host*/
+#define PORTCTRL_HIGHSPEEDMODE 0x10 /* device is in the high speed mode*/
+#define PORTCTRL_FULLSPEEDMODE 0x20 /* device is in the full speed mode*/
+
+/* Device itnerrupt enable register - 23*/
+#define INTENABLE_DEVICERESET 0x01 /* this bit is set when the bus reset is completed*/
+#define INTENABLE_SUSPENDDETECT 0x02 /* device controller detect the suspend signal*/
+#define INTENABLE_RESUMEDETECT 0x04 /* device controller detect the resume signal*/
+#define INTENABLE_COMPLETEINTEN 0x10 /* enable completion interrupt*/
+#define INTENABLE_BABBLEINTEN 0x20 /* enable babble interrupt*/
+#define INTENABLE_BUSACTINTEN 0x40 /* enable bus activity interrupt*/
+#define INTENABLE_ALL 0x70 /* enable all interrupt */
+#define INTENABLE_FULLSPEEDONLY 0x80 /* force device to support full speed only*/
+
+/* Control endpoint control - 24*/
+/* Bulk endpoint control - 28*/
+/* Interrupt endpoint control - 2C*/
+/* Bulk endpoint control - 0x310*/
+#define EP_RUN 0x01 /* run the enpoint DMA*/
+#define EP_ENABLEDMA 0x02 /* enable the DMA engine to run the schedule*/
+#define EP_DMALIGHTRESET 0x04 /* light reset the DMA engine*/
+#define EP_STALL 0x08 /* set the endpoint to stall*/
+#define EP_ACTIVE 0x10 /* the endpoint DMA is active*/
+#define EP_COMPLETEINT 0x20 /* endpoint transfer complete interrupt*/
+#define EP_BABBLE 0x40 /* endpoint babble interrupt*/
+
+/* Control transfer descriptor status byte - 30*/
+#define CTRLXFER_XACTERR 0x01 /* trnasacion error of control transfer*/
+#define CTRLXFER_BABBLE 0x02 /* babbe error of control transfer*/
+#define CTRLXFER_SHORTPKT 0x04 /* shortpacket detect of control transfer*/
+#define CTRLXFER_ACTIVE 0x08 /* transfer active of control transfer*/
+
+#define CTRLXFER_IN 0x08 /* I/O control bit 0 for OUT , 1 for In*/
+#define CTRLXFER_OUT 0x00 /**/
+#define CTRLXFER_CMDVALID 0x10 /* setup command is valid*/
+#define CTRLXFER_IOC 0x80 /* determine to gen interrupt for completion or not*/
+#define CTRLXFER_DATA1 0x80 /* for data_toggle 1*/
+#define CTRLXFER_DATA0 0x00 /* for data_toggle 0*/
+
+/* Bulk endpoint transfer descriptor status - 34*/
+/* Bulk endpoint transfer descriptor status - 0x314 */
+#define BULKXFER_XACTERR 0x01 /* trnasacion error of bulk transfer*/
+#define BULKXFER_BABBLE 0x02 /* babbe error of bulk transfer*/
+#define BULKXFER_SHORTPKT 0X04 /* shortpacket detect of bulk transfer*/
+#define BULKXFER_ACTIVE 0x08 /* transfer active of bulk transfer*/
+#define BULKXFER_IN 0x10 /* I/O control bit 0 for OUT , 1 for In*/
+#define BULKXFER_OUT 0x00
+/*HP05_Begin*/
+#define BULKXFER_CBWBUF 0x20 /* enable CBW dedicated buffer*/
+/*HP05_End*/
+#define BULKXFER_IOC 0x80 /* determine to generate interrupt for completion or not*/
+#define BULKXFER_DATA1 0x80 /* for data_toggle 1*/
+#define BULKXFER_DATA0 0x00 /* for data_toggle 0*/
+
+/* Interupt endpoint transfer descriptor - 33*/
+#define INTXFER_XACTERR 0x01 /* trnasacion error for interrupt transfer*/
+#define INTXFER_ACTIVE 0x02 /* transfer active*/
+#define INTXFER_IOC 0x04 /* determine to generate interrupt for completion or not*/
+#define INTXFER_DATA1 0x08 /* for data_toggle 1*/
+#define INTXFER_DATA0 0x00 /* for data_toggle 0*/
+
+/*UDC 0x400 ~ 0x7FF*/
+struct UDC_REGISTER{
+ UCHAR Reserved0[0x20]; /* 0x00~0x19 Reserved 0*/
+ UCHAR CommandStatus; /* USB device commmand/status register - 20*/
+ UCHAR DeviceAddr; /* The device address register - 21*/
+
+ UCHAR PortControl; /* Device port control register - 22*/
+ UCHAR IntEnable; /* Device itnerrupt enable register - 23*/
+
+ UCHAR ControlEpControl; /* Control endpoint control - 24*/
+ UCHAR ControlEpReserved; /* Control endpoint reserved byte - 25*/
+ UCHAR ControlEpMaxLen; /* max length of control endpoint - 26*/
+ UCHAR ControlEpEpNum; /* The control endpoint number - 27*/
+
+ UCHAR Bulk1EpControl; /* Bulk endpoint control - 28*/
+ UCHAR Bulk1EpOutEpNum; /* Bulk out endpoint number - 29*/
+ UCHAR Bulk1EpMaxLen; /* Bulk maximum length - 2A*/
+ UCHAR Bulk1EpInEpNum; /* Bulk In endpoint number - 2B*/
+
+ UCHAR InterruptEpControl; /* Interrupt endpoint control - 2C*/
+ UCHAR InterruptReserved; /* Interrupt endpoint reserved byte - 2D*/
+ UCHAR InterruptEpMaxLen; /* Interrupt maximum transfer length - 2E*/
+ UCHAR InterruptEpEpNum; /* interrupt endpoint number - 2F*/
+
+ UCHAR ControlDesStatus; /* Control transfer descriptor status byte - 30*/
+ UCHAR ControlDesControl; /* Control transfer descriptor control byte - 31*/
+ UCHAR ControlDesTbytes; /* Control transfer descriptor total bytes - 32*/
+
+ UCHAR InterruptDes; /* Interupt endpoint transfer descriptor - 33*/
+
+ UCHAR Bulk1DesStatus; /* Bulk endpoint transfer descriptor status - 34*/
+ UCHAR Bulk1DesTbytes0; /* Bulk endpoint transfer descriptor control - 35*/
+ UCHAR Bulk1DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 36*/
+ UCHAR Bulk1DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 37*/
+
+ UCHAR MacToParameter; /* USB2.0 MAC timeout parameter register - 38*/
+ UCHAR PhyMisc; /* PHY misc control register - 39*/
+ UCHAR MiscControl0; /* Misc. control register 0 - 3A*/
+ UCHAR MiscControl1; /* Misc. control register 1 - 3B*/
+ UCHAR MiscControl2; /* Misc. control register 2 - 3C*/
+ UCHAR MiscControl3; /* Misc. control register 3 - 3D*/
+ UCHAR MACDelay; /* MAC receiver enable delay parameter - 3E*/
+ UCHAR FunctionPatchEn; /* Function Patch Enable bits - 3F*/
+
+ UCHAR InterruptInBuf[32]; /* Interrupt In Endpoint Data Buffer - 40 ~ 5F (32 bytes) for CBW(31 bytes)*/
+
+ UCHAR Reserved1[0x2A0]; /* 0x060~0x2FF ; 0x2FF - 0x60 + 1 = 0x2A0 for Bulk Endpoint 01 02 DMA Source / Destination*/
+ UCHAR SetupCommand[8]; /* 0x300~0x307 */
+ UCHAR PHYControlBit; /* 0x308 Phy Control Bit */
+ UCHAR Reserved2[2]; /* 0x309 ~ 0x30A*/
+ UCHAR NewUSBPhyTestControl;/* 0x30B New USB 1.1 and USB 2.0 PHY test control bit*/
+ UCHAR NewUSBPhyTestStatus; /* 0x30C New USB 1.1 and USB 2.0 PHY test status bit*/
+ UCHAR SelfPowerConnect; /* 0x30D Debug pins for USBC side control bit*/
+
+ UCHAR Reserved3[2]; /* 0x30E ~ 0x30F*/
+
+ UCHAR Bulk2EpControl; /* Bulk endpoint control - 0x310*/
+ UCHAR Bulk2EpOutEpNum; /* Bulk out endpoint number - 0x311*/
+ UCHAR Bulk2EpMaxLen; /* Bulk maximum length - 0x312*/
+ UCHAR Bulk2EpInEpNum; /* Bulk In endpoint number - 0x313*/
+
+ UCHAR Bulk2DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/
+ UCHAR Bulk2DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/
+ UCHAR Bulk2DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/
+ UCHAR Bulk2DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/
+
+ UCHAR Bulk3EpControl; /* Bulk endpoint control - 0x310*/
+ UCHAR Bulk3EpOutEpNum; /* Bulk out endpoint number - 0x311*/
+ UCHAR Bulk3EpMaxLen; /* Bulk maximum length - 0x312*/
+ UCHAR Bulk3EpInEpNum; /* Bulk In endpoint number - 0x313*/
+
+ UCHAR Bulk3DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/
+ UCHAR Bulk3DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/
+ UCHAR Bulk3DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/
+ UCHAR Bulk3DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/
+
+ UCHAR Reserved4[0x20]; /*0x318 ~ 0x33F ; 0x33F - 0x318 + 1 = 0x28*/
+
+ UCHAR ControlDataBuf[64]; /*0x340~0x37F Control Endpoint Data Buffer */
+}__attribute__((packed));
+
+/*DMA_Context_Control*/
+/*1:IF0-->peripheral 0:peripher-->IF0*/
+#define DMA_TRANS_OUT_DIR 0x00400000
+/*1:Run 0:Stop Scheduled*/
+#define DMA_RUN 0x00000080
+
+/*DMA Interrupt Enable*/
+/*enable interfac 0 interrupt*/
+#define DMA_INTERRUPT_ENABLE0 0x00000001
+/*enable interfac 1 interrupt*/
+#define DMA_INTERRUPT_ENABLE1 0x00000002
+/*enable interfac 2 interrupt*/
+#define DMA_INTERRUPT_ENABLE2 0x00000010
+
+/*enable interfac 0 status*/
+#define DMA_INTERRUPT_STATUS0 0x00000001
+/*enable interfac 1 status*/
+#define DMA_INTERRUPT_STATUS1 0x00000002
+/*enable interfac 2 status*/
+#define DMA_INTERRUPT_STATUS2 0x00000004
+
+struct UDC_DMA_REG {
+ union { /*Rx00 - DMA Global Register (0x100~0x103)*/
+ UINT DMA_Global;
+ struct {
+ UINT DMAConrollerEnable:1;
+ UINT Reserved0:7;
+ UINT SoftwareReset:1;
+ UINT SoftwareReset0:1;
+ UINT SoftwareReset1:1;
+ UINT SoftwareReset2:1;
+ UINT Reserved1:20;
+ } DMA_Global_Bits;
+ };
+
+ union { /*Rx04 - DMA Interrupt Enable (0x104~x107)*/
+ UINT DMA_IER;
+ struct {
+ UINT DMAInterruptEnable0:1;
+ UINT DMAInterruptEnable1:1;
+ UINT Reserved:2;
+ UINT DMAInterruptEnable2:1;
+ UINT Reserved1:27;
+ } DMA_IER_Bits;
+ };
+
+ union { /*Rx08 - DMA Interrupt Status Register (0x108~0x10b)*/
+ UINT DMA_ISR;
+ struct {
+ UINT InterruptStatus0:1;
+ UINT InterruptStatus1:1;
+ UINT InterruptStatus2:1;
+ UINT Reserved:29;
+ } DMA_ISR_Bits;
+ };
+
+ /*Interface 0*/
+ union {/*Rx10c - DMA Memory-Descriptor Point Register dor Interdace 0 (0x10c~0x10f)*/
+ UINT DMA_Descriptor_Point0;
+ struct {
+ UINT Reserved:2;
+ UINT DesBaseAddr:30;
+ } DMA_Descriptor_Point0_Bits;
+ };
+
+ union { /*Rx110 - DMA Residual Bytes Register for Interface 0 (Rx110~Rx103)*/
+ UINT DMA_Residual_Bytes0;
+ struct {
+ UINT ResidualBytes:16;
+ UINT IntEn:1;
+ UINT Reseved:13;
+ UINT Format:1;
+ UINT End:1;
+ } DMA_Residual_Bytes0_Bits;
+ };
+
+ /*Rx114 - DMA Data Address Register for Interface 0 (0x114~0x117)*/
+ UINT DMA_Data_Addr0;
+
+ union {/*Rx118 DMA Branch Address Register for INterface 0(0x118~0x11b)*/
+ UINT DMA_Branch_Addr0;
+ struct {
+ UINT Reserved:4;
+ UINT BranchDesxriptorAddress:28;
+ } DMA_Branch_Addr0_Bits;
+ };
+
+ union {/*Rx11c DMA command Pointer Register for Interrface 0(0x11c~0x11f)*/
+ UINT Descriptor_Addr0;
+ struct {
+ UINT Reserved:4;
+ UINT DescriptorAddr:28;
+ } Descriptor_Addr0_Bits;
+ };
+
+ union {/*Rx120 DMA Context Control Register for Interfaxe 0(0x120~0x123)*/
+ UINT DMA_Context_Control0;
+ struct {
+ UINT EventCode:4;
+ UINT Reserved0:3;
+ UINT Run:1;
+ UINT Active:1;
+ UINT P0Cmpl:1;
+ UINT Reserved1:2;
+ UINT Prot:4;
+ UINT Reserved2:6;
+ UINT TransDir:1;
+ UINT Reserved3:9;
+ } DMA_Context_Control0_Bis;
+ };
+
+ /*Interface 1*/
+ union {/*Rx124 - DMA Memory-Descriptor Point Register dor Interdace 1 (0x124~0x127)*/
+ UINT DMA_Descriptor_Point1;
+ struct {
+ UINT Reserved:2;
+ UINT DesBaseAddr:30;
+ } DMA_Descriptor_Point1_Bits;
+ };
+
+ union { /*Rx128 - DMA Residual Bytes Register for Interface 1 (Rx128~Rx12b)*/
+ UINT DMA_Residual_Bytes1;
+ struct {
+ UINT ResidualBytes:16;
+ UINT IntEn:1;
+ UINT Reseved:13;
+ UINT Format:1;
+ UINT End:1;
+ } DMA_Residual_Bytes1_Bits;
+ };
+
+ /*Rx12c - DMA Data Address Register for Interface 1 (0x12c~0x12f)*/
+ UINT DMA_Data_Addr1;
+
+ union {/*Rx130 DMA Branch Address Register for INterface 10(0x130~0x133)*/
+ UINT DMA_Branch_Addr1;
+ struct {
+ UINT Reserved:4;
+ UINT BranchDesxriptorAddress:28;
+ } DMA_Branch_Addr1_Bits;
+ };
+
+ union {/*Rx134 DMA command Pointer Register for Interrface 1(0x134~0x137)*/
+ UINT Descriptor_Addr1;
+ struct {
+ UINT Reserved:4;
+ UINT DescriptorAddr:28;
+ } Descriptor_Addr1_Bits;
+ };
+
+ union {/*Rx138DMA Context Control Register for Interfaxe 1(0x138~0x13b)*/
+ UINT DMA_Context_Control1;
+ struct {
+ UINT EventCode:4;
+ UINT Reserved0:3;
+ UINT Run:1;
+ UINT Active:1;
+ UINT P0Cmpl:1;
+ UINT Reserved1:2;
+ UINT Prot:4;
+ UINT Reserved2:6;
+ UINT TransDir:1;
+ UINT Reserved3:9;
+ } DMA_Context_Control1_Bis;
+ };
+
+ /*Interface 2*/
+ union {/*Rx13c - DMA Memory-Descriptor Point Register dor Interdace 2 (0x10c~0x10f)*/
+ UINT DMA_Descriptor_Point2;
+ struct {
+ UINT Reserved:2;
+ UINT DesBaseAddr:30;
+ } DMA_Descriptor_Point2_Bits;
+ };
+
+ union { /*Rx140 - DMA Residual Bytes Register for Interface 2 (Rx110~Rx103)*/
+ UINT DMA_Residual_Bytes2;
+ struct {
+ UINT ResidualBytes:16;
+ UINT IntEn:1;
+ UINT Reseved:13;
+ UINT Format:1;
+ UINT End:1;
+ } DMA_Residual_Bytes2_Bits;
+ };
+
+ /*Rx144 - DMA Data Address Register for Interface 2 (0x144~0x147)*/
+ UINT DMA_Data_Addr2;
+
+ union {/*Rx148 DMA Branch Address Register for INterface 2(0x148~0x14b)*/
+ UINT DMA_Branch_Addr2;
+ struct {
+ UINT Reserved:4;
+ UINT BranchDesxriptorAddress:28;
+ } DMA_Branch_Addr2_Bits;
+ };
+
+ union {/*Rx14c DMA command Pointer Register for Interrface 2(0x14c~0x14f)*/
+ UINT Descriptor_Addr2;
+ struct {
+ UINT Reserved:4;
+ UINT DescriptorAddr:28;
+ } Descriptor_Addr2_Bits;
+ };
+
+ union {/*Rx150 DMA Context Control Register for Interfaxe 2(0x150~0x153)*/
+ UINT DMA_Context_Control2;
+ struct {
+ UINT EventCode:4;
+ UINT Reserved0:3;
+ UINT Run:1;
+ UINT Active:1;
+ UINT P0Cmpl:1;
+ UINT Reserved1:2;
+ UINT Prot:4;
+ UINT Reserved2:6;
+ UINT TransDir:1;
+ UINT Reserved3:9;
+ } DMA_Context_Control2_Bis;
+ };
+
+}__attribute__((packed));
+
+#define DESCRIPTOT_TYPE_SHORT 0
+#define DESCRIPTOT_TYPE_LONG 1
+#define DESCRIPTOT_TYPE_MIX 2
+
+#define TRANS_OUT 1
+#define TRANS_IN 0
+
+#define DES_L_SIZE 0x10
+#define DES_S_SIZE 0x4
+
+
+/*
+ * PDMA Descriptor short
+ */
+struct _UDC_PDMA_DESC_S {
+ union {
+ UINT D_Word0;
+ struct {
+ UINT ReqCount:16; /* bit 0 -15 -Request count*/
+ UINT i:1; /* bit 16 -interrupt*/
+ UINT Reserved:13;
+ UINT Format:1; /* bit 30 -The descriptor format*/
+ UINT End:1; /* bit 31-End flag of descriptor list*/
+ } D_Word0_Bits;
+ };
+
+ UINT Data_Addr; /* bit 0-31 -Data Buffer address*/
+}__attribute__((packed));
+
+/*
+ * PDMA Descriptor long
+ */
+
+struct _UDC_PDMA_DESC_L {
+ union {
+ UINT D_Word0;
+ struct {
+ UINT ReqCount:16; /* bit 0 -15-Request count*/
+ UINT i:1; /* bit 16-interrupt*/
+ UINT Reserved:13;
+ UINT Format:1; /* bit 30-The descriptor format*/
+ UINT End:1; /* bit 31-End flag of descriptor list*/
+ } D_Word0_Bits;
+ };
+
+ UINT Data_Addr; /* bit 0-31 -Data Buffer address*/
+
+ union {
+ UINT Branch_addr;
+ struct {
+ UINT Reserved:2;
+ UINT BranchAddr:30; /* bit 31-2 -Descriptor Branch address*/
+ } Branch_addr_Bits;
+ };
+
+ UINT Reserve0;
+}__attribute__((packed));
+
+/*Rx00 - UHDC Interrupt Status Register*/
+#define UHDC_INT_UDC 0x0300
+//#define UHDC_INT_UDC_DMA2 0x0400
+#define UHDC_INT_UDC_DMA1 0x0200
+#define UHDC_INT_UDC_CORE 0x0100
+
+#ifdef OTGIP
+/*UHDC Global Register Space : 0x7F0~0x7F7*/
+struct USB_GLOBAL_REG {
+ union { /*Rx00 - UHDC Interrupt Status Register*/
+ USHORT UHDC_Interrupt_Status;
+ struct {
+ USHORT EHCIInt:1; /* [0] EHCI Interrupt bit*/
+ USHORT UHCIInt:1; /* [1] UHCI Interrupt bit*/
+ USHORT Reserved0:6; /* reserved for future use*/
+ USHORT UDCCoreInt:1; /* [8] UDC Core Interrupt bit(IOC/Babble/Bus Activity)*/
+ USHORT UDCDMA1Int:1; /* [9] DMA1 Interrupt bit (Bulk Transfer)*/
+ USHORT UDCDMA2Int:1; /* [10] DMA2 Interrupt bit (Bulk Transfer)*/
+ USHORT Reserved1:5; /* reserved for future use*/
+ } UHDC_Interrupt_Status_Bits;
+ };
+
+ union { /*Rx01 - UHDC ID Status Register*/
+ UCHAR UHDC_ID_Status;
+ struct {
+ UCHAR DualRoleID:1; /* Dual-Role USB Controller ID Value*/
+ UCHAR Reserved:7; /* reserved for future use*/
+ } UHDC_ID_Status_Bits;
+ };
+
+ union { /*Rx02 - UHDC Offchip Power Control Register*/
+ UCHAR UHDC_OffChip_PowerControl;
+ struct {
+ UCHAR PowerSupplyMode:1; /* Power Supply Mode Select (1)SW mode (0)HW mode*/
+ UCHAR PowerSupplySWEn:1; /* Power Supply SW Mode Enable bit */
+ UCHAR Reserved:6; /* reserved for future use */
+ } UHDC_OffChip_PowerControl_Bits;
+ };
+
+ union { /*Rx03 - UHDC Clock Reset Control Register*/
+ USHORT UHDC_Clock_Reset_Control;
+ struct {
+ USHORT AHBClkGatingEn:1; /* [0] AHB clock Gating Enable bit*/
+ USHORT HCSuspendClkGatingEn:1; /* [1] Host Controller Suspend Clock Gating Enable bit*/
+ USHORT DCSuspendClkGatingEn:1; /* [2] Device Controller Suspend Clock Gating Enable bit*/
+ USHORT DataReceivingClkGatingEn:1;/* [3] Controller Data-Receiving Clock Gating Enable bit*/
+ USHORT Phy120MClkGatingEn:1; /* [4] Phy 120M Clock Gating Enable bit*/
+ USHORT Phy60MClkGatingEn:1; /* [5] Phy 60M Clock Gating Enable bit*/
+ USHORT Phy48MClkGatingEn:1; /* [6] Phy 48M Clock Gating Enable bit */
+ USHORT Reserved0:1; /* [7] reserved for future use*/
+ USHORT AHBResetGatingEn:1; /* [8] AHB Bus Reset Gating Enable bit*/
+ USHORT PowerOnResetGatingEn:1; /* [9] Power-on Reset Gating Enable bit */
+ USHORT Reserved1:6; /* [15:10] reserved for future use*/
+ } UHDC_Clock_Reset_Control_Bits;
+ };
+
+ union { /*Rx04 - UHDC Pullup/Pulldown Control Register*/
+ USHORT UHDC_Pull_Up_Down_Control;
+ struct {
+ USHORT PullUpDownSWControlEn:1; /* [0] Pullup/Pulldown SW Control Enable bit*/
+ USHORT DPLinePullUpEn:1; /* [1] DP Line Pullup Enable bit*/
+ USHORT DPLinePullDownEn:1; /* [2] DP Line Pulldown Enable bit*/
+ USHORT DMLinePullDownEn:1; /* [3] DM Line Pulldown Enable bit*/
+ USHORT HSTerminationRegisterEn:1; /* [4] High Speed Termination Register On bit*/
+ USHORT Reserved1:11; /* [15:5] reserved for future use*/
+ } UHDC_Pull_Up_Down_Control_Bits;
+ };
+}__attribute__((packed));
+#endif
+
+#define UDC_FULL_SPEED 0
+#define UDC_HIGH_SPEED 1
+/* Define the setup command buffer*/
+
+#define MAX_TRANSFER_LENGTH 0x200 /* original is 0x20000, shift 16bits for minimum block size is 0x200*/
+/*HP04_End*/
+
+/* Define the interrupt transfer buffer*/
+#define INTBUFFERSTART 0x308 /* the start byte of interrupt transfer buffer*/
+#define INTBUFFEREND 0x30F /* the last byte of interrupt transfer buffer*/
+#define INTBUFFERSIZE 0x08 /* the size of the interrupt transfer buffer*/
+
+/* Define the control endpoint buffer*/
+#define CONTROLBUFFERSTART 0x340 /* the start byte of the control data buffer*/
+#define CONTROLBUFFEREND 0x37F /* the last byte of the control data buffer*/
+#define CONTROLBUFFERSIZE 0x40 /* the size of the control data buffer*/
+
+/* Define the bulk transfer buffer*/
+#define BULKBUFFERSTART 0x800 /* the start byte of the bulk transfer buffer*/
+#define BULKBUFFEREND 0xFFF /* the last byte of the bulk transfer buffer*/
+#define BULKBUFFERSIZE 0x800 /* the size of the bulk transfer buffer*/
+
+/* define the endpoint number for each endpoint*/
+#define BULKINEPNUM 0x01
+/*HP01_begin*/
+#define BULKOUTEPNUM 0x02
+/*HP01_End*/
+#define INTEPNUM 0x03
+#define MAXEPNUM 0x04
+/* define the structure of string table for default strings and vendor specified strings*/
+
+/* define the IO state of USB to handle */
+#define IOSTATE_CBWIDLE 0x00 /* usb is idle and set the 8051 clock to stop*/
+#define IOSTATE_ACCEPTCBW 0x01 /* the usb accept a new CBW*/
+#define IOSTATE_DEVICEPREPAREIO 0x02 /* the state will call deivce startio to prepare IO*/
+#define IOSTATE_STARTIO 0x03 /* the CBW send to device to start IO operation*/
+#define IOSTATE_CSW 0x04 /* the state to send CSW back to host*/
+#define IOSTATE_CSWCOMPLETE 0x05 /* the CSW is returned, maybe need some more process*/
+#define IOSTATE_TIMEOUT 0x06 /* the IO is hang to long and it is timeout*/
+#define IOSTATE_FWDOWNLOAD 0x07 /* Download the new firmware.*/
+#define IOSTATE_WAITFORCBW 0x08 /* In this state, the controller is waiting for CBW*/
+#define IOSTATE_CSWIDLE 0x09 /* the idle state for wait for CSW complete, 8051 will stopped*/
+
+/*VT3214 Define */
+/* define the state of Control endpoint*/
+#define CONTROLSTATE_SETUP 0x00 /* the control endpoint is in the Setup state*/
+#define CONTROLSTATE_DATA 0x01 /* the control endpoint is in the Data state*/
+#define CONTROLSTATE_STATUS 0x02 /* the control endpoint is in the Status state*/
+
+
+/* VT3300 PACK Size Defination*/
+#define UCE_MAX_DMA ((unsigned)64)
+#define UIE_MAX_DMA ((unsigned)8)
+#define UBE_MAX_DMA ((unsigned)0x20000) /* max length = 128K */
+#define EP0_FIFO_SIZE ((unsigned)64)
+#define BULK_FIFO_SIZE ((unsigned)512)
+#define INT_FIFO_SIZE ((unsigned)8)
+
+/* Define the setup command buffer*/
+typedef struct _SETUP_COMMAND
+{
+unsigned char RequestType; /* the Request type of the SETUP command*/
+unsigned char Request; /* the Request code of the SETUP command*/
+unsigned char ValueLow; /* the lower value field of the SETUP command*/
+unsigned char ValueHigh; /* the higher value field of the SETUP command*/
+unsigned char IndexLow; /* the lower index field of the SETUP command*/
+unsigned char IndexHigh; /* the higher index field of the SETUP command*/
+unsigned char LengthLow; /* the lower length field of the SETUP command*/
+unsigned char LengthHigh; /* the higher length field of the SETUP command*/
+} SETUPCOMMAND, *PSETUPCOMMAND;
+
+
+
+struct vt8500_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ unsigned long irqs;
+ const struct usb_endpoint_descriptor *desc;
+ char name[14];
+ u16 maxpacket;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+ unsigned double_buf:1;
+ unsigned stopped:1;
+ unsigned fnf:1;
+ unsigned has_dma:1;
+ unsigned toggle_bit:1;
+ unsigned stall:1;
+ unsigned rndis:1;
+ u8 ackwait;
+ /*u8 dma_channel;*/
+ u32 dma_counter;
+ /*int lch;*/
+ struct vt8500_udc *udc;
+ struct timer_list timer;
+ /*volatile u32 *reg_payload_addr;*/
+ /*volatile u32 *reg_control_status;*/
+ /*volatile u32 *reg_irp_descriptor;*/
+
+ /*volatile u32 temp_payload_addr;*/
+ /*volatile u32 temp_control_status;*/
+
+ volatile u32 temp_buffer_address;
+ volatile u32 temp_dma_phy_address;
+ volatile u32 temp_buffer_address2;
+ volatile u32 temp_dma_phy_address2;
+
+ /*volatile u32 temp_req_length;*/
+ /*volatile u32 temp_irp_descriptor; */
+ volatile u32 rndis_buffer_address;
+ volatile u32 rndis_dma_phy_address;
+ unsigned int rndis_buffer_length;
+ unsigned int rndis_buffer_alloc ;
+
+ /*processing stall and clear stall.*/
+ volatile u32 stall_more_processing;
+ volatile u32 temp_dcmd;
+ volatile u32 temp_dma_ccr;
+ volatile u32 temp_bulk_dma_addr;
+ volatile u32 ep_stall_toggle_bit;
+ volatile u32 ep_fifo_length;
+
+}__attribute__((packed));
+
+struct vt8500_req {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned dma_bytes;
+ struct vt8500_ep *ep;
+ struct list_head mem_list; /* sw qtd list */
+ unsigned mapped:1;
+}__attribute__((packed));
+
+
+struct vt8500_udc {
+ struct device *dev;
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ spinlock_t lock;
+// struct vt8500_ep ep[5];
+ struct vt8500_ep ep[7];//gri
+ u16 devstat;
+ u16 ep0_in_status;
+ volatile u32 cbw_virtual_address;
+ /*volatile u32 ep3_virtual_address; */
+ struct usb_phy *transceiver;
+ unsigned softconnect:1;
+ unsigned vbus_active:1;
+ unsigned ep0_pending:1;
+ unsigned ep0_in:1;
+ unsigned ep0_set_config:1;
+ unsigned ep0_reset_config:1;
+ unsigned ep0_setup:1;
+ unsigned ep0_status_0_byte:1;
+ unsigned usb_connect:1;
+ unsigned file_storage_set_halt:1;
+ unsigned bulk_out_dma_write_error:1;
+ unsigned int chip_version;
+ struct completion *done;
+ u8 setup_command[8];
+ struct timer_list timer;
+}__attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+
+//#define DEBUG
+//#define VERBOSE
+
+#ifdef DEBUG
+#define DBG(stuff...) printk(KERN_INFO "udc: " stuff)
+#else
+#define DBG(stuff...) do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(stuff...) do{}while(0)
+#endif
+
+#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
+//#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+
+#define USB_BULK_RESET_REQUEST 0xff
+/*--------------------------------------------------------------------*/
+
+/*static void vt8500_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp);*/
+/*static void vt8500_udc_csr(struct vt8500_udc *udc);*/
+
+#endif /* __LINUX_USB_GADGET_VT8500_H */
diff --git a/ANDROID_3.4.5/drivers/usb/host/Kconfig b/ANDROID_3.4.5/drivers/usb/host/Kconfig
index f788eb86..302bae2a 100644
--- a/ANDROID_3.4.5/drivers/usb/host/Kconfig
+++ b/ANDROID_3.4.5/drivers/usb/host/Kconfig
@@ -63,6 +63,21 @@ config USB_EHCI_HCD
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
+#CharlesTu, for test mode #
+config USB_EHCI_EHSET
+ bool "Embedded High-speed Host Electrical Test Support (EXPERIMENTAL)"
+ depends on USB_EHCI_HCD
+ default y
+ ---help---
+ This option is only used if you are developing firmware for
+ an embedded device with a Hi-speed USB Host or OTG port.
+
+ If you say Y here, software support for the Embedded High-speed
+ Host Electrical Tests will be added to the EHCI driver. This is
+ one of the tests performed during High-speed USB Host certification
+ testing.
+
+ If you are at all unsure then say N here.
config USB_EHCI_ROOT_HUB_TT
bool "Root Hub Transaction Translators"
depends on USB_EHCI_HCD
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c
index bb73df65..dabd379f 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c
@@ -130,6 +130,10 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
/*-------------------------------------------------------------------------*/
+extern unsigned int usb_storage_id;
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+unsigned int usb_param[2] = {0xff};
+
static void
timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
{
@@ -599,6 +603,14 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_readl(ehci, &ehci->regs->status));
}
+int env_mos_gpio;
+unsigned int env_active;
+unsigned int env_port;
+unsigned int env_bitmap;
+unsigned int env_ctraddr;
+unsigned int env_ocaddr;
+unsigned int env_odaddr;
+
/* one-time init, only for memory state */
static int ehci_init(struct usb_hcd *hcd)
{
@@ -607,7 +619,14 @@ static int ehci_init(struct usb_hcd *hcd)
int retval;
u32 hcc_params;
struct ehci_qh_hw *hw;
-
+ char usb_env_name[] = "wmt.usb.param";
+ char usb_env_val[20] = "0";
+ int varlen = 20;
+
+ char usb_resume_env_name[] = "wmt.gpo.usb";
+ char usb_resume_env_val[80] = "0";
+ int varlen_resume = 80;
+
spin_lock_init(&ehci->lock);
/*
@@ -720,7 +739,37 @@ static int ehci_init(struct usb_hcd *hcd)
temp |= hird << 24;
}
ehci->command = temp;
+
+ if(wmt_getsyspara(usb_env_name, usb_env_val, &varlen) == 0) {
+ sscanf(usb_env_val,"%X:%X", &usb_param[0],&usb_param[1]);
+ //printk("usb_param[0] =%x ,usb_param[1]=%x \n",usb_param[0],usb_param[1]);
+ if (usb_param[0] & 0x01) {
+ if(usb_param[1] <= 0x03 ) {
+ usb_storage_id = usb_param[1]+1;
+ //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id);
+ } else {
+ usb_storage_id = 2;// default port B
+ }
+ } else {
+ usb_storage_id=0; //disable
+ }
+ }
+
+ if(wmt_getsyspara(usb_resume_env_name, usb_resume_env_val, &varlen_resume) == 0) {
+ sscanf(usb_resume_env_val,"%d:%X:%X:%X:%X:%X", &env_mos_gpio,&env_active,&env_bitmap,&env_ctraddr,&env_ocaddr,&env_odaddr);
+
+ if (env_active) {
+ env_port = (env_active >> 4);
+ env_active &= 0x1;
+ env_ctraddr = ((env_ctraddr & 0xffffff) | 0xfe000000);
+ env_ocaddr = ((env_ocaddr & 0xffffff) | 0xfe000000);
+ env_odaddr = ((env_odaddr & 0xffffff) | 0xfe000000);
+ }
+ } else
+ env_active = 0;
+ printk("env_mos_gpio=%d env_active =%x ,env_port=%x env_bitmap=%x env_ctraddr=%x env_ocaddr=%x env_odaddr=%x \n",env_mos_gpio,env_active,env_port,env_bitmap,env_ctraddr,env_ocaddr,env_odaddr);
+
/* Accept arbitrarily long scatter-gather lists */
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
hcd->self.sg_tablesize = ~0;
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c
index 38fe0762..714ca48b 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c
@@ -128,6 +128,9 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
return 0;
}
+extern char enable_ehci_wake;
+extern char enable_ehci_disc_wakeup;
+
static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup)
{
@@ -171,10 +174,13 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
* If we are resuming the controller, set the wakeup flags.
*/
if (!suspending) {
- if (t1 & PORT_CONNECT)
- t2 |= PORT_WKOC_E | PORT_WKDISC_E;
- else
- t2 |= PORT_WKOC_E | PORT_WKCONN_E;
+ if (enable_ehci_wake && enable_ehci_disc_wakeup) {
+ if (t1 & PORT_CONNECT)
+ t2 |= PORT_WKOC_E | PORT_WKDISC_E;
+ else
+ t2 |= PORT_WKOC_E | PORT_WKCONN_E;
+ } else
+ t2 |= PORT_WKOC_E;
}
ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
@@ -254,7 +260,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 & PORT_OWNER)
set_bit(port, &ehci->owned_ports);
else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
- t2 |= PORT_SUSPEND;
+ if (enable_ehci_wake)
+ t2 |= PORT_SUSPEND;
+ else
+ t2 &= ~PORT_PE;// CharlesTu, disable port
set_bit(port, &ehci->bus_suspended);
}
@@ -265,10 +274,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
* condition happens here(connection change during bits
* set), the port change detection will finally fix it.
*/
- if (t1 & PORT_CONNECT)
- t2 |= PORT_WKOC_E | PORT_WKDISC_E;
- else
- t2 |= PORT_WKOC_E | PORT_WKCONN_E;
+ if (enable_ehci_wake && enable_ehci_disc_wakeup) {
+ if (t1 & PORT_CONNECT)
+ t2 |= PORT_WKOC_E | PORT_WKDISC_E;
+ else
+ t2 |= PORT_WKOC_E | PORT_WKCONN_E;
+ } else
+ t2 |= PORT_WKOC_E;
}
if (t1 != t2) {
@@ -602,6 +614,16 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
* controller by the user.
*/
+ /*
+ *CharlesTu,2009.08.17,patch Trancend 8GB usb device ,
+ *copy and fast hot plug reset slowly issue.
+ *Due to Transcend 8GB device ,connect slowly and reset_done clear 0
+ */
+ /*if (!(temp & PORT_CONNECT))*/
+ if (!(temp & (PORT_CONNECT|PORT_RESET)))
+ ehci->reset_done [i] = 0;
+
+
if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
|| (ehci->reset_done[i] && time_after_eq(
jiffies, ehci->reset_done[i]))) {
@@ -611,6 +633,27 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [1] |= 1 << (i - 7);
status = STS_PCD;
}
+ /*CharlesTu,090415,patch usb card reader plug/unplug fastly
+ * port fail issue. Due to the port reset assert and not clear.
+ */
+ if ((temp & PORT_RESET)
+ && time_after (jiffies, ehci->reset_done [i])) {
+ /*printk("port reset \n");*/
+ /* force reset to complete */
+ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+ &ehci->regs->port_status [i]);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(ehci,
+ &ehci->regs->port_status [i],
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ ehci_err (ehci, "port %d reset error %d\n",
+ i + 1, retval);
+
+ }
+ }
}
/* FIXME autosuspend idle root hubs */
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -653,6 +696,190 @@ ehci_hub_descriptor (
}
/*-------------------------------------------------------------------------*/
+/*{CharlesTu,2010.08.26, for test mode --------------------------------*/
+#ifdef CONFIG_USB_EHCI_EHSET
+
+static int
+single_step_set_feature( struct usb_hcd *hcd, u8 port)
+{
+ struct usb_bus *bus = hcd_to_bus(hcd);
+ struct usb_device *udev;
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ struct list_head qtd_list;
+ struct list_head setup_list;
+ struct list_head data_list;
+ struct ehci_qtd *qtd;
+ struct urb urb;
+ struct usb_ctrlrequest setup_packet;
+ char data_buffer[USB_DT_DEVICE_SIZE];
+
+ ehci_info (ehci, "Testing SINGLE_STEP_SET_FEATURE\n");
+
+ if (bus == NULL) {
+ ehci_err (ehci, "EHSET: usb_bus pointer is NULL\n");
+ return -EPIPE;
+ }
+
+ udev = bus->root_hub;
+ if (udev == NULL) {
+ ehci_err (ehci, "EHSET: root_hub pointer is NULL\n");
+ return -EPIPE;
+ }
+ /* Charles, modify for MVL5 */
+ /*udev = udev->children[port - 1];*/
+ udev = udev->children[port ];
+
+ if (udev == NULL) {
+ ehci_err (ehci, "EHSET: No test device found on port %d\n",
+ port);
+ return -EPIPE;
+ }
+
+ setup_packet.bRequestType = USB_DIR_IN;
+ setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup_packet.wValue = (USB_DT_DEVICE << 8);
+ setup_packet.wIndex = 0;
+ setup_packet.wLength = USB_DT_DEVICE_SIZE;
+
+ INIT_LIST_HEAD (&qtd_list);
+ INIT_LIST_HEAD (&setup_list);
+ INIT_LIST_HEAD (&data_list);
+
+ urb.transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb.dev = udev;
+ urb.pipe = usb_rcvctrlpipe(udev, 0);
+ /* Charles, modify for MVL5 */
+ urb.hcpriv = udev->ep0.hcpriv;
+ /*urb.hcpriv = udev->ep0.hcpriv; */
+
+ urb.setup_packet = (char *)&setup_packet;
+ urb.transfer_buffer = data_buffer;
+ urb.transfer_flags = URB_HCD_DRIVER_TEST;
+ //spin_lock_init(&urb.lock);
+
+ urb.setup_dma = dma_map_single( hcd->self.controller,
+ urb.setup_packet,
+ sizeof (struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ urb.transfer_dma = dma_map_single (
+ hcd->self.controller,
+ urb.transfer_buffer,
+ sizeof (struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+
+ if (!urb.setup_dma || !urb.transfer_dma) {
+ ehci_err (ehci, "dma_map_single Failed\n");
+ return -EBUSY;
+ }
+
+ if (!qh_urb_transaction (ehci, &urb, &qtd_list, GFP_ATOMIC)) {
+ ehci_err (ehci, "qh_urb_transaction Failed\n");
+ return -EBUSY;
+ }
+
+ qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list);
+ list_del_init (&qtd->qtd_list);
+ list_add (&qtd->qtd_list, &setup_list);
+ qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list);
+ list_del_init (&qtd->qtd_list);
+ list_add (&qtd->qtd_list, &data_list);
+ qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list);
+ list_del_init (&qtd->qtd_list);
+ ehci_qtd_free (ehci, qtd);
+
+ ehci_info (ehci, "Sending SETUP PHASE\n");
+ /* Charles, modify for MVL5 */
+ //if (submit_async (ehci, &udev->ep0, &urb, &setup_list, GFP_ATOMIC)) {
+ if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) {
+ ehci_err (ehci, "Failed to queue up qtds\n");
+ return -EBUSY;
+ }
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(15000));
+ urb.status = 0;
+ urb.actual_length = 0;
+
+ ehci_info (ehci, "Sending DATA PHASE\n");
+ /* Charles, modify for MVL5 */
+ //if (submit_async (ehci, &udev->ep0, &urb, &data_list, GFP_ATOMIC)) {
+
+ if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) {
+
+ ehci_err (ehci, "Failed to queue up qtds\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+static void stop_test(struct ehci_hcd *ehci)
+{
+ volatile unsigned int temp32 = 0;
+ //int ports = 0,i = 0;
+
+ /*reset HC */
+ temp32 = readl(&ehci->regs->command);
+ ehci_info(ehci, "command before set reset 0x%8.8x\n", temp32);
+ temp32 |= 0x00000002;
+ writel(temp32, &ehci->regs->command);
+ temp32 = readl (&ehci->regs->command);
+ ehci_info(ehci, "command after set reset 0x%8.8x\n", temp32);
+ while ((readl(&ehci->regs->command)) & 0x00000002)
+ ;
+
+ /*set CF bit*/
+ temp32 = readl(&ehci->regs->configured_flag);
+ ehci_info(ehci, "CF before set CF 0x%8.8x\n", temp32);
+ if (!temp32)
+ writel (FLAG_CF, &ehci->regs->configured_flag);
+ temp32 = readl(&ehci->regs->configured_flag);
+ while (!((readl(&ehci->regs->configured_flag)) & 0x00000001))
+ ;
+ ehci_info(ehci, "CF after set CF 0x%8.8x\n", temp32);
+
+
+}
+#endif
+/*CharlesTu}-------------------------------------------------------------*/
+
+static int handshake_wmt (struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+ u32 result1;
+ int usec_250;
+
+ if (usec > 1000)
+ usec_250 = usec - 261;
+ else
+ usec_250 = usec;
+
+ do {
+ result = ehci_readl(ehci, ptr);
+ result1 = result;
+ if (result == ~(u32)0) /* card removed */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay (1);
+ usec--;
+ if (usec == usec_250) {
+ ehci_writel(ehci,
+ result1 & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND),
+ ptr);
+// printk("*2nd clear resume\n");
+ }
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+extern unsigned int env_active;
+extern unsigned int env_port;
+extern unsigned int env_bitmap;
+extern unsigned int env_ctraddr;
+extern unsigned int env_ocaddr;
+extern unsigned int env_odaddr;
static int ehci_hub_control (
struct usb_hcd *hcd,
@@ -670,7 +897,8 @@ static int ehci_hub_control (
u32 temp, temp1, status;
unsigned long flags;
int retval = 0;
- unsigned selector;
+ unsigned selector=0;
+ u8 port_num = 0; //CharlesTu, for testmode
/*
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -742,7 +970,8 @@ static int ehci_hub_control (
spin_lock_irqsave(&ehci->lock, flags);
}
/* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ //temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS | PORT_SUSPEND);
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
@@ -839,11 +1068,28 @@ static int ehci_hub_control (
/* stop resume signaling */
temp = ehci_readl(ehci, status_reg);
+// ehci_writel(ehci,
+// temp & ~(PORT_RWC_BITS | PORT_RESUME),
+// status_reg);
+ if ((env_active) && (env_port == wIndex)) {
+ *((volatile unsigned char *)(env_ctraddr)) |= env_bitmap;
+ *((volatile unsigned char *)(env_ocaddr)) |= env_bitmap;
+ *((volatile unsigned char *)(env_odaddr)) |= env_bitmap;
+ }
ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_RESUME),
- status_reg);
+ temp & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND),
+ status_reg);
clear_bit(wIndex, &ehci->resuming_ports);
- retval = handshake(ehci, status_reg,
+
+ udelay(1);
+
+ if ((env_active) && (env_port == wIndex)) {
+ *((volatile unsigned char *)(env_odaddr)) &= (~env_bitmap);
+ }
+
+// retval = handshake(ehci, status_reg,
+// PORT_RESUME, 0, 2000 /* 2msec */);
+ retval = handshake_wmt(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) {
ehci_err(ehci,
@@ -984,7 +1230,12 @@ static int ehci_hub_control (
* mode if we have hostpc feature
*/
temp &= ~PORT_WKCONN_E;
- temp |= PORT_WKDISC_E | PORT_WKOC_E;
+
+ if (enable_ehci_wake && enable_ehci_disc_wakeup)
+ temp |= PORT_WKDISC_E | PORT_WKOC_E;
+ else
+ temp |= PORT_WKOC_E;
+
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
if (hostpc_reg) {
spin_unlock_irqrestore(&ehci->lock, flags);
@@ -1040,12 +1291,13 @@ static int ehci_hub_control (
* or else system reboot). See EHCI 2.3.9 and 4.14 for info
* about the EHCI-specific stuff.
*/
+/*
case USB_PORT_FEAT_TEST:
if (!selector || selector > 5)
goto error;
ehci_quiesce(ehci);
- /* Put all enabled ports into suspend */
+ // Put all enabled ports into suspend
while (ports--) {
u32 __iomem *sreg =
&ehci->regs->port_status[ports];
@@ -1060,6 +1312,59 @@ static int ehci_hub_control (
temp |= selector << 16;
ehci_writel(ehci, temp, status_reg);
break;
+*/
+ /*{CharlesTu, 2010.8.26, for test mode */
+ case USB_PORT_FEAT_TEST:
+ ehci_info(ehci, "selector : %x\n ", selector);
+ //selector = (wIndex >> 8) & 0xff;
+ port_num = (wIndex) & 0xff;
+ ehci_info(ehci, "USB_PORT_FEAT_TEST : running test %x "
+ "on port %d\n", selector, port_num);
+ if (!selector || selector > 5)
+ ehci_info(ehci, "USB_PORT_FEAT_TEST 1: running test %x "
+ "on port %d\n", selector, port_num);
+
+ switch (selector) {
+ case USB_PORT_TEST_J:
+ case USB_PORT_TEST_K:
+ case USB_PORT_TEST_SE0_NAK:
+ case USB_PORT_TEST_PACKET:
+ case USB_PORT_TEST_FORCE_ENABLE:
+ ehci_quiesce(ehci);
+ ehci_halt(ehci);
+#ifdef CONFIG_USB_EHCI_EHSET
+ stop_test(ehci);
+#endif
+ temp = ehci_readl(ehci, &ehci->regs->command);
+ temp &= 0xfffffffe;
+ writel(temp, &ehci->regs->command);
+
+ temp = readl(&ehci->regs->port_status [(wIndex & 0x00ff)]);
+ temp &= 0xfff0ffff;
+ writel(temp, &ehci->regs->port_status[port_num]);
+ temp |= selector << 16;
+ writel(temp, &ehci->regs->port_status[port_num]);
+ break;
+#ifdef CONFIG_USB_EHCI_EHSET
+ case USB_PORT_TEST_SINGLE_STEP_SET_FEATURE:
+ spin_unlock_irqrestore (&ehci->lock, flags);
+ if (single_step_set_feature(hcd, port_num)) {
+ spin_lock_irqsave (&ehci->lock, flags);
+ goto error;
+ }
+ spin_lock_irqsave (&ehci->lock, flags);
+ break;
+#endif
+
+ default:
+ goto error;
+ ehci_quiesce(ehci);
+ ehci_halt(ehci);
+ temp |= selector << 16;
+ writel (temp, &ehci->regs->port_status[port_num - 1]);
+ }
+ break;
+ /*CharlesTu} */
default:
goto error;
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c b/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c
index 12348179..49726685 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c
@@ -27,6 +27,8 @@
/*-------------------------------------------------------------------------*/
+extern char enable_ehci_wake;
+
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
{
@@ -334,7 +336,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
int rc = 0;
-
+ u16 pmc_enable = 0;
if (time_before(jiffies, ehci->next_statechange))
msleep(10);
@@ -352,7 +354,12 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
// could save FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew
-
+ //CharlesTu,for PM high memory
+ if (enable_ehci_wake) {
+ pci_read_config_word(to_pci_dev(hcd->self.controller), 0x84, &pmc_enable);
+ pmc_enable |= 0x103;
+ pci_write_config_word(to_pci_dev(hcd->self.controller), 0x84, pmc_enable);
+ }
return rc;
}
@@ -399,6 +406,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
* a '1' to the port switchover registers should have no effect if the
* port was already switched over.
*/
+ u16 pmc_enable = 0;
+ //CharlesTu,for PM high memory
+ if (enable_ehci_wake) {
+ pci_read_config_word(pdev, 0x84, &pmc_enable);
+ pmc_enable &= ~0x03;
+ pci_write_config_word(pdev, 0x84, pmc_enable);
+ }
if (usb_is_intel_switchable_ehci(pdev))
ehci_enable_xhci_companion();
@@ -409,7 +423,11 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
/* Mark hardware accessible again as we are out of D3 state by now */
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
+ /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend
+ * when resume ehci hub activate ,type= HUB_RESET_RESUME
+ */
+ if (!enable_ehci_wake)
+ usb_root_hub_lost_power(hcd->self.root_hub);
/* If CF is still set and we aren't resuming from hibernation
* then we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
@@ -425,8 +443,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
ehci_readl(ehci, &ehci->regs->intr_enable);
return 0;
}
-
- usb_root_hub_lost_power(hcd->self.root_hub);
+ /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend*/
+ if (enable_ehci_wake)
+ usb_root_hub_lost_power(hcd->self.root_hub);
/* Else reset, to cope with power loss or flush-to-storage
* style "resume" having let BIOS kick in during reboot.
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c b/ANDROID_3.4.5/drivers/usb/host/ehci-q.c
index 36ca5077..9e11e38a 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci-q.c
@@ -286,7 +286,12 @@ __acquires(ehci->lock)
status,
urb->actual_length, urb->transfer_buffer_length);
#endif
-
+ /*{CharlesTu, 2008.12.26, for test mode */
+#ifdef CONFIG_USB_EHCI_EHSET
+ if (likely(urb->transfer_flags == URB_HCD_DRIVER_TEST))
+ return;
+#endif
+ /*CharlesTu}*/
/* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c b/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c
index a60679cb..757e3463 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c
@@ -655,7 +655,8 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh_put (qh);
/* maybe turn off periodic schedule */
- return disable_periodic(ehci);
+ //return disable_periodic(ehci);
+ return 0;
}
static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -1767,7 +1768,7 @@ itd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- (void) disable_periodic(ehci);
+ //(void) disable_periodic(ehci); gri
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
@@ -2163,7 +2164,7 @@ sitd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- (void) disable_periodic(ehci);
+ //(void) disable_periodic(ehci);//gri
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci.h b/ANDROID_3.4.5/drivers/usb/host/ehci.h
index 2694ed65..f04172ef 100644
--- a/ANDROID_3.4.5/drivers/usb/host/ehci.h
+++ b/ANDROID_3.4.5/drivers/usb/host/ehci.h
@@ -771,5 +771,26 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
#endif /* DEBUG */
/*-------------------------------------------------------------------------*/
-
+/*{CharlesTu, 2010.08.26, for test mode */
+
+static struct list_head *
+qh_urb_transaction (
+ struct ehci_hcd *ehci,
+ struct urb *urb,
+ struct list_head *head,
+ gfp_t flags
+);
+
+static int submit_async (
+ struct ehci_hcd *ehci,
+ struct urb *urb,
+ struct list_head *qtd_list,
+ gfp_t mem_flags
+) ;
+
+static inline void ehci_qtd_free (
+ struct ehci_hcd *ehci,
+ struct ehci_qtd *qtd);
+
+/*CharlesTu}*/
#endif /* __LINUX_EHCI_HCD_H */
diff --git a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c
index df0828cb..2efade76 100644
--- a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c
+++ b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c
@@ -389,7 +389,7 @@ EXPORT_SYMBOL_GPL(uhci_reset_hc);
*/
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
{
- u16 legsup;
+ //u16 legsup;
unsigned int cmd, intr;
/*
@@ -402,16 +402,19 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
*
* If any of these conditions are violated we do a complete reset.
*/
+ #if 0
pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup);
if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) {
dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n",
__func__, legsup);
goto reset_needed;
}
+ #endif
cmd = inw(base + UHCI_USBCMD);
- if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) ||
- !(cmd & UHCI_USBCMD_EGSM)) {
+// if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) ||
+// !(cmd & UHCI_USBCMD_EGSM)) {
+ if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_EGSM)) {
dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n",
__func__, cmd);
goto reset_needed;
diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c
index e4db3506..3e0d2a8c 100644
--- a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c
+++ b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c
@@ -89,6 +89,8 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
/*
* Calculate the link pointer DMA value for the first Skeleton QH in a frame.
*/
@@ -338,6 +340,11 @@ __acquires(uhci->lock)
uhci->RD_enable = !!int_enable;
uhci_writew(uhci, int_enable, USBINTR);
+ //gri
+ uhci_writew(uhci, 0, USBCMD);
+ mb();
+ while (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH));
+ //
uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
mb();
udelay(5);
@@ -855,7 +862,7 @@ static int __init uhci_hcd_init(void)
int retval = -ENOMEM;
if (usb_disabled())
- return -ENODEV;
+ return -ENODEV;
printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n",
ignore_oc ? ", overcurrent ignored" : "");
diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c
index 768d5429..fb0da10f 100644
--- a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c
+++ b/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c
@@ -98,9 +98,12 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
{
int status;
int i;
+ u16 tmp;
+
if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) {
CLR_RH_PORTSTAT(SUSPEND_BITS);
+ wmb();
if (test_bit(port, &uhci->resuming_ports))
set_bit(port, &uhci->port_c_suspend);
@@ -110,9 +113,13 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
* Experiments show that some controllers take longer, so
* we'll poll for completion. */
for (i = 0; i < 10; ++i) {
- if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS))
- break;
udelay(1);
+ tmp = uhci_readw(uhci, port_addr);
+ //if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS)){
+ //printk("uhci_finish_suspend 01\n");
+ if (!(tmp & SUSPEND_BITS)){
+ break;
+ }
}
}
clear_bit(port, &uhci->resuming_ports);
diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c b/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c
index c300bd2f..2de5a93b 100644
--- a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c
+++ b/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c
@@ -18,6 +18,7 @@
*/
#include "pci-quirks.h"
+#include <mach/hardware.h>
/*
* Make sure the controller is completely inactive, unable to
@@ -162,11 +163,16 @@ static void uhci_shutdown(struct pci_dev *pdev)
#ifdef CONFIG_PM
+extern char enable_ehci_wake;
+extern char enable_uhci0_wake;
+extern char enable_uhci1_wake;
+
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
int rc = 0;
+ u16 pmc_enable = 0;
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
@@ -192,6 +198,12 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
pci_write_config_byte(pdev, USBRES_INTEL,
USBPORT1EN | USBPORT2EN);
}
+ //CharlesTu, for PM
+ if (((hcd->self.busnum == 2) && enable_uhci0_wake) || ((hcd->self.busnum == 3) && enable_uhci1_wake)){
+ pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable);
+ pmc_enable |= 0x103;
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable);
+ }
done_okay:
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -203,7 +215,19 @@ done:
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
+ u16 pmc_enable = 0;
+ /*CharlesTu,2009.08.30,patch uhci device disconnet irq nobody care issue
+ * Before clear D3 mode ,disable UHCI resume interrupt
+ * The right sequence: disconnect->wakeup->D0 mode->clear resume.
+ */
+ if (enable_ehci_wake){
+ REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x0304) &= ~0x02;
+ REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x1504) &= ~0x02;
+
+ pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable);
+ pmc_enable &= ~0x03;
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable);
+ }
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
/* Since we aren't in D3 any more, it's safe to set this flag
diff --git a/ANDROID_3.4.5/drivers/usb/serial/Makefile b/ANDROID_3.4.5/drivers/usb/serial/Makefile
index 07f198ee..d0bd3be2 100644
--- a/ANDROID_3.4.5/drivers/usb/serial/Makefile
+++ b/ANDROID_3.4.5/drivers/usb/serial/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
+obj-m += via_option.o
diff --git a/ANDROID_3.4.5/drivers/usb/serial/option.c b/ANDROID_3.4.5/drivers/usb/serial/option.c
index 49484b39..82d5ecf9 100644
--- a/ANDROID_3.4.5/drivers/usb/serial/option.c
+++ b/ANDROID_3.4.5/drivers/usb/serial/option.c
@@ -50,6 +50,11 @@ static int option_probe(struct usb_serial *serial,
static void option_release(struct usb_serial *serial);
static int option_send_setup(struct usb_serial_port *port);
static void option_instat_callback(struct urb *urb);
+/* VIA-Telecom CBP(Non-CDC version) IDs */
+#define VIATELECOM_VENDOR_ID 0x15EB
+#define VIATELECOM_PRODUCT_ID 0x0001
+#define BORA9380_VENDOR_ID 0x16d8
+#define BORA9380_PRODUCT_ID 0x4000
/* Vendor and product IDs */
#define OPTION_VENDOR_ID 0x0AF0
@@ -158,8 +163,10 @@ static void option_instat_callback(struct urb *urb);
#define HUAWEI_PRODUCT_K4511 0x14CC
#define HUAWEI_PRODUCT_ETS1220 0x1803
#define HUAWEI_PRODUCT_E353 0x1506
-#define HUAWEI_PRODUCT_E173S 0x1C05
-
+//aron add--------
+#define HUAWEI_PRODUCT_E153 0x1446
+#define HUAWEI_PRODUCT_E173 0x1C05
+//----------
#define QUANTA_VENDOR_ID 0x0408
#define QUANTA_PRODUCT_Q101 0xEA02
#define QUANTA_PRODUCT_Q111 0xEA03
@@ -681,7 +688,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
@@ -704,6 +711,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E153) }, //aaron add
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173) },//aron add
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) },
@@ -1128,7 +1137,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2000, 0xff, 0xff, 0xff) }, //aron add.
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) },
@@ -1267,6 +1276,28 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
+ { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) },/* VIA-Telecom CBP CDC Version*/
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, 0xff, 0xff, 0xff) }, /*huawei E173*/
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x1000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x6000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0xf00e, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0x1105, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */
+ { USB_DEVICE(0x19f5, 0x9909) }, /*UW100 */
+ { USB_DEVICE(0x19f5, 0x9013) }, /*UW100 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x0015, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1176, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(BORA9380_VENDOR_ID, BORA9380_PRODUCT_ID) },/* ²¨ÀÖ9380*/
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14a8, 0xff, 0xff, 0xff) },
+
+ { USB_DEVICE(0x1c9e, 0x9605) }, /*a dongle without brand */
+ { USB_DEVICE(0x231e, 0x0036) }, /*CYIT TD/GSM modem*/
+ { USB_DEVICE(ZTE_VENDOR_ID, 0x1176) }, /*vodafone k3770-z*/
+ { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1506) }, /*hw e1731*/
+ { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1573) }, /*hw mu609*/
+ { USB_DEVICE(0x1782, 0x0002) }, /*spectrum G3 3g modem*/
+ { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1c25) }, /*hw mu709*/
+ { USB_DEVICE(0x2001, 0x7d01) }, /*dlink dwm156*/
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1347,6 +1378,21 @@ static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
}
return false;
}
+static int viatelecom_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+ int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+
+ /* VIA-Telecom CBP DTR format */
+ return usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+
+}
+
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
@@ -1381,10 +1427,22 @@ static int option_probe(struct usb_serial *serial,
serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA)
return -ENODEV;
+
+ if(serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID){
+ if(0!=(serial->dev->config->desc.bmAttributes&0x20)){
+ usb_enable_autosuspend(serial->dev);
+ }
+ }
+
data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->send_setup = option_send_setup;
+
+ if ((serial->dev->descriptor.idVendor == BORA9380_VENDOR_ID &&
+ serial->dev->descriptor.idProduct == BORA9380_PRODUCT_ID)) {
+ data->send_setup = viatelecom_send_setup;
+ } else
+ data->send_setup = option_send_setup;
spin_lock_init(&data->susp_lock);
data->private = (void *)id->driver_info;
return 0;
diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c b/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c
index bcf26177..03c117c9 100644
--- a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c
+++ b/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c
@@ -93,16 +93,16 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
}
static struct usb_serial *get_free_serial(struct usb_serial *serial,
- int num_ports, unsigned int *minor)
+ int num_ports, unsigned int *minor,int startIndex)
{
unsigned int i, j;
int good_spot;
dbg("%s %d", __func__, num_ports);
+ *minor = startIndex;
- *minor = 0;
mutex_lock(&table_lock);
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ for (i = startIndex; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
@@ -736,7 +736,7 @@ int usb_serial_probe(struct usb_interface *interface,
int num_bulk_out = 0;
int num_ports = 0;
int max_endpoints;
-
+ int startIndex = 0;
mutex_lock(&table_lock);
type = search_serial_device(interface);
if (!type) {
@@ -1066,8 +1066,10 @@ int usb_serial_probe(struct usb_interface *interface,
* registered.
*/
serial->disconnected = 1;
+ if(!strcmp(type->driver.name,"pl2303")||!strcmp(type->driver.name,"ftdi_sio")||!strcmp(type->driver.name,"cp210x"))
+ startIndex = 5;
- if (get_free_serial(serial, num_ports, &minor) == NULL) {
+ if (get_free_serial(serial, num_ports, &minor, startIndex) == NULL) {
dev_err(&interface->dev, "No more free serial devices\n");
goto probe_error;
}
diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_option.c b/ANDROID_3.4.5/drivers/usb/serial/via_option.c
new file mode 100755
index 00000000..2c8a84f3
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/serial/via_option.c
@@ -0,0 +1,1218 @@
+/*
+ USB Driver for GSM modems
+
+ Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
+
+ This driver is free software; you can redistribute it and/or modify
+ it under the terms of Version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+ History: see the git log.
+
+ Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
+
+ This driver exists because the "normal" serial driver doesn't work too well
+ with GSM modems. Issues:
+ - data loss -- one single Receive URB is not nearly enough
+ - nonstandard flow (Option devices) control
+ - controlling the baud rate doesn't make sense
+
+ This driver is named "option" because the most common device it's
+ used for is a PC-Card (with an internal OHCI-USB interface, behind
+ which the GSM interface sits), made by Option Inc.
+
+ Some of the "one port" devices actually exhibit multiple USB instances
+ on the USB bus. This is not a bug, these ports are used for different
+ device features.
+*/
+
+#define DRIVER_VERSION "v0.7.2"
+#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
+#define DRIVER_DESC "USB Driver for GSM modems"
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/usb/rawbulk.h>
+#include <linux/suspend.h>
+#include "via_usb-wwan.h"
+#include "via_usb_wwan.c"
+
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+#include <mach/viatel.h>
+//#include "../drivers/usb/core/usb.h"
+#endif
+
+/* Function prototypes */
+static int option_probe(struct usb_serial *serial,
+ const struct usb_device_id *id);
+static void option_release(struct usb_serial *serial);
+static int option_send_setup(struct usb_serial_port *port);
+static void option_instat_callback(struct urb *urb);
+/* VIA-Telecom CBP(Non-CDC version) IDs */
+struct wake_lock ets_wake_lock;
+int ets_wake_lock_init = 0;
+#define VIATELECOM_VENDOR_ID 0x15EB
+#define VIATELECOM_PRODUCT_ID 0x0001
+#define BORA9380_VENDOR_ID 0x16d8
+#define BORA9380_PRODUCT_ID 0x4000
+
+/* Vendor and product IDs */
+#define OPTION_VENDOR_ID 0x0AF0
+#define OPTION_PRODUCT_COLT 0x5000
+#define OPTION_PRODUCT_RICOLA 0x6000
+#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100
+#define OPTION_PRODUCT_RICOLA_QUAD 0x6200
+#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300
+#define OPTION_PRODUCT_RICOLA_NDIS 0x6050
+#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350
+#define OPTION_PRODUCT_COBRA 0x6500
+#define OPTION_PRODUCT_COBRA_BUS 0x6501
+#define OPTION_PRODUCT_VIPER 0x6600
+#define OPTION_PRODUCT_VIPER_BUS 0x6601
+#define OPTION_PRODUCT_GT_MAX_READY 0x6701
+#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
+#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
+#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
+#define OPTION_PRODUCT_KOI_MODEM 0x6800
+#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
+#define OPTION_PRODUCT_ETNA_MODEM 0x7001
+#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
+#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
+#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
+#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
+#define OPTION_PRODUCT_GTM380_MODEM 0x7201
+
+#define HUAWEI_VENDOR_ID 0x12D1
+#define HUAWEI_PRODUCT_E600 0x1001
+#define HUAWEI_PRODUCT_E220 0x1003
+#define HUAWEI_PRODUCT_E220BIS 0x1004
+#define HUAWEI_PRODUCT_E1401 0x1401
+#define HUAWEI_PRODUCT_E1402 0x1402
+#define HUAWEI_PRODUCT_E1403 0x1403
+#define HUAWEI_PRODUCT_E1404 0x1404
+#define HUAWEI_PRODUCT_E1405 0x1405
+#define HUAWEI_PRODUCT_E1406 0x1406
+#define HUAWEI_PRODUCT_E1407 0x1407
+#define HUAWEI_PRODUCT_E1408 0x1408
+#define HUAWEI_PRODUCT_E1409 0x1409
+#define HUAWEI_PRODUCT_E140A 0x140A
+#define HUAWEI_PRODUCT_E140B 0x140B
+#define HUAWEI_PRODUCT_E140C 0x140C
+#define HUAWEI_PRODUCT_E140D 0x140D
+#define HUAWEI_PRODUCT_E140E 0x140E
+#define HUAWEI_PRODUCT_E140F 0x140F
+#define HUAWEI_PRODUCT_E1410 0x1410
+#define HUAWEI_PRODUCT_E1411 0x1411
+#define HUAWEI_PRODUCT_E1412 0x1412
+#define HUAWEI_PRODUCT_E1413 0x1413
+#define HUAWEI_PRODUCT_E1414 0x1414
+#define HUAWEI_PRODUCT_E1415 0x1415
+#define HUAWEI_PRODUCT_E1416 0x1416
+#define HUAWEI_PRODUCT_E1417 0x1417
+#define HUAWEI_PRODUCT_E1418 0x1418
+#define HUAWEI_PRODUCT_E1419 0x1419
+#define HUAWEI_PRODUCT_E141A 0x141A
+#define HUAWEI_PRODUCT_E141B 0x141B
+#define HUAWEI_PRODUCT_E141C 0x141C
+#define HUAWEI_PRODUCT_E141D 0x141D
+#define HUAWEI_PRODUCT_E141E 0x141E
+#define HUAWEI_PRODUCT_E141F 0x141F
+#define HUAWEI_PRODUCT_E1420 0x1420
+#define HUAWEI_PRODUCT_E1421 0x1421
+#define HUAWEI_PRODUCT_E1422 0x1422
+#define HUAWEI_PRODUCT_E1423 0x1423
+#define HUAWEI_PRODUCT_E1424 0x1424
+#define HUAWEI_PRODUCT_E1425 0x1425
+#define HUAWEI_PRODUCT_E1426 0x1426
+#define HUAWEI_PRODUCT_E1427 0x1427
+#define HUAWEI_PRODUCT_E1428 0x1428
+#define HUAWEI_PRODUCT_E1429 0x1429
+#define HUAWEI_PRODUCT_E142A 0x142A
+#define HUAWEI_PRODUCT_E142B 0x142B
+#define HUAWEI_PRODUCT_E142C 0x142C
+#define HUAWEI_PRODUCT_E142D 0x142D
+#define HUAWEI_PRODUCT_E142E 0x142E
+#define HUAWEI_PRODUCT_E142F 0x142F
+#define HUAWEI_PRODUCT_E1430 0x1430
+#define HUAWEI_PRODUCT_E1431 0x1431
+#define HUAWEI_PRODUCT_E1432 0x1432
+#define HUAWEI_PRODUCT_E1433 0x1433
+#define HUAWEI_PRODUCT_E1434 0x1434
+#define HUAWEI_PRODUCT_E1435 0x1435
+#define HUAWEI_PRODUCT_E1436 0x1436
+#define HUAWEI_PRODUCT_E1437 0x1437
+#define HUAWEI_PRODUCT_E1438 0x1438
+#define HUAWEI_PRODUCT_E1439 0x1439
+#define HUAWEI_PRODUCT_E143A 0x143A
+#define HUAWEI_PRODUCT_E143B 0x143B
+#define HUAWEI_PRODUCT_E143C 0x143C
+#define HUAWEI_PRODUCT_E143D 0x143D
+#define HUAWEI_PRODUCT_E143E 0x143E
+#define HUAWEI_PRODUCT_E143F 0x143F
+#define HUAWEI_PRODUCT_K4505 0x1464
+#define HUAWEI_PRODUCT_K3765 0x1465
+#define HUAWEI_PRODUCT_E14AC 0x14AC
+#define HUAWEI_PRODUCT_K3806 0x14AE
+#define HUAWEI_PRODUCT_K4605 0x14C6
+#define HUAWEI_PRODUCT_K5005 0x14C8
+#define HUAWEI_PRODUCT_K3770 0x14C9
+#define HUAWEI_PRODUCT_K3771 0x14CA
+#define HUAWEI_PRODUCT_K4510 0x14CB
+#define HUAWEI_PRODUCT_K4511 0x14CC
+#define HUAWEI_PRODUCT_ETS1220 0x1803
+#define HUAWEI_PRODUCT_E353 0x1506
+//aron add--------
+#define HUAWEI_PRODUCT_E153 0x1446
+#define HUAWEI_PRODUCT_E173 0x1C05
+//----------
+#define QUANTA_VENDOR_ID 0x0408
+#define QUANTA_PRODUCT_Q101 0xEA02
+#define QUANTA_PRODUCT_Q111 0xEA03
+#define QUANTA_PRODUCT_GLX 0xEA04
+#define QUANTA_PRODUCT_GKE 0xEA05
+#define QUANTA_PRODUCT_GLE 0xEA06
+
+#define NOVATELWIRELESS_VENDOR_ID 0x1410
+
+/* YISO PRODUCTS */
+
+#define YISO_VENDOR_ID 0x0EAB
+#define YISO_PRODUCT_U893 0xC893
+
+/*
+ * NOVATEL WIRELESS PRODUCTS
+ *
+ * Note from Novatel Wireless:
+ * If your Novatel modem does not work on linux, don't
+ * change the option module, but check our website. If
+ * that does not help, contact ddeschepper@nvtl.com
+*/
+/* MERLIN EVDO PRODUCTS */
+#define NOVATELWIRELESS_PRODUCT_V640 0x1100
+#define NOVATELWIRELESS_PRODUCT_V620 0x1110
+#define NOVATELWIRELESS_PRODUCT_V740 0x1120
+#define NOVATELWIRELESS_PRODUCT_V720 0x1130
+
+/* MERLIN HSDPA/HSPA PRODUCTS */
+#define NOVATELWIRELESS_PRODUCT_U730 0x1400
+#define NOVATELWIRELESS_PRODUCT_U740 0x1410
+#define NOVATELWIRELESS_PRODUCT_U870 0x1420
+#define NOVATELWIRELESS_PRODUCT_XU870 0x1430
+#define NOVATELWIRELESS_PRODUCT_X950D 0x1450
+
+/* EXPEDITE PRODUCTS */
+#define NOVATELWIRELESS_PRODUCT_EV620 0x2100
+#define NOVATELWIRELESS_PRODUCT_ES720 0x2110
+#define NOVATELWIRELESS_PRODUCT_E725 0x2120
+#define NOVATELWIRELESS_PRODUCT_ES620 0x2130
+#define NOVATELWIRELESS_PRODUCT_EU730 0x2400
+#define NOVATELWIRELESS_PRODUCT_EU740 0x2410
+#define NOVATELWIRELESS_PRODUCT_EU870D 0x2420
+/* OVATION PRODUCTS */
+#define NOVATELWIRELESS_PRODUCT_MC727 0x4100
+#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400
+/*
+ * Note from Novatel Wireless:
+ * All PID in the 5xxx range are currently reserved for
+ * auto-install CDROMs, and should not be added to this
+ * module.
+ *
+ * #define NOVATELWIRELESS_PRODUCT_U727 0x5010
+ * #define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100
+*/
+#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002
+#define NOVATELWIRELESS_PRODUCT_MC780 0x6010
+#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0x6000
+#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0x6001
+#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0x7000
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0x7001
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3 0x7003
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4 0x7004
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5 0x7005
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6 0x7006
+#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7 0x7007
+#define NOVATELWIRELESS_PRODUCT_MC996D 0x7030
+#define NOVATELWIRELESS_PRODUCT_MF3470 0x7041
+#define NOVATELWIRELESS_PRODUCT_MC547 0x7042
+#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0x8000
+#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001
+#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
+#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
+#define NOVATELWIRELESS_PRODUCT_G1 0xA001
+#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002
+#define NOVATELWIRELESS_PRODUCT_G2 0xA010
+#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
+
+/* AMOI PRODUCTS */
+#define AMOI_VENDOR_ID 0x1614
+#define AMOI_PRODUCT_H01 0x0800
+#define AMOI_PRODUCT_H01A 0x7002
+#define AMOI_PRODUCT_H02 0x0802
+#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407
+
+#define DELL_VENDOR_ID 0x413C
+
+/* Dell modems */
+#define DELL_PRODUCT_5700_MINICARD 0x8114
+#define DELL_PRODUCT_5500_MINICARD 0x8115
+#define DELL_PRODUCT_5505_MINICARD 0x8116
+#define DELL_PRODUCT_5700_EXPRESSCARD 0x8117
+#define DELL_PRODUCT_5510_EXPRESSCARD 0x8118
+
+#define DELL_PRODUCT_5700_MINICARD_SPRINT 0x8128
+#define DELL_PRODUCT_5700_MINICARD_TELUS 0x8129
+
+#define DELL_PRODUCT_5720_MINICARD_VZW 0x8133
+#define DELL_PRODUCT_5720_MINICARD_SPRINT 0x8134
+#define DELL_PRODUCT_5720_MINICARD_TELUS 0x8135
+#define DELL_PRODUCT_5520_MINICARD_CINGULAR 0x8136
+#define DELL_PRODUCT_5520_MINICARD_GENERIC_L 0x8137
+#define DELL_PRODUCT_5520_MINICARD_GENERIC_I 0x8138
+
+#define DELL_PRODUCT_5730_MINICARD_SPRINT 0x8180
+#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181
+#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182
+
+#define KYOCERA_VENDOR_ID 0x0c88
+#define KYOCERA_PRODUCT_KPC650 0x17da
+#define KYOCERA_PRODUCT_KPC680 0x180a
+
+#define ANYDATA_VENDOR_ID 0x16d5
+#define ANYDATA_PRODUCT_ADU_620UW 0x6202
+#define ANYDATA_PRODUCT_ADU_E100A 0x6501
+#define ANYDATA_PRODUCT_ADU_500A 0x6502
+
+#define AXESSTEL_VENDOR_ID 0x1726
+#define AXESSTEL_PRODUCT_MV110H 0x1000
+
+#define BANDRICH_VENDOR_ID 0x1A8D
+#define BANDRICH_PRODUCT_C100_1 0x1002
+#define BANDRICH_PRODUCT_C100_2 0x1003
+#define BANDRICH_PRODUCT_1004 0x1004
+#define BANDRICH_PRODUCT_1005 0x1005
+#define BANDRICH_PRODUCT_1006 0x1006
+#define BANDRICH_PRODUCT_1007 0x1007
+#define BANDRICH_PRODUCT_1008 0x1008
+#define BANDRICH_PRODUCT_1009 0x1009
+#define BANDRICH_PRODUCT_100A 0x100a
+
+#define BANDRICH_PRODUCT_100B 0x100b
+#define BANDRICH_PRODUCT_100C 0x100c
+#define BANDRICH_PRODUCT_100D 0x100d
+#define BANDRICH_PRODUCT_100E 0x100e
+
+#define BANDRICH_PRODUCT_100F 0x100f
+#define BANDRICH_PRODUCT_1010 0x1010
+#define BANDRICH_PRODUCT_1011 0x1011
+#define BANDRICH_PRODUCT_1012 0x1012
+
+#define QUALCOMM_VENDOR_ID 0x05C6
+
+#define CMOTECH_VENDOR_ID 0x16d8
+#define CMOTECH_PRODUCT_6008 0x6008
+#define CMOTECH_PRODUCT_6280 0x6280
+
+#define TELIT_VENDOR_ID 0x1bc7
+#define TELIT_PRODUCT_UC864E 0x1003
+#define TELIT_PRODUCT_UC864G 0x1004
+#define TELIT_PRODUCT_CC864_DUAL 0x1005
+#define TELIT_PRODUCT_CC864_SINGLE 0x1006
+#define TELIT_PRODUCT_DE910_DUAL 0x1010
+
+/* ZTE PRODUCTS */
+#define ZTE_VENDOR_ID 0x19d2
+#define ZTE_PRODUCT_MF622 0x0001
+#define ZTE_PRODUCT_MF628 0x0015
+#define ZTE_PRODUCT_MF626 0x0031
+#define ZTE_PRODUCT_CDMA_TECH 0xfffe
+#define ZTE_PRODUCT_AC8710 0xfff1
+#define ZTE_PRODUCT_AC2726 0xfff5
+#define ZTE_PRODUCT_AC8710T 0xffff
+#define ZTE_PRODUCT_MC2718 0xffe8
+#define ZTE_PRODUCT_AD3812 0xffeb
+#define ZTE_PRODUCT_MC2716 0xffed
+
+#define BENQ_VENDOR_ID 0x04a5
+#define BENQ_PRODUCT_H10 0x4068
+
+#define DLINK_VENDOR_ID 0x1186
+#define DLINK_PRODUCT_DWM_652 0x3e04
+#define DLINK_PRODUCT_DWM_652_U5 0xce16
+#define DLINK_PRODUCT_DWM_652_U5A 0xce1e
+
+#define QISDA_VENDOR_ID 0x1da5
+#define QISDA_PRODUCT_H21_4512 0x4512
+#define QISDA_PRODUCT_H21_4523 0x4523
+#define QISDA_PRODUCT_H20_4515 0x4515
+#define QISDA_PRODUCT_H20_4518 0x4518
+#define QISDA_PRODUCT_H20_4519 0x4519
+
+/* TLAYTECH PRODUCTS */
+#define TLAYTECH_VENDOR_ID 0x20B9
+#define TLAYTECH_PRODUCT_TEU800 0x1682
+
+/* TOSHIBA PRODUCTS */
+#define TOSHIBA_VENDOR_ID 0x0930
+#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302
+#define TOSHIBA_PRODUCT_G450 0x0d45
+
+#define ALINK_VENDOR_ID 0x1e0e
+#define ALINK_PRODUCT_PH300 0x9100
+#define ALINK_PRODUCT_3GU 0x9200
+
+/* ALCATEL PRODUCTS */
+#define ALCATEL_VENDOR_ID 0x1bbb
+#define ALCATEL_PRODUCT_X060S_X200 0x0000
+
+#define PIRELLI_VENDOR_ID 0x1266
+#define PIRELLI_PRODUCT_C100_1 0x1002
+#define PIRELLI_PRODUCT_C100_2 0x1003
+#define PIRELLI_PRODUCT_1004 0x1004
+#define PIRELLI_PRODUCT_1005 0x1005
+#define PIRELLI_PRODUCT_1006 0x1006
+#define PIRELLI_PRODUCT_1007 0x1007
+#define PIRELLI_PRODUCT_1008 0x1008
+#define PIRELLI_PRODUCT_1009 0x1009
+#define PIRELLI_PRODUCT_100A 0x100a
+#define PIRELLI_PRODUCT_100B 0x100b
+#define PIRELLI_PRODUCT_100C 0x100c
+#define PIRELLI_PRODUCT_100D 0x100d
+#define PIRELLI_PRODUCT_100E 0x100e
+#define PIRELLI_PRODUCT_100F 0x100f
+#define PIRELLI_PRODUCT_1011 0x1011
+#define PIRELLI_PRODUCT_1012 0x1012
+
+/* Airplus products */
+#define AIRPLUS_VENDOR_ID 0x1011
+#define AIRPLUS_PRODUCT_MCD650 0x3198
+
+/* Longcheer/Longsung vendor ID; makes whitelabel devices that
+ * many other vendors like 4G Systems, Alcatel, ChinaBird,
+ * Mobidata, etc sell under their own brand names.
+ */
+#define LONGCHEER_VENDOR_ID 0x1c9e
+
+/* 4G Systems products */
+/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
+ * It seems to contain a Qualcomm QSC6240/6290 chipset */
+#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
+
+/* Zoom */
+#define ZOOM_PRODUCT_4597 0x9607
+
+/* Haier products */
+#define HAIER_VENDOR_ID 0x201e
+#define HAIER_PRODUCT_CE100 0x2009
+
+/* Cinterion (formerly Siemens) products */
+#define SIEMENS_VENDOR_ID 0x0681
+#define CINTERION_VENDOR_ID 0x1e2d
+#define CINTERION_PRODUCT_HC25_MDM 0x0047
+#define CINTERION_PRODUCT_HC25_MDMNET 0x0040
+#define CINTERION_PRODUCT_HC28_MDM 0x004C
+#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */
+#define CINTERION_PRODUCT_EU3_E 0x0051
+#define CINTERION_PRODUCT_EU3_P 0x0052
+#define CINTERION_PRODUCT_PH8 0x0053
+
+/* Olivetti products */
+#define OLIVETTI_VENDOR_ID 0x0b3c
+#define OLIVETTI_PRODUCT_OLICARD100 0xc000
+
+/* Celot products */
+#define CELOT_VENDOR_ID 0x211f
+#define CELOT_PRODUCT_CT680M 0x6801
+
+/* ONDA Communication vendor id */
+#define ONDA_VENDOR_ID 0x1ee8
+
+/* ONDA MT825UP HSDPA 14.2 modem */
+#define ONDA_MT825UP 0x000b
+
+/* Samsung products */
+#define SAMSUNG_VENDOR_ID 0x04e8
+#define SAMSUNG_PRODUCT_GT_B3730 0x6889
+
+/* YUGA products www.yuga-info.com gavin.kx@qq.com */
+#define YUGA_VENDOR_ID 0x257A
+#define YUGA_PRODUCT_CEM600 0x1601
+#define YUGA_PRODUCT_CEM610 0x1602
+#define YUGA_PRODUCT_CEM500 0x1603
+#define YUGA_PRODUCT_CEM510 0x1604
+#define YUGA_PRODUCT_CEM800 0x1605
+#define YUGA_PRODUCT_CEM900 0x1606
+
+#define YUGA_PRODUCT_CEU818 0x1607
+#define YUGA_PRODUCT_CEU816 0x1608
+#define YUGA_PRODUCT_CEU828 0x1609
+#define YUGA_PRODUCT_CEU826 0x160A
+#define YUGA_PRODUCT_CEU518 0x160B
+#define YUGA_PRODUCT_CEU516 0x160C
+#define YUGA_PRODUCT_CEU528 0x160D
+#define YUGA_PRODUCT_CEU526 0x160F
+#define YUGA_PRODUCT_CEU881 0x161F
+#define YUGA_PRODUCT_CEU882 0x162F
+
+#define YUGA_PRODUCT_CWM600 0x2601
+#define YUGA_PRODUCT_CWM610 0x2602
+#define YUGA_PRODUCT_CWM500 0x2603
+#define YUGA_PRODUCT_CWM510 0x2604
+#define YUGA_PRODUCT_CWM800 0x2605
+#define YUGA_PRODUCT_CWM900 0x2606
+
+#define YUGA_PRODUCT_CWU718 0x2607
+#define YUGA_PRODUCT_CWU716 0x2608
+#define YUGA_PRODUCT_CWU728 0x2609
+#define YUGA_PRODUCT_CWU726 0x260A
+#define YUGA_PRODUCT_CWU518 0x260B
+#define YUGA_PRODUCT_CWU516 0x260C
+#define YUGA_PRODUCT_CWU528 0x260D
+#define YUGA_PRODUCT_CWU581 0x260E
+#define YUGA_PRODUCT_CWU526 0x260F
+#define YUGA_PRODUCT_CWU582 0x261F
+#define YUGA_PRODUCT_CWU583 0x262F
+
+#define YUGA_PRODUCT_CLM600 0x3601
+#define YUGA_PRODUCT_CLM610 0x3602
+#define YUGA_PRODUCT_CLM500 0x3603
+#define YUGA_PRODUCT_CLM510 0x3604
+#define YUGA_PRODUCT_CLM800 0x3605
+#define YUGA_PRODUCT_CLM900 0x3606
+
+#define YUGA_PRODUCT_CLU718 0x3607
+#define YUGA_PRODUCT_CLU716 0x3608
+#define YUGA_PRODUCT_CLU728 0x3609
+#define YUGA_PRODUCT_CLU726 0x360A
+#define YUGA_PRODUCT_CLU518 0x360B
+#define YUGA_PRODUCT_CLU516 0x360C
+#define YUGA_PRODUCT_CLU528 0x360D
+#define YUGA_PRODUCT_CLU526 0x360F
+
+/* Viettel products */
+#define VIETTEL_VENDOR_ID 0x2262
+#define VIETTEL_PRODUCT_VT1000 0x0002
+
+/* ZD Incorporated */
+#define ZD_VENDOR_ID 0x0685
+#define ZD_PRODUCT_7000 0x7000
+
+/* LG products */
+#define LG_VENDOR_ID 0x1004
+#define LG_PRODUCT_L02C 0x618f
+
+/* MediaTek products */
+#define MEDIATEK_VENDOR_ID 0x0e8d
+#define MEDIATEK_PRODUCT_DC_1COM 0x00a0
+#define MEDIATEK_PRODUCT_DC_4COM 0x00a5
+#define MEDIATEK_PRODUCT_DC_5COM 0x00a4
+#define MEDIATEK_PRODUCT_7208_1COM 0x7101
+#define MEDIATEK_PRODUCT_7208_2COM 0x7102
+#define MEDIATEK_PRODUCT_FP_1COM 0x0003
+#define MEDIATEK_PRODUCT_FP_2COM 0x0023
+#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043
+#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033
+
+/* Cellient products */
+#define CELLIENT_VENDOR_ID 0x2692
+#define CELLIENT_PRODUCT_MEN200 0x9005
+
+/* some devices interfaces need special handling due to a number of reasons */
+enum option_blacklist_reason {
+ OPTION_BLACKLIST_NONE = 0,
+ OPTION_BLACKLIST_SENDSETUP = 1,
+ OPTION_BLACKLIST_RESERVED_IF = 2
+};
+
+#define MAX_BL_NUM 8
+struct option_blacklist_info {
+ /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
+ const unsigned long sendsetup;
+ /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */
+ const unsigned long reserved;
+};
+
+static const struct option_blacklist_info four_g_w14_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
+};
+
+static const struct option_blacklist_info alcatel_x200_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
+};
+
+static const struct option_blacklist_info zte_0037_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
+};
+
+static const struct option_blacklist_info zte_k3765_z_blacklist = {
+ .sendsetup = BIT(0) | BIT(1) | BIT(2),
+ .reserved = BIT(4),
+};
+
+static const struct option_blacklist_info zte_ad3812_z_blacklist = {
+ .sendsetup = BIT(0) | BIT(1) | BIT(2),
+};
+
+static const struct option_blacklist_info zte_mc2718_z_blacklist = {
+ .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
+};
+
+static const struct option_blacklist_info zte_mc2716_z_blacklist = {
+ .sendsetup = BIT(1) | BIT(2) | BIT(3),
+};
+
+static const struct option_blacklist_info huawei_cdc12_blacklist = {
+ .reserved = BIT(1) | BIT(2),
+};
+
+static const struct option_blacklist_info net_intf1_blacklist = {
+ .reserved = BIT(1),
+};
+
+static const struct option_blacklist_info net_intf2_blacklist = {
+ .reserved = BIT(2),
+};
+
+static const struct option_blacklist_info net_intf3_blacklist = {
+ .reserved = BIT(3),
+};
+
+static const struct option_blacklist_info net_intf4_blacklist = {
+ .reserved = BIT(4),
+};
+
+static const struct option_blacklist_info net_intf5_blacklist = {
+ .reserved = BIT(5),
+};
+
+static const struct option_blacklist_info zte_mf626_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
+ .reserved = BIT(4),
+};
+
+static const struct usb_device_id option_ids[] = {
+ { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) },
+ { USB_DEVICE(0x201e, 0x1022) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, option_ids);
+
+
+/* add rawbulk suspend support */
+static int usb_serial_option_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ int rc = 0;
+
+ rc = usb_serial_suspend(intf, message);
+ if(rc < 0)
+ {
+ err("usb_serial_suspend return error, errno=%d\n", rc);
+ return rc;
+ }
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ return rawbulk_suspend_host_interface(intf->cur_altsetting->desc.bInterfaceNumber, message);
+#else
+ return rc;
+#endif
+}
+
+static int usb_serial_option_resume(struct usb_interface *intf)
+{
+ int rc = 0;
+
+ rc = usb_serial_resume(intf);
+ if(rc < 0)
+ {
+ err("usb_serial_resume return error, errno=%d\n", rc);
+ return rc;
+ }
+
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ return rawbulk_resume_host_interface(intf->cur_altsetting->desc.bInterfaceNumber);
+#else
+ return rc;
+#endif
+}
+/* End of temp added */
+
+static int usb_serial_option_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void usb_serial_option_disconnect(struct usb_interface *interface);
+static struct usb_driver option_driver = {
+ .name = "via_option",
+ .probe = usb_serial_option_probe,
+ .disconnect = usb_serial_option_disconnect,
+#ifdef CONFIG_PM
+ .suspend = usb_serial_option_suspend,
+ .resume = usb_serial_option_resume,
+ .supports_autosuspend = 1,
+#endif
+ .id_table = option_ids,
+};
+
+static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port
+ *port, const unsigned char *buf, int count);
+
+
+/* The card has three separate interfaces, which the serial driver
+ * recognizes separately, thus num_port=1.
+ */
+
+static struct usb_serial_driver option_1port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "via_option1",
+ },
+ .description = "GSM modem (1-port)",
+ .id_table = option_ids,
+ .num_ports = 1,
+ .probe = option_probe,
+ .open = usb_wwan_open,
+ .close = usb_wwan_close,
+ .dtr_rts = usb_wwan_dtr_rts,
+ .write = usb_wwan_option_write,
+ .write_room = usb_wwan_write_room,
+ .chars_in_buffer = usb_wwan_chars_in_buffer,
+ .set_termios = usb_wwan_set_termios,
+ .tiocmget = usb_wwan_tiocmget,
+ .tiocmset = usb_wwan_tiocmset,
+ .ioctl = usb_wwan_ioctl,
+ .attach = usb_wwan_startup,
+ .disconnect = usb_wwan_disconnect,
+ .release = usb_wwan_release,
+ .read_int_callback = option_instat_callback,
+#ifdef CONFIG_PM
+ .suspend = usb_wwan_suspend,
+ .resume = usb_wwan_resume,
+#endif
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &option_1port_device, NULL
+};
+
+//static bool debug;
+
+//module_usb_serial_driver(option_driver, serial_drivers);
+
+static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
+ const struct option_blacklist_info *blacklist)
+{
+ unsigned long num;
+ const unsigned long *intf_list;
+
+ if (blacklist) {
+ if (reason == OPTION_BLACKLIST_SENDSETUP)
+ intf_list = &blacklist->sendsetup;
+ else if (reason == OPTION_BLACKLIST_RESERVED_IF)
+ intf_list = &blacklist->reserved;
+ else {
+ BUG_ON(reason);
+ return false;
+ }
+
+ for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) {
+ if (num == ifnum)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ int inception;
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+ spin_lock_irq(&portdata->incept_lock);
+ inception = portdata->inception;
+ spin_unlock_irq(&portdata->incept_lock);
+
+ if (inception)
+ return 0;
+#endif
+
+ return usb_wwan_write(tty, port, buf, count);
+}
+
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_AP2MODEM_VIATELECOM)
+extern void ap_wake_modem(void);
+extern void ap_sleep_modem(void);
+#endif
+
+#ifdef CONFIG_VIATELECOM_SYNC_CBP
+static int option_rawbulk_asc_notifier(int msg, void *data) {
+ int opened;
+ struct usb_serial *serial = data;
+ struct usb_serial_port *port = serial->port[0];
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+ struct usb_wwan_intf_private *intfdata = serial->private;
+
+ spin_lock_irq(&intfdata->susp_lock);
+ opened = portdata->opened;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ if (!opened && msg == ASC_NTF_RX_PREPARE)
+ asc_rx_confirm_ready(USB_RX_HD_NAME, 1);
+ return 0;
+}
+#endif
+
+static int option_rawbulk_intercept(struct usb_interface *interface, unsigned int flags) {
+ int rc = 0;
+ struct usb_serial *serial = usb_get_intfdata(interface);
+ struct usb_serial_port *port = serial->port[0];
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+ struct usb_wwan_intf_private *intfdata = serial->private;
+ int nif = interface->cur_altsetting->desc.bInterfaceNumber;
+ int enable = flags & RAWBULK_INCEPT_FLAG_ENABLE;
+ int opened;
+ int n;
+
+ spin_lock_irq(&portdata->incept_lock);
+ if (portdata->inception == !!enable) {
+ spin_unlock_irq(&portdata->incept_lock);
+ return -ENOENT;
+ }
+ spin_unlock_irq(&portdata->incept_lock);
+
+ spin_lock_irq(&intfdata->susp_lock);
+ opened = portdata->opened;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ printk(KERN_DEBUG "rawbulk do %s on port %d (%s)\n", enable? "incept":
+ "unincept", port->number, opened? "opened": "not-in-use");
+
+ if (enable) {
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ struct asc_infor user = {
+ .notifier = option_rawbulk_asc_notifier,
+ .data = serial,
+ };
+ snprintf(user.name, ASC_NAME_LEN, "%s%d", RAWBULK_RX_USER_NAME, nif);
+ asc_rx_add_user(USB_RX_HD_NAME, &user);
+ asc_tx_auto_ready(USB_TX_HD_NAME, 0);
+#endif
+
+#ifdef CONFIG_PM
+ rc = usb_autopm_get_interface(interface);
+ if (rc < 0)
+ printk(KERN_ERR "incept failed while geting interface#%d\n", nif);
+#endif
+ /* Stop reading/writing urbs */
+ if (opened) {
+ if (!(flags & RAWBULK_INCEPT_FLAG_PUSH_WAY))
+ for (n = 0; n < portdata->n_in_urb; n++)
+ usb_kill_urb(portdata->in_urbs[n]);
+ for (n = 0; n < portdata->n_out_urb; n++)
+ usb_kill_urb(portdata->out_urbs[n]);
+ }
+ /* Start urb for push-way */
+ if (flags & RAWBULK_INCEPT_FLAG_PUSH_WAY) {
+ for (n = 0; n < portdata->n_in_urb; n ++) {
+ struct urb *urb = portdata->in_urbs[n];
+ if (!urb || !urb->dev)
+ continue;
+ /* reset urb */
+ usb_kill_urb(urb);
+ usb_clear_halt(urb->dev, urb->pipe);
+ rc = usb_submit_urb(urb, GFP_KERNEL);
+ if (rc < 0)
+ break;
+ }
+ if (rc < 0)
+ printk(KERN_ERR "incept %d while re-submitting " \
+ "pushable urbs %d\n", nif, rc);
+ }
+ } else {
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ char asc_user[ASC_NAME_LEN];
+#endif
+ rc = usb_autopm_get_interface(interface);
+ if (rc < 0)
+ printk(KERN_ERR "unincept while get interface#%d\n", nif);
+ if (!intfdata->suspended && opened) {
+ for (n = 0; n < portdata->n_in_urb; n ++) {
+ struct urb *urb = portdata->in_urbs[n];
+ if (!urb || !urb->dev)
+ continue;
+ /* reset urb */
+ usb_kill_urb(urb);
+ usb_clear_halt(urb->dev, urb->pipe);
+ rc = usb_submit_urb(urb, GFP_KERNEL);
+ if (rc < 0)
+ break;
+ }
+ if (rc < 0)
+ printk(KERN_ERR "unincept %d while reseting " \
+ "bulk IN urbs %d\n", nif, rc);
+ }
+#ifdef CONFIG_PM
+ usb_autopm_put_interface(interface);
+#endif
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ snprintf(asc_user, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, RAWBULK_RX_USER_NAME), nif);
+ asc_rx_del_user(asc_user);
+#endif
+ }
+
+ if (!rc) {
+ spin_lock_irq(&portdata->incept_lock);
+ portdata->inception = !!enable;
+ spin_unlock_irq(&portdata->incept_lock);
+ } else
+ printk(KERN_ERR "failed(%d) to %s inception on interface#%d\n",
+ rc, enable? "enable": "disable", nif);
+
+ return rc;
+}
+
+#endif
+
+int serial_ntcall(struct notifier_block *nb, unsigned long val, void *nodata)
+{
+ struct usb_wwan_intf_private *data = container_of(nb,struct usb_wwan_intf_private,pm_nb);
+
+ switch (val) {
+ case PM_SUSPEND_PREPARE:
+ usb_disable_autosuspend(data->udev);
+ return NOTIFY_DONE;
+ case PM_POST_SUSPEND:
+ usb_enable_autosuspend(data->udev);
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_DONE;
+}
+
+static int viatelecom_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+ int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+
+ /* VIA-Telecom CBP DTR format */
+ return usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+
+}
+static int option_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ struct usb_wwan_intf_private *data;
+
+ /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
+ if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
+ serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
+ serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8)
+ return -ENODEV;
+
+ /* Bandrich modem and AT command interface is 0xff */
+ if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID ||
+ serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) &&
+ serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
+ return -ENODEV;
+
+ /* Don't bind reserved interfaces (like network ones) which often have
+ * the same class/subclass/protocol as the serial interfaces. Look at
+ * the Windows driver .INF files for reserved interface numbers.
+ */
+ if (is_blacklisted(
+ serial->interface->cur_altsetting->desc.bInterfaceNumber,
+ OPTION_BLACKLIST_RESERVED_IF,
+ (const struct option_blacklist_info *) id->driver_info))
+ return -ENODEV;
+
+ /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
+ if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
+ serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 &&
+ serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA)
+ return -ENODEV;
+
+ data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+
+ //kevin modify for viatel modem
+ data->send_setup = viatelecom_send_setup;
+ //data->send_setup = option_send_setup;
+
+ spin_lock_init(&data->susp_lock);
+ data->private = (void *)id->driver_info;
+ return 0;
+}
+
+static void option_release(struct usb_serial *serial)
+{
+ struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+
+ usb_wwan_release(serial);
+
+ kfree(priv);
+}
+
+#define USB_CBP_TESTMODE_ENABLE 0x1
+#define USB_CBP_TESTMODE_QUERY 0x2
+#define USB_CBP_TESTMODE_UNSOLICTED 0x3
+static ssize_t option_port_testmode_show(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int rc;
+ struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev);
+ struct usb_device *udev = port0->serial->dev;
+ struct usb_interface *interface = port0->serial->interface;
+ int ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+ int feedback = -1;
+ rc = usb_autopm_get_interface(interface);
+ if (rc < 0) {
+ printk(KERN_ERR "failed to awake cp-usb when query testmode. %d\n", rc);
+ return -ENODEV;
+ }
+ rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_CBP_TESTMODE_QUERY,
+ USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ 0, ifnum, &feedback, 2, USB_CTRL_GET_TIMEOUT * 5);
+ usb_autopm_put_interface(interface);
+ if ((feedback & 0xff) == 0x1)
+ return sprintf(buf, "%s", "enabled");
+ if ((feedback & 0xff) == 0x0)
+ return sprintf(buf, "%s", "disabled");
+ printk(KERN_ERR "connot query cp testmode %d, feedback %04x\n", rc, feedback & 0xffff);
+ return -EOPNOTSUPP;
+}
+
+static ssize_t option_port_testmode_store(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
+{
+ int rc = 0;
+ int enable = -1;
+ struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev);
+ struct usb_device *udev = port0->serial->dev;
+ struct usb_interface *interface = port0->serial->interface;
+ int ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ if (!strncmp(buf, "enable", 6))
+ enable = 1;
+ else if (!strncmp(buf, "disable", 7))
+ enable = 0;
+ if (enable >= 0) {
+ rc = usb_autopm_get_interface(interface);
+ if (rc < 0) {
+ printk(KERN_ERR "failed to awake cp-usb when set testmode. %d\n", rc);
+ return -ENODEV;
+ }
+ rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_CBP_TESTMODE_ENABLE,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ enable, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ usb_autopm_put_interface(interface);
+ if (rc < 0) {
+ printk(KERN_DEBUG "failed to sent testmode contorl msg %d\n", rc);
+ return rc;
+ }
+ } else if (!strncmp(buf, "unsolited", 9)) {
+ /* rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_CBP_TESTMODE_UNSOLICTED,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ 0, ifnum, &param, sizeof(param), USB_CTRL_SET_TIMEOUT); */
+ printk(KERN_DEBUG "unsolited test mode for cp does not supported yet.\n");
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(testmode, S_IRUGO | S_IWUSR,
+ option_port_testmode_show,
+ option_port_testmode_store);
+
+static int usb_serial_option_probe(struct usb_interface *interface,
+ const struct usb_device_id *id) {
+ struct usb_serial *serial;
+ int ret = usb_serial_probe(interface, id);
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ ret = rawbulk_bind_host_interface(interface, option_rawbulk_intercept);
+ if (ret < 0)
+ return ret;
+#endif
+
+
+
+
+ serial = usb_get_intfdata(interface);
+ return sysfs_create_file(&serial->port[0]->dev.kobj,
+ &dev_attr_testmode.attr);
+}
+
+static void usb_serial_option_disconnect(struct usb_interface *interface) {
+ struct usb_serial *serial = usb_get_intfdata(interface);
+ struct usb_wwan_intf_private *data = serial->private;
+
+
+
+ unregister_pm_notifier(&data->pm_nb);
+
+ sysfs_remove_file(&serial->port[0]->dev.kobj, &dev_attr_testmode.attr);
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ rawbulk_unbind_host_interface(interface);
+#endif
+
+ usb_serial_disconnect(interface);
+}
+
+
+static void option_instat_callback(struct urb *urb)
+{
+ int err;
+ int status = urb->status;
+ struct usb_serial_port *port = urb->context;
+ struct usb_wwan_port_private *portdata =
+ usb_get_serial_port_data(port);
+
+ dbg("%s", __func__);
+ dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
+
+ if (status == 0) {
+ struct usb_ctrlrequest *req_pkt =
+ (struct usb_ctrlrequest *)urb->transfer_buffer;
+
+ if (!req_pkt) {
+ dbg("%s: NULL req_pkt", __func__);
+ return;
+ }
+ if ((req_pkt->bRequestType == 0xA1) &&
+ (req_pkt->bRequest == 0x20)) {
+ int old_dcd_state;
+ unsigned char signals = *((unsigned char *)
+ urb->transfer_buffer +
+ sizeof(struct usb_ctrlrequest));
+
+ dbg("%s: signal x%x", __func__, signals);
+
+ old_dcd_state = portdata->dcd_state;
+ portdata->cts_state = 1;
+ portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+ portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+ portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+ if (old_dcd_state && !portdata->dcd_state) {
+ struct tty_struct *tty =
+ tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
+ } else {
+ dbg("%s: type %x req %x", __func__,
+ req_pkt->bRequestType, req_pkt->bRequest);
+ }
+ } else
+ err("%s: error %d", __func__, status);
+
+ /* Resubmit urb so we continue receiving IRQ data */
+ if (status != -ESHUTDOWN && status != -ENOENT) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+ dbg("%s: resubmit intr urb failed. (%d)",
+ __func__, err);
+ }
+}
+
+/** send RTS/DTR state to the port.
+ *
+ * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN
+ * CDC.
+*/
+static int option_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_intf_private *intfdata =
+ (struct usb_wwan_intf_private *) serial->private;
+ struct usb_wwan_port_private *portdata;
+ int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+ int val = 0;
+ dbg("%s", __func__);
+
+ if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
+ (struct option_blacklist_info *) intfdata->private)) {
+ dbg("No send_setup on blacklisted interface #%d\n", ifNum);
+ return -EIO;
+ }
+
+ portdata = usb_get_serial_port_data(port);
+
+ if (portdata->dtr_state)
+ val |= 0x01;
+ if (portdata->rts_state)
+ val |= 0x02;
+
+ return usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+
+
+
+static int __init via_option_init(void)
+{
+ int retval;
+
+
+ retval = usb_serial_register_drivers(&option_driver, serial_drivers);
+ if (retval)
+ goto failed_driver_register;
+
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
+
+
+
+ wake_lock_init(&ets_wake_lock, WAKE_LOCK_SUSPEND, "ETS_Prevent_Suspend");
+ usb_ap_sync_cbp_init();
+ return 0;
+
+failed_driver_register:
+
+
+ return retval;
+}
+
+
+static void __exit via_option_exit (void)
+{
+
+ wake_lock_destroy(&ets_wake_lock);
+
+ usb_serial_deregister_drivers(&option_driver, serial_drivers);
+}
+
+
+module_init(via_option_init);
+module_exit(via_option_exit);
+
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+//module_param(debug, bool, S_IRUGO | S_IWUSR);
+//MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h b/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h
new file mode 100755
index 00000000..415b74c6
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h
@@ -0,0 +1,88 @@
+/*
+ * Definitions for USB serial mobile broadband cards
+ */
+
+#ifndef __LINUX_USB_USB_WWAN
+#define __LINUX_USB_USB_WWAN
+
+#define CONFIG_VIATELECOM_SYNC_CBP 1
+#define CONFIG_USB_ANDROID_RAWBULK 1
+
+
+
+extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on);
+extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
+extern void usb_wwan_close(struct usb_serial_port *port);
+extern int usb_wwan_startup(struct usb_serial *serial);
+extern void usb_wwan_disconnect(struct usb_serial *serial);
+extern void usb_wwan_release(struct usb_serial *serial);
+extern int usb_wwan_write_room(struct tty_struct *tty);
+extern void usb_wwan_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old);
+extern int usb_wwan_tiocmget(struct tty_struct *tty);
+extern int usb_wwan_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear);
+extern int usb_wwan_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg);
+extern int usb_wwan_send_setup(struct usb_serial_port *port);
+extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
+#ifdef CONFIG_PM
+extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message);
+extern int usb_wwan_resume(struct usb_serial *serial);
+#endif
+
+/* per port private data */
+
+#define N_IN_URB 8
+#define N_OUT_URB 16
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 4096
+
+#define MAX_IN_URBS 16
+#define MAX_OUT_URBS 16
+
+struct usb_wwan_intf_private {
+ spinlock_t susp_lock;
+ struct usb_device *udev;
+ struct notifier_block pm_nb;
+ unsigned int suspended:1;
+ int in_flight;
+ int (*send_setup) (struct usb_serial_port *port);
+ void *private;
+};
+
+struct usb_wwan_port_private {
+ /* Input endpoints and buffer for this port */
+ unsigned int n_in_urb;
+ unsigned int in_buflen;
+ struct urb *in_urbs[MAX_IN_URBS];
+ u8 *in_buffer[MAX_IN_URBS];
+ /* Output endpoints and buffer for this port */
+ unsigned int n_out_urb;
+ unsigned int out_buflen;
+ struct urb *out_urbs[MAX_OUT_URBS];
+ u8 *out_buffer[MAX_OUT_URBS];
+ unsigned long out_busy; /* Bit vector of URBs in use */
+ int opened;
+ struct usb_anchor delayed;
+
+ /* Settings for the port */
+ int rts_state; /* Handshaking pins (outputs) */
+ int dtr_state;
+ int cts_state; /* Handshaking pins (inputs) */
+ int dsr_state;
+ int dcd_state;
+ int ri_state;
+
+ unsigned long tx_start_time[MAX_OUT_URBS];
+
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ spinlock_t incept_lock;
+ unsigned int inception:1;
+#endif
+};
+
+#endif /* __LINUX_USB_USB_WWAN */
diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c b/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c
new file mode 100755
index 00000000..56c11455
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c
@@ -0,0 +1,1013 @@
+/*
+ USB Driver layer for GSM modems
+
+ Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
+
+ This driver is free software; you can redistribute it and/or modify
+ it under the terms of Version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+ History: see the git log.
+
+ Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
+
+ This driver exists because the "normal" serial driver doesn't work too well
+ with GSM modems. Issues:
+ - data loss -- one single Receive URB is not nearly enough
+ - controlling the baud rate doesn't make sense
+*/
+
+#define DRIVER_VERSION "v0.7.2"
+#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
+#define DRIVER_DESC "USB Driver for GSM modems"
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+#include <linux/wakelock.h>
+#include "via_usb-wwan.h"
+
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+#include <linux/usb/rawbulk.h>
+#endif
+
+#ifdef CONFIG_VIATELECOM_SYNC_CBP
+#include <mach/viatel.h>
+#define ASC_INTF_NUM (10)
+atomic_t intf_pm_count[ASC_INTF_NUM];
+
+#define EXPORT_SYMBOL(x)
+
+
+static struct asc_config usb_tx_handle = {
+ .name = USB_TX_HD_NAME,
+ .gpio_wake = GPIO_VIATEL_USB_AP_WAKE_MDM,
+ .gpio_ready = GPIO_VIATEL_USB_MDM_RDY,
+ .polar = 1,
+};
+
+struct asc_config usb_rx_handle = {
+ .name = USB_RX_HD_NAME,
+ .gpio_wake = GPIO_VIATEL_USB_MDM_WAKE_AP,
+ .gpio_ready = GPIO_VIATEL_USB_AP_RDY,
+ .polar = 1,
+};
+
+static int usb_ap_sync_cbp_init(void)
+{
+ int i, ret = 0;
+ for(i = 0; i < ASC_INTF_NUM; i++){
+ atomic_set(&intf_pm_count[i], 0);
+ }
+ asc_tx_register_handle(&usb_tx_handle);
+ asc_rx_register_handle(&usb_rx_handle);
+ return ret;
+}
+
+//late_initcall(usb_ap_sync_cbp_init);
+
+static int cbp_usb_interface_notifier(int msg, void *data)
+ {
+ int index, ret = 0;
+ struct usb_interface * intf = (struct usb_interface *)data;
+
+ if(!intf) {
+ printk(KERN_ERR "%s - usb find device interface error\n", __func__);
+ return -ENODEV;
+ }
+
+ index = (int)intf->cur_altsetting->desc.bInterfaceNumber;
+ if(index < 0 || index > ASC_INTF_NUM){
+ printk(KERN_ERR "%s - error interface index %d.\n", __func__, index);
+ return -ENODEV;
+ }
+ switch(msg){
+ case ASC_NTF_RX_PREPARE:
+ //printk("%s:inft%d get cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index]));
+ if(!atomic_read(&intf_pm_count[index])){
+ if(!usb_autopm_get_interface(intf)){
+ atomic_set(&intf_pm_count[index], 1);
+ }
+ }
+ asc_rx_confirm_ready(USB_RX_HD_NAME, !ret);
+ break;
+
+ case ASC_NTF_RX_POST:
+ //printk("%s:inft%d put cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index]));
+ if(atomic_read(&intf_pm_count[index])){
+ usb_autopm_put_interface(intf);
+ atomic_set(&intf_pm_count[index], 0);
+ }
+ break;
+ default:
+ printk("%s unknow message %d\n", __FUNCTION__, msg);
+ }
+
+ return ret;
+}
+static int cbp_usb_interface_add_user(struct usb_interface * intf)
+{
+ int index;
+ struct asc_infor user;
+
+ if(!intf){
+ return -EINVAL;
+ }
+
+ index = (int)intf->cur_altsetting->desc.bInterfaceNumber;
+ memset(&user, 0, sizeof(user));
+ user.notifier = cbp_usb_interface_notifier;
+ user.data = intf;
+ snprintf(user.name, ASC_NAME_LEN, "%s%d", USB_RX_USER_NAME, index);
+ return asc_rx_add_user(USB_RX_HD_NAME, &user);
+}
+
+static void cbp_usb_interface_del_user(struct usb_interface * intf)
+{
+ int index;
+ char path[ASC_NAME_LEN];
+
+ if(!intf){
+ return ;
+ }
+
+ index = (int)intf->cur_altsetting->desc.bInterfaceNumber;
+ if(atomic_read(&intf_pm_count[index])){
+ usb_autopm_put_interface_no_suspend(intf);
+ atomic_set(&intf_pm_count[index], 0);
+ }
+ memset(path, 0, ASC_NAME_LEN);
+ snprintf(path, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, USB_RX_USER_NAME), index);
+ return asc_rx_del_user(path);
+}
+#endif
+
+static int debug;
+extern struct wake_lock ets_wake_lock;
+
+static unsigned int dump_mask = 0;
+module_param(dump_mask, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_mask, "Set data dump mask for each interface");
+
+static void usb_wwan_dump_data(struct usb_interface *interface,
+ const char *str, const unsigned char *data, int size) {
+ int i;
+ int no_chars = 0;
+ int n = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ if (!(dump_mask & (1 << n)))
+ return;
+
+ printk(KERN_DEBUG "usb_wwan: dump on interface#%d, %s: len = %d, chars = \"",
+ n, str, size);
+ for (i = 0; i < size; ++i) {
+ char c = data[i];
+ if (c > 0x20 && c < 0x7e) {
+ printk("%c", c);
+ } else {
+ printk(".");
+ no_chars ++;
+ }
+ }
+ printk("\", data = ");
+ for (i = 0; i < size; ++i) {
+ printk("%.2x ", data[i]);
+ if (i > 7)
+ break;
+ }
+ if (size < 8) {
+ printk("\n");
+ return;
+ } else if (i < size - 8) {
+ printk("... ");
+ i = size - 8;
+ }
+ for (; i < size; ++i)
+ printk("%.2x ", data[i]);
+ printk("\n");
+}
+
+void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_port_private *portdata;
+
+ struct usb_wwan_intf_private *intfdata;
+
+ dbg("%s", __func__);
+
+ intfdata = port->serial->private;
+
+ if (!intfdata->send_setup)
+ return;
+
+ portdata = usb_get_serial_port_data(port);
+ mutex_lock(&serial->disc_mutex);
+ portdata->rts_state = on;
+ portdata->dtr_state = on;
+ if (serial->dev)
+ intfdata->send_setup(port);
+ mutex_unlock(&serial->disc_mutex);
+}
+EXPORT_SYMBOL(usb_wwan_dtr_rts);
+
+void usb_wwan_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct usb_wwan_intf_private *intfdata = port->serial->private;
+
+ dbg("%s", __func__);
+
+ /* Doesn't support option setting */
+ tty_termios_copy_hw(tty->termios, old_termios);
+
+ if (intfdata->send_setup)
+ intfdata->send_setup(port);
+}
+EXPORT_SYMBOL(usb_wwan_set_termios);
+
+int usb_wwan_tiocmget(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ unsigned int value;
+ struct usb_wwan_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+
+ value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+ ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+ ((portdata->cts_state) ? TIOCM_CTS : 0) |
+ ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+ ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+ ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+ return value;
+}
+EXPORT_SYMBOL(usb_wwan_tiocmget);
+
+int usb_wwan_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata;
+
+ portdata = usb_get_serial_port_data(port);
+ intfdata = port->serial->private;
+
+ if (!intfdata->send_setup)
+ return -EINVAL;
+
+ /* FIXME: what locks portdata fields ? */
+ if (set & TIOCM_RTS)
+ portdata->rts_state = 1;
+ if (set & TIOCM_DTR)
+ portdata->dtr_state = 1;
+
+ if (clear & TIOCM_RTS)
+ portdata->rts_state = 0;
+ if (clear & TIOCM_DTR)
+ portdata->dtr_state = 0;
+ return intfdata->send_setup(port);
+}
+EXPORT_SYMBOL(usb_wwan_tiocmset);
+
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = port->number;
+ tmp.baud_base = tty_get_baud_rate(port->port.tty);
+ tmp.close_delay = port->port.close_delay / 10;
+ tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE :
+ port->port.closing_wait / 10;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *newinfo)
+{
+ struct serial_struct new_serial;
+ unsigned int closing_wait, close_delay;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ close_delay = new_serial.close_delay * 10;
+ closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+ mutex_lock(&port->port.mutex);
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((close_delay != port->port.close_delay) ||
+ (closing_wait != port->port.closing_wait))
+ retval = -EPERM;
+ else
+ retval = -EOPNOTSUPP;
+ } else {
+ port->port.close_delay = close_delay;
+ port->port.closing_wait = closing_wait;
+ }
+
+ mutex_unlock(&port->port.mutex);
+ return retval;
+}
+
+int usb_wwan_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ dbg("%s cmd 0x%04x", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(port,
+ (struct serial_struct __user *) arg);
+ default:
+ break;
+ }
+
+ dbg("%s arg not supported", __func__);
+
+ return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(usb_wwan_ioctl);
+
+/* Write */
+int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata;
+ int i;
+ int left, todo;
+ struct urb *this_urb = NULL; /* spurious */
+ int err;
+ unsigned long flags;
+
+ portdata = usb_get_serial_port_data(port);
+ intfdata = port->serial->private;
+
+ dbg("%s: write (%d chars)", __func__, count);
+
+#ifdef CONFIG_VIATELECOM_SYNC_CBP
+ asc_tx_auto_ready(USB_TX_HD_NAME, 0);
+#endif
+
+ i = 0;
+ left = count;
+ for (i = 0; left > 0 && i < portdata->n_out_urb; i++) {
+ todo = left;
+ if (todo > portdata->out_buflen)
+ todo = portdata->out_buflen;
+
+ this_urb = portdata->out_urbs[i];
+ if (test_and_set_bit(i, &portdata->out_busy)) {
+ if (time_before(jiffies,
+ portdata->tx_start_time[i] + 10 * HZ))
+ continue;
+ usb_unlink_urb(this_urb);
+ continue;
+ }
+ dbg("%s: endpoint %d buf %d", __func__,
+ usb_pipeendpoint(this_urb->pipe), i);
+
+ err = usb_autopm_get_interface_async(port->serial->interface);
+ if (err < 0)
+ break;
+
+ /* send the data */
+ memcpy(this_urb->transfer_buffer, buf, todo);
+ this_urb->transfer_buffer_length = todo;
+
+ spin_lock_irqsave(&intfdata->susp_lock, flags);
+ if (intfdata->suspended) {
+ usb_anchor_urb(this_urb, &portdata->delayed);
+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+ } else {
+ intfdata->in_flight++;
+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+ err = usb_submit_urb(this_urb, GFP_ATOMIC);
+ if (err) {
+ dbg("usb_submit_urb %p (write bulk) failed "
+ "(%d)", this_urb, err);
+ clear_bit(i, &portdata->out_busy);
+ spin_lock_irqsave(&intfdata->susp_lock, flags);
+ intfdata->in_flight--;
+ spin_unlock_irqrestore(&intfdata->susp_lock,
+ flags);
+ usb_autopm_put_interface_async(port->serial->interface);
+ break;
+ }
+ }
+
+ portdata->tx_start_time[i] = jiffies;
+ buf += todo;
+ left -= todo;
+ }
+
+ count -= left;
+ dbg("%s: wrote (did %d)", __func__, count);
+ return count;
+}
+EXPORT_SYMBOL(usb_wwan_write);
+
+static void usb_wwan_indat_callback(struct urb *urb)
+{
+ int err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
+
+ dbg("%s: %p", __func__, urb);
+
+ endpoint = usb_pipeendpoint(urb->pipe);
+ port = urb->context;
+
+ if (status) {
+ dbg("%s: nonzero status: %d on endpoint %02x.",
+ __func__, status, endpoint);
+ } else {
+ int inception = 0;
+ struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port);
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ spin_lock(&portdata->incept_lock);
+ inception = portdata->inception;
+ spin_unlock(&portdata->incept_lock);
+#endif
+ if (inception) {
+#ifdef CONFIG_USB_ANDROID_RAWBULK
+ struct usb_interface *interface = port->serial->interface;
+ int tid = interface->cur_altsetting->desc.bInterfaceNumber;
+ err = rawbulk_push_upstream_buffer(tid, data, urb->actual_length);
+ if (err < 0)
+ printk(KERN_DEBUG "failed to push data to rawbulk(%d) %d\n", tid, err);
+#endif
+ } else {
+ usb_wwan_dump_data(port->serial->interface, "from device", data,
+ urb->actual_length);
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ if (urb->actual_length) {
+ tty_insert_flip_string(tty, data,
+ urb->actual_length);
+ tty_flip_buffer_push(tty);
+ } else
+ dbg("%s: empty read urb received", __func__);
+ tty_kref_put(tty);
+ }
+ }
+
+ /* Resubmit urb so we continue receiving */
+ if (status != -ESHUTDOWN) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ if (err != -EPERM) {
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __func__, err);
+ /* busy also in error unless we are killed */
+ usb_mark_last_busy(port->serial->dev);
+ }
+ } else {
+ usb_mark_last_busy(port->serial->dev);
+ }
+ }
+
+ }
+}
+
+static void usb_wwan_outdat_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata;
+ int i;
+
+ dbg("%s", __func__);
+
+ port = urb->context;
+ intfdata = port->serial->private;
+ usb_wwan_dump_data(port->serial->interface, urb->status < 0?
+ "failed sent to device": "to device",
+ urb->transfer_buffer, urb->transfer_buffer_length);
+ usb_serial_port_softint(port);
+ usb_autopm_put_interface_async(port->serial->interface);
+ portdata = usb_get_serial_port_data(port);
+ spin_lock(&intfdata->susp_lock);
+ intfdata->in_flight--;
+ spin_unlock(&intfdata->susp_lock);
+
+ for (i = 0; i < portdata->n_out_urb; ++i) {
+ if (portdata->out_urbs[i] == urb) {
+ smp_mb__before_clear_bit();
+ clear_bit(i, &portdata->out_busy);
+ break;
+ }
+ }
+}
+
+int usb_wwan_write_room(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_wwan_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i = 0; i < portdata->n_out_urb; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && !test_bit(i, &portdata->out_busy))
+ data_len += portdata->out_buflen;
+ }
+
+ dbg("%s: %d", __func__, data_len);
+ return data_len;
+}
+EXPORT_SYMBOL(usb_wwan_write_room);
+
+int usb_wwan_chars_in_buffer(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_wwan_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i = 0; i < portdata->n_out_urb; i++) {
+ this_urb = portdata->out_urbs[i];
+ /* FIXME: This locking is insufficient as this_urb may
+ go unused during the test */
+ if (this_urb && test_bit(i, &portdata->out_busy))
+ data_len += this_urb->transfer_buffer_length;
+ }
+ dbg("%s: %d", __func__, data_len);
+ return data_len;
+}
+EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
+
+static int port_to_infnum(struct usb_serial_port *port)
+{
+ struct usb_interface *interface = port->serial->interface;
+ int tid = interface->cur_altsetting->desc.bInterfaceNumber;
+ return tid;
+}
+
+int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata;
+ struct usb_serial *serial = port->serial;
+ int i, err;
+ struct urb *urb;
+
+ portdata = usb_get_serial_port_data(port);
+ intfdata = serial->private;
+
+ dbg("%s", __func__);
+
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ cbp_usb_interface_add_user(serial->interface);
+#endif
+
+ /* Start reading from the IN endpoint */
+ for (i = 0; i < portdata->n_in_urb; i++) {
+ urb = portdata->in_urbs[i];
+ if (!urb)
+ continue;
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ dbg("%s: submit urb %d failed (%d) %d",
+ __func__, i, err, urb->transfer_buffer_length);
+ }
+ }
+
+ if (intfdata->send_setup)
+ intfdata->send_setup(port);
+
+ serial->interface->needs_remote_wakeup = 0;
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 1;
+ spin_unlock_irq(&intfdata->susp_lock);
+ /* this balances a get in the generic USB serial code */
+ if(port_to_infnum(port) == 1)
+ {
+ usb_autopm_get_interface(serial->interface);
+ wake_lock(&ets_wake_lock);
+ }
+ else
+ usb_autopm_put_interface(serial->interface);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_wwan_open);
+
+void usb_wwan_close(struct usb_serial_port *port)
+{
+ int i;
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata = port->serial->private;
+
+ dbg("%s", __func__);
+ portdata = usb_get_serial_port_data(port);
+
+ if (serial->dev) {
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ cbp_usb_interface_del_user(serial->interface);
+#endif
+ /* Stop reading/writing urbs */
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ for (i = 0; i < portdata->n_in_urb; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < portdata->n_out_urb; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
+ /* balancing - important as an error cannot be handled*/
+ if(port_to_infnum(port) == 1)
+ {
+ usb_autopm_put_interface(serial->interface);
+ wake_unlock(&ets_wake_lock);
+ }
+ else
+ usb_autopm_get_interface_no_resume(serial->interface);
+ serial->interface->needs_remote_wakeup = 0;
+ }
+}
+EXPORT_SYMBOL(usb_wwan_close);
+
+/* Helper functions used by usb_wwan_setup_urbs */
+static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+ void (*callback) (struct urb *))
+{
+ struct urb *urb;
+
+ if (endpoint == -1)
+ return NULL; /* endpoint not needed */
+
+ urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
+ if (urb == NULL) {
+ dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
+ return NULL;
+ }
+
+ /* Fill URB using supplied data. */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+
+ return urb;
+}
+
+/* Setup urbs */
+static void usb_wwan_setup_urbs(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct usb_wwan_port_private *portdata;
+
+ dbg("%s", __func__);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ /* Do indat endpoints first */
+ for (j = 0; j < portdata->n_in_urb; ++j) {
+ portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
+ port->
+ bulk_in_endpointAddress,
+ USB_DIR_IN,
+ port,
+ portdata->in_buffer[j],
+ portdata->in_buflen,
+ usb_wwan_indat_callback);
+ }
+
+ /* outdat endpoints */
+ for (j = 0; j < portdata->n_out_urb; ++j) {
+ portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
+ port->
+ bulk_out_endpointAddress,
+ USB_DIR_OUT,
+ port,
+ portdata->out_buffer[j],
+ portdata->out_buflen,
+ usb_wwan_outdat_callback);
+ }
+ }
+}
+
+static struct _via_cbp_port_init_params {
+ unsigned int n_in_urb;
+ unsigned int n_out_urb;
+ unsigned int in_buflen;
+ unsigned int out_buflen;
+} _cbp_init_params[] = {
+ { 16, 16, 4096, 4096 }, /* Data Port */
+ { 4, 4, 4096, 4096 }, /* ETS */
+ { 1, 1, 4096, 4096 }, /* AT Channel */
+ { 1, 1, 4096, 4096 }, /* PCV */
+ { 1, 1, 4096, 4096 }, /* GPS */
+ { },
+};
+
+int usb_wwan_startup(struct usb_serial *serial)
+{
+ int i, j, err;
+ struct usb_serial_port *port;
+ struct usb_wwan_port_private *portdata;
+ u8 *buffer;
+
+ dbg("%s", __func__);
+
+ /* Now setup per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ int nr;
+ port = serial->port[i];
+ portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+ if (!portdata) {
+ dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
+ __func__, i);
+ return 1;
+ }
+ init_usb_anchor(&portdata->delayed);
+
+ //if (__le16_to_cpu(serial->dev->descriptor.idVendor) == 0x15eb &&
+ // __le16_to_cpu(serial->dev->descriptor.idProduct) == 0x0001) {
+ nr = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+ portdata->n_in_urb = min((int)_cbp_init_params[nr].n_in_urb, MAX_IN_URBS);
+ portdata->n_out_urb = min((int)_cbp_init_params[nr].n_out_urb, MAX_OUT_URBS);
+ portdata->in_buflen = _cbp_init_params[nr].in_buflen;
+ portdata->out_buflen = _cbp_init_params[nr].out_buflen;
+ //} else {
+ // portdata->n_in_urb = N_IN_URB;
+ // portdata->n_out_urb = N_OUT_URB;
+ // portdata->in_buflen = IN_BUFLEN;
+ // portdata->out_buflen = OUT_BUFLEN;
+ //}
+
+ for (j = 0; j < portdata->n_in_urb; j++) {
+ buffer = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto bail_out_error;
+ portdata->in_buffer[j] = buffer;
+ portdata->in_buflen = PAGE_SIZE;
+ }
+
+ for (j = 0; j < portdata->n_out_urb; j++) {
+ buffer = kmalloc(portdata->out_buflen, GFP_KERNEL);
+ if (!buffer)
+ goto bail_out_error2;
+ portdata->out_buffer[j] = buffer;
+ }
+
+ usb_set_serial_port_data(port, portdata);
+
+ if (!port->interrupt_in_urb)
+ continue;
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (err)
+ dbg("%s: submit irq_in urb failed %d", __func__, err);
+ }
+ usb_wwan_setup_urbs(serial);
+ return 0;
+
+bail_out_error2:
+ for (j = 0; j < portdata->n_out_urb; j++)
+ kfree(portdata->out_buffer[j]);
+bail_out_error:
+ for (j = 0; j < portdata->n_in_urb; j++)
+ if (portdata->in_buffer[j])
+ free_page((unsigned long)portdata->in_buffer[j]);
+ kfree(portdata);
+ return 1;
+}
+EXPORT_SYMBOL(usb_wwan_startup);
+
+static void stop_read_write_urbs(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct usb_wwan_port_private *portdata;
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+ for (j = 0; j < portdata->n_in_urb; j++)
+ usb_kill_urb(portdata->in_urbs[j]);
+ for (j = 0; j < portdata->n_out_urb; j++)
+ usb_kill_urb(portdata->out_urbs[j]);
+ }
+}
+
+void usb_wwan_disconnect(struct usb_serial *serial)
+{
+ dbg("%s", __func__);
+ stop_read_write_urbs(serial);
+#if defined(CONFIG_VIATELECOM_SYNC_CBP)
+ cbp_usb_interface_del_user(serial->interface);
+#endif
+}
+EXPORT_SYMBOL(usb_wwan_disconnect);
+
+void usb_wwan_release(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct usb_wwan_port_private *portdata;
+
+ dbg("%s", __func__);
+
+ /* Now free them */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ for (j = 0; j < portdata->n_in_urb; j++) {
+ usb_free_urb(portdata->in_urbs[j]);
+ free_page((unsigned long)
+ portdata->in_buffer[j]);
+ portdata->in_urbs[j] = NULL;
+ }
+ for (j = 0; j < portdata->n_out_urb; j++) {
+ usb_free_urb(portdata->out_urbs[j]);
+ kfree(portdata->out_buffer[j]);
+ portdata->out_urbs[j] = NULL;
+ }
+ }
+
+ /* Now free per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ kfree(usb_get_serial_port_data(port));
+ }
+}
+EXPORT_SYMBOL(usb_wwan_release);
+
+#ifdef CONFIG_PM
+int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
+{
+ struct usb_wwan_intf_private *intfdata = serial->private;
+ int b;
+
+ dbg("%s entered", __func__);
+
+ if (PMSG_IS_AUTO(message)) {
+ spin_lock_irq(&intfdata->susp_lock);
+ b = intfdata->in_flight;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ if (b)
+ return -EBUSY;
+ }
+
+ spin_lock_irq(&intfdata->susp_lock);
+ intfdata->suspended = 1;
+ spin_unlock_irq(&intfdata->susp_lock);
+ stop_read_write_urbs(serial);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_wwan_suspend);
+
+static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
+{
+ int i;
+
+ for (i = 0; i < portdata->n_out_urb; i++) {
+ if (urb == portdata->out_urbs[i]) {
+ clear_bit(i, &portdata->out_busy);
+ break;
+ }
+ }
+}
+
+static void play_delayed(struct usb_serial_port *port)
+{
+ struct usb_wwan_intf_private *data;
+ struct usb_wwan_port_private *portdata;
+ struct urb *urb;
+ int err;
+
+ portdata = usb_get_serial_port_data(port);
+ data = port->serial->private;
+ while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!err) {
+ data->in_flight++;
+ } else {
+ /* we have to throw away the rest */
+ do {
+ unbusy_queued_urb(urb, portdata);
+ usb_autopm_put_interface_no_suspend(port->serial->interface);
+ } while ((urb = usb_get_from_anchor(&portdata->delayed)));
+ break;
+ }
+ }
+}
+
+int usb_wwan_resume(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct usb_wwan_intf_private *intfdata = serial->private;
+ struct usb_wwan_port_private *portdata;
+ struct urb *urb;
+ int err = 0;
+
+ dbg("%s entered", __func__);
+ /* get the interrupt URBs resubmitted unconditionally */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ if (!port->interrupt_in_urb) {
+ dbg("%s: No interrupt URB for port %d", __func__, i);
+ continue;
+ }
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+ dbg("Submitted interrupt URB for port %d (result %d)", i, err);
+ if (err < 0) {
+ err("%s: Error %d for interrupt URB of port%d",
+ __func__, err, i);
+ goto err_out;
+ }
+ }
+
+ for (i = 0; i < serial->num_ports; i++) {
+ /* walk all ports */
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ /* skip closed ports */
+ spin_lock_irq(&intfdata->susp_lock);
+ if (!portdata->opened) {
+ spin_unlock_irq(&intfdata->susp_lock);
+ continue;
+ }
+
+ for (j = 0; j < portdata->n_in_urb; j++) {
+ urb = portdata->in_urbs[j];
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ err("%s: Error %d for bulk URB %d",
+ __func__, err, i);
+ spin_unlock_irq(&intfdata->susp_lock);
+ goto err_out;
+ }
+ }
+ play_delayed(port);
+ spin_unlock_irq(&intfdata->susp_lock);
+ }
+ spin_lock_irq(&intfdata->susp_lock);
+ intfdata->suspended = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
+err_out:
+ return err;
+}
+EXPORT_SYMBOL(usb_wwan_resume);
+#endif
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/ANDROID_3.4.5/drivers/usb/storage/usb.c b/ANDROID_3.4.5/drivers/usb/storage/usb.c
index 2653e73d..95f5395a 100644
--- a/ANDROID_3.4.5/drivers/usb/storage/usb.c
+++ b/ANDROID_3.4.5/drivers/usb/storage/usb.c
@@ -78,7 +78,7 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
-static unsigned int delay_use = 1;
+static unsigned int delay_use = 0;/*add by jay*/
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");