summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/usb/gadget
diff options
context:
space:
mode:
authorKevin2014-11-15 10:00:36 +0800
committerKevin2014-11-15 10:00:36 +0800
commit9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch)
treede942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/usb/gadget
parent392e8802486cb573b916e746010e141a75f507e6 (diff)
downloadFOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.gz
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.bz2
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.zip
add via modify part source code for wm8880 4.4 kitkat
Diffstat (limited to 'ANDROID_3.4.5/drivers/usb/gadget')
-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
19 files changed, 8742 insertions, 22 deletions
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 */