diff options
author | Kevin | 2014-11-15 10:00:36 +0800 |
---|---|---|
committer | Kevin | 2014-11-15 10:00:36 +0800 |
commit | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch) | |
tree | de942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/usb | |
parent | 392e8802486cb573b916e746010e141a75f507e6 (diff) | |
download | FOSSEE-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')
42 files changed, 11742 insertions, 78 deletions
diff --git a/ANDROID_3.4.5/drivers/usb/core/driver.c b/ANDROID_3.4.5/drivers/usb/core/driver.c index 9a56635d..b3df4e9a 100644 --- a/ANDROID_3.4.5/drivers/usb/core/driver.c +++ b/ANDROID_3.4.5/drivers/usb/core/driver.c @@ -1269,6 +1269,10 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) done: dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + if (!(&udev->dev)) + printk("(NULL device *): %s: status %d\n", __func__, status); + else + printk("%s%s : %s: status %d\n",dev_driver_string(&udev->dev), dev_name(&udev->dev), __func__, status); if (!status) udev->reset_resume = 0; return status; diff --git a/ANDROID_3.4.5/drivers/usb/core/generic.c b/ANDROID_3.4.5/drivers/usb/core/generic.c index 69ecd3c9..ec4bfde3 100644 --- a/ANDROID_3.4.5/drivers/usb/core/generic.c +++ b/ANDROID_3.4.5/drivers/usb/core/generic.c @@ -20,6 +20,7 @@ #include <linux/usb.h> #include <linux/usb/hcd.h> #include "usb.h" +extern int usb_power_insuf_skip=0; //read from uboot,default is false; static inline const char *plural(int n) { @@ -97,6 +98,7 @@ int usb_choose_configuration(struct usb_device *udev) */ /* Rule out configs that draw too much bus current */ + if(!usb_power_insuf_skip) if (c->desc.bMaxPower * 2 > udev->bus_mA) { insufficient_power++; continue; diff --git a/ANDROID_3.4.5/drivers/usb/core/hcd.c b/ANDROID_3.4.5/drivers/usb/core/hcd.c index 140d3e11..8318901f 100644 --- a/ANDROID_3.4.5/drivers/usb/core/hcd.c +++ b/ANDROID_3.4.5/drivers/usb/core/hcd.c @@ -2384,6 +2384,8 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, * buffers of consistent memory, register the bus, request the IRQ line, * and call the driver's reset() and start() routines. */ +extern char enable_ehci_wake; + int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { @@ -2437,7 +2439,11 @@ int usb_add_hcd(struct usb_hcd *hcd, * but drivers can override it in reset() if needed, along with * recording the overall controller's system wakeup capability. */ - device_set_wakeup_capable(&rhdev->dev, 1); + if (enable_ehci_wake) { + device_init_wakeup(&rhdev->dev, 1); + } + + //device_set_wakeup_capable(&rhdev->dev, 1); /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is * registered. But since the controller can die at any time, @@ -2494,7 +2500,11 @@ int usb_add_hcd(struct usb_hcd *hcd, * they only forward requests from the root hub. Therefore * controllers should always be enabled for remote wakeup. */ - device_wakeup_enable(hcd->self.controller); + + if (enable_ehci_wake) { + device_wakeup_enable(hcd->self.controller); + } + return retval; error_create_attr_group: diff --git a/ANDROID_3.4.5/drivers/usb/core/hub.c b/ANDROID_3.4.5/drivers/usb/core/hub.c index 6241b717..d6dab03a 100644 --- a/ANDROID_3.4.5/drivers/usb/core/hub.c +++ b/ANDROID_3.4.5/drivers/usb/core/hub.c @@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); #define HUB_DEBOUNCE_TIMEOUT 1500 #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 - +unsigned int usb_storage_id = 0; static int usb_reset_and_verify_device(struct usb_device *udev); @@ -592,6 +592,8 @@ EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); /* If do_delay is false, return the number of milliseconds the caller * needs to delay. */ +/*CharlesTu,2012.09.14,improve resume time*/ +unsigned char usb_resume_flag=0; static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) { int port1; @@ -617,7 +619,9 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) /* Wait at least 100 msec for power to become stable */ delay = max(pgood_delay, (unsigned) 100); if (do_delay) - msleep(delay); + if (!usb_resume_flag) { + msleep(delay); + } return delay; } @@ -839,12 +843,17 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Clear status-change flags; we'll debounce later */ if (portchange & USB_PORT_STAT_C_CONNECTION) { + if (!usb_resume_flag) { need_debounce_delay = true; + } clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); } if (portchange & USB_PORT_STAT_C_ENABLE) { - need_debounce_delay = true; + + if (!usb_resume_flag) { + need_debounce_delay = true; + } clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } @@ -1530,6 +1539,9 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set * to USB_STATE_NOTATTACHED. */ + +extern char enable_ehci_wake; + void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state) { @@ -1564,8 +1576,11 @@ void usb_set_device_state(struct usb_device *udev, } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); - if (wakeup >= 0) + if (wakeup >= 0) { device_set_wakeup_capable(&udev->dev, wakeup); + if (enable_ehci_wake) + device_wakeup_enable(&udev->dev);//gri + } } EXPORT_SYMBOL_GPL(usb_set_device_state); @@ -1668,6 +1683,14 @@ void usb_disconnect(struct usb_device **pdev) struct usb_device *udev = *pdev; int i; + int wmt_usb_patch = 0; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub) + && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00))) + wmt_usb_patch = 1; + + /* mark the device as inactive, so any further urb submissions for * this device (and any of its children) will fail immediately. * this quiesces everything except pending urbs. @@ -1714,6 +1737,9 @@ void usb_disconnect(struct usb_device **pdev) hub_free_dev(udev); put_device(&udev->dev); + + if (wmt_usb_patch) + *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x2); } #ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES @@ -1974,6 +2000,14 @@ int usb_new_device(struct usb_device *udev) (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); usb_mark_last_busy(udev); pm_runtime_put_sync_autosuspend(&udev->dev); + + { + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub) + && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00))) + *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x1); + } return err; fail: @@ -2219,7 +2253,7 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, if (!warm) { struct usb_hcd *hcd; /* TRSTRCY = 10 ms; plus some extra */ - msleep(10 + 40); + msleep(10); /*CharlesTu,2012.09.14,improve resume time*/ update_devnum(udev, 0); hcd = bus_to_hcd(udev->bus); if (hcd->driver->reset_device) { @@ -2808,9 +2842,10 @@ static int hub_resume(struct usb_interface *intf) static int hub_reset_resume(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); - + usb_resume_flag = 1; dev_dbg(&intf->dev, "%s\n", __func__); hub_activate(hub, HUB_RESET_RESUME); + usb_resume_flag = 0; return 0; } @@ -3588,7 +3623,7 @@ static void hub_events(void) u16 hubchange; u16 portstatus; u16 portchange; - int i, ret; + int i, ret,j = 0; int connect_change, wakeup_change; /* @@ -3663,8 +3698,18 @@ static void hub_events(void) hub->error = 0; } - /* deal with port status changes */ - for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { + /* deal with other port status changes */ + + //for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { + for (j = 1; j <= hub->descriptor->bNbrPorts; j++) { + i = j; + if (hub->descriptor->bNbrPorts > 2 ) { + if (usb_storage_id) + i = (j + usb_storage_id -2 ) % hub->descriptor->bNbrPorts + 1 ; + + }; + + if (test_bit(i, hub->busy_bits)) continue; connect_change = test_bit(i, hub->change_bits); diff --git a/ANDROID_3.4.5/drivers/usb/core/usb.c b/ANDROID_3.4.5/drivers/usb/core/usb.c index c74ba7bb..0fc63407 100644 --- a/ANDROID_3.4.5/drivers/usb/core/usb.c +++ b/ANDROID_3.4.5/drivers/usb/core/usb.c @@ -1000,12 +1000,59 @@ static void usb_debugfs_cleanup(void) debugfs_remove(usb_debug_root); } +unsigned char usb_sus = 0; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + /* * Init */ + +extern char enable_uhci0_wake; +extern char enable_uhci1_wake; +extern char enable_ehci_wake ; + +char enable_ehci_disc_wakeup = 0; + static int __init usb_init(void) { + int retval; + + char usb_env_pmc_name[] = "wmt.pmc.param"; + char usb_env_pmc_val[120] = "0"; + int varpmclen = 120; + unsigned int usb_pmc_param[7]; + + if(wmt_getsyspara(usb_env_pmc_name, usb_env_pmc_val, &varpmclen) == 0) { + sscanf(usb_env_pmc_val,"%X:%X:%X:%X:%X:%X:%X", &usb_pmc_param[0],&usb_pmc_param[1], + &usb_pmc_param[2],&usb_pmc_param[3],&usb_pmc_param[4],&usb_pmc_param[5],&usb_pmc_param[6]); + printk("*** uhci_hcd_init usb_param[0] =%x ,usb_param[1]=%x ,usb_param[2]=%x ,usb_param[3]=%x ,usb_param[4]=%x, usb_param[5]=%x, usb_param[6]=%x\n" + ,usb_pmc_param[0],usb_pmc_param[1],usb_pmc_param[2],usb_pmc_param[3],usb_pmc_param[4] + ,usb_pmc_param[5],usb_pmc_param[6]); + if (usb_pmc_param[0]) { + if(usb_pmc_param[1] & 0x00100000) { + enable_ehci_wake = 1; + //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id); + } else { + enable_ehci_wake = 0;// default port B + } + if (usb_pmc_param[5] & 0x1) + enable_uhci0_wake = 1; + else + enable_uhci0_wake = 0; + if (usb_pmc_param[5] & 0x2) + enable_uhci1_wake = 1; + else + enable_uhci1_wake = 0; + if (usb_pmc_param[6] & 0x1) + enable_ehci_disc_wakeup = 1; + } else { + enable_ehci_wake = 0; + enable_uhci1_wake = 0; + enable_uhci0_wake = 0; + } + } + if (nousb) { pr_info("%s: USB support disabled\n", usbcore_name); return 0; diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig index a04b3f57..21a5f4cd 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig +++ b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig @@ -135,6 +135,17 @@ choice # Integrated controllers # +config USB_GADGET_WMT + tristate "GADGET WMT" + select USB_GADGET_SELECTED + select USB_GADGET_DUALSPEED +# default USB_GADGET + +config USB_WMT + tristate "USB WMT" + depends on USB_GADGET_WMT +# default USB_GADGET + config USB_AT91 tristate "Atmel AT91 USB Device Port" depends on ARCH_AT91 @@ -540,8 +551,8 @@ config USB_GADGET_SUPERSPEED # USB Gadget Drivers # choice - tristate "USB Gadget Drivers" - default USB_ETH + boolean "USB Gadget Drivers" + default USB_G_ANDROID help A Linux "Gadget Driver" talks to the USB Peripheral Controller driver through the abstract "gadget" API. Some other operating diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Makefile b/ANDROID_3.4.5/drivers/usb/gadget/Makefile index b91866a6..8df55f44 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/Makefile +++ b/ANDROID_3.4.5/drivers/usb/gadget/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o +obj-$(CONFIG_USB_WMT) += udc_wmt.o # # USB gadget drivers @@ -73,3 +74,5 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_G_ANDROID) += g_android.o +obj-y += rawbulk.o +obj-y += rawbulk_transfer.o diff --git a/ANDROID_3.4.5/drivers/usb/gadget/android.c b/ANDROID_3.4.5/drivers/usb/gadget/android.c index 4e73bf1a..c5ce536a 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/android.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/android.c @@ -28,6 +28,8 @@ #include <linux/usb/composite.h> #include <linux/usb/gadget.h> +#include <linux/power/wmt_battery.h> + #include "gadget_chips.h" /* @@ -54,6 +56,7 @@ #include "f_rndis.c" #include "rndis.c" #include "u_ether.c" +#include "f_rawbulk.c" MODULE_AUTHOR("Mike Lockwood"); MODULE_DESCRIPTION("Android Composite USB Driver"); @@ -62,6 +65,9 @@ MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, char *varval); + /* Default vendor and product IDs, overridden by userspace */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 @@ -215,6 +221,7 @@ static void android_disable(struct android_dev *dev) /* Cancel pending control requests */ usb_ep_dequeue(cdev->gadget->ep0, cdev->req); usb_remove_config(cdev, &android_config_driver); + usb_ep_autoconfig_reset(cdev->gadget); } } @@ -917,6 +924,86 @@ static struct android_usb_function accessory_function = { .bind_config = accessory_function_bind_config, .ctrlrequest = accessory_function_ctrlrequest, }; +#define CONFIG_USB_ANDROID_RAWBULK 1 + +/* VIA Rawbulk functions */ +#ifdef CONFIG_USB_ANDROID_RAWBULK +static int rawbulk_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) +{ + return 0; +} + +static void rawbulk_function_cleanup(struct android_usb_function *f) +{ + ; +} + +static int rawbulk_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + char *i = f->name + strlen("via_"); + if (!strncmp(i, "modem", 5)) + return rawbulk_bind_config(c, RAWBULK_TID_MODEM); + else if (!strncmp(i, "ets", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_ETS); + else if (!strncmp(i, "atc", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_AT); + else if (!strncmp(i, "pcv", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_PCV); + else if (!strncmp(i, "gps", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_GPS); + return -EINVAL; +} + +static int rawbulk_function_modem_ctrlrequest(struct android_usb_function *f, + struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *c) +{ + if ((c->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE && + (c->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { + struct rawbulk_function *fn = rawbulk_lookup_function(RAWBULK_TID_MODEM); + return rawbulk_function_setup(&fn->function, c); + } + return -1; +} + +static struct android_usb_function rawbulk_modem_function = { + .name = "via_modem", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, + .ctrlrequest = rawbulk_function_modem_ctrlrequest, +}; + +static struct android_usb_function rawbulk_ets_function = { + .name = "via_ets", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_atc_function = { + .name = "via_atc", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_pcv_function = { + .name = "via_pcv", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_gps_function = { + .name = "via_gps", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; +#endif /* CONFIG_USB_ANDROID_RAWBULK */ static int audio_source_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) @@ -990,6 +1077,11 @@ static struct android_usb_function *supported_functions[] = { &mass_storage_function, &accessory_function, &audio_source_function, + &rawbulk_modem_function, + &rawbulk_ets_function, + &rawbulk_atc_function, + &rawbulk_pcv_function, + &rawbulk_gps_function, NULL }; @@ -1356,6 +1448,23 @@ static void android_unbind_config(struct usb_configuration *c) android_unbind_enabled_functions(dev, c); } +unsigned char buf_android_serialno[32]; + +int get_android_serialno(void) +{ + int varlen =127; + int retval; + memset(buf_android_serialno,0,sizeof(buf_android_serialno)); + retval = wmt_getsyspara("androidboot.serialno", buf_android_serialno, &varlen); + if(!retval) + { + printk("androidboot.serialno=%s\n",buf_android_serialno); + return 0x0; + }else{ + printk("uboot variant androidboot.serialno do not exit\n"); + return -1; + } +} static int android_bind(struct usb_composite_dev *cdev) { @@ -1391,7 +1500,15 @@ static int android_bind(struct usb_composite_dev *cdev) /* Default strings - should be updated by userspace */ strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1); strncpy(product_string, "Android", sizeof(product_string) - 1); - strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); + + get_android_serialno(); + if(strlen(buf_android_serialno)==0){ + strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); + printk("buf_android_serialno is null\n"); + }else{ + strncpy(serial_string, buf_android_serialno, sizeof(serial_string) - 1); + printk("buf_android_serialno:%s\n",buf_android_serialno); + } id = usb_string_id(cdev); if (id < 0) @@ -1467,6 +1584,9 @@ android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) if (!dev->connected) { dev->connected = 1; schedule_work(&dev->work); +#if defined(CONFIG_BATTERY_WMT) + wmt_do_pc_connected(); +#endif } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) { schedule_work(&dev->work); @@ -1518,6 +1638,12 @@ static int android_create_device(struct android_dev *dev) return 0; } +/* provide usb connected state for charger */ +int wmt_is_pc_connected(void) +{ + return _android_dev ? _android_dev->connected : 0; +} +EXPORT_SYMBOL(wmt_is_pc_connected); static int __init init(void) { diff --git a/ANDROID_3.4.5/drivers/usb/gadget/composite.c b/ANDROID_3.4.5/drivers/usb/gadget/composite.c index 8f82fc0e..6cfe5f24 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/composite.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/composite.c @@ -798,6 +798,7 @@ static int unbind_config(struct usb_composite_dev *cdev, return 0; } +extern void wmt_cleanup_done_thread(int number); /** * usb_remove_config() - remove a configuration from a device. * @cdev: wraps the USB gadget @@ -811,16 +812,14 @@ int usb_remove_config(struct usb_composite_dev *cdev, struct usb_configuration *config) { unsigned long flags; - + //wmt_cleanup_done_thread(1); spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config == config) reset_config(cdev); list_del(&config->list); spin_unlock_irqrestore(&cdev->lock, flags); - return unbind_config(cdev, config); } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c index 51f3d42f..fc5eb804 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c @@ -280,6 +280,43 @@ struct usb_ep *usb_ep_autoconfig_ss( if (ep && ep_matches(gadget, ep, desc, ep_comp)) goto found_ep; + } else if (gadget_is_wmt (gadget)) { + //printk(KERN_INFO "usb_ep_autoconfig find wmt_gadget \n"); + if (USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep3in-int \n"); + ep = find_ep (gadget, "ep3in-int"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep3in-int \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_BULK == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); + ep = find_ep (gadget, "ep1in-bulk"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_BULK == type) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep2out-bulk \n"); + ep = find_ep (gadget, "ep2out-bulk"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep2out-bulk \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_ISOC == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); + ep = find_ep (gadget, "ep4in-iso"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); + goto found_ep; + } + } } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c index a244265c..bfb3a777 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c @@ -502,6 +502,7 @@ static int create_bulk_endpoints(struct acc_dev *dev, ep->driver_data = dev; /* claim the endpoint */ dev->ep_in = ep; +#if 0 ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); @@ -510,6 +511,7 @@ static int create_bulk_endpoints(struct acc_dev *dev, DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#endif ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { @@ -568,6 +570,10 @@ static ssize_t acc_read(struct file *fp, char __user *buf, ret = wait_event_interruptible(dev->read_wq, dev->online); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + goto done; } @@ -588,6 +594,10 @@ requeue_req: ret = wait_event_interruptible(dev->read_wq, dev->rx_done); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + usb_ep_dequeue(dev->ep_out, req); goto done; } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c index 1629ffb5..0eea2191 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c @@ -502,7 +502,8 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) dev->error = 1; wake_up(&dev->read_wq); - + extern void wmt_cleanup_done_thread(int number); + wmt_cleanup_done_thread(1); adb_request_free(dev->rx_req, dev->ep_out); while ((req = adb_req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c index cb8c162c..68c3d9f6 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c @@ -2691,6 +2691,8 @@ static int fsg_main_thread(void *common_) static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); +static DEVICE_ATTR(cdrom, 0644, fsg_show_cdrom, fsg_store_cdrom); + /****************************** FSG COMMON ******************************/ @@ -2815,7 +2817,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, rc = device_create_file(&curlun->dev, &dev_attr_nofua); if (rc) goto error_luns; - + rc = device_create_file(&curlun->dev, &dev_attr_cdrom); + if (rc) + goto error_luns; if (lcfg->filename) { rc = fsg_lun_open(curlun, lcfg->filename); if (rc) @@ -2947,6 +2951,7 @@ static void fsg_common_release(struct kref *ref) device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); + device_remove_file(&lun->dev, &dev_attr_cdrom); fsg_lun_close(lun); device_unregister(&lun->dev); } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c index 1638977a..6279bfb0 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c @@ -410,6 +410,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#if 0 ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); @@ -418,6 +419,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#endif ep = usb_ep_autoconfig(cdev->gadget, intr_desc); if (!ep) { @@ -478,6 +480,10 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, dev->state != STATE_OFFLINE); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + goto done; } spin_lock_irq(&dev->lock); @@ -506,7 +512,11 @@ requeue_req: /* wait for a request to complete */ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); if (ret < 0) { - r = ret; + r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + usb_ep_dequeue(dev->ep_out, req); goto done; } @@ -1121,7 +1131,8 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) struct mtp_dev *dev = func_to_mtp(f); struct usb_request *req; int i; - + extern void wmt_cleanup_done_thread(int number); + wmt_cleanup_done_thread(1); while ((req = mtp_req_get(dev, &dev->tx_idle))) mtp_request_free(req, dev->ep_in); for (i = 0; i < RX_REQ_MAX; i++) @@ -1175,21 +1186,22 @@ static int mtp_function_set_alt(struct usb_function *f, return 0; } + static void mtp_function_disable(struct usb_function *f) { struct mtp_dev *dev = func_to_mtp(f); struct usb_composite_dev *cdev = dev->cdev; - DBG(cdev, "mtp_function_disable\n"); + printk("mtp_function_disable\n"); dev->state = STATE_OFFLINE; usb_ep_disable(dev->ep_in); usb_ep_disable(dev->ep_out); usb_ep_disable(dev->ep_intr); - +// wmt_cleanup_done_thread(1); /* readers may be blocked waiting for us to go online */ wake_up(&dev->read_wq); - VDBG(cdev, "%s disabled\n", dev->function.name); + printk("%s disabled\n", dev->function.name); } static int mtp_bind_config(struct usb_configuration *c, bool ptp_config) diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c new file mode 100755 index 00000000..92bce0fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c @@ -0,0 +1,322 @@ +/* + * Rawbulk Gadget Function Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" +#define DRIVER_VERSION "1.0.1" +#define DRIVER_NAME "usb_rawbulk" + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/wakelock.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + +#include <linux/usb/composite.h> +#include <linux/usb/rawbulk.h> +struct usb_composite_dev * wmt_cdev; +#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) + +static void simple_setup_complete(struct usb_ep *ep, + struct usb_request *req) { + ;//DO NOTHING +} + +unsigned int dump_mask = 0; +static int rawbulk_function_setup(struct usb_function *f, const struct + usb_ctrlrequest *ctrl) { + int rc; + struct rawbulk_function *fn = function_to_rawbulk(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + + if (rawbulk_transfer_state(fn->transfer_id) < 0) + return -EOPNOTSUPP; + + if (dump_mask & (1 << RAWBULK_TID_MODEM)) + printk(KERN_DEBUG "DUMP ctrl: bRequestType = %02X, bRequest = %02X, " \ + "wValue = %04X, wIndex = %04X, wLength = %d\n", + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, + ctrl->wLength); + + if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x02) { + /* Query CD109 Status */ + if (rawbulk_check_enable(fn)) + goto forwarding; + *(unsigned char *)req->buf = 0x02; /* Test!!! */ + req->length = 1; + req->complete = simple_setup_complete; + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0x01) { + /* Set/Clear DTR */ + if (rawbulk_check_enable(fn)) + goto forwarding; + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x04) { + /* Request CBP Product Name */ + req->length = sprintf(req->buf, "CBP_KUNLUN"); + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } + + return -EOPNOTSUPP; +forwarding: + rc = rawbulk_forward_ctrlrequest(ctrl); + if (rc < 0) { + printk(KERN_DEBUG "rawbulk forwarding failed %d\n", rc); + return rc; + } + return 256 + 999;//USB_GADGET_DELAYED_STATUS; +} + +static void rawbulk_auto_reconnect(int transfer_id) { + int rc; + struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); + if (!fn || fn->autoreconn == 0) + return; + + if (rawbulk_check_enable(fn) && fn->activated) { + printk(KERN_DEBUG "start %s again automatically.\n", fn->longname); + rc = rawbulk_start_transactions(transfer_id, fn->nups, + fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); + if (rc < 0) { + rawbulk_disable_function(fn); + rawbulk_tty_start_io(fn); + } + } +} + +static struct usb_ep *match_ep(struct usb_configuration *c, + struct rawbulk_function *fn, int in) { + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep; + struct usb_endpoint_descriptor *desc = + (struct usb_endpoint_descriptor *)(in? fn->fs_descs[BULKIN_DESC]: + fn->fs_descs[BULKOUT_DESC]); + return usb_ep_autoconfig(gadget, desc); +} + +static int rawbulk_function_bind(struct usb_configuration *c, struct + usb_function *f) { + int rc, ifnum; + struct rawbulk_function *fn = function_to_rawbulk(f); + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep_out, *ep_in; + + rc = usb_interface_id(c, f); + if (rc < 0) + return rc; + ifnum = rc; + + fn->interface.bInterfaceNumber = cpu_to_le16(ifnum); + + + + usb_ep_autoconfig_reset(c->cdev->gadget); //added by griffen + + + if (!(ep_out = match_ep(c, fn, 0))) { + printk(KERN_DEBUG "unfortunately, we could not find endpoint(OUT) for %s", + fn->longname); + return -ENOMEM; + } + + if (!(ep_in = match_ep(c, fn, 1))) { + printk(KERN_DEBUG "unfortunately, we could not find endpoint(IN) for %s", + fn->longname); + return -ENOMEM; + } + + ep_out->driver_data = fn; + ep_in->driver_data = fn; + fn->bulk_out = ep_out; + fn->bulk_in = ep_in; + + f->descriptors = usb_copy_descriptors(fn->fs_descs); + if (unlikely(!f->descriptors)) + return -ENOMEM; + + if (gadget_is_dualspeed(gadget)) { + fn->hs_bulkin_endpoint.bEndpointAddress = + fn->fs_bulkin_endpoint.bEndpointAddress; + fn->hs_bulkout_endpoint.bEndpointAddress = + fn->fs_bulkout_endpoint.bEndpointAddress; + f->hs_descriptors = usb_copy_descriptors(fn->hs_descs); + if (unlikely(!f->hs_descriptors)) { + usb_free_descriptors(f->descriptors); + return -ENOMEM; + } + } + + fn->cdev = c->cdev; + fn->activated = 0; + + /* + rc = rawbulk_register_tty(fn); + if (rc < 0) + printk(KERN_ERR "failed to register tty for %s\n", fn->longname); + */ + + return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in, + rawbulk_auto_reconnect); +} + +static void rawbulk_function_unbind(struct usb_configuration *c, struct + usb_function *f) { + struct rawbulk_function *fn = function_to_rawbulk(f); + + printk(KERN_DEBUG "%s - unbind %s.\n", __func__, fn->longname); + //rawbulk_unregister_tty(fn); + rawbulk_unbind_function(fn->transfer_id); +} + +static void do_activate(struct work_struct *data) { + struct rawbulk_function *fn = container_of(data, struct rawbulk_function, + activator); + int rc; + printk(KERN_DEBUG "%s rawbulk %s channel (enabled? %s).\n", + fn->activated? "activte": "detach", fn->shortname, + rawbulk_check_enable(fn)? "yes": "no"); + if (fn->activated) { /* enumerated */ + int ret; + ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_out); + if (ret) + return ; + + /* enabled endpoints */ + rc = usb_ep_enable(fn->bulk_out); + if (rc < 0) { + printk(KERN_ERR "failed to enable rawbulk %s %d\n", + fn->bulk_out->name, rc); + return; + } + + + ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_in); + if (ret) + return ; + + rc = usb_ep_enable(fn->bulk_in); + if (rc < 0) { + printk(KERN_ERR "failed to enable rawbulk %s %d\n", + fn->bulk_in->name, rc); + usb_ep_disable(fn->bulk_out); + return; + } + + /* start rawbulk if enabled */ + if (rawbulk_check_enable(fn)) { + wake_lock(&fn->keep_awake); + rc = rawbulk_start_transactions(fn->transfer_id, fn->nups, + fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); + if (rc < 0) + rawbulk_disable_function(fn); + } + + /* start tty io */ + rc = rawbulk_tty_alloc_request(fn); + if (rc < 0) + return; + if (!rawbulk_check_enable(fn)) + rawbulk_tty_start_io(fn); + } else { /* disconnect */ + if (rawbulk_check_enable(fn)) { + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* this in interrupt, but DTR need be set firstly then clear it + * */ + //control_dtr(0); + } + rawbulk_stop_transactions(fn->transfer_id); + /* keep the enable state, so we can enable again in next time */ + //set_enable_state(fn, 0); + wake_unlock(&fn->keep_awake); + } else + rawbulk_tty_stop_io(fn); + + rawbulk_tty_free_request(fn); + + usb_ep_disable(fn->bulk_out); + usb_ep_disable(fn->bulk_in); + + fn->bulk_out->driver_data = NULL; + fn->bulk_in->driver_data = NULL; + } +} + +static int rawbulk_function_setalt(struct usb_function *f, unsigned intf, + unsigned alt) { + struct rawbulk_function *fn = function_to_rawbulk(f); + fn->activated = 1; + schedule_work(&fn->activator); + return 0; +} + +static void rawbulk_function_disable(struct usb_function *f) { + struct rawbulk_function *fn = function_to_rawbulk(f); + fn->activated = 0; + schedule_work(&fn->activator); +} + +static int rawbulk_bind_config(struct usb_configuration *c, int transfer_id) { + int rc; + struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); + + printk(KERN_DEBUG "add %s to config.\n", fn->longname); + + if (!fn) + return -ENOMEM; + + if (fn->string_defs[0].id == 0) { + rc = usb_string_id(c->cdev); + if (rc < 0) + return rc; + fn->string_defs[0].id = rc; + fn->interface.iInterface = rc; + } + wmt_cdev = c->cdev; + + fn->function.name = fn->longname; + fn->function.setup = rawbulk_function_setup; + fn->function.bind = rawbulk_function_bind; + fn->function.unbind = rawbulk_function_unbind; + fn->function.set_alt = rawbulk_function_setalt; + fn->function.disable = rawbulk_function_disable; + + INIT_WORK(&fn->activator, do_activate); + + rc = usb_add_function(c, &fn->function); + if (rc < 0) + printk(KERN_DEBUG "%s - failed to config %d.\n", __func__, rc); + + return rc; +} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c index 3a6e5587..5a4fdbc7 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c @@ -458,7 +458,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) status, req->actual, req->length); // spin_unlock(&dev->lock); } - +extern bool get_rndis_initialized(void); static int rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -469,7 +469,8 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); - + if(!get_rndis_initialized()) + return; /* composite driver infrastructure handles everything except * CDC class messages; interface activation uses set_alt(). */ @@ -614,7 +615,7 @@ static void rndis_disable(struct usb_function *f) if (!rndis->notify->driver_data) return; - DBG(cdev, "rndis deactivated\n"); + printk("rndis deactivated\n"); rndis_uninit(rndis->config); gether_disconnect(&rndis->port); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h index a8855d0b..30fad3e8 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h +++ b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h @@ -26,6 +26,7 @@ * do that for you. */ #define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) +#define gadget_is_wmt(g) (!strcmp("wmotgdev", (g)->name)) #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) #define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) #define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) @@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x31; else if (gadget_is_dwc3(gadget)) return 0x32; + else if (gadget_is_wmt(gadget)) + return 0x33; return -ENOENT; } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c new file mode 100755 index 00000000..5c027da4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c @@ -0,0 +1,1272 @@ +/* + * Rawbulk Gadget Function Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" +#define DRIVER_VERSION "1.0.1" +#define DRIVER_NAME "usb_rawbulk" + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/wakelock.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/types.h> +#include <linux/device.h> + +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + +#include <linux/usb/composite.h> +#include <linux/usb/rawbulk.h> + +#ifdef DEBUG +#define ldbg(f, a...) printk(KERN_DEBUG "%s - " f "\n", __func__, ##a) +#else +#define ldbg(...) {} +#endif + +/* sysfs attr idx assignment */ +enum _attr_idx { + ATTR_ENABLE = 0, /** enable switch for Rawbulk */ +#ifdef SUPPORT_LEGACY_CONTROL + ATTR_ENABLE_C, /** enable switch too, but for legacy */ +#endif + ATTR_AUTORECONN, /** enable to rebind cp when it reconnect */ + ATTR_STATISTICS, /** Rawbulk summary/statistics for one pipe */ + ATTR_NUPS, /** upstream transfers count */ + ATTR_NDOWNS, /** downstram transfers count */ + ATTR_UPSIZE, /** upstream buffer for each transaction */ + ATTR_DOWNSIZE, /** downstram buffer for each transaction */ + ATTR_SPLIT, /** split option for downstream */ + ATTR_PUSHABLE, /** set to use push-way for upstream */ + ATTR_DTR, /** DTR control, only for Data-Call port */ +}; + +/* USB gadget framework is not strong enough, and not be compatiable with some + * controller, such as musb. + * in musb driver, the usb_request's member list is used internally, but in some + * applications it used in function driver too. to avoid this, here we + * re-wrap the usb_request */ +struct usb_request_wrapper { + struct list_head list; + struct usb_request *request; + int length; + struct rawbulk_function *fn; + char buffer[0]; +}; + +static struct usb_request_wrapper *get_wrapper(struct usb_request *req) { + if (!req->buf) + return NULL; + return container_of(req->buf, struct usb_request_wrapper, buffer); +} + +/* Internal TTY functions/data */ +static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct + *tty); +static void rawbulk_tty_deactivate(struct tty_port *port); +static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct + *tty); +static void rawbulk_tty_cleanup(struct tty_struct *tty); +static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip); +static void rawbulk_tty_hangup(struct tty_struct *tty); +static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip); +static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count); +static int rawbulk_tty_write_room(struct tty_struct *tty); +static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty); +static void rawbulk_tty_throttle(struct tty_struct *tty); +static void rawbulk_tty_unthrottle(struct tty_struct *tty); +static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios + *old); +static int rawbulk_tty_tiocmget(struct tty_struct *tty); +static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); + +static struct tty_port_operations rawbulk_tty_port_ops = { + .activate = rawbulk_tty_activate, + .shutdown = rawbulk_tty_deactivate, +}; + +static struct tty_operations rawbulk_tty_ops = { + .open = rawbulk_tty_open, + .close = rawbulk_tty_close, + .write = rawbulk_tty_write, + .hangup = rawbulk_tty_hangup, + .write_room = rawbulk_tty_write_room, + .set_termios = rawbulk_tty_set_termios, + .throttle = rawbulk_tty_throttle, + .unthrottle = rawbulk_tty_unthrottle, + .chars_in_buffer = rawbulk_tty_chars_in_buffer, + .tiocmget = rawbulk_tty_tiocmget, + .tiocmset = rawbulk_tty_tiocmset, + .cleanup = rawbulk_tty_cleanup, + .install = rawbulk_tty_install, +}; + +struct tty_driver *rawbulk_tty_driver; + +struct rawbulk_function *prealloced_functions[_MAX_TID] = { NULL }; +struct rawbulk_function *rawbulk_lookup_function(int transfer_id) { + if (transfer_id >= 0 && transfer_id < _MAX_TID) + return prealloced_functions[transfer_id]; + return NULL; +} +EXPORT_SYMBOL_GPL(rawbulk_lookup_function); + +static struct rawbulk_function *lookup_by_tty_minor(int minor) { + int n; + struct rawbulk_function *fn; + for (n = 0; n < _MAX_TID; n ++) { + fn = prealloced_functions[n]; + if (fn->tty_minor == minor) + return fn; + } + return NULL; +} + +static inline int check_enable_state(struct rawbulk_function *fn) { + int enab; + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + enab = fn->enable? 1: 0; + spin_unlock_irqrestore(&fn->lock, flags); + return enab; +} + +int rawbulk_check_enable(struct rawbulk_function *fn) { + return check_enable_state(fn); +} +EXPORT_SYMBOL_GPL(rawbulk_check_enable); + +static inline int check_tty_opened(struct rawbulk_function *fn) { + int opened; + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + opened = fn->tty_opened? 1: 0; + spin_unlock_irqrestore(&fn->lock, flags); + return opened; +} + +static inline void set_enable_state(struct rawbulk_function *fn, int enab) { + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + fn->enable = !!enab; + spin_unlock_irqrestore(&fn->lock, flags); +} + +void rawbulk_disable_function(struct rawbulk_function *fn) { + set_enable_state(fn, 0); +} +EXPORT_SYMBOL_GPL(rawbulk_disable_function); + +static inline void set_tty_opened(struct rawbulk_function *fn, int opened) { + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + fn->tty_opened = !!opened; + spin_unlock_irqrestore(&fn->lock, flags); +} + +#define port_to_rawbulk(p) container_of(p, struct rawbulk_function, port) +#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) + +static struct usb_request_wrapper *get_req(struct list_head *head, spinlock_t + *lock) { + unsigned long flags; + struct usb_request_wrapper *req = NULL; + spin_lock_irqsave(lock, flags); + if (!list_empty(head)) { + req = list_first_entry(head, struct usb_request_wrapper, list); + list_del(&req->list); + } + spin_unlock_irqrestore(lock, flags); + return req; +} + +static void put_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_add_tail(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static void move_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_move_tail(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static void insert_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_add(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static int control_dtr(int set) { + struct usb_ctrlrequest ctrl = { + .bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR, //0x40 + .bRequest = 0x01, + .wLength = 0, + .wIndex = 0, + }; + + ctrl.wValue = cpu_to_le16(!!set); + return rawbulk_forward_ctrlrequest(&ctrl); +} + +static void init_endpoint_desc(struct usb_endpoint_descriptor *epdesc, int in, + int maxpacksize) { + struct usb_endpoint_descriptor template = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }; + + *epdesc = template; + if (in) + epdesc->bEndpointAddress = USB_DIR_IN; + else + epdesc->bEndpointAddress = USB_DIR_OUT; + epdesc->wMaxPacketSize = cpu_to_le16(maxpacksize); +} + +static void init_interface_desc(struct usb_interface_descriptor *ifdesc) { + struct usb_interface_descriptor template = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff,//USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .iInterface = 0, + }; + + *ifdesc = template; +} + +static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute + *attr, char *buf); +static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count); + +static inline void add_device_attr(struct rawbulk_function *fn, int n, const char + *name, int mode) { + if (n < MAX_ATTRIBUTES) { + fn->attr[n].attr.name = name; + fn->attr[n].attr.mode = mode; + fn->attr[n].show = rawbulk_attr_show; + fn->attr[n].store = rawbulk_attr_store; + } +} + +static int which_attr(struct rawbulk_function *fn, struct device_attribute + *attr) { + int n; + for (n = 0; n < fn->max_attrs; n ++) { + if (attr == &fn->attr[n]) + return n; + } + return -1; +} + +static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute *attr, + char *buf) { + int n; + int idx; + int enab; + struct rawbulk_function *fn; + + for (n = 0; n < _MAX_TID; n ++) { + fn = rawbulk_lookup_function(n); + if (fn->dev == dev) { + idx = which_attr(fn, attr); + break; + } +#ifdef SUPPORT_LEGACY_CONTROL + if (!strcmp(attr->attr.name, fn->shortname)) { + idx = ATTR_ENABLE_C; + break; + } +#endif + } + + if (n == _MAX_TID) + return 0; + + enab = check_enable_state(fn); + switch (idx) { + case ATTR_ENABLE: + return sprintf(buf, "%d", enab); +#ifdef SUPPORT_LEGACY_CONTROL + case ATTR_ENABLE_C: + return sprintf(buf, "%s", enab? "gadget": "tty"); +#endif + case ATTR_AUTORECONN: + return sprintf(buf, "%d", fn->autoreconn); + case ATTR_STATISTICS: + return rawbulk_transfer_statistics(fn->transfer_id, buf); + case ATTR_NUPS: + return sprintf(buf, "%d", enab? fn->nups: -1); + case ATTR_NDOWNS: + return sprintf(buf, "%d", enab? fn->ndowns: -1); + case ATTR_UPSIZE: + return sprintf(buf, "%d", enab? fn->upsz: -1); + case ATTR_DOWNSIZE: + return sprintf(buf, "%d", enab? fn->downsz: -1); + case ATTR_SPLIT: + return sprintf(buf, "%d", enab? fn->splitsz: -1); + case ATTR_PUSHABLE: + return sprintf(buf, "%d", fn->pushable); + default: + break; + } + return 0; +} + +static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int n; + int rc = 0; + int idx = -1; + int nups; + int ndowns; + int upsz; + int downsz; + int splitsz; + int pushable; + struct rawbulk_function *fn; + + for (n = 0; n < _MAX_TID; n ++) { + fn = rawbulk_lookup_function(n); + if (fn->dev == dev) { + idx = which_attr(fn, attr); + break; + } +#ifdef SUPPORT_LEGACY_CONTROL + if (!strcmp(attr->attr.name, fn->shortname)) { + idx = ATTR_ENABLE_C; + break; + } +#endif + } + + if (idx < 0) { + printk(KERN_ERR "sorry, I cannot find rawbulk fn '%s'\n", attr->attr.name); + goto exit; + } + + nups = fn->nups; + ndowns = fn->ndowns; + upsz = fn->upsz; + downsz = fn->downsz; + splitsz = fn->splitsz; + pushable = fn->pushable; + + /* find out which attr(file) we write */ + +#ifdef SUPPORT_LEGACY_CONTROL + if (idx <= ATTR_ENABLE_C) +#else + if (idx == ATTR_ENABLE) +#endif + { + int enable; + if (idx == ATTR_ENABLE) { + enable = simple_strtoul(buf, NULL, 10); +#ifdef SUPPORT_LEGACY_CONTROL + } else if (idx == ATTR_ENABLE_C) { + if (!strncmp(buf, "tty", 3)) + enable = 0; + else if (!strncmp(buf, "gadget", 6)) + enable = 1; + else { + printk(KERN_ERR "invalid option(%s) for bypass, try again...\n", buf); + goto exit; + } +#endif /* SUPPORT_LEGACY_CONTROL */ + } else + goto exit; + + if (check_enable_state(fn) != (!!enable)) { + set_enable_state(fn, enable); + if (!!enable && fn->activated) { + printk(KERN_DEBUG "enable rawbulk %s channel, been activated? %s\n", + fn->shortname, fn->activated? "yes": "no"); + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* clear DTR to endup last session between AP and CP */ + control_dtr(1); + msleep(10); + control_dtr(0); + } + + /* Stop TTY i/o */ + rawbulk_tty_stop_io(fn); + + /* Start rawbulk transfer */ + wake_lock(&fn->keep_awake); + rc = rawbulk_start_transactions(fn->transfer_id, nups, + ndowns, upsz, downsz, splitsz, pushable); + if (rc < 0) { + set_enable_state(fn, !enable); + rawbulk_tty_start_io(fn); + } + } else { + /* Stop rawbulk transfer */ + printk(KERN_DEBUG "disable rawbulk %s channel, been activated? %s\n", + fn->shortname, fn->activated? "yes": "no"); + rawbulk_stop_transactions(fn->transfer_id); + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* clear DTR automatically when disable modem rawbulk */ + control_dtr(1); + msleep(10); + control_dtr(0); + } + wake_unlock(&fn->keep_awake); + + /* Start TTY i/o */ + rawbulk_tty_start_io(fn); + } + } + } else if (idx == ATTR_DTR) { + if (fn->transfer_id == RAWBULK_TID_MODEM) { + if (check_enable_state(fn)) + control_dtr(simple_strtoul(buf, NULL, 10)); + } + } else if (idx == ATTR_AUTORECONN) { + fn->autoreconn = !!simple_strtoul(buf, NULL, 10); + } else { + int val = simple_strtoul(buf, NULL, 10); + switch (idx) { + case ATTR_NUPS: nups = val; break; + case ATTR_NDOWNS: ndowns = val; break; + case ATTR_UPSIZE: upsz = val; break; + case ATTR_DOWNSIZE: downsz = val; break; + case ATTR_SPLIT: splitsz = val; break; + case ATTR_PUSHABLE: + pushable = !!val; + fn->pushable = pushable; + break; + default: goto exit; + } + + if (!check_enable_state(fn)) + goto exit; + + if (!fn->activated) + goto exit; + + rawbulk_stop_transactions(fn->transfer_id); + rc = rawbulk_start_transactions(fn->transfer_id, nups, ndowns, upsz, + downsz, splitsz, pushable); + if (rc >= 0) { + fn->nups = nups; + fn->ndowns = ndowns; + fn->upsz = upsz; + fn->downsz = downsz; + fn->splitsz = splitsz; + fn->pushable = pushable; + } else { + rawbulk_stop_transactions(fn->transfer_id); + wake_unlock(&fn->keep_awake); + set_enable_state(fn, 0); + } + } + +exit: + return count; +} + +static int rawbulk_create_files(struct rawbulk_function *fn) { + int n, rc; + for (n = 0; n < fn->max_attrs; n ++){ +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + rc = device_create_file(fn->dev, &fn->attr[n]); + if (rc < 0) { + while (--n >= 0) { +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + device_remove_file(fn->dev, &fn->attr[n]); + } + return rc; + } + } + return 0; +} + +static void rawbulk_remove_files(struct rawbulk_function *fn) { + int n = fn->max_attrs; + while (--n >= 0) { +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + device_remove_file(fn->dev, &fn->attr[n]); + } +} + +#define RAWBULK_TTY_MINORS 255 +static int tty_minors[RAWBULK_TTY_MINORS] = { 0 }; +static int alloc_tty_minor(struct rawbulk_function *fn) { + int n; + if (check_tty_opened(fn)) + printk(KERN_WARNING "ttyRB%d has opened yet %s has been disconnected\n", + fn->tty_minor, fn->longname); + for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { + if (tty_minors[n] == 0) { + tty_minors[n] = fn->transfer_id + 0x8000; + return n; + } + } + return -ENODEV; +} + +static void free_tty_minor(struct rawbulk_function *fn) { + int n; + struct tty_struct **ttys = rawbulk_tty_driver->ttys; + if (!check_tty_opened(fn)) + tty_minors[fn->tty_minor] = 0; + /* Clear the closed tty minors of this port */ + for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { + if ((tty_minors[n] == fn->transfer_id + 0x8000) && ttys[n]) { + struct tty_struct *tty = ttys[n]; + if (tty->count > 0) + continue; /* Keep the minor while tty is being used */ + if (test_bit(TTY_CLOSING, &tty->flags)) { + /* FIXME: Cannot close the tty_struct! */ + printk(KERN_DEBUG "cannot recycle the minor %d because " \ + "the TTY_CLOSING flags is still on\n", n); + continue; + } + tty_minors[n] = 0; + } + } +} + +int rawbulk_register_tty(struct rawbulk_function *fn) { + struct device *dev; + + spin_lock_init(&fn->tx_lock); + spin_lock_init(&fn->rx_lock); + INIT_LIST_HEAD(&fn->tx_free); + INIT_LIST_HEAD(&fn->rx_free); + INIT_LIST_HEAD(&fn->tx_inproc); + INIT_LIST_HEAD(&fn->rx_inproc); + INIT_LIST_HEAD(&fn->rx_throttled); + + fn->tty_minor = alloc_tty_minor(fn); + if (fn->tty_minor < 0) + return -ENODEV; + fn->tty_opened = 0; + fn->last_pushed = 0; + tty_port_init(&fn->port); + fn->port.ops = &rawbulk_tty_port_ops; + + /* Bring up the tty device */ + dev = tty_register_device(rawbulk_tty_driver, fn->tty_minor, fn->dev); + if (IS_ERR(dev)) + printk(KERN_ERR "Failed to attach ttyRB%d to %s device.\n", + fn->tty_minor, fn->longname); + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_register_tty); + +void rawbulk_unregister_tty(struct rawbulk_function *fn) { + tty_unregister_device(rawbulk_tty_driver, fn->tty_minor); + free_tty_minor(fn); +} +EXPORT_SYMBOL_GPL(rawbulk_unregister_tty); + +/******************************************************************************/ + +/* Call this after all request has detached! */ +void rawbulk_tty_free_request(struct rawbulk_function *fn) { + struct usb_request_wrapper *req; + + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + usb_ep_free_request(fn->bulk_out, req->request); + kfree(req); + } + + while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { + usb_ep_free_request(fn->bulk_in, req->request); + kfree(req); + } +} +EXPORT_SYMBOL_GPL(rawbulk_tty_free_request); + +static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req); +static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req); + +int rawbulk_tty_alloc_request(struct rawbulk_function *fn) { + int n; + struct usb_request_wrapper *req; + unsigned long flags; + + spin_lock_irqsave(&fn->lock, flags); + if (!fn->bulk_out || !fn->bulk_in) { + spin_unlock_irqrestore(&fn->lock, flags); + return -ENODEV; + } + spin_unlock_irqrestore(&fn->lock, flags); + + /* Allocate and init rx request */ + for (n = 0; n < MAX_TTY_RX; n ++) { + req = kmalloc(sizeof(struct usb_request_wrapper) + + MAX_TTY_RX_PACKAGE, GFP_KERNEL); + if (!req) + break; + + req->request = usb_ep_alloc_request(fn->bulk_out, GFP_KERNEL); + if (!req->request) { + kfree(req); + break; + } + + req->fn = fn; + INIT_LIST_HEAD(&req->list); + req->length = MAX_TTY_RX_PACKAGE; + req->request->buf = req->buffer; + req->request->length = MAX_TTY_RX_PACKAGE; + req->request->complete = rawbulk_tty_rx_complete; + put_req(req, &fn->rx_free, &fn->rx_lock); + } + + if (n < MAX_TTY_RX) { + /* free allocated request */ + rawbulk_tty_free_request(fn); + return -ENOMEM; + } + + /* Allocate and init tx request */ + for (n = 0; n < MAX_TTY_TX; n ++) { + req = kmalloc(sizeof(struct usb_request_wrapper) + + MAX_TTY_TX_PACKAGE, GFP_KERNEL); + if (!req) + break; + + req->request = usb_ep_alloc_request(fn->bulk_in, GFP_KERNEL); + if (!req->request) { + kfree(req); + break; + } + + req->fn = fn; + INIT_LIST_HEAD(&req->list); + req->length = MAX_TTY_TX_PACKAGE; + req->request->zero = 0; + req->request->buf = req->buffer; + req->request->complete = rawbulk_tty_tx_complete; + put_req(req, &fn->tx_free, &fn->tx_lock); + } + + if (n < MAX_TTY_TX) { + /* free allocated request */ + rawbulk_tty_free_request(fn); + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_alloc_request); + +int rawbulk_tty_stop_io(struct rawbulk_function *fn) { + struct usb_request_wrapper *req; + + if (!check_tty_opened(fn)) + return -ENODEV; + + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + } + + while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->tx_inproc, &fn->tx_lock); + usb_ep_dequeue(fn->bulk_in, req->request); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_stop_io); + +int rawbulk_tty_start_io(struct rawbulk_function *fn) { + int ret; + struct usb_request_wrapper *req; + + if (!check_tty_opened(fn)) + return -ENODEV; + + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->rx_free, &fn->rx_lock); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_start_io); + +/* Complete the data send stage */ +static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req) { + struct usb_request_wrapper *r = get_wrapper(req); + struct rawbulk_function *fn = r->fn; + + move_req(r, &fn->tx_free, &fn->tx_lock); +} + +static void rawbulk_tty_push_data(struct rawbulk_function *fn) { + struct usb_request_wrapper *r; + struct tty_struct *tty; + + tty = tty_port_tty_get(&fn->port); + tty->minimum_to_wake = 1; /* wakeup to read even pushed only once */ + /* walk the throttled list, push all the data to TTY */ + while ((r = get_req(&fn->rx_throttled, &fn->rx_lock))) { + char *sbuf; + int push_count; + struct usb_request *req = r->request; + + if (req->status < 0) { + put_req(r, &fn->rx_free, &fn->rx_lock); + continue; + } + sbuf = req->buf + fn->last_pushed; + push_count = req->actual - fn->last_pushed; + if (push_count) { + int count = tty_insert_flip_string(tty, sbuf, push_count); + if (count < push_count) { + /* We met throttled again */ + fn->last_pushed += count; + if (count) + tty_flip_buffer_push(tty); + insert_req(r, &fn->rx_throttled, &fn->rx_lock); + break; + } + tty_flip_buffer_push(tty); + fn->last_pushed = 0; + } + put_req(r, &fn->rx_free, &fn->rx_lock); + } + tty_kref_put(tty); +} + +/* Recieve data from host */ +static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req) { + int ret; + struct usb_request_wrapper *r = get_wrapper(req); + struct rawbulk_function *fn = r->fn; + struct tty_struct *tty = fn->tty; + + if (req->status < 0 || !check_tty_opened(fn)) { + move_req(r, &fn->rx_free, &fn->rx_lock); + return; + } + + if (test_bit(TTY_THROTTLED, &tty->flags)) { + /* Give up to resubmitted the request */ + move_req(r, &fn->rx_free, &fn->rx_lock); + return; + } else { + /* Move the request to the throttled queue */ + move_req(r, &fn->rx_throttled, &fn->rx_lock); + /* Start to push data */ + rawbulk_tty_push_data(fn); + } + + /* Re-queue the request again */ + while ((r = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(r, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, r->request, GFP_ATOMIC); + if (ret < 0) { + move_req(r, &fn->rx_free, &fn->rx_lock); + break; + } + } +} + +/* Start to queue request on BULK OUT endpoint, when tty is try to open */ +static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct + *tty) { + struct rawbulk_function *fn = port_to_rawbulk(port); + /* Low latency for tty */ + tty->low_latency = 1; + tty->termios->c_cc[VMIN] = 1; + return rawbulk_tty_start_io(fn); +} + +static void rawbulk_tty_deactivate(struct tty_port *port) { + struct usb_request_wrapper *req; + struct rawbulk_function *fn = port_to_rawbulk(port); + + /* This is a little different from stop_io */ + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + + while ((req = get_req(&fn->rx_throttled, &fn->rx_lock))) + put_req(req, &fn->rx_free, &fn->rx_lock); + + while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { + put_req(req, &fn->tx_inproc, &fn->tx_lock); + usb_ep_dequeue(fn->bulk_in, req->request); + } +} + +static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count) { + int ret; + int submitted = 0; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return -EBUSY; + + /* Get new request(s) that freed, fill it, queue it to the endpoint */ + while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { + int length = count - submitted; + if (length <= 0) { + put_req(req, &fn->tx_free, &fn->tx_lock); + break; + } + if (length > MAX_TTY_TX_PACKAGE) + length = MAX_TTY_TX_PACKAGE; + memcpy(req->buffer, buf + submitted, length); + req->request->length = length; + put_req(req, &fn->tx_inproc, &fn->tx_lock); + ret = usb_ep_queue(fn->bulk_in, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->tx_free, &fn->tx_lock); + return ret; + } + submitted += length; + } + + return submitted; +} + +static int rawbulk_tty_write_room(struct tty_struct *tty) { + int room = 0; + unsigned long flags; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return 0; + + spin_lock_irqsave(&fn->tx_lock, flags); + list_for_each_entry(req, &fn->tx_free, list) + room += req->length; + spin_unlock_irqrestore(&fn->tx_lock, flags); + + return room; +} + +static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty) { + int chars = 0; + unsigned long flags; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return 0; + + spin_lock_irqsave(&fn->rx_lock, flags); + list_for_each_entry(req, &fn->rx_throttled, list) { + if (req->request->status < 0) + continue; + chars += req->request->actual; + } + chars -= fn->last_pushed; + spin_unlock_irqrestore(&fn->rx_lock, flags); + + return chars; +} + +static void rawbulk_tty_throttle(struct tty_struct *tty) { + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + /* Stop the processing requests */ + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + } +} + +static void rawbulk_tty_unthrottle(struct tty_struct *tty) { + int ret; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + /* Try to push the throttled requests' data to TTY */ + rawbulk_tty_push_data(fn); + + /* Restart the free requests */ + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->rx_free, &fn->rx_lock); + break; + } + } +} + +static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios + *old) { + //struct rawbulk_function *fn = tty->driver_data; +} + +static int rawbulk_tty_tiocmget(struct tty_struct *tty) { + //struct rawbulk_function *fn = tty->driver_data; + return 0; +} + +static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear) { + //struct rawbulk_function *fn = tty->driver_data; + return 0; +} + +static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct + *tty) { + int ret = 0; + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + + if (!fn) + return -ENODEV; + + ret = tty_init_termios(tty); + if (ret < 0) + return ret; + + tty->driver_data = fn; + fn->tty = tty; + + /* Final install (we use the default method) */ + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[tty->index] = tty; + return ret; +} + +static void rawbulk_tty_cleanup(struct tty_struct *tty) { + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + tty->driver_data = NULL; + if (fn) + fn->tty = NULL; +} + +static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip) { + int ret; + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + + if (!fn) + return -ENODEV; + + tty->driver_data = fn; + fn->tty = tty; + + if (check_enable_state(fn)) + return -EBUSY; + + if (check_tty_opened(fn)) + return -EBUSY; + + set_tty_opened(fn, 1); + + ret = tty_port_open(&fn->port, tty, flip); + if (ret < 0) + return ret; + return 0; +} + +static void rawbulk_tty_hangup(struct tty_struct *tty) { + struct rawbulk_function *fn = tty->driver_data; + if (!fn) + return; + tty_port_hangup(&fn->port); +} + +static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip) { + struct rawbulk_function *fn = tty->driver_data; + if (!fn) + return; + set_tty_opened(fn, 0); + tty_port_close(&fn->port, tty, flip); +} + +static __init int rawbulk_tty_init(void) { + int ret; + struct tty_driver *drv = alloc_tty_driver(_MAX_TID); + if (!drv) + return -ENOMEM; + + drv->owner = THIS_MODULE; + drv->driver_name = "rawbulkport"; + drv->name = "ttyRB";//prefix + drv->type = TTY_DRIVER_TYPE_SERIAL; + drv->subtype = SERIAL_TYPE_NORMAL; + drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + drv->init_termios = tty_std_termios; + drv->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + drv->init_termios.c_lflag = 0; + drv->init_termios.c_ispeed = 9600; + drv->init_termios.c_ospeed = 9600; + + tty_set_operations(drv, &rawbulk_tty_ops); + + ret = tty_register_driver(drv); + if (ret < 0) { + put_tty_driver(drv); + } else + rawbulk_tty_driver = drv; + return ret; +} + +/******************************************************************************/ +static struct class *rawbulk_class; + +static struct _function_init_stuff { + const char *longname; + const char *shortname; + const char *iString; + unsigned int ep_maxpkg; + unsigned int nups; + unsigned int ndowns; + unsigned int upsz; + unsigned int downsz; + unsigned int splitsz; + bool autoreconn; + bool pushable; +} _init_params[] = { + {"rawbulk-modem", "data", "Modem Port", 64, 16, 16, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-ets", "ets", "ETS Port", 512, 4, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-at", "atc", "AT Channel", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-pcv", "pcv", "PCM Voice", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-gps", "gps", "LBS GPS Port", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + { }, /* End of configurations */ +}; + +static __init struct rawbulk_function *rawbulk_alloc_function(int transfer_id) { + int rc; + struct rawbulk_function *fn; + struct _function_init_stuff *_init = &_init_params[transfer_id]; + + if (transfer_id == _MAX_TID) + return NULL; + + fn = kzalloc(sizeof *fn, GFP_KERNEL); + if (IS_ERR(fn)) + return NULL; + + /* init default features of rawbulk functions */ + fn->longname = _init->longname; + fn->shortname = _init->shortname; + fn->string_defs[0].s = _init->iString; + fn->nups = _init->nups; + fn->ndowns = _init->ndowns; + fn->upsz = _init->upsz; + fn->downsz = _init->downsz; + fn->splitsz = _init->splitsz; + fn->autoreconn = _init->autoreconn; + fn->pushable = _init->pushable; + + fn->tty_minor = -1; + /* init descriptors */ + init_interface_desc(&fn->interface); + init_endpoint_desc(&fn->fs_bulkin_endpoint, 1, _init->ep_maxpkg); + init_endpoint_desc(&fn->hs_bulkin_endpoint, 1, _init->ep_maxpkg); + init_endpoint_desc(&fn->fs_bulkout_endpoint, 0, _init->ep_maxpkg); + init_endpoint_desc(&fn->hs_bulkout_endpoint, 0, _init->ep_maxpkg); + + fn->fs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; + fn->fs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkin_endpoint; + fn->fs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkout_endpoint; + + fn->hs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; + fn->hs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkin_endpoint; + fn->hs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkout_endpoint; + + fn->string_table.language = 0x0409; + fn->string_table.strings = fn->string_defs; + fn->strings[0] = &fn->string_table; + fn->strings[1] = NULL; + + fn->transfer_id = transfer_id; + + /* init function callbacks */ + fn->function.strings = fn->strings; + fn->function.descriptors = fn->fs_descs; + fn->function.hs_descriptors = fn->hs_descs; + + /* init device attributes */ + add_device_attr(fn, ATTR_ENABLE, "enable", 0755); +#ifdef SUPPORT_LEGACY_CONTROL + add_device_attr(fn, ATTR_ENABLE_C, fn->shortname, 0755); +#endif + add_device_attr(fn, ATTR_AUTORECONN, "autoreconn", 0755); + add_device_attr(fn, ATTR_STATISTICS, "statistics", 0644); + add_device_attr(fn, ATTR_NUPS, "nups", 0755); + add_device_attr(fn, ATTR_NDOWNS, "ndowns", 0755); + add_device_attr(fn, ATTR_UPSIZE, "ups_size", 0755); + add_device_attr(fn, ATTR_DOWNSIZE, "downs_size", 0755); + add_device_attr(fn, ATTR_SPLIT, "split_size", 0755); + add_device_attr(fn, ATTR_PUSHABLE, "pushable", 0755); + + fn->max_attrs = ATTR_PUSHABLE + 1; + + if (transfer_id == RAWBULK_TID_MODEM) { + // printk(" kevin chagnge dtr for 200 for cts, disable usb est bypass \n"); + add_device_attr(fn, ATTR_DTR, "dtr", 0200); + fn->max_attrs ++; + } + + fn->dev = device_create(rawbulk_class, NULL, MKDEV(0, + fn->transfer_id), NULL, fn->shortname); + if (IS_ERR(fn->dev)) { + kfree(fn); + return NULL; + } + + rc = rawbulk_create_files(fn); + if (rc < 0) { + device_destroy(rawbulk_class, fn->dev->devt); + kfree(fn); + return NULL; + } + + spin_lock_init(&fn->lock); + wake_lock_init(&fn->keep_awake, WAKE_LOCK_SUSPEND, fn->longname); + return fn; +} + +static void rawbulk_destory_function(struct rawbulk_function *fn) { + if (!fn) + return; + wake_lock_destroy(&fn->keep_awake); + rawbulk_remove_files(fn); + device_destroy(rawbulk_class, fn->dev->devt); + kfree(fn); +} + +#ifdef SUPPORT_LEGACY_CONTROL +static struct attribute *legacy_sysfs[_MAX_TID + 1] = { NULL }; +static struct attribute_group legacy_sysfs_group = { + .attrs = legacy_sysfs, +}; +struct kobject *legacy_sysfs_stuff; +#endif /* SUPPORT_LEGACY_CONTROL */ + +static int __init init(void) { + int n; + int rc = 0; + + printk(KERN_INFO "rawbulk functions init.\n"); + + rawbulk_class = class_create(THIS_MODULE, "usb_rawbulk"); + if (IS_ERR(rawbulk_class)) + return PTR_ERR(rawbulk_class); + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_function *fn = rawbulk_alloc_function(n); + if (IS_ERR(fn)) { + while (n --) + rawbulk_destory_function(prealloced_functions[n]); + rc = PTR_ERR(fn); + break; + } + prealloced_functions[n] = fn; +#ifdef SUPPORT_LEGACY_CONTROL + legacy_sysfs[n] = &fn->attr[ATTR_ENABLE_C].attr; +#endif + } + + if (rc < 0) { + class_destroy(rawbulk_class); + return rc; + } + +#ifdef SUPPORT_LEGACY_CONTROL + /* make compatiable with old bypass sysfs access */ + legacy_sysfs_stuff = kobject_create_and_add("usb_bypass", NULL); + if (legacy_sysfs_stuff) { + rc = sysfs_create_group(legacy_sysfs_stuff, &legacy_sysfs_group); + if (rc < 0) + printk(KERN_ERR "failed to create legacy bypass sys-stuff, but continue...\n"); + } +#endif /* SUPPORT_LEGACY_CONTROL */ + + rc = rawbulk_tty_init(); + if (rc < 0) { + printk(KERN_ERR "failed to init rawbulk tty driver.\n"); + return rc; + } + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_function *fn = prealloced_functions[n]; + rc = rawbulk_register_tty(fn); + if (rc < 0) { + printk(KERN_ERR "fatal error: we cannot create ttyRB%d for %s\n", + n, fn->longname); + return rc; + } + } + + return 0; +} + +module_init(init); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c new file mode 100755 index 00000000..70ec5be1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c @@ -0,0 +1,1372 @@ +/* + * Rawbulk Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/* + * Rawbulk is transfer performer between CBP host driver and Gadget driver + * + * 1 rawbulk transfer can be consist by serval upstream and/or downstream + * transactions. + * + * upstream: CBP Driver ---> Gadget IN + * downstream: Gadget OUT ---> CBP Driver + * + * upstream flowchart: + * + * -x-> usb_submit_urb -> complete -> usb_ep_queue -> complete -, + * | | + * `----------------------(control)----------------------------' + * + * downstream flowchart: + * + * -x-> usb_ep_queue -> complete -> usb_submit_urb -> complete -, + * | | + * `----------------------(control)----------------------------' + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Driver - perform bypass for Kunlun" +#define DRIVER_VERSION "1.0.3" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/usb/rawbulk.h> +#include <linux/moduleparam.h> + +#ifdef VERBOSE_DEBUG +#define ldbg(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args) +#define tdbg(t, fmt, args...) \ + printk(KERN_DEBUG "Rawbulk %s: " fmt "\n", t->name, ##args) +#else +#define ldbg(args...) +#define tdbg(args...) +#endif + +#define lerr(fmt, args...) \ + printk(KERN_ERR "%s: " fmt "\n", __func__, ##args) +#define terr(t, fmt, args...) \ + printk(KERN_ERR "Rawbulk [%s]:" fmt "\n", t->name, ##args) + +#define FREE_STALLED 1 +#define FREE_IDLED 2 +#define FREE_RETRIVING 4 +#define FREE_ALL (FREE_STALLED | FREE_IDLED | FREE_RETRIVING) + +#define STOP_UPSTREAM 0x1 +#define STOP_DOWNSTREAM 0x2 + +struct rawbulk_transfer { + enum transfer_id id; + spinlock_t lock; + int control; + struct usb_anchor submitted; + struct usb_function *function; + struct usb_interface *interface; + struct mutex mutex; /* protection for API calling */ + rawbulk_autoreconn_callback_t autoreconn; + rawbulk_intercept_t inceptor; + spinlock_t suspend_lock; + int suspended; + struct { + int ntrans; + struct list_head transactions; + struct usb_ep *ep; + struct usb_host_endpoint *host_ep; + } upstream, downstream; +}; + +static inline int get_epnum(struct usb_host_endpoint *ep) { + return (int)(ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); +} + +static inline int get_maxpacksize(struct usb_host_endpoint *ep) { + return (int)(le16_to_cpu(ep->desc.wMaxPacketSize)); +} + + +#define MAX_RESPONSE 32 +struct rawbulk_transfer_model { + struct usb_device *udev; + struct usb_composite_dev *cdev; + char ctrl_response[MAX_RESPONSE]; + struct usb_ctrlrequest forward_dr; + struct urb *forwarding_urb; + struct rawbulk_transfer transfer[_MAX_TID]; +}; +static struct rawbulk_transfer_model *rawbulk; + +static struct rawbulk_transfer *id_to_transfer(int transfer_id) { + if (transfer_id < 0 || transfer_id >= _MAX_TID) + return NULL; + return &rawbulk->transfer[transfer_id]; +} + +/* + * upstream + */ + +#define UPSTREAM_STAT_FREE 0 +#define UPSTREAM_STAT_RETRIEVING 1 +#define UPSTREAM_STAT_UPLOADING 2 + +struct upstream_transaction { + int state; + int stalled; + char name[32]; + struct list_head tlist; + struct delayed_work delayed; + struct rawbulk_transfer *transfer; + struct usb_request *req; + struct urb *urb; + int buffer_length; + unsigned char *buffer; +}; + +static void upstream_delayed_work(struct work_struct *work); +static struct upstream_transaction * +alloc_upstream_transaction(struct rawbulk_transfer *transfer, int bufsz, int pushable) +{ + struct upstream_transaction *t; + + if (bufsz < get_maxpacksize(transfer->upstream.host_ep)) + return NULL; + if (bufsz < PAGE_SIZE || bufsz % PAGE_SIZE != 0) + return NULL; + + t = kzalloc(sizeof *t, GFP_KERNEL); + if (!t) + return NULL; + + t->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(bufsz)); + if (!t->buffer) { + kfree(t); + return NULL; + } + + t->buffer_length = bufsz; + + t->req = usb_ep_alloc_request(transfer->upstream.ep, GFP_KERNEL); + if (!t->req) + goto failto_alloc_usb_request; + + if (!pushable) { + t->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!t->urb) + goto failto_alloc_urb; + } + + t->name[0] = 0; + sprintf(t->name, "U%d (H:ep%din, G:%s)", transfer->upstream.ntrans, + get_epnum(transfer->upstream.host_ep), + transfer->upstream.ep->name); + + INIT_LIST_HEAD(&t->tlist); + list_add_tail(&t->tlist, &transfer->upstream.transactions); + transfer->upstream.ntrans ++; + t->transfer = transfer; + + INIT_DELAYED_WORK(&t->delayed, upstream_delayed_work); + t->state = UPSTREAM_STAT_FREE; + return t; + +failto_alloc_urb: + usb_ep_free_request(transfer->upstream.ep, t->req); +failto_alloc_usb_request: + free_page((unsigned long)t->buffer); + kfree(t); + return NULL; +} + +static void free_upstream_transaction(struct rawbulk_transfer *transfer, int option) { + struct list_head *p, *n; + list_for_each_safe(p, n, &transfer->upstream.transactions) { + struct upstream_transaction *t = list_entry(p, struct + upstream_transaction, tlist); + + if ((option & FREE_RETRIVING) && + (t->state == UPSTREAM_STAT_RETRIEVING)) { + if (t->urb) usb_unlink_urb(t->urb); + goto free; + } + + if ((option & FREE_STALLED) && t->stalled) + goto free; + + if ((option & FREE_IDLED) && (t->state == UPSTREAM_STAT_FREE)) + goto free; + + continue; +free: + list_del(p); + if (t->urb) + usb_free_urb(t->urb); + usb_ep_free_request(transfer->upstream.ep, t->req); + free_page((unsigned long)t->buffer); + kfree(t); + + transfer->upstream.ntrans --; + } +} + +static void upstream_second_stage(struct urb *urb); +static void upstream_final_stage(struct usb_ep *ep, struct usb_request + *req); + +static int start_upstream(struct upstream_transaction *t, gfp_t mem_flags) { + int rc; + unsigned long flags; + struct rawbulk_transfer *transfer = t->transfer; + + spin_lock_irqsave(&transfer->lock, flags); + if (transfer->control & STOP_UPSTREAM) { + spin_unlock_irqrestore(&transfer->lock, flags); + cancel_delayed_work(&t->delayed); + t->state = UPSTREAM_STAT_FREE; + t->stalled = 1; + return -EPIPE; + } + spin_unlock_irqrestore(&transfer->lock, flags); + + t->stalled = 0; + t->state = UPSTREAM_STAT_FREE; + + usb_fill_bulk_urb(t->urb, rawbulk->udev, + usb_rcvbulkpipe(rawbulk->udev, + get_epnum(transfer->upstream.host_ep)), + t->buffer, t->buffer_length, + upstream_second_stage, t); + usb_anchor_urb(t->urb, &transfer->submitted); + + rc = usb_submit_urb(t->urb, mem_flags); + usb_mark_last_busy(rawbulk->udev); + if (rc < 0) { + terr(t, "fail to submit urb %d", rc); + /* FIXME: if we met the host is suspending yet, we may add re-submit + * this urb in a ashman thread. so what is a ashman? this can deal any + * error that occur in this driver, and maintain the driver's health, I + * will complete this code in future, here we just stall the transaction + */ + t->stalled = 1; + usb_unanchor_urb(t->urb); + } + + t->state = UPSTREAM_STAT_RETRIEVING; + return rc; +} + +static void upstream_delayed_work(struct work_struct *work) { + int rc; + int stop; + unsigned long flags; + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct upstream_transaction *t = container_of (work, struct + upstream_transaction, delayed.work); + struct rawbulk_transfer *transfer = t->transfer; + + spin_lock_irqsave(&transfer->lock, flags); + stop = !!(transfer->control & STOP_UPSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + rc = start_upstream(t, GFP_ATOMIC); + if (rc < 0 && !stop) + schedule_delayed_work(dw, HZ); +} + +static unsigned int dump_mask = 0; +module_param(dump_mask, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_mask, "Set data dump mask for each transfers"); + +static inline void dump_data(struct rawbulk_transfer *trans, + const char *str, const unsigned char *data, int size) { + int i; + int no_chars = 0; + + if (!(dump_mask & (1 << trans->id))) + return; + + printk(KERN_DEBUG "DUMP tid = %d, %s: len = %d, chars = \"", + trans->id, str, size); + for (i = 0; i < size; ++i) { + char c = data[i]; + if (c > 0x20 && c < 0x7e) { + printk("%c", c); + } else { + printk("."); + no_chars ++; + } + } + printk("\", data = "); + for (i = 0; i < size; ++i) { + printk("%.2x ", data[i]); + if (i > 7) + break; + } + if (size < 8) { + printk("\n"); + return; + } else if (i < size - 8) { + printk("... "); + i = size - 8; + } + for (; i < size; ++i) + printk("%.2x ", data[i]); + printk("\n"); +} + +static void upstream_second_stage(struct urb *urb) { + int rc; + struct upstream_transaction *t = urb->context; + struct rawbulk_transfer *transfer = t->transfer; + struct usb_request *req = t->req; + + if (urb->status < 0) { + if (urb->status == -ECONNRESET) { + terr(t, "usb-device connection reset!"); + return; + } + printk("WTF?! %s failed %d\n", __func__, urb->status); + /* start again atomatically */ + rc = start_upstream(t, GFP_ATOMIC); +#if 0 + if (rc < 0) + schedule_delayed_work(&t->delayed, HZ); +#endif + return; + } + + dump_data(transfer, "upstream", t->buffer, urb->actual_length); + /* allow zero-length package to pass + if (!urb->actual_length) { + terr(t, "urb actual_length 0"); + start_upstream(t, GFP_ATOMIC); + return; + } + */ + + req->status = 0; + req->context = t; + req->buf = urb->transfer_buffer; + req->length = urb->actual_length; + req->complete = upstream_final_stage; + if (urb->actual_length == 0) + req->zero = 1; + else + req->zero = 0; + + t->state = UPSTREAM_STAT_UPLOADING; + rc = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); + if (rc < 0) { + terr(t, "fail to queue request, %d", rc); + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; + } +} + +static void upstream_final_stage(struct usb_ep *ep, + struct usb_request *req) { + struct upstream_transaction *t = req->context; + + t->state = UPSTREAM_STAT_FREE; + + if (req->status < 0) { + if (req->status != -ECONNRESET) + terr(t, "req status %d", req->status); + if (req->status == -ESHUTDOWN) { + t->stalled = 1; + return; + } + } + + if (!req->actual) + terr(t, "req actual 0"); + + if (t->urb) + start_upstream(t, GFP_ATOMIC); +} + +static void stop_upstream(struct upstream_transaction *t) { + struct rawbulk_transfer *transfer = t->transfer; + if (t->state == UPSTREAM_STAT_RETRIEVING) { + cancel_delayed_work(&t->delayed); + if (t->urb) + usb_unlink_urb(t->urb); + } else if (t->state == UPSTREAM_STAT_UPLOADING) { + usb_ep_dequeue(transfer->upstream.ep, t->req); + } + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; +} + +int rawbulk_push_upstream_buffer(int transfer_id, const void *buffer, + unsigned int length) { + int ret = -ENOENT; + struct upstream_transaction *t; + struct rawbulk_transfer *transfer; + struct usb_request *req; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + /* search for free transfer */ + mutex_lock(&transfer->mutex); + list_for_each_entry(t, &transfer->upstream.transactions, tlist) { + if (t && t->state != UPSTREAM_STAT_UPLOADING) { + ret = 0; + break; + } + } + mutex_unlock(&transfer->mutex); + if (ret < 0) { + terr(t, "no entry for transfer %d while pushing!\n", transfer_id); + return ret; + } + req = t->req; + if (!req) + return -EINVAL; + + /* copy the buffer */ + memcpy(t->buffer, buffer, length); + dump_data(transfer, "pushing up", t->buffer, length); + + req->status = 0; + req->length = length; + req->buf = t->buffer; + req->complete = upstream_final_stage; + req->zero = (length > 0)? 0: 1; + + t->state = UPSTREAM_STAT_UPLOADING; + ret = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); + if (ret < 0) { + terr(t, "fail to queue request, %d", ret); + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; + return ret; + } + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_push_upstream_buffer); + +/* + * downstream + */ + +#define MAX_SPLIT_LIMITED 64 + +#define DOWNSTREAM_STAT_FREE 0 +#define DOWNSTREAM_STAT_RETRIEVING 1 +#define DOWNSTREAM_STAT_DOWNLOADING 2 + +struct downstream_transaction { + int state; + int stalled; + char name[32]; + struct list_head tlist; + struct rawbulk_transfer *transfer; + struct usb_request *req; + int nurb; + struct urb *urb[MAX_SPLIT_LIMITED]; + int urb_length; + int buffer_length; + unsigned char buffer[0]; +}; + +static void downstream_second_stage(struct usb_ep *ep, + struct usb_request *req); +static void downstream_final_stage(struct urb *urb); + +static struct downstream_transaction *alloc_downstream_transaction( + struct rawbulk_transfer *transfer, int bufsz, int urbsz) { + int n = 0; + struct downstream_transaction *t; + int maxurbs = bufsz / urbsz; + + if (urbsz < get_maxpacksize(transfer->downstream.host_ep)) + return NULL; + + if (maxurbs > MAX_SPLIT_LIMITED) + return NULL; + + t = kzalloc(sizeof *t + bufsz * sizeof(unsigned char), GFP_KERNEL); + if (!t) + return NULL; + + t->buffer_length = bufsz; + t->urb_length = urbsz; + + t->req = usb_ep_alloc_request(transfer->downstream.ep, GFP_KERNEL); + if (!t->req) + goto failto_alloc_usb_request; + + for (n = 0; n < maxurbs; n ++) { + t->urb[n] = usb_alloc_urb(0, GFP_KERNEL); + if (!t->urb[n]) + goto failto_alloc_urb; + } + t->nurb = 0; + + t->name[0] = 0; + sprintf(t->name, "D%d (G:%s, H:ep%dout)", transfer->downstream.ntrans, + transfer->downstream.ep->name, + get_epnum(transfer->downstream.host_ep)); + + INIT_LIST_HEAD(&t->tlist); + list_add_tail(&t->tlist, &transfer->downstream.transactions); + transfer->downstream.ntrans ++; + t->transfer = transfer; + + t->state = DOWNSTREAM_STAT_FREE; + return t; + +failto_alloc_urb: + while (n --) + usb_free_urb(t->urb[n]); + usb_ep_free_request(transfer->downstream.ep, t->req); +failto_alloc_usb_request: + kfree(t); + return NULL; +} + +static void free_downstream_transaction(struct rawbulk_transfer *transfer, int option) { + int i; + int maxurbs; + struct list_head *p, *n; + list_for_each_safe(p, n, &transfer->downstream.transactions) { + struct downstream_transaction *t = list_entry(p, struct + downstream_transaction, tlist); + + if ((option & FREE_STALLED) && t->stalled) + goto free; + + if ((option & FREE_IDLED) && (t->state == DOWNSTREAM_STAT_FREE)) + goto free; + + if ((option & FREE_RETRIVING) && + (t->state == DOWNSTREAM_STAT_RETRIEVING)) { + usb_ep_dequeue(transfer->downstream.ep, t->req); + goto free; + } + + continue; +free: + list_del(p); + maxurbs = t->buffer_length / t->urb_length; + for (i = 0; i < maxurbs; i ++) + usb_free_urb(t->urb[i]); + usb_ep_free_request(transfer->downstream.ep, t->req); + kfree(t); + + transfer->downstream.ntrans --; + } +} + +static int start_downstream(struct downstream_transaction *t) { + int rc; + unsigned long flags; + struct rawbulk_transfer *transfer = t->transfer; + struct usb_request *req = t->req; + + spin_lock_irqsave(&transfer->lock, flags); + if (transfer->control & STOP_DOWNSTREAM) { + spin_unlock_irqrestore(&transfer->lock, flags); + t->state = DOWNSTREAM_STAT_FREE; + t->stalled = 1; + return -EPIPE; + } + spin_unlock_irqrestore(&transfer->lock, flags); + + t->stalled = 0; + t->state = DOWNSTREAM_STAT_FREE; + + req->buf = t->buffer; + req->length = t->buffer_length; + req->complete = downstream_second_stage; + + rc = usb_ep_queue(transfer->downstream.ep, req, GFP_ATOMIC); + if (rc < 0) { + terr(t, "fail to queue request, %d", rc); + t->stalled = 1; + return rc; + } + + t->state = DOWNSTREAM_STAT_RETRIEVING; + return 0; +} + +static void downstream_second_stage(struct usb_ep *ep, + struct usb_request *req) { + int n = 0; + void *next_buf = req->buf; + int data_length = req->actual; + struct downstream_transaction *t = container_of(req->buf, + struct downstream_transaction, buffer); + struct rawbulk_transfer *transfer = t->transfer; + + if (req->status) { + if (req->status != -ECONNRESET) + terr(t, "req status %d", req->status); + if (req->status == -ESHUTDOWN ||req->status == -ECONNRESET ) + t->stalled = 1; + else + start_downstream(t); + return; + } + + dump_data(transfer, "downstream", t->buffer, req->actual); + /* + if (!data_length) { + terr(t, "req actual 0"); + start_downstream(t); + return; + } + */ + + /* split recieved data into servral urb size less than maxpacket of cbp + * endpoint */ + do { + int rc; + struct urb *urb = t->urb[n]; + int tsize = (data_length > t->urb_length)? t->urb_length: + data_length; + + urb->status = 0; + usb_fill_bulk_urb(urb, rawbulk->udev, + usb_sndbulkpipe(rawbulk->udev, + get_epnum(transfer->downstream.host_ep)), + next_buf, tsize, downstream_final_stage, t); + usb_anchor_urb(urb, &transfer->submitted); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + usb_mark_last_busy(rawbulk->udev); + if (rc < 0) { + terr(t, "fail to submit urb %d, n %d", rc, n); + usb_unanchor_urb(urb); + break; + } + + data_length -= tsize; + next_buf += tsize; + n ++; + } while (data_length > 0); + + t->nurb = n; + t->state = DOWNSTREAM_STAT_DOWNLOADING; +} + +static void downstream_final_stage(struct urb *urb) { + int n; + int actual_total = 0; + struct downstream_transaction *t = urb->context; + + if (urb->status < 0) { + printk("WTF?! - %s failed %d\n", __func__, urb->status); + } + + /* check the condition, re-queue usb_request on gadget ep again if possible */ + for (n = 0; n < t->nurb; n ++) { + int status = t->urb[n]->status; + + if (status == -EINPROGRESS) + return; + + if (!status) + actual_total += t->urb[n]->actual_length; + } + + if (actual_total < t->req->actual) { + terr(t, "requested %d actual %d", t->req->actual, actual_total); + t->stalled = 1; + return; + } + + /* completely transfered over, we can start next transfer now */ + start_downstream(t); +} + +static void stop_downstream(struct downstream_transaction *t) { + int n; + struct rawbulk_transfer *transfer = t->transfer; + int maxurbs = t->buffer_length / t->urb_length; + + if (t->state == DOWNSTREAM_STAT_RETRIEVING) { + usb_ep_dequeue(transfer->downstream.ep, t->req); + } else if (t->state == DOWNSTREAM_STAT_DOWNLOADING) { + for (n = 0; n < maxurbs; n ++) + usb_unlink_urb(t->urb[n]); + } + + t->stalled = 1; +} + +/* + * Ctrlrequest forwarding + */ + +static void response_complete(struct usb_ep *ep, struct usb_request *req) { + if (req->status < 0) + ldbg("feedback error %d\n", req->status); +} + +static void forward_ctrl_complete(struct urb *urb) { + struct usb_composite_dev *cdev = urb->context; + if (!cdev) + return; + + if (urb->status >= 0) { + struct usb_request *req = cdev->req; + if (urb->pipe & USB_DIR_IN) { + memcpy(req->buf, urb->transfer_buffer, urb->actual_length); + req->zero = 0; + req->length = urb->actual_length; + req->complete = response_complete; + ldbg("cp echo: len %d data[0] %02x", req->length, *((char *)req->buf)); + usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else /* Finish the status stage */ + usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } +} + +int rawbulk_forward_ctrlrequest(const struct usb_ctrlrequest *ctrl) { + struct usb_device *dev; + struct urb *urb; + + ldbg("req_type %02x req %02x value %04x index %04x len %d", + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, + ctrl->wLength); + + dev = rawbulk->udev; + if (!dev) { + return -ENODEV; + } + + rawbulk->forward_dr.bRequestType = ctrl->bRequestType; + rawbulk->forward_dr.bRequest = ctrl->bRequest; + rawbulk->forward_dr.wValue = ctrl->wValue; + //rawbulk->forward_dr.wIndex = ctrl->wIndex; + rawbulk->forward_dr.wIndex = 0;//MODEM DATA PORT + rawbulk->forward_dr.wLength = ctrl->wLength; + + if (!rawbulk->forwarding_urb) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + rawbulk->forwarding_urb = urb; + } else + urb = rawbulk->forwarding_urb; + + if (ctrl->bRequestType & USB_DIR_IN) + usb_fill_control_urb(urb, dev, + usb_rcvctrlpipe(dev, 0), + (unsigned char *)&rawbulk->forward_dr, + rawbulk->ctrl_response, + __le16_to_cpu(ctrl->wLength), + forward_ctrl_complete, + rawbulk->cdev); + else + usb_fill_control_urb(urb, dev, + usb_sndctrlpipe(dev, 0), + (unsigned char *)&rawbulk->forward_dr, + NULL, 0, + forward_ctrl_complete, + rawbulk->cdev); + + return usb_submit_urb(urb, GFP_ATOMIC); +} + +EXPORT_SYMBOL_GPL(rawbulk_forward_ctrlrequest); + +int rawbulk_start_transactions(int transfer_id, int nups, int ndowns, int upsz, + int downsz, int splitsz, int pushable) { + int n; + int rc; + unsigned long flags = 0; + int suspended; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + if (!rawbulk->cdev || !rawbulk->udev) + return -ENODEV; + + if (!transfer->function || !transfer->interface) + return -ENODEV; + + ldbg("start transactions on id %d, nups %d ndowns %d upsz %d downsz %d split %d pushable %d\n", + transfer_id, nups, ndowns, upsz, downsz, splitsz, pushable); + + mutex_lock(&transfer->mutex); + + /* stop host transfer 1stly */ + if (transfer->inceptor) + transfer->inceptor(transfer->interface, pushable? + (RAWBULK_INCEPT_FLAG_ENABLE | RAWBULK_INCEPT_FLAG_PUSH_WAY): + RAWBULK_INCEPT_FLAG_ENABLE); + + /* Make upstream buffer larger than the pusher */ + if (pushable && (upsz < 4096)) + upsz = 4096; + + for (n = 0; n < nups; n ++) { + upstream = alloc_upstream_transaction(transfer, upsz, pushable); + if (!upstream) { + rc = -ENOMEM; + ldbg("fail to allocate upstream transaction n %d", n); + goto failto_alloc_upstream; + } + } + + for (n = 0; n < ndowns; n ++) { + downstream = alloc_downstream_transaction(transfer, downsz, splitsz); + if (!downstream) { + rc = -ENOMEM; + ldbg("fail to allocate downstream transaction n %d", n); + goto failto_alloc_downstream; + } + } + + spin_lock_irqsave(&transfer->suspend_lock, flags); + suspended = transfer->suspended; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + if (suspended) { + ldbg("interface %d is sleeping", transfer_id); + mutex_unlock(&transfer->mutex); + return 0; + } + + transfer->control &= ~STOP_UPSTREAM; + if (!pushable) { + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d\n", upstream->name, rc); + goto failto_start_upstream; + } + } + } + } + + transfer->control &= ~STOP_DOWNSTREAM; + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d\n", downstream->name, rc); + goto failto_start_downstream; + } + } + } + + mutex_unlock(&transfer->mutex); + return 0; + +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); +failto_alloc_downstream: + free_downstream_transaction(transfer, FREE_ALL); +failto_alloc_upstream: + free_upstream_transaction(transfer, FREE_ALL); + /* recover host transfer */ + if (transfer->inceptor) + transfer->inceptor(transfer->interface, 0); + mutex_unlock(&transfer->mutex); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_start_transactions); + +void rawbulk_stop_transactions(int transfer_id) { + unsigned long flags; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + mutex_lock(&transfer->mutex); + spin_lock_irqsave(&transfer->lock, flags); + transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + free_upstream_transaction(transfer, FREE_ALL); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); + free_downstream_transaction(transfer, FREE_ALL); + if (transfer->inceptor) + transfer->inceptor(transfer->interface, 0); + mutex_unlock(&transfer->mutex); +} + +EXPORT_SYMBOL_GPL(rawbulk_stop_transactions); + +int rawbulk_halt_transactions(int transfer_id) { + unsigned long flags; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + spin_lock_irqsave(&transfer->lock, flags); + transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_halt_transactions); + +int rawbulk_resume_transactions(int transfer_id) { + int rc; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + if (!rawbulk->cdev || !rawbulk->udev) + return -ENODEV; + + if (!transfer->function || !transfer->interface) + return -ENODEV; + + transfer->control &= ~STOP_UPSTREAM; + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d", upstream->name, rc); + goto failto_start_upstream; + } + } + } + + transfer->control &= ~STOP_DOWNSTREAM; + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d", downstream->name, rc); + goto failto_start_downstream; + } + } + } + return 0; + +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_resume_transactions); + +int rawbulk_transfer_state(int transfer_id) { + int stalled = 1; + int count = 0; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + if (!rawbulk->udev || !rawbulk->cdev) + return -ENODEV; + + if (!transfer->interface || !transfer->function) + return -EIO; + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (!upstream->stalled) + stalled = 0; + count ++; + } + + if (stalled || count == 0) + return -EACCES; + + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (!downstream->stalled) + stalled = 0; + count ++; + } + if (stalled || count == 0) + return -EACCES; + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_transfer_state); + +static char *state2string(int state, int upstream) { + if (upstream) { + switch (state) { + case UPSTREAM_STAT_FREE: + return "FREE"; + case UPSTREAM_STAT_RETRIEVING: + return "RETRIEVING"; + case UPSTREAM_STAT_UPLOADING: + return "UPLOADING"; + default: + return "UNKNOW"; + } + } else { + switch (state) { + case DOWNSTREAM_STAT_FREE: + return "FREE"; + case DOWNSTREAM_STAT_RETRIEVING: + return "RETRIEVING"; + case DOWNSTREAM_STAT_DOWNLOADING: + return "DOWNLOADING"; + default: + return "UNKNOW"; + } + } +} + +int rawbulk_transfer_statistics(int transfer_id, char *buf) { + char *pbuf = buf; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return sprintf(pbuf, "-ENODEV, id %d\n", transfer_id); + + pbuf += sprintf(pbuf, "rawbulk statistics:\n"); + if (rawbulk->udev) + pbuf += sprintf(pbuf, " host device: %d-%d\n", rawbulk->udev->bus->busnum, + rawbulk->udev->devnum); + else + pbuf += sprintf(pbuf, " host device: -ENODEV\n"); + if (rawbulk->cdev && rawbulk->cdev->config) + pbuf += sprintf(pbuf, " gadget device: %s\n", + rawbulk->cdev->config->label); + else + pbuf += sprintf(pbuf, " gadget device: -ENODEV\n"); + pbuf += sprintf(pbuf, " upstreams (total %d transactions)\n", + transfer->upstream.ntrans); + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + pbuf += sprintf(pbuf, " %s state: %s", upstream->name, + state2string(upstream->state, 1)); + pbuf += sprintf(pbuf, ", maxbuf: %d bytes", upstream->buffer_length); + if (upstream->stalled) + pbuf += sprintf(pbuf, " (stalled!)"); + pbuf += sprintf(pbuf, "\n"); + } + pbuf += sprintf(pbuf, " downstreams (total %d transactions)\n", + transfer->downstream.ntrans); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + pbuf += sprintf(pbuf, " %s state: %s", downstream->name, + state2string(downstream->state, 0)); + pbuf += sprintf(pbuf, ", maxbuf: %d bytes", downstream->buffer_length); + if (downstream->state == DOWNSTREAM_STAT_DOWNLOADING) + pbuf += sprintf(pbuf, ", spliting: %d urbs(%d bytes)", downstream->nurb, + downstream->urb_length); + if (downstream->stalled) + pbuf += sprintf(pbuf, " (stalled!)"); + pbuf += sprintf(pbuf, "\n"); + } + pbuf += sprintf(pbuf, "\n"); + return (int)(pbuf - buf); +} + +EXPORT_SYMBOL_GPL(rawbulk_transfer_statistics); + +int rawbulk_bind_function(int transfer_id, struct usb_function *function, struct + usb_ep *bulk_out, struct usb_ep *bulk_in, + rawbulk_autoreconn_callback_t autoreconn_callback) { + struct rawbulk_transfer *transfer; + + if (!function || !bulk_out || !bulk_in) + return -EINVAL; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + transfer->downstream.ep = bulk_out; + transfer->upstream.ep = bulk_in; + transfer->function = function; + rawbulk->cdev = function->config->cdev; + + transfer->autoreconn = autoreconn_callback; + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_bind_function); + +void rawbulk_unbind_function(int transfer_id) { + int n; + int no_functions = 1; + struct rawbulk_transfer *transfer; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + rawbulk_stop_transactions(transfer_id); + transfer->downstream.ep = NULL; + transfer->upstream.ep = NULL; + transfer->function = NULL; + + for (n = 0; n < _MAX_TID; n ++) { + if (!!rawbulk->transfer[n].function) + no_functions = 0; + } + + if (no_functions) + rawbulk->cdev = NULL; +} + +EXPORT_SYMBOL_GPL(rawbulk_unbind_function); + +int rawbulk_bind_host_interface(struct usb_interface *interface, + rawbulk_intercept_t inceptor) { + int n; + int transfer_id; + struct rawbulk_transfer *transfer; + struct usb_device *udev; + + if (!interface || !inceptor) + return -EINVAL; + + transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + udev = interface_to_usbdev(interface); + if (!udev) + return -ENODEV; + + if (!rawbulk->udev) { + rawbulk->udev = udev; + } + + /* search host bulk ep for up/downstreams */ + for (n = 0; n < interface->cur_altsetting->desc.bNumEndpoints; n++) { + struct usb_host_endpoint *endpoint = + &interface->cur_altsetting->endpoint[n]; + if (usb_endpoint_is_bulk_out(&endpoint->desc)) + transfer->upstream.host_ep = endpoint; + if (usb_endpoint_is_bulk_in(&endpoint->desc)) + transfer->downstream.host_ep = endpoint; + } + + if (!transfer->upstream.host_ep || !transfer->downstream.host_ep) { + lerr("endpoints do not match bulk pair that needed\n"); + return -EINVAL; + } + + transfer->interface = interface; + transfer->inceptor = inceptor; + + if (transfer->autoreconn) + transfer->autoreconn(transfer->id); + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_bind_host_interface); + +void rawbulk_unbind_host_interface(struct usb_interface *interface) { + int n; + int no_interfaces = 1; + struct rawbulk_transfer *transfer; + int transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + rawbulk_stop_transactions(transfer_id); + transfer->upstream.host_ep = NULL; + transfer->downstream.host_ep = NULL; + transfer->interface = NULL; + transfer->inceptor = NULL; + + for (n = 0; n < _MAX_TID; n ++) { + if(!!rawbulk->transfer[n].interface) + no_interfaces = 0; + } + + if (no_interfaces) { + usb_kill_urb(rawbulk->forwarding_urb); + usb_free_urb(rawbulk->forwarding_urb); + rawbulk->forwarding_urb = NULL; + rawbulk->udev = NULL; + } +} + +EXPORT_SYMBOL_GPL(rawbulk_unbind_host_interface); + +int rawbulk_suspend_host_interface(int transfer_id, pm_message_t message) { + unsigned long flags = 0; + struct rawbulk_transfer *transfer; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + spin_lock_irqsave(&transfer->suspend_lock, flags); + transfer->suspended = 1; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_suspend_host_interface); + +int rawbulk_resume_host_interface(int transfer_id) { + int rc; + unsigned long flags = 0; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + spin_lock_irqsave(&transfer->suspend_lock, flags); + transfer->suspended = 0; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->stalled) { + transfer->control &= ~STOP_UPSTREAM; + /* restart transaction again */ + ldbg("restart upstream: %s", upstream->name); + stop_upstream(upstream); + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d", upstream->name, rc); + goto failto_start_upstream; + } + } + } + + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->stalled) { + transfer->control &= ~STOP_DOWNSTREAM; + ldbg("restart downstream: %s", downstream->name); + stop_downstream(downstream); + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d", downstream->name, rc); + goto failto_start_downstream; + } + } + } + + return 0; +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_resume_host_interface); + +static __init int rawbulk_init(void) { + int n; + + rawbulk = kzalloc(sizeof *rawbulk, GFP_KERNEL); + if (!rawbulk) + return -ENOMEM; + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_transfer *t = &rawbulk->transfer[n]; + + t->id = n; + INIT_LIST_HEAD(&t->upstream.transactions); + INIT_LIST_HEAD(&t->downstream.transactions); + + mutex_init(&t->mutex); + spin_lock_init(&t->lock); + spin_lock_init(&t->suspend_lock); + t->suspended = 0; + t->control = STOP_UPSTREAM | STOP_DOWNSTREAM; + + init_usb_anchor(&t->submitted); + } + + return 0; +} + +fs_initcall (rawbulk_init); + +static __exit void rawbulk_exit(void) { + int n; + for (n = 0; n < _MAX_TID; n ++) + rawbulk_stop_transactions(n); + + if (rawbulk->forwarding_urb) { + usb_kill_urb(rawbulk->forwarding_urb); + usb_free_urb(rawbulk->forwarding_urb); + rawbulk->forwarding_urb = NULL; + } + + kfree(rawbulk); +} + +module_exit (rawbulk_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c index 0cb21218..953439d4 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c @@ -1203,3 +1203,7 @@ void rndis_exit(void) } #endif } +bool get_rndis_initialized(void) +{ + return rndis_initialized; +}
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c index 8081ca3a..88e9c0ef 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c @@ -813,6 +813,14 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, return rc; } +static ssize_t fsg_show_cdrom(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%d\n", curlun->cdrom); +} + static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -898,3 +906,33 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, up_write(filesem); return (rc < 0 ? rc : count); } + +static ssize_t fsg_store_cdrom(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t rc; + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + unsigned cdrom; + + rc = kstrtouint(buf, 2, &cdrom); + if (rc) + return rc; + + /* + * Allow the write-enable status to change only while the + * backing file is closed. + */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { + curlun->cdrom = cdrom; + LDBG(curlun, "cdrom status set to %d\n", curlun->cdrom); + rc = count; + } + up_read(filesem); + return rc; +} + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c index c8702c8e..59ac7227 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c @@ -457,7 +457,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; - + unsigned long flags; switch (req->status) { default: dev->net->stats.tx_errors++; @@ -471,9 +471,11 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) } dev->net->stats.tx_packets++; - spin_lock(&dev->req_lock); + //spin_lock(&dev->req_lock); + spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->tx_reqs); - spin_unlock(&dev->req_lock); + //spin_unlock(&dev->req_lock); + spin_unlock_irqrestore(&dev->req_lock, flags); dev_kfree_skb_any(skb); atomic_dec(&dev->tx_qlen); @@ -703,7 +705,7 @@ module_param(dev_addr, charp, S_IRUGO); MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); /* this address is invisible to ifconfig */ -static char *host_addr; +static char *host_addr="02:50:e6:a8:b8:63"; module_param(host_addr, charp, S_IRUGO); MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); @@ -938,7 +940,7 @@ fail0: return ERR_PTR(result); return dev->net; } - +extern void wmt_cleanup_done_thread(int number); /** * gether_disconnect - notify network layer that USB link is inactive * @link: the USB link, on which gether_connect() was called @@ -955,7 +957,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; - + unsigned long flags; WARN_ON(!dev); if (!dev) return; @@ -970,6 +972,7 @@ void gether_disconnect(struct gether *link) * and forget about the endpoints. */ usb_ep_disable(link->in_ep); + wmt_cleanup_done_thread(1); spin_lock(&dev->req_lock); while (!list_empty(&dev->tx_reqs)) { req = container_of(dev->tx_reqs.next, @@ -985,6 +988,7 @@ void gether_disconnect(struct gether *link) link->in_ep->desc = NULL; usb_ep_disable(link->out_ep); + wmt_cleanup_done_thread(1); spin_lock(&dev->req_lock); while (!list_empty(&dev->rx_reqs)) { req = container_of(dev->rx_reqs.next, diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c new file mode 100755 index 00000000..c239e3d8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c @@ -0,0 +1,4699 @@ +/* + * wmt_udc.c -- for WonderMedia Technology udc + * + * Copyright (C) 2007 VIA Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef DEBUG +#undef VERBOSE + +#include <generated/autoconf.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/mm.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/suspend.h> + + + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> +#include <asm/mach-types.h> +#include <linux/usb/composite.h> + +#include "udc_wmt.h" + +#define USE_BULK3_TO_INTERRUPT //gri + +//#define FULL_SPEED_ONLY +/*#define HW_BUG_HIGH_SPEED_PHY*/ +#undef USB_TRACE + +/* bulk DMA seems to be behaving for both IN and OUT */ +#define USE_DMA + +/*#define DEBUG_UDC_ISR_TIMER*/ +#undef DEBUG_UDC_ISR_TIMER + +/*#define RNDIS_INFO_DEBUG_BULK_OUT*/ +#undef RNDIS_INFO_DEBUG_BULK_OUT + +/*#define RNDIS_INFO_DEBUG_BULK_IN*/ +#undef RNDIS_INFO_DEBUG_BULK_IN + +/*#define MSC_COMPLIANCE_TEST*/ +#undef MSC_COMPLIANCE_TEST + +/*#define UDC_A1_SELF_POWER_ENABLE*/ + +/*-----------------------------------------------------------------------------*/ + +#define DRIVER_DESC "VIA UDC driver" +#define DRIVER_VERSION "3 December 2007" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +static unsigned fifo_mode; + +static unsigned fiq_using = 0; + +/* "modprobe vt8500_udc fifo_mode=42", or else as a kernel + * boot parameter "vt8500_udc:fifo_mode=42" + */ + +module_param(fifo_mode, uint, 0); +MODULE_PARM_DESC(fifo_mode, "endpoint setup (0 == default)"); + +static bool use_dma = 1; + +module_param(use_dma, bool, 0); +MODULE_PARM_DESC(use_dma, "enable/disable DMA"); + +static const char driver_name[] = "wmotgdev";/*"wmt_udc";*/ +static const char driver_desc[] = DRIVER_DESC; + +static DEFINE_SEMAPHORE(wmt_udc_sem); +static int f_ep3_used = 0; + +static struct vt8500_udc *udc; +static struct device *pDMADescLI, *pDMADescSI; +static struct device *pDMADescLO, *pDMADescSO; + +static struct device *pDMADescL2I, *pDMADescS2I; + +dma_addr_t UdcPdmaPhyAddrLI, UdcPdmaPhyAddrSI; +static UINT UdcPdmaVirAddrLI, UdcPdmaVirAddrSI; +dma_addr_t UdcPdmaPhyAddrLO, UdcPdmaPhyAddrSO; +static UINT UdcPdmaVirAddrLO, UdcPdmaVirAddrSO; + +dma_addr_t UdcPdmaPhyAddrL2I, UdcPdmaPhyAddrS2I; +static UINT UdcPdmaVirAddrL2I, UdcPdmaVirAddrS2I; + +dma_addr_t UdcRndisEp1PhyAddr, UdcRndisEp2PhyAddr, UdcRndisEp3PhyAddr; +static UINT UdcRndisEp1VirAddr, UdcRndisEp2VirAddr, UdcRndisEp3VirAddr; + +#ifdef OTGIP +static struct USB_GLOBAL_REG *pGlobalReg; +#endif +/*static struct UDC_REGISTER *udc_reg;*/ + +static volatile struct UDC_REGISTER *pDevReg; +static volatile struct UDC_DMA_REG *pUdcDmaReg; + +PSETUPCOMMAND pSetupCommand; +UCHAR *pSetupCommandBuf; +UCHAR *SetupBuf; +UCHAR *IntBuf; + +UCHAR ControlState; /* the state the control pipe*/ +UCHAR USBState; +UCHAR TestMode; + +/* Basic Define*/ +//#define REG32 *(volatile unsigned int *) +//#define REG_GET32(addr) (REG32(addr)) /* Read 32 bits Register */ + +static unsigned long irq_flags;//gri + +volatile unsigned char *pUSBMiscControlRegister5; + +unsigned int interrupt_transfer_size; + +static void wmt_pdma_reset(void); +static void wmt_pdma0_reset(void); +static void wmt_pdma1_reset(void); + +#ifdef USE_BULK3_TO_INTERRUPT +static void wmt_pdma2_reset(void); +#endif + +/* 1 : storage */ +static unsigned int gadget_connect=0; +//static unsigned int first_mount=0; + + +struct work_struct online_thread; +struct work_struct offline_thread; +struct work_struct done_thread; +struct work_struct chkiso_thread; + + + +struct list_head done_main_list; +spinlock_t gri_lock; +static unsigned long gri_flags;//gri + +static unsigned int b_pullup=0; + +void run_chkiso (struct work_struct *work); + +static inline unsigned int wmt_ost_counter(void) +{ + OSTC_VAL |= OSTC_RDREQ; + while (OSTA_VAL & OSTA_RCA) + ; + + return (u32)OSCR_VAL; +} + +static inline void wmt_ost2_set_match(u32 new_match) +{ + /* check if can write OS Timer2 match register nows */ + while (OSTA_VAL & OSTA_MWA2) + ; + + OSM2_VAL = new_match; +} + +void wmt_enable_fiq(unsigned int how_many_us) +{ + unsigned int cnt = 0; + + cnt = wmt_ost_counter(); + cnt += (3*how_many_us); + wmt_ost2_set_match(cnt); + OSTI_VAL |= OSTI_E2; +} + +void wmt_disable_fiq(void) +{ + OSTI_VAL &= ~OSTI_E2; +} + +static irqreturn_t +test_fiq_handler(int irq, void *_udc)//, struct pt_regs *r) +{ + OSTS_VAL = OSTI_E2; + + //printk("i am test_fiq_handler\n"); + + run_chkiso(NULL); + return IRQ_HANDLED; +} + +void initial_test_fiq(void) +{ + //int ret = -1; + int status = -ENODEV; + + printk("\n\n\ninitial_test_fiq\n\n"); + // set fiq + + OSTS_VAL = OSTI_E2; + OSTI_VAL &= ~OSTI_E2; +#if 0 + fhandler.fiq = test_fiq_handler; + fhandler.resume = test_fiq_resume; + ret = fiq_wmt_register_handler(&fhandler); + if (ret) { + pr_err("%s: could not install fiq handler ( %d )\n", __func__, ret); + return; + } + + //use OST2 to test + + enable_fiq(70); +#else + status = request_irq(IRQ_OST2, test_fiq_handler, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_DISABLED), driver_name, udc);//gri + if (status != 0) { + ERR("**** can't get irq %d, err %d\n", + IRQ_OST2, status); + } else + INFO("**** wmt_udc_probe - request_irq(0x%02X) pass!\n", IRQ_OST2); +#endif +} + +/** + * + * Run these two functions to execute shell script to mount / umount storage + * + */ +#if 0 +static int run_online(void) +{ + kobject_uevent(&udc->dev->kobj, 2); + return 0; +} +#endif +void wmt_cleanup_done_thread(int number); +static void run_offline (struct work_struct *work) +{ + if ((udc->driver) && b_pullup){ +// printk(KERN_INFO "disconnect\n"); //gri + udc->driver->disconnect(&udc->gadget); + } +// return 0; +} + +static void run_done (struct work_struct *work) +{ + struct vt8500_req * req; + + spin_lock_irqsave(&gri_lock, gri_flags); +// printk(KERN_INFO "d1\n"); //gri + while (!list_empty(&done_main_list)){ +// printk(KERN_INFO "d3\n"); //gri + req = list_entry(done_main_list.next, struct vt8500_req, mem_list); + list_del_init(&req->mem_list); + spin_unlock_irqrestore(&gri_lock, gri_flags); + req->req.complete(&req->ep->ep, &req->req); + spin_lock_irqsave(&gri_lock, gri_flags); + } +// printk(KERN_INFO "d2\n"); //gri + spin_unlock_irqrestore(&gri_lock, gri_flags); +// return 0; +} + +void dma_irq(u8 addr); +void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req); +void iso_prepare_0byte(void); +void run_chkiso (struct work_struct *work) +{ + spin_lock_irqsave(&udc->lock, irq_flags); + if (!fiq_using) { + //printk("iso fail\n"); + spin_unlock_irqrestore(&udc->lock, irq_flags); + return; + } + + //do { + //schedule(); + if (pDevReg->Bulk3DesStatus & BULKXFER_XACTERR) { + { + struct vt8500_ep *ep; + struct vt8500_req *req; + /*u32 temp32;*/ + /*u32 i;*/ + + ep = &udc->ep[4]; + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + //printk("iso h q\n"); + next_in_dma(ep, req); + } else { + //printk("no q\n"); + wmt_disable_fiq(); + fiq_using = 0; + wmt_pdma2_reset(); + iso_prepare_0byte(); + } + } + //printk("iso hit\n"); + //break; + } else { + wmt_enable_fiq(300); + //printk("iso hit miss\n"); + } + //} while (1); + spin_unlock_irqrestore(&udc->lock, irq_flags); +} + +enum schedule_work_action +{ + action_done, action_off_line, action_chkiso +}; + +static void run_script(enum schedule_work_action dwAction) +{ + + if (dwAction == action_done){//8 + schedule_work(&done_thread); + }else if (dwAction == action_off_line){//7 + schedule_work(&offline_thread); + }else if (dwAction == action_chkiso){//7 + schedule_work(&chkiso_thread); + }else { + } + +} + + +void udc_device_dump_register(void) +{ + volatile unsigned int address; + volatile unsigned char temp8; + int i; + + for (i = 0x20; i <= 0x3F; i++) { /*0x20~0x3F (0x3F-0x20 + 1) /4 = 8 DWORD*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + for (i = 0x308; i <= 0x30D; i++) { /*0x308~0x30D*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + for (i = 0x310; i <= 0x317; i++) { /*0x310~0x317*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + INFO("[UDC Device] Dump Reigster PASS!\n"); + +} /*void udc_device_dump_register(void)*/ + +void udc_bulk_dma_dump_register(void) +{ + volatile unsigned int temp32; + int i; + + for (i = 0; i <= 0x10; i++) { /*0x100 ~ 0x113 (0x113 - 0x100 + 1) = 0x14 /4 = 5*/ + temp32 = REG_GET32(USB_UDC_DMA_REG_BASE + i*4); + INFO("[UDC Bulk DMA] Offset[0x%8.8X] = 0x%8.8X \n", (USB_UDC_DMA_REG_BASE + i*4), temp32); + } + INFO("[UDC Bulk DMAD] Dump Reigster PASS!\n"); + +} /*void udc_bulk_dma_dump_register(void)*/ + +void wmt_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp) +{ + struct vt8500_ep *ep; + /*u32 epn_rxtx = 0;*/ + /*U8 temp_adr;*/ + + VDBG("wmt_ep_setup_csr()\n"); + + /* OUT endpoints first, then IN*/ + + ep = &udc->ep[addr & 0x7f]; + + VDBG("wmt_ep_setup()\n"); + + /* OUT endpoints first, then IN*/ + ep = &udc->ep[addr & 0x7f]; + + if (type == USB_ENDPOINT_XFER_CONTROL) { + /*pDevReg->ControlEpControl;*/ + pDevReg->ControlEpReserved = 0; + pDevReg->ControlEpMaxLen = (maxp & 0xFF); + pDevReg->ControlEpEpNum = 0; + } else if (type == USB_ENDPOINT_XFER_BULK) { + if (addr & USB_DIR_IN) { + /*pDevReg->Bulk1EpControl;*/ + pDevReg->Bulk1EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk1EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk1EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } else { + /*pDevReg->Bulk2EpControl;*/ + pDevReg->Bulk2EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk2EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk2EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } + } else if (type == USB_ENDPOINT_XFER_INT) { +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + + pDevReg->InterruptReserved = (0x85 & 0x7f) << 4; + pDevReg->InterruptEpMaxLen = (8 & 0xFF); /* Interrupt maximum transfer length - 2E*/ + pDevReg->InterruptEpEpNum = (((0x85 & 0x7f) << 4) | ((8 & 0x700) >> 8)); +#else + /*pDevReg->InterruptEpControl; // Interrupt endpoint control - 2C*/ + /* Interrupt endpoint reserved byte - 2D*/ + pDevReg->InterruptReserved = (addr & 0x7f) << 4; + pDevReg->InterruptEpMaxLen = (maxp & 0xFF); /* Interrupt maximum transfer length - 2E*/ + pDevReg->InterruptEpEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); +#endif + } else if (type == USB_ENDPOINT_XFER_ISOC) { + pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } + + /*Setting address pointer ...*/ + wmb(); + VDBG("wmt_ep_setup_csr() - %s addr %02x maxp %d\n", + name, addr, maxp); + + ep->toggle_bit = 0; + ep->ep.maxpacket = maxp; +} /*tatic void wmt_ep_setup_csr()*/ + +static int wmt_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_udc *udc; + + u16 maxp; + + DBG("wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); + printk(KERN_INFO "gri wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); + + /* catch various bogus parameters*/ + if (!_ep || !desc || (ep->desc && ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC)) + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep->maxpacket < usb_endpoint_maxp(desc)) { + VDBG("ep->bEndpointAddress = 0x%08X\n", ep->bEndpointAddress); + VDBG("desc->bEndpointAddres = 0x%08X\n", desc->bEndpointAddress); + VDBG("ep->maxpacket =0x%08X\n", ep->maxpacket); + VDBG("desc->wMaxPacketSize =0x%08X\n", desc->wMaxPacketSize); + VDBG("_ep =0x%08X\n", (unsigned int)_ep); + VDBG("desc =0x%08X\n", (unsigned int)desc); + VDBG("ep->desc =0x%08X\n", (unsigned int)ep->desc); + + /*DBG("%s, bad ep or descriptor\n", __FUNCTION__);*/ + return -EINVAL; + } + + maxp = usb_endpoint_maxp(desc); + + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK) + && (usb_endpoint_maxp(desc) > ep->maxpacket + || !desc->wMaxPacketSize)) { + DBG("[wmt_ep_enable]bad %s maxpacket\n", _ep->name); + return -ERANGE; + } + +#if 1 + if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC + && desc->bInterval != 1)) { + /* hardware wants period = 1; USB allows 2^(Interval-1) */ + DBG("%s, unsupported ISO period %dms\n", _ep->name, + 1 << (desc->bInterval - 1)); + return -EDOM; + } + +#if 0 + /* xfer types must match, except that interrupt ~= bulk*/ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DBG("[wmt_ep_enable], %s type mismatch\n", _ep->name); + printk("[wmt_ep_enable], %s type mismatch\n", _ep->name); + return -EINVAL; + } +#endif +#endif + + udc = ep->udc; + + spin_lock_irqsave(&udc->lock, irq_flags); + + ep->desc = desc; + ep->irqs = 0; + ep->stopped = 0; + ep->ep.maxpacket = maxp; + + ep->has_dma = 1; + ep->ackwait = 0; + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); + wmb(); + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 1:/*Bulk In*/ + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, maxp); + wmb(); + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 2:/*Bulk Out*/ + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, maxp); + wmb(); + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + if (f_ep3_used == 4) + return -ERANGE; + f_ep3_used = 3; + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); + wmb(); + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); + wmb(); + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif + break; + + case 4:/*iso in*/ + if (f_ep3_used == 3) + return -ERANGE; + f_ep3_used = 4; + wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISOC, 384); + wmb(); + + wmt_pdma2_reset(); + iso_prepare_0byte(); + + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; + break; + + } + wmb(); + spin_unlock_irqrestore(&udc->lock, irq_flags); + VDBG("%s enabled\n", _ep->name); +// printk(KERN_INFO "gri enabled %s\n", ep ? ep->ep.name : NULL); + + return 0; +} /*static int wmt_ep_enable()*/ + +static void nuke(struct vt8500_ep *, int status); + +static int wmt_ep_disable(struct usb_ep *_ep) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); +// unsigned long flags; + + DBG("wmt_ep_disable() %s\n", ep ? ep->ep.name : NULL); + + if (!_ep || !ep->desc) { + DBG("[wmt_ep_disable], %s not enabled\n", + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + ep->desc = 0; + nuke(ep, -ESHUTDOWN); + ep->ep.maxpacket = ep->maxpacket; + ep->has_dma = 0; + + del_timer(&ep->timer); + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xFC; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl &= 0xFC; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xFC; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + if (f_ep3_used == 3) + f_ep3_used = 0; + pDevReg->Bulk3EpControl &= 0xFC; +#else + pDevReg->InterruptEpControl &= 0xFC; +#endif + break; + + case 4:/*Iso In*/ + if (f_ep3_used == 4) + f_ep3_used = 0; + pDevReg->Bulk3EpControl &= 0xFC; + fiq_using = 0; + break; + } + wmb(); + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + VDBG("%s disabled\n", _ep->name); + return 0; +} /*static int wmt_ep_disable()*/ + + +static struct usb_request * +wmt_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct vt8500_req *req; + struct vt8500_ep *ep = NULL; + +// DBG("gri wmt_alloc_request() %s\n", ep->name); + + ep = container_of(_ep, struct vt8500_ep, ep); +// printk(KERN_INFO "gri wmt_alloc_request() %s\n", ep->name); +// if ((ep->bEndpointAddress & 0x7F) > 4) +// return NULL; + + + /*if(ep->bEndpointAddress == 3)*/ + /* INFO("wmt_alloc_request() %s\n", ep->name);*/ + + req = kmalloc(sizeof *req, gfp_flags); + if (req) { + memset(req, 0, sizeof *req); + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD(&req->queue); + } + return &req->req;/*struct usb_request for file_storage.o*/ +} /*wmt_alloc_request()*/ + +static void +wmt_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vt8500_req *req = container_of(_req, struct vt8500_req, req); + struct vt8500_ep *ep = NULL; + + DBG("wmt_free_request() %s\n", ep->name); + ep = container_of(_ep, struct vt8500_ep, ep); + + /*if(ep->bEndpointAddress == 3)*/ + /* INFO("wmt_free_request() %s\n", ep->name);*/ + + if (_req) + kfree(req); +} /*wmt_free_request()*/ + +/*EP0 - Control 256 bytes*/ +/*EP2,3 Bulk In/Out 16384 bytes (16K)*/ +/*file_storeage.c - req->buf*/ +/*struct usb_request req;*/ +static void wmt_pdma_init(struct device *dev); + + +static void ep0_status(struct vt8500_udc *udc) +{ + struct vt8500_ep *ep; + + ep = &udc->ep[0]; + + if (udc->ep0_in) { /*OUT STATUS*/ + if (udc->ep0_status_0_byte == 1) { + udc->ep0_status_0_byte = 0; + + /* the data phase is OUT*/ + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_STATUS; + } /*if(udc->ep0_status_0_byte == 1)*/ + } else { /*IN STATUS*/ + if (udc->ep0_status_0_byte == 1) { + udc->ep0_status_0_byte = 0; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA0; + + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; /* zero length*/ + pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_STATUS; + } /*if(udc->ep0_status_0_byte == 1)*/ + } + +} /*static void ep0_status(struct vt8500_udc *udc)*/ + + +static void +done(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ + unsigned stopped = ep->stopped; + + DBG("done() %s\n", ep ? ep->ep.name : NULL); + + list_del_init(&req->queue); + + /*#define EINPROGRESS 115*/ /* Operation now in progress */ + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else { + if (status != 0) + status = req->req.status; + } + + DBG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback*/ + ep->stopped = 1; + + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + req->req.complete(&ep->ep, &req->req); + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + if ((ep->bEndpointAddress & 0x7F) == 0)/*Control*/ + { + if (req->req.actual != 0) { + ep->udc->ep0_status_0_byte = 1; + } + } +#if 0 + else + printk("**done() %s\n", ep ? ep->ep.name : NULL); +#endif + + ep->stopped = stopped; + +} /*done(struct vt8500_ep *ep, struct vt8500_req *req, int status)*/ + +static u32 dma_src_len(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*dma_addr_t end;*/ + /*U32 ep_trans_len;*/ + unsigned start = 0 , end = 0; + u32 temp32 = 0; + + start = req->req.length; + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control In*/ + end = (pDevReg->ControlDesTbytes & 0x7F); + temp32 = (ep->ep_fifo_length - end); + return temp32; + } else if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ + end = (pDevReg->Bulk1DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk1DesTbytes1 << 8; + end |= pDevReg->Bulk1DesTbytes0; + } else if ((ep->bEndpointAddress & 0x7F) == 3)/*Interrupt In*/ + { +#ifdef USE_BULK3_TO_INTERRUPT + end = (pDevReg->Bulk3DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk3DesTbytes1 << 8; + end |= pDevReg->Bulk3DesTbytes0; +#else + start = req->dma_bytes; + end = (pDevReg->InterruptDes >> 4); +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4)/*Iso In*/ + { + end = 0; + } + + temp32 = (start - end); + return temp32; +} /*static u32 dma_src_len()*/ + +static u32 dma_dest_len(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*dma_addr_t end;*/ + unsigned start = 0 , end = 0; + u32 temp32 = 0; + + start = req->req.length; + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control Out*/ + end = (pDevReg->ControlDesTbytes & 0x7F); + temp32 = (ep->ep_fifo_length - end); + return temp32; + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + end = (pDevReg->Bulk2DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk2DesTbytes1 << 8; + end |= pDevReg->Bulk2DesTbytes0; + } + + temp32 = (start - end); + return temp32; +} /*static u32 dma_dest_len()*/ + +/* Each USB transfer request using DMA maps to one or more DMA transfers. + * When DMA completion isn't request completion, the UDC continues with + * the next DMA transfer for that USB transfer. + */ + +static void wmt_udc_pdma_des_prepare(unsigned int size, unsigned int dma_phy + , unsigned char des_type, unsigned char channel, int is_bulk) +{ + unsigned int res_size = size; + volatile unsigned int trans_dma_phy = dma_phy, des_phy_addr = 0, des_vir_addr = 0; + unsigned int cut_size = 0x40; + + switch (des_type) { + case DESCRIPTOT_TYPE_SHORT: + { + struct _UDC_PDMA_DESC_S *pDMADescS; + + if (channel == TRANS_OUT) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrSO; + des_vir_addr = UdcPdmaVirAddrSO; + pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; + } else if (channel == TRANS_IN) { + if (is_bulk) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrSI; + des_vir_addr = UdcPdmaVirAddrSI; + pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; + } + else { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrS2I; + des_vir_addr = UdcPdmaVirAddrS2I; + pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; + } + } else + DBG("!! wrong channel %d\n", channel); + + while (res_size) { + pDMADescS = (struct _UDC_PDMA_DESC_S *) des_vir_addr; + + pDMADescS->Data_Addr = trans_dma_phy; + pDMADescS->D_Word0_Bits.Format = 0; + +// if (res_size <= 65535) { + if (res_size <= 32767) { + pDMADescS->D_Word0_Bits.i = 1; + pDMADescS->D_Word0_Bits.End = 1; + pDMADescS->D_Word0_Bits.ReqCount = res_size; + + res_size -= res_size; + } else { + pDMADescS->D_Word0_Bits.i = 0; + pDMADescS->D_Word0_Bits.End = 0; + pDMADescS->D_Word0_Bits.ReqCount = 0x8000 - cut_size; + + res_size -= 0x8000; + des_vir_addr += (unsigned int)DES_S_SIZE; + trans_dma_phy += (unsigned int)0x8000; + } + } + break; + } + + case DESCRIPTOT_TYPE_LONG: + { + struct _UDC_PDMA_DESC_L *pDMADescL; + + if (channel == TRANS_OUT) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrLO; + des_vir_addr = UdcPdmaVirAddrLO; + pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; + +// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", +// pUdcDmaReg->DMA_Descriptor_Point1); //gri + +// printk(KERN_INFO "des_vir_addr=0x%08X", +// des_vir_addr); //gri + + } else if (channel == TRANS_IN) { + if (is_bulk){ + des_phy_addr = (unsigned int) UdcPdmaPhyAddrLI; + des_vir_addr = UdcPdmaVirAddrLI; + pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; + + // printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", + // pUdcDmaReg->DMA_Descriptor_Point0); //gri + +// printk(KERN_INFO "des_vir_addr=0x%08X", +// des_vir_addr); //gri + } + else { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrL2I; + des_vir_addr = UdcPdmaVirAddrL2I; + pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; + +// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point2=0x%08X", +// pUdcDmaReg->DMA_Descriptor_Point2); //gri + +// printk(KERN_INFO "des_vir_addr 2 =0x%08X", +// des_vir_addr); //gri + } + + } else + DBG("!! wrong channel %d\n", channel); + + memset((void *)des_vir_addr, 0, 0x100); + + while (res_size) { + pDMADescL = (struct _UDC_PDMA_DESC_L *) des_vir_addr; + + pDMADescL->Data_Addr = trans_dma_phy; + pDMADescL->D_Word0_Bits.Format = 1; + +// if (res_size <= 65535) { + if (res_size <= 32767) { + pDMADescL->D_Word0_Bits.i = 1; + pDMADescL->D_Word0_Bits.End = 1; + pDMADescL->Branch_addr = 0; + pDMADescL->D_Word0_Bits.ReqCount = res_size; + + res_size -= res_size; + } else { + pDMADescL->D_Word0_Bits.i = 0; + pDMADescL->D_Word0_Bits.End = 0; + pDMADescL->Branch_addr = des_vir_addr + (unsigned int)DES_L_SIZE; + pDMADescL->D_Word0_Bits.ReqCount = 0x8000 - cut_size; + + res_size -= 0x8000; + des_vir_addr += (unsigned int)DES_L_SIZE; + trans_dma_phy += (unsigned int)0x8000; + } + } + +#if 0 + if (channel == TRANS_IN) { + if (!is_bulk) { + printk(KERN_INFO "pDMADescL(0x%08X)\n", + des_vir_addr); //gri + printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri + printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri + printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri + } + else { + printk(KERN_INFO "pDMADescL(0x%08X)\n", + des_vir_addr); //gri + printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri + printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri + printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri + } + } +#endif + + break; + } + + case DESCRIPTOT_TYPE_MIX: + break; + default: + break; + } + + //wmb(); +} /*wmt_udc_pdma_des_prepare*/ + +void iso_prepare_0byte(void) +{ + unsigned char ubulk3tmp; + + ubulk3tmp = pDevReg->Bulk3EpControl; + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3DesStatus = 0; + pDevReg->Bulk3DesTbytes2 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes0 = 0; + + pDevReg->Bulk3EpControl = ubulk3tmp; + + /* set endpoint data toggle*/ + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + //wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + +} +void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req) +{ + u32 temp32; + u32 dma_ccr = 0; + unsigned int length; + u32 dcmd; + u32 buf; + int is_in, i; + u8 *pctrlbuf; +#ifndef USE_BULK3_TO_INTERRUPT + u8 *pintbuf; +#endif + +// printk(KERN_INFO "next_in_dma s\n"); //gri + + dcmd = length = req->req.length - req->req.actual;/*wmt_ep_queue() : req->req.actual = 0*/ + buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); + + is_in = 1;/*ep->bEndpointAddress & USB_DIR_IN;*/ + + DBG("next_in_dma() %s\n", ep ? ep->ep.name : NULL); + +#ifdef RNDIS_INFO_DEBUG_BULK_IN + if ((ep->bEndpointAddress & 0x7F) == 1) + INFO("next_in_dma() %s\n", ep ? ep->ep.name : NULL); +#endif + + if (((ep->bEndpointAddress & 0x7F) == 1) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +printk(KERN_INFO "rndis xxxxx %d\n",req->req.length); + + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp1VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp1PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (((ep->bEndpointAddress & 0x7F) == 3) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } +#endif + + if (((ep->bEndpointAddress & 0x7F) == 4) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } + + if (((ep->bEndpointAddress & 0x7F) == 1) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { + //void *retval; + //dma_addr_t dma; + +printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (((ep->bEndpointAddress & 0x7F) == 3) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { + //void *retval; + //dma_addr_t dma; + +//printk(KERN_INFO "rndis 3 ooooobb %d\n",req->req.length); + } +#endif + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control*/ + ep->ep_fifo_length = 0; + + if (length >= 64) + length = 64; + + ep->ep_fifo_length = length; + pctrlbuf = (u8 *)(req->req.buf + req->req.actual); + + for (i = 0; i < length; i++) + SetupBuf[i] = pctrlbuf[i]; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = length | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = length | CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_DATA; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } else if (((ep->bEndpointAddress & 0x7F) == 1)) {/*Bulk In*/ + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk1EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + if (ep->toggle_bit) + pDevReg->Bulk1DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ + else + pDevReg->Bulk1DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk1DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control0 = dma_ccr; + + wmb(); + pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; + } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk3EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + if (ep->toggle_bit) + pDevReg->Bulk3DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ + else + pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + //dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + dma_ccr |= DMA_RUN; + + wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; +#else + +//printk(KERN_INFO "udc interrupt\n"); + + if (dcmd > INT_FIFO_SIZE) + dcmd = INT_FIFO_SIZE; + interrupt_transfer_size = dcmd; + + pintbuf = (u8 *)(req->req.buf);/* + req->req.actual);*/ + + for (i = req->req.actual; i < (req->req.actual + dcmd); i++) + IntBuf[(i-req->req.actual)] = pintbuf[i]; + + pDevReg->InterruptDes = 0x00; + pDevReg->InterruptDes = (dcmd << 4); + + if (ep->toggle_bit) + pDevReg->InterruptDes |= INTXFER_DATA1; + else + pDevReg->InterruptDes &= 0xF7; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + pDevReg->InterruptDes |= INTXFER_IOC; + wmb(); + pDevReg->InterruptDes |= INTXFER_ACTIVE; +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ + + unsigned char tmp; + + tmp = pDevReg->Bulk3EpControl; + + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3EpControl = tmp; + + wmt_pdma2_reset(); + + ep->stall_more_processing = 0; + + //printk(KERN_INFO "next_in_dma 4 %d %d %d\n", length, req->req.length,req->req.actual); //gri + //printk(KERN_INFO "next_in_dma 4\n"); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk3EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + ep->toggle_bit = 0; + + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + //dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + +// wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + dma_ccr |= DMA_RUN; + +// wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + +// wmb(); + + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + fiq_using = 1; + + wmt_enable_fiq(300); + //run_script(action_chkiso); + } + + DBG("req->req.dma 0x%08X \n", req->req.dma); + +#ifdef MSC_COMPLIANCE_TEST + INFO("req->req.dma 0x%08X \n", req->req.dma); +#endif + + req->dma_bytes = dcmd;//length; + +#if 0 + if (((ep->bEndpointAddress & 0x7F) == 3) || ((ep->bEndpointAddress & 0x7F) == 4)) { + printk(KERN_INFO "next_in_dma 3 e\n"); //gri + printk(KERN_INFO "Bulk3EpInEpNum =0x%2.2x\n", pDevReg->Bulk3EpInEpNum); //gri + printk(KERN_INFO "Bulk3EpMaxLen =0x%2.2x\n", pDevReg->Bulk3EpMaxLen); //gri + printk(KERN_INFO "Bulk3EpOutEpNum =0x%2.2x\n", pDevReg->Bulk3EpOutEpNum); //gri + printk(KERN_INFO "Bulk3EpControl =0x%2.2x\n", pDevReg->Bulk3EpControl); //gri + + printk(KERN_INFO "Bulk3DesTbytes2 =0x%2.2x\n", pDevReg->Bulk3DesTbytes2); //gri + printk(KERN_INFO "Bulk3DesTbytes1 =0x%2.2x\n", pDevReg->Bulk3DesTbytes1); //gri + printk(KERN_INFO "Bulk3DesTbytes0 =0x%2.2x\n", pDevReg->Bulk3DesTbytes0); //gri + printk(KERN_INFO "Bulk3DesStatus =0x%2.2x\n", pDevReg->Bulk3DesStatus); //gri + + printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point2); //gri + printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes2); //gri + printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr2); //gri + printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr2); //gri + printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr2); //gri + printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control2); //gri + + } + else if ((ep->bEndpointAddress & 0x7F) == 1) { + printk(KERN_INFO "next_in_dma 1 e\n"); //gri + printk(KERN_INFO "Bulk1EpInEpNum =0x%2.2x\n", pDevReg->Bulk1EpInEpNum); //gri + printk(KERN_INFO "Bulk1EpMaxLen =0x%2.2x\n", pDevReg->Bulk1EpMaxLen); //gri + printk(KERN_INFO "Bulk1EpOutEpNum =0x%2.2x\n", pDevReg->Bulk1EpOutEpNum); //gri + printk(KERN_INFO "Bulk1EpControl =0x%2.2x\n", pDevReg->Bulk1EpControl); //gri + + printk(KERN_INFO "Bulk1DesTbytes2 =0x%2.2x\n", pDevReg->Bulk1DesTbytes2); //gri + printk(KERN_INFO "Bulk1DesTbytes1 =0x%2.2x\n", pDevReg->Bulk1DesTbytes1); //gri + printk(KERN_INFO "Bulk1DesTbytes0 =0x%2.2x\n", pDevReg->Bulk1DesTbytes0); //gri + printk(KERN_INFO "Bulk1DesStatus =0x%2.2x\n", pDevReg->Bulk1DesStatus); //gri + + printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point0); //gri + printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes0); //gri + printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr0); //gri + printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr0); //gri + printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr0); //gri + printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control0); //gri + } +#endif + +} /*static void next_in_dma()*/ + +static void finish_in_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ +// printk(KERN_INFO "finish_in_dma()s\n"); //gri + + DBG("finish_in_dma() %s\n", ep ? ep->ep.name : NULL); + + if (status == 0) { /* Normal complete!*/ +#ifdef USE_BULK3_TO_INTERRUPT + req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ +#else +// if ((ep->bEndpointAddress & 0x7F) == 3) +// req->req.actual += interrupt_transfer_size; +// else + if ((ep->bEndpointAddress & 0x7F) != 3) + req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ +#endif + + /* return if this request needs to send data or zlp*/ + if (req->req.actual < req->req.length) + return; + + if (req->req.zero + && req->dma_bytes != 0 + && (req->req.actual % ep->maxpacket) == 0) + return; + + } else + req->req.actual += dma_src_len(ep, req); + +#ifdef RNDIS_INFO_DEBUG_BULK_IN + if ((ep->bEndpointAddress & 0x7F) == 1) + INFO("finish_in_dma()e %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", + ep ? ep->ep.name : NULL, req->req.actual, req->req.length); +#endif + + done(ep, req, status); + +//printk(KERN_INFO "finish_in_dma() %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", +//ep ? ep->ep.name : NULL, req->req.actual, req->req.length); //gri + + +} /*static void finish_in_dma()*/ + +static void next_out_dma(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*unsigned packets;*/ + u32 dma_ccr = 0; + u32 dcmd; + u32 buf; + int is_in; + +// printk(KERN_INFO "next_out_dma s\n"); //gri + + is_in = 0;/*ep->bEndpointAddress & USB_DIR_IN;*/ + +#ifdef RNDIS_INFO_DEBUG_BULK_OUT + if (ep->bEndpointAddress == 2) + INFO("next_out_dma() %s\n", ep ? ep->ep.name : NULL); +#endif + + DBG("next_out_dma() %s\n", ep ? ep->ep.name : NULL); + + dcmd = req->dma_bytes = req->req.length - req->req.actual; + buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); + + if ((ep->bEndpointAddress == 2) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +printk(KERN_INFO "rndis ooooo %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp2VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp2PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + } + if ((ep->bEndpointAddress == 2) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { +// void *retval; +// dma_addr_t dma; + +printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); +#if 0 + dma_free_coherent (ep->udc->dev, + ep->rndis_buffer_length, + (void *)ep->rndis_buffer_address, (dma_addr_t)ep->rndis_dma_phy_address); + + retval = dma_alloc_coherent(ep->udc->dev, + req->req.length, &dma, GFP_ATOMIC); + + ep->rndis_buffer_address = (unsigned int)retval; + ep->rndis_dma_phy_address = (u32)dma; + ep->rndis_buffer_length = req->req.length; + ep->rndis = 1; +#endif + } + + if (ep->bEndpointAddress == 0) {/*Control*/ + ep->ep_fifo_length = 0; + + if (dcmd >= 64) + dcmd = 64; + + ep->ep_fifo_length = dcmd; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_DATA; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_out_dma %d %d %d\n", req->dma_bytes, req->req.length,req->req.actual); //gri + + /*if(req->dma_bytes == 64)*/ + ep->udc->cbw_virtual_address = (((u32)req->req.buf + req->req.actual) & 0xFFFFFFFC); + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk2EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + /* Set Address*/ + if (ep->rndis == 1) + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + /* DMA Global Controller Reg*/ + /* DMA Controller Enable +*/ + /* DMA Global Interrupt Enable(if any TC, error, or abort status in any channels occurs)*/ + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->toggle_bit) + pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; + else + pDevReg->Bulk2DesTbytes2 &= 0x3F;/*BULKXFER_DATA0;*/ + + pDevReg->Bulk2DesStatus = BULKXFER_IOC;/*| BULKXFER_IN;*/ + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + dma_ccr = 0; + dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + wmb(); + pUdcDmaReg->DMA_Context_Control1 = dma_ccr; + wmb(); + pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; + /*udc_device_dump_register();*/ + } + + VDBG("req->req.dma 0x%08X \n", req->req.dma); + +//printk(KERN_INFO "next_out_dma e\n"); //gri + +} /*static void next_out_dma()*/ + +static void +finish_out_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ + u16 count; + u8 temp8; + u32 temp32; + /*u8 bulk_dma_csr;*/ + +// printk(KERN_INFO "finish_out_dma s\n"); //gri + + DBG("finish_out_dma() %s\n", ep ? ep->ep.name : NULL); + + count = dma_dest_len(ep, req); + + if (ep->bEndpointAddress == 0) {/*Control*/ + u8 *pctrlbuf; + int i; + + pctrlbuf = (u8 *)(req->req.buf + req->req.actual); + for (i = 0; i < count; i++) + pctrlbuf[i] = SetupBuf[i]; + + /*INFO("finish_out_dma() %s\n", ep ? ep->ep.name : NULL);*/ + /*dump_bulk_buffer((req->req.buf + req->req.actual), count);*/ + } + + count += req->req.actual; + + if (count <= req->req.length) + req->req.actual = count; + + if (ep->bEndpointAddress == 0) {/*Control*/ + if (req->req.actual < req->req.length) { + temp8 = pDevReg->ControlDesStatus; + + if ((temp8 & CTRLXFER_SHORTPKT) == 0) + return; /*Continue...*/ + } + } else if (ep->bEndpointAddress == 2) { + + if (pDevReg->Bulk2DesTbytes2 & 0x80) + ep->toggle_bit= 1; + else + ep->toggle_bit= 0; + +// while((pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0xf) && +// (pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0x5)); + +// printk(KERN_INFO "finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", +// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);//gri + // INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", + // ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); + + + { + { + unsigned int gri_t_d; + unsigned int gri_count=0; + unsigned int dma_count; + do{ + gri_t_d=pUdcDmaReg->DMA_ISR ; + gri_t_d &= 0x2; + gri_count++; + if (gri_count & 0x10){ + gri_count=0; +// printk(KERN_INFO "pUdcDmaReg->DMA_Context_Control1 0x%08x\n", &(pUdcDmaReg->DMA_Context_Control1)); + printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); + dma_count = req->req.length - pUdcDmaReg->DMA_Residual_Bytes1_Bits.ResidualBytes; +// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); + if (pUdcDmaReg->DMA_Context_Control1_Bis.Run == 0) + break; + if ((count == dma_count) || (count == 0)){ +// printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); +// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); +// while(1); + pUdcDmaReg->DMA_Context_Control1_Bis.Run = 0; + break; + } + } + }while(!gri_t_d); + } + } + + + if (req->req.actual < req->req.length) { + DBG("finish_out_dma() req->actual < req->req.length\n"); + temp8 = pDevReg->Bulk2DesStatus; + + if ((temp8 & BULKXFER_SHORTPKT) == 0) + return; /*Continue...*/ + else { /*Short Package.*/ + pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; + wmb(); + + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) + ; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + wmb(); + } + } + } + /* rx completion*/ + /*UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);*/ + +//#ifdef RNDIS_INFO_DEBUG_BULK_OUT +// if (ep->bEndpointAddress == 2) +// INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", +// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); +//#endif + + /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ + + if ((ep->bEndpointAddress == 2) && (ep->rndis == 1)) { + memcpy((void *)((u32)req->req.buf), (void *)((u32)ep->rndis_buffer_address), req->req.actual); + + #ifdef RNDIS_INFO_DEBUG_BULK_OUT + /*if ((req->req.actual % 4 == 3))// && (b_message == 0))*/ + /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ + #endif +#if 0 + if ((req->req.length == 1600) || (req->req.length == 2048)) {/*F.S. [1600] : H.S. [2048]*/ + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else + INFO("Different Length for Bulk Out (%08d) Toggle Bit would Error\n" + , req->req.length); +#else +#if 0 + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } +#endif + +#endif + } else { +#if 1 + if (ep->bEndpointAddress == 0){ + /*GigaHsu-B 2008.5.15 : Add this caculate toggle from next_out_dma() : + fixed sideshow gadget issue.*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + } +#endif + + /*GigaHsu-E 2008.5.15*/ + } + + done(ep, req, status); + +//printk(KERN_INFO "finish_out_dma e\n"); //gri + +} /*finish_out_dma()*/ + +void dma_irq(u8 addr) +{ + struct vt8500_ep *ep; + struct vt8500_req *req; + /*u32 temp32;*/ + /*u32 i;*/ + + ep = &udc->ep[addr & 0x7f]; + + if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ + + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->Bulk1EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_in_dma(ep, req); + } + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + + /* OUT dma: rx from host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_out_dma(ep, req, 0); + } + + while (pDevReg->Bulk2EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_out_dma(ep, req); + } + } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ + +#ifdef USE_BULK3_TO_INTERRUPT + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->Bulk3EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_in_dma(ep, req); + } +#else + /* IN dma: tx to host*/ + while (pDevReg->InterruptEpControl & EP_COMPLETEINT) + ; + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + req->req.actual += dma_src_len(ep, req); + if (req->req.actual < req->req.length) + next_in_dma(ep, req); + else + finish_in_dma(ep, req, 0); + } + +// if (!list_empty(&ep->queue)) { +// req = container_of(ep->queue.next, struct vt8500_req, queue); +// next_in_dma(ep, req); +// } +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ + + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + } + +} /*static void dma_irq()*/ + + +static void pullup_enable(struct vt8500_udc *udc) +{ + INFO("gri pullup_enable()\n"); + b_pullup = 1; + /*Enable port control's FSM to enable 1.5k pull-up on D+.*/ + //pDevReg->PhyMisc &= 0x0F;/*Hardware auto-mode*/ + pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + wmb(); + /*pDevReg->PhyMisc |= 0x50;*/ + +} /*static void pullup_enable()*/ + + + +/*-------------------------------------------------------------------------*/ +/*file_storage.c ep0_queue() - control*/ +/*file_storage.c start_transfer() - bulk*/ +static int +wmt_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_req *req = container_of(_req, struct vt8500_req, req); + /*struct vt8500_udc *udc;*/ +// unsigned long flags; + unsigned char empty_data = 0; + + DBG("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); +// INFO("gri wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); + +// if ((ep->bEndpointAddress & 0x7F) > 4) +// return -EINVAL; + +#ifdef RNDIS_INFO_DEBUG_BULK_OUT + if ((ep->bEndpointAddress == 3))/* || ((ep->bEndpointAddress & 0x7F) == 2))*/ + INFO("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); +#endif + + /* catch various bogus parameters*/ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + DBG("[wmt_ep_queue], bad params\n"); + return -EINVAL; + } + if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + DBG("[wmt_ep_queue], bad ep\n"); + return -EINVAL; + } + +//#ifdef RNDIS_INFO_DEBUG_BULK_OUT +// if ((ep->bEndpointAddress == 2))/* || ((ep->bEndpointAddress & 0x7F) == 1))*/ +// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", +// ep->ep.name, _req, _req->length, _req->buf); +//#endif + +//#ifdef MSC_COMPLIANCE_TEST +// if ((ep->bEndpointAddress & 0x7F) == 1) +// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", +// ep->ep.name, _req, _req->length, _req->buf); +//#endif + + DBG("wmt_ep_queue() %s queue req %p, len %d buf %p\n", + ep->ep.name, _req, _req->length, _req->buf); + + spin_lock_irqsave(&udc->lock, irq_flags); + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + + /* maybe kickstart non-iso i/o queues*/ + + if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { + int is_in; + + if (ep->bEndpointAddress == 0) { + if (!udc->ep0_pending || !list_empty(&ep->queue)) { + spin_unlock_irqrestore(&udc->lock, irq_flags); + return -EL2HLT; + } + + /* empty DATA stage?*/ + is_in = udc->ep0_in; + + if (!req->req.length) { /*status 0 bytes*/ + + udc->ep0_status_0_byte = 1; + ep0_status(udc); + + /* cleanup*/ + udc->ep0_pending = 0; + done(ep, req, 0); + empty_data = 1; + } + + if (req->req.length) { + udc->bulk_out_dma_write_error = 0; + (is_in ? next_in_dma : next_out_dma)(ep, req); + } + } else { + is_in = ep->bEndpointAddress & USB_DIR_IN; + + if (req != 0){ + list_add_tail(&req->queue, &ep->queue); + empty_data = 1; + } +// else +// { +// printk(KERN_INFO "xxx %x %x\n",req,empty_data); //gri +// } + /*if (!ep->has_dma)*/ + /* use_ep(ep, UDC_EP_SEL);*/ + /* if ISO: SOF IRQs must be enabled/disabled!*/ + if (((ep->bEndpointAddress & 0x7F) != 4) || (!fiq_using)) + (is_in ? next_in_dma : next_out_dma)(ep, req); +#if 0 + else + printk("gri w_e_q() 01 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); +#endif + } + } + /* irq handler advances the queue*/ +#if 0 + if ((ep->bEndpointAddress & 0x7F) == 4) + printk("gri w_e_q() 02 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); +#endif + + if ((req != 0) && (empty_data == 0)) + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&udc->lock, irq_flags); + + return 0; +} /*wmt_ep_queue()*/ + +void ep1_cancel_tx(struct vt8500_ep *ep) +{ + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk1EpControl & 0xE3; + pDevReg->Bulk1DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk1DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk1DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk1DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk1DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk1EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk1EpControl = bctrl0; + + wmt_pdma0_reset(); + wmb(); +} + +void ep2_cancel_tx(struct vt8500_ep *ep) +{ + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk2EpControl & 0xE3; + pDevReg->Bulk2DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk2DesTbytes2 & 0x80; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk2DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk2DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk2DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk2EpControl = bctrl0; + + wmt_pdma1_reset(); + wmb(); +} + +void ep3_cancel_tx(struct vt8500_ep *ep) +{ +#ifdef USE_BULK3_TO_INTERRUPT + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk3EpControl & 0xE3; + pDevReg->Bulk3DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk3DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk3EpControl = bctrl0; + + wmt_pdma2_reset(); + wmb(); +#else + unsigned char tmp0, tmp1, tmp2, tmp3; + + pDevReg->InterruptDes = 0x00; + wmb(); + tmp0 = InterruptEpControl; + tmp1 = InterruptReserved; + tmp2 = InterruptEpMaxLen; + tmp3 = InterruptEpEpNum; + InterruptEpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->InterruptEpControl & EP_DMALIGHTRESET); + InterruptEpControl = tmp0; + InterruptReserved = tmp1; + InterruptEpMaxLen = tmp2; + InterruptEpEpNum = tmp3; + wmb(); +#endif +} + +void ep4_cancel_tx(struct vt8500_ep *ep) +{ + + unsigned char btmp; + unsigned char bctrl0; + + fiq_using = 0; + + bctrl0 = pDevReg->Bulk3EpControl & 0xE3; + pDevReg->Bulk3DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk3DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk3EpControl = bctrl0; + + wmt_pdma2_reset(); + wmb(); +} + +static int wmt_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_req *req; + int is_in; +// unsigned long flags; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + DBG("wmt_ep_dequeue() %s\n", ep ? ep->ep.name : NULL); + /* make sure it's actually queued on this endpoint*/ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + return -EINVAL; + } + + + if (((ep->bEndpointAddress & 0x7F) != 0) && ep->queue.next == &req->queue) { + + if (ep->bEndpointAddress == 1){ + ep1_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 2){ + ep2_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 3){ + ep3_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 4){ + ep4_cancel_tx(ep); + } + } + + done(ep, req, -ECONNRESET); + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + is_in = ep->bEndpointAddress & USB_DIR_IN; + (is_in ? next_in_dma : next_out_dma)(ep, req); + } + + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + return 0; +} /*static int wmt_ep_dequeue()*/ + +/*-------------------------------------------------------------------------*/ + +static int wmt_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); +// unsigned long flags; + int status = -EOPNOTSUPP; + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + ep->toggle_bit = 0; /*patch CLEAR_FEATURE ENDPOINT_HALT*/ + DBG("wmt_ep_set_halt() %s\n", ep ? ep->ep.name : NULL); + + if (value) { + u8 temp32bytes[31]; + + memset(temp32bytes, 0, 31); + temp32bytes[0] = 0xEF; + temp32bytes[1] = 0xBE; + temp32bytes[2] = 0xAD; + temp32bytes[3] = 0xDE; + + /*usb_ep_set_halt() - value == 1 stall*/ + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl |= EP_STALL; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl |= EP_STALL; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl |= EP_STALL; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl |= EP_STALL; +#else + pDevReg->InterruptEpControl |= EP_STALL; +#endif + break; + + case 4:/*Iso In*/ + pDevReg->Bulk3EpControl |= EP_STALL; + break; + } + + ep->stall = 1; + /*DBG("wmt_ep_set_halt(1) HALT CSR(0x%08X)\n", *ep->reg_control_status);*/ + status = 0; + + if (memcmp(temp32bytes, (void *)ep->udc->cbw_virtual_address, 4) == 0) + udc->file_storage_set_halt = 1; /*forbid to CLEAR FEATURE*/ + } else {/*usb_ep_clear_halt - value == 0 reset*/ + + /**ep->reg_control_status &= 0xFFFFFFFB;*/ + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xF7; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl &= 0xF7; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xF7; + break; + + case 3:/*Interrupt In*/ + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl &= 0xF7; +#else + pDevReg->InterruptEpControl &= 0xF7; +#endif + break; + + case 4:/*Iso In*/ + pDevReg->Bulk3EpControl &= 0xF7; + break; + } + + ep->stall = 0; + status = 0; + udc->file_storage_set_halt = 0; + } + + VDBG("%s %s halt stat %d\n", ep->ep.name, + value ? "set" : "clear", status); + wmb(); + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + return status; +} /*static int wmt_ep_set_halt()*/ + +static struct usb_ep_ops wmt_ep_ops = { + .enable = wmt_ep_enable, + .disable = wmt_ep_disable, + + .alloc_request = wmt_alloc_request, + .free_request = wmt_free_request, + +// .alloc_buffer = wmt_alloc_buffer, +// .free_buffer = wmt_free_buffer, + + .queue = wmt_ep_queue, + .dequeue = wmt_ep_dequeue, + + .set_halt = wmt_ep_set_halt, + + /* fifo_status ... report bytes in fifo*/ + /* fifo_flush ... flush fifo*/ +}; + +#if 0 +static void +wmt_udc_csr(struct vt8500_udc *udc) +{ + /* abolish any previous hardware state*/ + + DBG("wmt_udc_csr()\n"); + + if (udc->gadget.speed == USB_SPEED_FULL) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); + } else if (udc->gadget.speed == USB_SPEED_HIGH) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); + } else if (udc->gadget.speed == USB_SPEED_UNKNOWN) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); + } + //wmt_ep_setup_csr("ep3in""-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif +} /*wmt_udc_csr(void)*/ +#endif + +static int wmt_get_frame(struct usb_gadget *gadget) +{ + DBG("wmt_get_frame()\n"); + return 0; +} + +static int wmt_wakeup(struct usb_gadget *gadget) +{ + /*struct vt8500_udc *udc;*/ + /*unsigned long flags;*/ + int retval = 0; + DBG("wmt_wakeup()\n"); +/* + udc = container_of(gadget, struct vt8500_udc, gadget); + + spin_lock_irqsave(&udc->lock, irq_flags); + if (udc->devstat & UDC_SUS) { + // NOTE: OTG spec erratum says that OTG devices may + // issue wakeups without host enable. + // + if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { + DBG("remote wakeup...\n"); + UDC_SYSCON2_REG = UDC_RMT_WKP; + retval = 0; + } + + // NOTE: non-OTG systems may use SRP TOO... + } else if (!(udc->devstat & UDC_ATT)) { + if (udc->transceiver) + retval = otg_start_srp(udc->transceiver->otg); + } + spin_unlock_irqrestore(&udc->lock, irq_flags); +*/ + return retval; +} + +static int +wmt_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + DBG("wmt_set_selfpowered()\n"); +/* struct vt8500_udc *udc; + unsigned long flags; + u16 syscon1; + + udc = container_of(gadget, struct vt8500_udc, gadget); + spin_lock_irqsave(&udc->lock, irq_flags); + syscon1 = UDC_SYSCON1_REG; + if (is_selfpowered) + syscon1 |= UDC_SELF_PWR; + else + syscon1 &= ~UDC_SELF_PWR; + UDC_SYSCON1_REG = syscon1; + spin_unlock_irqrestore(&udc->lock, irq_flags); +*/ + return 0; +} + + +void reset_ep(void) +{ +#if 1 + wmt_disable_fiq(); + fiq_using = 0; + + pDevReg->Bulk1EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk2EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; +#else + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; +#endif + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; + + /* enable DMA and run the control endpoint*/ + wmb(); + + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; +#if 0 + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif +#endif + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + wmb(); + pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + wmb(); + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + /*status = wmt_udc_setup(odev, xceiv);*/ + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); +#if 1 + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); +#if 0 +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif +#endif +#endif +} + +void reset_udc(void) +{ +/* if (!((*(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254))&0x00000080))*/ +/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) |= 0x00000080;*/ /*DPM needed*/ + +pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + wmb(); + + if ((*(volatile unsigned char *)(USB_IP_BASE + 0x249))&0x04) { + *(volatile unsigned char*)(USB_IP_BASE + 0x249)&= ~0x04; + mdelay(1); + } + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ + /* reset Bulk descriptor control*/ + wmb(); + + f_ep3_used = 0; + reset_ep(); + + pDevReg->SelfPowerConnect |= 0x10;//Neil + wmb(); + /* enable all interrupt*/ +#ifdef FULL_SPEED_ONLY + pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ +#else + pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ +#endif + wmb(); + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl = CTRLXFER_IOC; +/*Neil_080731*/ +/* pullup_disable here and enable in /arch/arm/kernel/apm.c:395 + apm_ioctl() to patch issue signal fail when resume when recive*/ +/* set_configuration time out.*/ +/* pullup_enable(udc);//usb_gadget_probe_driver()*/ + wmb(); + wmt_pdma_reset(); + +// pullup_enable(udc); +// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ +/* pullup_disable(udc);*/ +/*Neil_080731*/ + +} + + +/* +static int can_pullup(struct vt8500_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} +*/ +static void pullup_disable(struct vt8500_udc *udc) +{ + INFO("pullup_disable()\n"); + /*Hold port control's FSM from enter device mode.*/ + //pDevReg->PhyMisc &= 0x0F; + //pDevReg->PhyMisc |= 0x10; + pDevReg->FunctionPatchEn &= (~0x20); /* HW attach process evaluation enable bit*/ + wmb(); + gadget_connect=0; + + f_ep3_used = 0; + reset_ep(); + wmt_pdma_reset(); + + +} /*static void pullup_disable()*/ + +/* + * Called by whatever detects VBUS sessions: external transceiver + * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. + */ +static int wmt_vbus_session(struct usb_gadget *gadget, int is_active) +{ + DBG("wmt_vbus_session()\n"); + return 0; +} + +static int wmt_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + DBG("wmt_vbus_draw()\n"); + return -EOPNOTSUPP; +} + +static int wmt_pullup(struct usb_gadget *gadget, int is_on) +{ + struct vt8500_udc *udc; +// unsigned long flags; + + DBG("wmt_pullup()\n"); + + udc = container_of(gadget, struct vt8500_udc, gadget); + down(&wmt_udc_sem); + spin_lock_irqsave(&udc->lock, irq_flags); + udc->softconnect = (is_on != 0); +// if (can_pullup(udc)) + + if (udc->softconnect) + pullup_enable(udc); + else { + pullup_disable(udc); + //run_script(action_off_line); + } + spin_unlock_irqrestore(&udc->lock, irq_flags); + up(&wmt_udc_sem); + + return 0; +} + +void get_udc_sem (void) +{ + down(&wmt_udc_sem); +} + +void release_udc_sem (void) +{ + up(&wmt_udc_sem); +} + +static int wmt_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int wmt_udc_stop(struct usb_gadget_driver *driver); + +static struct usb_gadget_ops wmt_gadget_ops = { + .get_frame = wmt_get_frame, + .wakeup = wmt_wakeup, + .set_selfpowered = wmt_set_selfpowered, + .vbus_session = wmt_vbus_session, + .vbus_draw = wmt_vbus_draw, + .pullup = wmt_pullup, + .start = wmt_udc_start, + .stop = wmt_udc_stop, +}; + +/* dequeue ALL requests; caller holds udc->lock */ +static void nuke(struct vt8500_ep *ep, int status) +{ + struct vt8500_req *req; + + DBG("nuke()\n"); + ep->stopped = 1; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct vt8500_req, queue); + done(ep, req, status); + } +} /*void nuke()*/ + +/* caller holds udc->lock */ +static void udc_quiesce(struct vt8500_udc *udc) +{ + struct vt8500_ep *ep; + DBG("udc_quiesce()\n"); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->ep[0], -ESHUTDOWN); + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) + nuke(ep, -ESHUTDOWN); +} /*void udc_quiesce()*/ + +/* +static void update_otg(struct vt8500_udc *udc) +{ + u16 devstat; + + if (!udc->gadget.is_otg) + return; + + if (OTG_CTRL_REG & OTG_ID) + devstat = UDC_DEVSTAT_REG; + else + devstat = 0; + + udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); + udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); + udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); + + // Enable HNP early, avoiding races on suspend irq path. + // ASSUMES OTG state machine B_BUS_REQ input is true. + // + if (udc->gadget.b_hnp_enable) + OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ) + & ~OTG_PULLUP; + +}//static void update_otg() +*/ + + +/* define the prepare result codes*/ +#define RESPOK 0 +#define RESPFAIL 1 +u16 Control_Length; /* the length of transfer for current control transfer*/ +u16 Configure_Length; + + +/*UDC_IS_SETUP_INT*/ +static void udc_control_prepare_data_resp(void)/*(struct vt8500_udc *udc, u32 udc_irq_src)*/ +{ + struct vt8500_ep *ep0 = &udc->ep[0]; + struct vt8500_req *req = 0; + /*UCHAR Result = RESPFAIL;*/ + /*unsigned char CurXferLength = 0;*/ + /*unsigned char Control_Length = 0;*/ + int i; + u8 test_mode_enable = 0; + + Configure_Length = 0; + + /*ep0->irqs++;*/ + DBG("ep0_irq()\n"); + ep0->toggle_bit = 1; + + if (!list_empty(&ep0->queue)) + req = container_of(ep0->queue.next, struct vt8500_req, queue); + + /* SETUP starts all control transfers*/ + { + union u { + u8 bytes[8]; + struct usb_ctrlrequest r; + } u; + int status = -EINVAL; + struct vt8500_ep *ep = &udc->ep[0]; + int ep0_status_phase_0_byte = 0; + + nuke(ep0, 0); + /* read the (latest) SETUP message*/ + for (i = 0; i <= 7; i++) + u.bytes[i] = pSetupCommandBuf[i]; + + le32_to_cpus(&u.r.wValue); + le32_to_cpus(&u.r.wIndex); + le32_to_cpus(&u.r.wLength); + + /* Delegate almost all control requests to the gadget driver,*/ + /* except for a handful of ch9 status/feature requests that*/ + /* hardware doesn't autodecode _and_ the gadget API hides.*/ + /**/ + udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; + udc->ep0_set_config = 0; + udc->ep0_pending = 1; + udc->ep0_in_status = 0; + + ep0->stopped = 0; + ep0->ackwait = 0; + + if ((u.r.bRequestType & USB_RECIP_OTHER) == USB_RECIP_OTHER) {/*USB_RECIP_OTHER(0x03)*/ + status = 0; + + /*INFO("ep0_irq() setup command[0]=(0x%08X)\n",u.dword[0]);*/ + /*INFO("ep0_irq() setup command[1]=(0x%08X)\n",u.dword[1]);*/ + /*INFO("ep0_irq() address(%08X)", udc_reg->AddressControl);*/ + goto delegate; + } + + switch (u.r.bRequest) { + case USB_REQ_SET_CONFIGURATION: + /* udc needs to know when ep != 0 is valid*/ + /*SETUP 00.09 v0001 i0000 l0000*/ + if (u.r.bRequestType != USB_RECIP_DEVICE)/*USB_RECIP_DEVICE(0x00)*/ + goto delegate; + if (u.r.wLength != 0) + goto do_stall; + udc->ep0_set_config = 1; + udc->ep0_reset_config = (u.r.wValue == 0); + VDBG("set config %d\n", u.r.wValue); + + if (u.r.wValue == 0) + USBState = USBSTATE_ADDRESS; + else + USBState = USBSTATE_CONFIGED; + /* update udc NOW since gadget driver may start*/ + /* queueing requests immediately; clear config*/ + /* later if it fails the request.*/ + /**/ + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + + status = 0; + goto delegate; + + /* Giga Hsu : 2007.6.6 This would cause set interface status 0 + return to fast and cause bulk endpoint in out error*/ + case USB_REQ_SET_INTERFACE: + + VDBG("set interface %d\n", u.r.wValue); + status = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + goto delegate; + /*break;*/ + + case USB_REQ_CLEAR_FEATURE: + /* clear endpoint halt*/ + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep != ep0) { + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) + goto do_stall; + + if (udc->file_storage_set_halt == 0) { + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xF7; + break; + + case 1:/*Bulk In*/ + + pDevReg->Bulk1EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma0_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk1DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk1DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk1DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control0 = dma_ccr; //neil + wmb(); + pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; + } + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xF7; + + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + ep->stall_more_processing = 0; + wmt_pdma1_reset(); + // wmt_pdma_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + /* DMA Global Controller Reg*/ + /* DMA Controller Enable +*/ + /* DMA Global Interrupt Enable(if any TC, error, + or abort status in any channels occurs)*/ + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = + ep->temp_dcmd & 0xFF; + + if (ep->ep_stall_toggle_bit) + pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; + else + pDevReg->Bulk2DesTbytes2 &= 0x3F; + + pDevReg->Bulk2DesStatus = BULKXFER_IOC; + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + + /*udc_bulk_dma_dump_register();*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + dma_ccr |= DMA_TRANS_OUT_DIR; + wmb(); + pUdcDmaReg->DMA_Context_Control1 = dma_ccr; + wmb(); + pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; + } + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT +/*Bulk In*/ + + pDevReg->Bulk3EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma2_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + } + +#else +/*Interrupt In*/ + pDevReg->InterruptEpControl &= 0xF7; +#endif + break; + + case 4:/*Iso In*/ + + pDevReg->Bulk3EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma2_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + } + + break; + + } + + ep->stall = 0; + ep->stopped = 0; + /**ep->reg_irp_descriptor = ep->temp_irp_descriptor;*/ + } + } /*if (ep != ep0)*/ + + ep0_status_phase_0_byte = 1; + VDBG("%s halt cleared by host\n", ep->name); + /*goto ep0out_status_stage;*/ + status = 0; + udc->ep0_pending = 0; + /*break;*/ + goto delegate; + + case USB_REQ_SET_FEATURE: + /* set endpoint halt*/ + + if ((u.r.wValue == USB_DEVICE_TEST_MODE)) {/*(USBState == USBSTATE_DEFAULT) &&*/ + TestMode = (UCHAR)(u.r.wIndex >> 8); + test_mode_enable = 1; + INFO("USB_REQ_SET_FEATURE - TestMode (0x%02X)\n", TestMode); + + /*ControlState = CONTROLSTATE_STATUS;*/ + ep0_status_phase_0_byte = 1; + status = 0; + break; + } + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) + goto do_stall; + + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) + goto do_stall; + + wmb(); + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl |= EP_STALL; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl |= EP_STALL; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl |= EP_STALL; + break; + + case 3: +#ifdef USE_BULK3_TO_INTERRUPT + /*Bulk Out*/ + pDevReg->Bulk3EpControl |= EP_STALL; +#else + /*Interrupt In*/ + pDevReg->InterruptEpControl |= EP_STALL; +#endif + break; + + case 4: + /*Bulk Out*/ + pDevReg->Bulk3EpControl |= EP_STALL; + break; + } + wmb(); + ep->stall = 1; + ep->stopped = 1; + + ep0_status_phase_0_byte = 1; + /*use_ep(ep, 0);*/ + /* can't halt if fifo isn't empty...*/ + /*UDC_CTRL_REG = UDC_CLR_EP;*/ + /*UDC_CTRL_REG = UDC_SET_HALT;*/ + VDBG("%s halted by host\n", ep->name); + /*ep0out_status_stage:*/ + status = 0; + + udc->ep0_pending = 0; + /*break;*/ + goto delegate; + + case USB_REQ_GET_STATUS: + /* return interface status. if we were pedantic,*/ + /* we'd detect non-existent interfaces, and stall.*/ + /**/ + + if (u.r.bRequestType == (USB_DIR_IN|USB_RECIP_ENDPOINT)) { + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep->stall == 1) { + udc->ep0_in_status = 0x01; + + /*GgiaHsu-B 2007.08.10 : patch HW Bug : + MSC Compliance Test : Error Recovery Items.*/ + ep = &udc->ep[3]; + if ((udc->file_storage_set_halt == 1) && (ep->stall == 1)) + ep->stall = 1; + /*GgiaHsu-E 2007.08.10 : + --------------------------------------------*/ + + ep = &udc->ep[0]; + ep->stall = 0; + } else + udc->ep0_in_status = 0x00; + + VDBG("GET_STATUS, interface wIndex(0x%02X) ep0_in_status(0x%04X)\n" + , u.r.wIndex, udc->ep0_in_status); + } else + udc->ep0_in_status = 0x00; + + /* return two zero bytes*/ + status = 0; + + /* next, status stage*/ + goto delegate; + break; + + case USB_REQ_SET_ADDRESS: + if (u.r.bRequestType == USB_RECIP_DEVICE) { /*USB_RECIP_DEVICE(0x00)*/ + if (USBState == USBSTATE_DEFAULT) { + if (u.r.wValue != 0) + USBState = USBSTATE_ADDRESS; + } else if (USBState == USBSTATE_ADDRESS) { + if (u.r.wValue == 0) + USBState = USBSTATE_DEFAULT; + } + + pDevReg->DeviceAddr |= (DEVADDR_ADDRCHANGE | u.r.wValue); + VDBG("USB_REQ_SET_ADDRESS 0x%03d\n", u.r.wValue); + ControlState = CONTROLSTATE_STATUS; + ep0_status_phase_0_byte = 1; + status = 0; + } + break; + + case USB_BULK_RESET_REQUEST: + + VDBG("USB_BULK_RESET_REQUEST\n"); + udc->file_storage_set_halt = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + status = 0; + + goto delegate; + /*break;*/ + + default: +delegate: + VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + /* + // The gadget driver may return an error here, + // causing an immediate protocol stall. + // + // Else it must issue a response, either queueing a + // response buffer for the DATA stage, or halting ep0 + // (causing a protocol stall, not a real halt). A + // zero length buffer means no DATA stage. + // + // It's fine to issue that response after the setup() + // call returns, and this IRQ was handled. + // + */ + udc->ep0_setup = 1; + + spin_unlock_irqrestore(&udc->lock, irq_flags); + /*usb gadget driver prepare setup data phase(control in)*/ + status = udc->driver->setup(&udc->gadget, &u.r); /*usb_gadget_driver->setup()*/ + spin_lock_irqsave(&udc->lock, irq_flags); + udc->ep0_setup = 0; + } /*switch (u.r.bRequest)*/ + + if (ep0_status_phase_0_byte == 1) {/* && (udc->ep[0].stall==0))*/ + udc->ep0_status_0_byte = 1; + if (test_mode_enable == 1) + ep0_status(udc); + } + + if (status < 0) { +do_stall: + /* ep = &udc->ep[0];*/ + /**ep->reg_control_status |= UDC_EP0_STALL;*/ + /* fail in the command parsing*/ + pDevReg->ControlEpControl |= EP_STALL; /* stall the pipe*/ + wmb(); + ControlState = CONTROLSTATE_SETUP; /* go back to setup state*/ + + ep->stall = 1; + DBG("Setup Command STALL : req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, status); + + udc->ep0_pending = 0; + } /*if (status < 0)*/ + } /*if (udc_irq_src & UDC_IS_SETUP_INT)*/ +} /*udc_control_prepare_data_resp()*/ + +#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) + +static void devstate_irq(struct vt8500_udc *udc, u32 port0_status) +{ + udc->usb_connect = 0; + + if (pDevReg->IntEnable & INTENABLE_DEVICERESET) { + /*vt3357 hw issue : clear all device register.*/ + /*payload & address needs re-set again...*/ + pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; + VDBG("devstate_irq() - Global Reset...\n"); +//printk("[devstate_irq]0xd8009834 = 0x%8.8x\n",*(volatile unsigned int *)(USB_IP_BASE+0x2034)); + + if (udc->driver) { + udc->gadget.speed = USB_SPEED_UNKNOWN; +// ppudc = udc; +// run_script(action_off_line); +// udc->driver->disconnect(&udc->gadget); + } + + udc->ep0_set_config = 0; + pDevReg->Bulk1DesStatus = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + + udc->ep[0].rndis = 0; + udc->ep[1].rndis = 0; + udc->ep[2].rndis = 0; + udc->ep[3].rndis = 0; + udc->ep[4].rndis = 0; + udc->ep[5].rndis = 0;//gri + udc->ep[6].rndis = 0;//gri + + udc->file_storage_set_halt = 0; + udc->bulk_out_dma_write_error = 0; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + wmt_pdma_reset(); + + gadget_connect=0; + /*vt8500_usb_device_reg_dump();*/ + + } /*if (pDevReg->IntEnable & INTENABLE_DEVICERESET)*/ + + if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT) { + VDBG("devstate_irq() - Global Suspend...\n"); + pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; + + + + } /*if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT)*/ + + if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT) { + pDevReg->IntEnable |= INTENABLE_RESUMEDETECT; + VDBG("devstate_irq() - Global Resume...\n"); + + } /*if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT)*/ + +/*#ifdef UDC_A1_SELF_POWER_ENABLE*/ + /* USB Bus Connection Change*/ + /* clear connection change event*/ + if (pDevReg->PortControl & PORTCTRL_SELFPOWER)/* Device port control register - 22)*/ + if (pDevReg->PortControl & PORTCTRL_CONNECTCHANGE)/* Device port control register - 22)*/ + pDevReg->PortControl |= PORTCTRL_CONNECTCHANGE;/* 0x02 // connection change bit*/ + +/*#endif*/ + + if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { + udc->gadget.speed = USB_SPEED_FULL; + udc->usb_connect = 1; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + VDBG("devstate_irq() - full speed host connect...\n"); + } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ + + if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { + udc->gadget.speed = USB_SPEED_HIGH; + udc->usb_connect = 1; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + VDBG("devstate_irq() - high speed host connect...\n"); + } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ + +} /*static void devstate_irq()*/ + +void USB_ControlXferComplete(void) +{ + struct vt8500_ep *ep; + struct vt8500_req *req; + + ep = &udc->ep[0]; + /* when ever a setup received, the Control state will reset*/ + /* check for the valid bit of the contol descriptor*/ + /*DBG("USB_ControlXferComplete()\n");*/ + if (pDevReg->ControlDesControl & CTRLXFER_CMDVALID) { + ep->toggle_bit = 1; + if (udc->usb_connect == 0) { + if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { + udc->gadget.speed = USB_SPEED_FULL; + udc->usb_connect = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + //wmt_udc_csr(udc); + VDBG("devstate_irq() - full speed host connect...\n"); + USBState = USBSTATE_DEFAULT; + } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ + + if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { + udc->gadget.speed = USB_SPEED_HIGH; + udc->usb_connect = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + //wmt_udc_csr(udc); + VDBG("devstate_irq() - high speed host connect...\n"); + USBState = USBSTATE_DEFAULT; + } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ + } + /* HP11_Begin*/ + /* clear the command valid bit*/ + /* pDevReg->ControlDesControl |= CTRLXFER_CMDVALID;*/ + /* always clear control stall when SETUP received*/ + pDevReg->ControlEpControl &= 0x17; /* clear the stall*/ + wmb(); + ControlState = CONTROLSTATE_DATA; + udc_control_prepare_data_resp(); /*processing SETUP command ...*/ + pDevReg->ControlDesControl &= 0xEF;/*(~CTRLXFER_CMDVALID);*/ + wmb(); + /*HP11_End*/ + return; + } + + if (udc->ep0_in) { + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + VDBG("dma_irq : finish_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ + ; + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + VDBG("dma_irq : next_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); + next_in_dma(ep, req); + } + } else {/*ep0 out*/ + /* OUT dma: rx from host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_out_dma(ep, req, 0); + } + + while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ + ; + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_out_dma(ep, req); + } + } + +} /*void USB_ControlXferComplete(void)*/ +static irqreturn_t +wmt_udc_dma_irq(int irq, void *_udc)//, struct pt_regs *r) +{ + irqreturn_t status = IRQ_NONE; + u32 bulk_dma_csr; + + bulk_dma_csr = pUdcDmaReg->DMA_ISR; + /*printk("[udc_dma_isr]dma int_sts = 0x%8.8x\n",pUdcDmaReg->DMA_ISR);*/ + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS0) { + /* printk("[udc_dma_isr]channel0 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control0);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS0; + status = IRQ_HANDLED; + } + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS1) { + /* printk("[udc_dma_isr]channel1 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control1);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS1; + status = IRQ_HANDLED; + } + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS2) { + /* printk("[udc_dma_isr]channel2 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control2);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS2; + //printk("iso dma hit\n"); + dma_irq(0x84); + status = IRQ_HANDLED; + } + return status; +} + +static irqreturn_t +wmt_udc_irq(int irq, void *_udc)//, struct pt_regs *r) +{ + struct vt8500_udc *udc = _udc; + u32 udc_irq_src; + irqreturn_t status = IRQ_NONE; +// unsigned long flags; +#ifdef OTGIP + u32 global_irq_src; +#endif + /*u32 i;*/ + + spin_lock_irqsave(&udc->lock, irq_flags); + + DBG("wmt_udc_irq()\n"); + +#ifdef OTGIP + /*Global Interrupt Status*/ + global_irq_src = pGlobalReg->UHDC_Interrupt_Status; + + if (global_irq_src & UHDC_INT_UDC) {/*UDC Core + UDC DMA1 + UDC DMA2 */ + if (global_irq_src & UHDC_INT_UDC_CORE) {/*UDC Core*/ +#endif + /*connection interrupt*/ + if (pDevReg->SelfPowerConnect & 0x02) { + //struct usb_gadget_driver *driver = udc->driver; + + if (pDevReg->SelfPowerConnect & 0x01) //connect + { +// wmt_pdma_reset(); +reset_udc(); +//pullup_enable(udc); + } + else {//disconnct +// spin_unlock_irqrestore(&udc->lock, irq_flags); +// if (udc->driver) +// udc->driver->disconnect(&udc->gadget); +// ppudc = udc; + printk(KERN_INFO "disconnect 1\n"); //gri + run_script(action_off_line); + gadget_connect=0; + +// pullup_disable(udc); + + } + + status = IRQ_HANDLED; + pDevReg->SelfPowerConnect |= 0x02; + } + wmb(); + /* Device Global Interrupt Pending Status*/ + udc_irq_src = pDevReg->CommandStatus; + + /* Device state change (usb ch9 stuff)*/ + if (udc_irq_src & USBREG_BUSACTINT) {/* the bus activity interrupt occured*/ + /*caused by Port 0 Statsu Change*/ + devstate_irq(_udc, udc_irq_src); + status = IRQ_HANDLED; + pDevReg->CommandStatus |= USBREG_BUSACTINT; + wmb(); + } + + if (udc_irq_src & USBREG_BABBLEINT) {/* the Babble interrupt ocuured*/ + /* check for Control endpoint for BABBLE error*/ + if (pDevReg->ControlEpControl & EP_BABBLE) { + /* the Control endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->ControlEpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP0 Babble Detect!\n"); + udc->ep[0].stopped = 1; + udc->ep[0].stall = 1; + } + + if (pDevReg->Bulk1EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk1EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP1 Babble Detect!\n"); + udc->ep[1].stopped = 1; + udc->ep[1].stall = 1; + } + + if (pDevReg->Bulk2EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk2EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP2 Babble Detect!\n"); + udc->ep[2].stopped = 1; + udc->ep[2].stall = 1; + } + + if (pDevReg->Bulk3EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk3EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP3 Babble Detect!\n"); + udc->ep[3].stopped = 1; + udc->ep[3].stall = 1; + } + wmb(); + status = IRQ_HANDLED; + } + + if (udc_irq_src & USBREG_COMPLETEINT) {/* the complete inerrupt occured*/ + if (pDevReg->ControlEpControl & EP_COMPLETEINT) { + /* the control transfer complete event*/ + pDevReg->ControlEpControl |= EP_COMPLETEINT; /* clear the event*/ + wmb(); + USB_ControlXferComplete(); +#if 0 + gadget_connect=1; +#endif + + } + + if (pDevReg->Bulk1EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk1EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 1 DMA()\n");*/ + dma_irq(0x81); +#if 1 + gadget_connect=1; +#endif + } + + if (pDevReg->Bulk2EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk2EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 2 DMA()\n");*/ + dma_irq(2); +#if 1 + gadget_connect=1; +#endif + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (pDevReg->Bulk3EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk3EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 3 DMA()\n");*/ + dma_irq(0x83); +#if 1 + gadget_connect=1; +#endif + } +#else + if (pDevReg->InterruptEpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->InterruptEpControl |= EP_COMPLETEINT; + /*DBG("USB_INT 3 DMA()\n");*/ + if (f_ep3_used == 3) + dma_irq(0x83); +#if 1 + gadget_connect=1; +#endif + } +#endif + status = IRQ_HANDLED; + } + + if (udc->ep0_status_0_byte == 1)/* && (udc_ep[0].stall==0))*/ + ep0_status(udc); + + if (ControlState == CONTROLSTATE_STATUS) { + /* checking for test mode*/ + if (TestMode != 0x00) { +#if 0 + pDevReg->CommandStatus &= 0x1F; + wmb(); + pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) + ; + /* HW attach process evaluation enable bit*/ +#if 0 + pDevReg->FunctionPatchEn |= 0x20; + /* Device port control register - 22*/ + pDevReg->PortControl |= PORTCTRL_SELFPOWER; + wmb(); +#else + pullup_enable(udc); + pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + wmb(); + //msleep(1000); +#endif +#endif + wmb(); + udelay(1000); + /*GigaHsu 2008.1.26 : Don't set RUN bit while TestMode enable*/ + /* setting the test mode*/ + switch (TestMode) { + case UDC_TEST_MODE_NOT_ENABLED:/*0*/ + INFO("UDC_TEST_MODE_NOT_ENABLED (0x%02X)\n", TestMode); + break; + + case UDC_TEST_J_STATE:/*1*/ + pDevReg->CommandStatus = USBREG_TEST_J; + INFO("UDC_TEST_J_STATE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_K_STATE:/*2*/ + pDevReg->CommandStatus = USBREG_TEST_K; + INFO("UDC_TEST_K_STATE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_SE0_NAK:/*3*/ + pDevReg->CommandStatus = USBREG_SE0_NAK; + INFO("UDC_TEST_SE0_NAK wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_PACKET:/*4*/ + pDevReg->CommandStatus = USBREG_TESTPACKET; + INFO("UDC_TEST_PACKET wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_FRORCE_ENABLE:/*5*/ + pDevReg->CommandStatus = USBREG_FORCEENABLE; + INFO("UDC_TEST_FRORCE_ENABLE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_EYE_PATTERN:/*6*/ + pDevReg->CommandStatus = USBREG_TESTEYE; + INFO("UDC_TEST_EYE_PATTERN wIndex(0x%02X)\n", TestMode); + break; + } /*switch(TestMode)*/ + + INFO("UDC - CommandStatus(0x%02X)\n", pDevReg->CommandStatus); + /* stop the 8051*/ + /*ChipTopRegister.Config |= CT_STOP8051;*/ + } + ControlState = CONTROLSTATE_SETUP; /* go back SETUP state*/ + } +#ifdef OTGIP + } + + global_irq_src = pGlobalReg->UHDC_Interrupt_Status; + if (global_irq_src & UHDC_INT_UDC_DMA1)/*UDC Bulk DMA 1*/ + status = wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + +// if (global_irq_src & UHDC_INT_UDC_DMA2)/*UDC Bulk DMA 1*/ +// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + +// if (global_irq_src & UHDC_INT_UDC_DMA3)/*UDC Bulk DMA 1*/ +// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + + } +#endif + spin_unlock_irqrestore(&udc->lock, irq_flags); + //printk("udc s =0x%x\n",pGlobalReg->UHDC_Interrupt_Status); + + return status; +} /*wmt_udc_irq()*/ + +/* workaround for seemingly-lost IRQs for RX ACKs... */ +#define PIO_OUT_TIMEOUT (jiffies + HZ/3) + +#ifdef DEBUG_UDC_ISR_TIMER +static void wmt_udc_softirq(unsigned long _udc) +{ + struct vt8500_udc *udc = (void *) _udc; + /*unsigned long flags;*/ + struct pt_regs r; + + INFO("wmt_udc_softirq()\n"); + wmt_udc_irq(UDC_IRQ_USB, udc, &r); + mod_timer(&udc->timer, PIO_OUT_TIMEOUT); + +} +#endif + +static void __init wmt_ep_setup(char *name, u8 addr, u8 type, unsigned maxp); + +static int wmt_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) + +{ + int status = -ENODEV; + struct vt8500_ep *ep; +// unsigned long flags; + + DBG("wmt_udc_start()\n"); + + /* basic sanity tests */ + if (!udc) + return -ENODEV; + if (!driver + /* FIXME if otg, check: driver->is_otg*/ + || driver->max_speed < USB_SPEED_FULL + || !bind +// || !driver->unbind + || !driver->setup){ +// printk(KERN_INFO "gri usb_gadget_probe_driver f2\n"); +// printk(KERN_INFO "gri driver=%x driver->speed=%x driver->bind=%x driver->unbind=%x driver->setup=%x\n", +// (unsigned int)driver,(unsigned int)driver->speed,(unsigned int)driver->bind,(unsigned int)driver->unbind,(unsigned int)driver->setup); + return -EINVAL; + } + + spin_lock_irqsave(&udc->lock, irq_flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, irq_flags); + return -EBUSY; + } + + /* reset state */ + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + ep->irqs = 0; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + continue; + /*use_ep(ep, 0);*/ + /*UDC_CTRL_REG = UDC_SET_HALT;*/ + } + udc->ep0_pending = 0; + udc->ep0_status_0_byte = 0; + udc->ep[0].irqs = 0; + udc->softconnect = 1; + udc->file_storage_set_halt = 0; + /* hook up the driver */ + driver->driver.bus = 0; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, irq_flags); + + status = bind(&udc->gadget); + spin_lock_irqsave(&udc->lock, irq_flags); +printk(KERN_INFO "bind to %s --> %d\n", driver->driver.name, status); + + if (status) { + /* %s -> g_file_storage*/ + DBG("bind to %s --> %d\n", driver->driver.name, status); +// printk(KERN_INFO "gri usb_gadget_probe_driver %d\n", status); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + + DBG("bound to driver %s\n", driver->driver.name);/*udc: bound to driver g_file_storage*/ + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + + *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ + wmb(); +#if 0 + /* reset Bulk descriptor control*/ + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk1EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk2EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk3EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; + + /* enable DMA and run the control endpoint*/ + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif +#endif + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + + + pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ + wmb(); + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + wmb(); + + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); +#if 0 + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif + wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISO, 384); +#endif + + /* enable all interrupt*/ +#ifdef FULL_SPEED_ONLY + pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ +#else + pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ +#endif + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl = CTRLXFER_IOC; + wmt_pdma_reset();/*NeilChen*/ + +// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + +#ifdef DEBUG_UDC_ISR_TIMER + init_timer(&udc->timer); + udc->timer.function = wmt_udc_softirq; + udc->timer.data = (unsigned long) udc; + add_timer(&udc->timer); +#endif + +done: + spin_unlock_irqrestore(&udc->lock, irq_flags); + return status; +} /*int wmt_udc_start ()*/ + +static int wmt_udc_stop(struct usb_gadget_driver *driver) +{ +// unsigned long flags; + int status = -ENODEV; + + if (!udc) + return -ENODEV; + if (!driver || driver != udc->driver) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, irq_flags); + udc_quiesce(udc); + spin_unlock_irqrestore(&udc->lock, irq_flags); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + + pDevReg->IntEnable &= 0x8F;/*INTENABLE_ALL(0x70)*/ + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl &= 0x7F;/*CTRLXFER_IOC;*/ + + if (udc->transceiver) + (void) otg_set_peripheral(udc->transceiver->otg, NULL); + else { + pullup_disable(udc); +// pDevReg->FunctionPatchEn &= ~0x20; + } + + if (TestMode != 0x00) { + pDevReg->CommandStatus &= 0x1F; + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + *pUSBMiscControlRegister5 = 0x00;/* USB PHY in power down & USB in reset*/ + + INFO("usb_gadget_unregister_driver() RESET_UDC OK!\n"); + TestMode = 0; + } + + DBG("unregistered driver '%s'\n", driver->driver.name); + return status; +} /*int wmt_udc_stop ()*/ + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_vt8500_PROC + +#include <linux/seq_file.h> + +static const char proc_filename[] = "driver/udc"; + +#define FOURBITS "%s%s%s%s" +#define EIGHTBITS FOURBITS FOURBITS + +static void proc_ep_show(struct seq_file *s, struct vt8500_ep *ep) +{ + +} /*proc_ep_show()*/ + + +static char *trx_mode(unsigned m) +{ + switch (m) { + case 3: + case 0: return "6wire"; + case 1: return "4wire"; + case 2: return "3wire"; + default: return "unknown"; + } +} + +static int proc_udc_show(struct seq_file *s, void *_) +{ + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, 0); +} + +static struct file_operations proc_ops = { + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_proc_file(void) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry(proc_filename, 0, NULL); + if (pde) + pde->proc_fops = &proc_ops; +} + +static void remove_proc_file(void) +{ + remove_proc_entry(proc_filename, 0); +} + +#else + +static inline void create_proc_file(void) {} +static inline void remove_proc_file(void) {} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* Before this controller can enumerate, we need to pick an endpoint + * configuration, or "fifo_mode" That involves allocating 2KB of packet + * buffer space among the endpoints we'll be operating. + */ +static void __init +wmt_ep_setup(char *name, u8 addr, u8 type, + unsigned maxp) +{ + struct vt8500_ep *ep; + + VDBG("wmt_ep_setup()\n"); + + /* OUT endpoints first, then IN*/ + ep = &udc->ep[addr & 0x7f]; + + VDBG("wmt_ep_setup() - %s addr %02x maxp %d\n", + name, addr, maxp); + + strlcpy(ep->name, name, sizeof ep->name); + INIT_LIST_HEAD(&ep->queue); + ep->bEndpointAddress = addr; + ep->bmAttributes = type; + ep->double_buf = 0;/*dbuf;*/ + ep->udc = udc; + ep->toggle_bit = 0; + ep->ep.name = ep->name; + ep->ep.ops = &wmt_ep_ops;/*struct usb_ep_ops*/ + ep->ep.maxpacket = ep->maxpacket = maxp; + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + + /*return buf;*/ +} /*wmt_ep_setup()*/ + +static void wmt_udc_release(struct device *dev) +{ + DBG("wmt_udc_release()\n"); + complete(udc->done); + kfree(udc); + udc = 0; +} /*wmt_udc_release()*/ + +static int __init +wmt_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) +{ + DBG("wmt_udc_setup()\n"); + udc = kmalloc(sizeof *udc, GFP_KERNEL); + + if (!udc) + return -ENOMEM; + + memset(udc, 0, sizeof *udc); + spin_lock_init(&udc->lock); + + spin_lock_init(&gri_lock); + + sema_init(&wmt_udc_sem, 1); + + udc->gadget.ops = &wmt_gadget_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + INIT_LIST_HEAD(&udc->gadget.ep_list); + /*INIT_LIST_HEAD(&udc->iso);*/ + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.name = driver_name; + + device_initialize(&udc->gadget.dev); + //strcpy(udc->gadget.dev.bus_id, "gadget"); + dev_set_name(&udc->gadget.dev, "gadget"); + udc->gadget.dev.release = wmt_udc_release; + udc->transceiver = NULL; + /* ep0 is special; put it right after the SETUP buffer*/ + wmt_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); + + list_del_init(&udc->ep[0].ep.ep_list); + +#if 1 +#if 1 +#define VT8430_BULK_EP(name, addr) \ + wmt_ep_setup(name "-bulk", addr, \ + USB_ENDPOINT_XFER_BULK, 512); + +/*usb_ch9.h*/ +/*#define USB_DIR_OUT 0 *//* to device */ +/*#define USB_DIR_IN 0x80 *//* to host */ +#define VT8430_INT_EP(name, addr, maxp) \ + wmt_ep_setup(name "-int", addr, \ + USB_ENDPOINT_XFER_INT, maxp); + +#define VT8430_ISO_EP(name, addr, maxp) \ + wmt_ep_setup(name "-iso", addr, \ + USB_ENDPOINT_XFER_ISOC, maxp); +#endif + + VT8430_BULK_EP("ep1in", USB_DIR_IN | 1); + VT8430_BULK_EP("ep2out", USB_DIR_OUT | 2); +#ifdef USE_BULK3_TO_INTERRUPT + VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 512); +#else + VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 8); +#endif + VT8430_ISO_EP("ep4in", USB_DIR_IN | 4, 512); +#endif + udc->ep[0].rndis_buffer_alloc = 0; + udc->ep[1].rndis_buffer_alloc = 0; + udc->ep[2].rndis_buffer_alloc = 0; + udc->ep[3].rndis_buffer_alloc = 0; + udc->ep[4].rndis_buffer_alloc = 0; + udc->ep[5].rndis_buffer_alloc = 0;//gri + udc->ep[6].rndis_buffer_alloc = 0;//gri + + /*INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);*/ + return 0; +} /*wmt_udc_setup()*/ + +static void wmt_pdma_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + +static void wmt_pdma0_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset0 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset0)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + + +static void wmt_pdma1_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset1 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset1)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + +#ifdef USE_BULK3_TO_INTERRUPT +static void wmt_pdma2_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset2 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset2)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ +#endif + + +/*static void wmt_pdma_init(struct device *dev)*/ +static void wmt_pdma_init(struct device *dev) +{ + UdcRndisEp1VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp1PhyAddr), GFP_KERNEL|GFP_ATOMIC); + UdcRndisEp2VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp2PhyAddr), GFP_KERNEL|GFP_ATOMIC); + UdcRndisEp3VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp3PhyAddr), GFP_KERNEL|GFP_ATOMIC); + + UdcPdmaVirAddrLI = (unsigned int) dma_alloc_coherent(pDMADescLI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLI), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrSI = (unsigned int) dma_alloc_coherent(pDMADescSI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSI), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrLO = (unsigned int) dma_alloc_coherent(pDMADescLO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLO), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrSO = (unsigned int) dma_alloc_coherent(pDMADescSO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSO), GFP_KERNEL|GFP_ATOMIC); + +#ifdef USE_BULK3_TO_INTERRUPT + UdcPdmaVirAddrL2I = (unsigned int) dma_alloc_coherent(pDMADescL2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrL2I), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrS2I = (unsigned int) dma_alloc_coherent(pDMADescS2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrS2I), GFP_KERNEL|GFP_ATOMIC); +#endif + + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ + ; + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + +#ifdef USE_BULK3_TO_INTERRUPT + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; +#endif + wmb(); + +} /*wmt_pdma_init*/ + +/*static int __init wmt_udc_probe(struct device *dev)*/ +static int __init wmt_udc_probe(struct platform_device *pdev) +{ +/* struct platform_device *odev = to_platform_device(dev);*/ + struct device *dev = &pdev->dev; + int status = -ENODEV; + struct usb_phy *xceiv = 0; + + DBG("wmt_udc_probe()\n"); + + /*UDC Register Space 0x400~0x7EF*/ + + INIT_LIST_HEAD (&done_main_list); + + b_pullup = 0; + + pDevReg = (struct UDC_REGISTER *)USB_UDC_REG_BASE; + pUdcDmaReg = (struct UDC_DMA_REG *)USB_UDC_DMA_REG_BASE; + pSetupCommand = (PSETUPCOMMAND)(USB_UDC_REG_BASE + 0x300); + pSetupCommandBuf = (unsigned char *)(USB_UDC_REG_BASE + 0x300); + SetupBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x340); + IntBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x40); + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + +#ifdef OTGIP + /*UHDC Global Register Space 0x7F0~0x7F7*/ + pGlobalReg = (struct USB_GLOBAL_REG *) USB_GLOBAL_REG_BASE; +#endif + + *pUSBMiscControlRegister5 = 0x01; + pDevReg->CommandStatus &= 0x1F; + pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + wmb(); + while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) + ; + + wmt_pdma_init(dev); + + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; +#endif + + /* enable DMA and run the control endpoint*/ + wmb(); + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif + wmb(); + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + + /* HW attach process evaluation enable bit For WM3426 and after project*/ + /*pDevReg->FunctionPatchEn |= 0x20;*/ +#ifdef HW_BUG_HIGH_SPEED_PHY + pDevReg->MiscControl0 &= ~0x80; +#endif + pDevReg->MiscControl0 |= 0x02; + wmb(); + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + status = wmt_udc_setup(pdev, xceiv); + if (status) + goto cleanup0; + + xceiv = 0; + + /*udc->chip_version = tmp8;*/ + /* "udc" is now valid*/ + pullup_disable(udc); + + udc->gadget.is_otg = 0;/*(config->otg != 0);*/ + udc->dev = dev; + udc->gadget.max_speed = USB_SPEED_HIGH;; + udc->ep0_status_0_byte = 0; + udc->usb_connect = 0; + /* USB general purpose IRQ: ep0, state changes, dma, etc*/ + status = request_irq(UDC_IRQ_USB, wmt_udc_irq, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);//gri + pDevReg->SelfPowerConnect |= 0x10;//Neil + +#ifndef OTGIP + status = request_irq(UDC_IRQ_DMA, wmt_udc_dma_irq, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); +#endif + /*SA_SAMPLE_RANDOM, driver_name, udc);*/ + if (status != 0) { + ERR("can't get irq %d, err %d\n", + UDC_IRQ_USB, status); + goto cleanup1; + } else + INFO("wmt_udc_probe - request_irq(0x%02X) pass!\n", UDC_IRQ_USB); + + create_proc_file(); + status = device_add(&udc->gadget.dev); + if (status) + goto cleanup4; + + status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + initial_test_fiq(); + if (!status) + return 0; + +cleanup4: + remove_proc_file(); + +/*cleanup2:*/ + free_irq(UDC_IRQ_USB, udc); + INFO("wmt_udc_probe - free_irq(0x%02X)?\n", UDC_IRQ_USB); +cleanup1: + kfree(udc); + udc = 0; + +cleanup0: + if (xceiv) + usb_put_transceiver(xceiv); + /*release_mem_region(odev->resource[0].start,*/ + /* odev->resource[0].end - odev->resource[0].start + 1);*/ + return status; + +} /*wmt_udc_probe()*/ + +static int __exit wmt_udc_remove(struct platform_device *pdev) +{ + /*struct platform_device *odev = to_platform_device(dev);*/ + DECLARE_COMPLETION(done); + DBG("wmt_udc_remove()\n"); + + if (!udc) + return -ENODEV; + + udc->done = &done; + + pullup_disable(udc); + if (udc->transceiver) { + usb_put_transceiver(udc->transceiver); + udc->transceiver = 0; + } + /*UDC_SYSCON1_REG = 0;*/ + + remove_proc_file(); + + free_irq(UDC_IRQ_USB, udc); + + device_unregister(&udc->gadget.dev); + wait_for_completion(&done); + + return 0; +} /*wmt_udc_remove()*/ + +/* suspend/resume/wakeup from sysfs (echo > power/state) */ + +static int +wmt_udc_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) +{ + + + if (event == PM_SUSPEND_PREPARE) { + if (udc->driver){ + run_script(action_off_line); + } + gadget_connect=0; + down(&wmt_udc_sem); + pullup_disable(udc); + up(&wmt_udc_sem); + } + else if (event == PM_POST_SUSPEND) { + + down(&wmt_udc_sem); + pullup_enable(udc); + up(&wmt_udc_sem); + + wmt_wakeup(&udc->gadget); + } + + return NOTIFY_OK; +} + + +static struct notifier_block wmt_udc_pm_notifier = { + .notifier_call = wmt_udc_pm_notify, +}; + + + + +static int wmt_udc_suspend(struct platform_device *pdev, pm_message_t state) +{ + DBG("wmt_udc_suspend()\n"); + printk(KERN_INFO "wmt_udc_suspend\n"); //gri +#if 0 + if (udc->driver){ + run_script(action_off_line); + } + gadget_connect=0; + run_script(action_mount); +#endif + pDevReg->CommandStatus &= 0x1F; + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + /**pUSBMiscControlRegister5 = 0x02;// USB PHY in power down & USB in reset*/ + *pUSBMiscControlRegister5 = 0x00;/*USB in reset*/ + wmb(); + + TestMode = 0; +#if 0 + down(&wmt_udc_sem); + pullup_disable(udc); + up(&wmt_udc_sem); +#endif + +/* if ((state == 3) && (level == 3))*/ +/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) &= ~0x00000080;*/ /*DPM needed*/ + *(volatile unsigned char*)(USB_IP_BASE + 0x249) |= 0x04; + + return 0; + +} /*wmt_udc_suspend()*/ + +static int wmt_udc_resume(struct platform_device *pdev) +{ +#if 0 + DBG("wmt_udc_resume()\n"); + printk(KERN_INFO "wmt_udc_resume\n"); //gri + down(&wmt_udc_sem); + reset_udc(); + pullup_enable(udc); + up(&wmt_udc_sem); + + return wmt_wakeup(&udc->gadget); +#endif + reset_udc(); + return 0; + +} /*wmt_udc_resume()*/ + +/*-------------------------------------------------------------------------*/ + +static struct platform_driver udc_driver = { + .driver.name = (char *) driver_name, + .probe = wmt_udc_probe, + .remove = __exit_p(wmt_udc_remove), + .suspend = wmt_udc_suspend, + .resume = wmt_udc_resume, +}; + +static struct resource wmt_udc_resources[] = { + [0] = { + .start = (USB_IP_BASE + 0x2000), + .end = (USB_IP_BASE + 0x2400), + .flags = IORESOURCE_MEM, + }, +}; +static u64 wmt_udc_dma_mask = 0xFFFFF000; + +static struct platform_device wmt_udc_device = { + .name = (char *) driver_name, + .id = 0, + .dev = { + .dma_mask = &wmt_udc_dma_mask, + .coherent_dma_mask = ~0, + }, + .num_resources = ARRAY_SIZE(wmt_udc_resources), + .resource = wmt_udc_resources, +}; + +void wmt_cleanup_done_thread(int number) +{ + unsigned long flags; + struct usb_composite_dev *cdev = get_gadget_data(&(udc->gadget)); +#if 1 + if(number == 1) + { + if(in_interrupt()) + return; + if(spin_is_locked(&cdev->lock)){ + //local_irq_save(flags); + spin_unlock(&cdev->lock); + //local_irq_enable(); + //schedule_work(&done_thread); + flush_work_sync(&done_thread); + //local_irq_restore(flags); + spin_lock(&cdev->lock); + }else{ + flush_work_sync(&done_thread); + } + //wmt_ep_disable(&udc->ep[0]); + spin_lock_irqsave(&udc->lock, flags); + nuke(&udc->ep[0],ESHUTDOWN); + spin_unlock_irqrestore(&udc->lock, flags); + }else if(number == 2) + { + }else{ + //flush_work_sync(&mount_thread); + printk("erro parameter:%s\n",__func__); + } +#endif +} +EXPORT_SYMBOL(wmt_cleanup_done_thread); + +static int __init udc_init(void) +{ + INFO("%s, version: " DRIVER_VERSION + "%s\n", driver_desc, + use_dma ? " (dma)" : ""); + + DBG("udc_init()\n"); + +//INIT_WORK(&online_thread, run_online); +INIT_WORK(&offline_thread, run_offline); +INIT_WORK(&done_thread, run_done); +INIT_WORK(&chkiso_thread, run_chkiso); + +platform_device_register(&wmt_udc_device); + + register_pm_notifier(&wmt_udc_pm_notifier); + + return platform_driver_register(&udc_driver); +} /*udc_init()*/ + +module_init(udc_init); + +static void __exit udc_exit(void) +{ + DBG("udc_exit()\n"); + //driver_unregister(&udc_driver); + platform_driver_unregister(&udc_driver); + platform_device_unregister(&wmt_udc_device); +} /*udc_exit()*/ + +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h new file mode 100755 index 00000000..c566f3cd --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h @@ -0,0 +1,801 @@ +/* + * wmt_udc.c -- for WonderMedia Technology udc + * + * Copyright (C) 2007 VIA Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_USB_GADGET_VT8500_H +#define __LINUX_USB_GADGET_VT8500_H + +#include <linux/types.h> +/*#include <stdio.h>*/ +/*#include <stdlib.h>*/ +/*#include <string.h>*/ +#include <mach/hardware.h> +#include <asm/irq.h> + +#define OTGIP + +#define UINT volatile unsigned int +#define USHORT volatile unsigned short +#define UCHAR volatile unsigned char +#define ULL volatile unsigned long long + +#define UDC_IRQ_USB IRQ_UHDC + +#ifndef OTGIP +#define UDC_IRQ_DMA 2 +#endif +/*#define DWORD volatile unsigned long*/ +/*#define WORD volatile unsigned short*/ +/*#define BYTE volatile unsigned char*/ +#define USB_IP_BASE USB20_HOST_DEVICE_CFG_BASE_ADDR +/*UDC Register Space 0x400~0x7EF*/ +#define USB_UDC_REG_BASE (USB_IP_BASE + 0x400) +/*Bulk Endpoint DMA Register Space 0x100*/ +#define USB_UDC_DMA_REG_BASE (USB_IP_BASE + 0x500) +#ifdef OTGIP +/*UHDC Global Register Space 0x7F0~0x7F7*/ +#define USB_GLOBAL_REG_BASE (USB_IP_BASE + 0x7f0) +#endif + +#define UDC_REG(offset) REG32_PTR(USB_UDC_REG_BASE + offset) + +#define OTG_HOST_MEM_BASE 0x01400000/*20MB*/ + +#define USB_EP0_CTRL_DMA_BASE OTG_HOST_MEM_BASE /*64 bytes*/ +#define USB_EP1_BULK_IN_DMA_BASE 0x01400040/*OTG_HOST_MEM_BASE + 64 */ /*64B +64KB*/ +#define USB_EP2_BULK_OUT_DMA_BASE 0x01410040/*OTG_HOST_MEM_BASE + 65536*/ /* ~ END*/ +#define USB_DOWNLOAD_KERNEL_RAM_ADDR USB_EP2_BULK_OUT_DMA_BASE + +/* Basic Define*/ +#define REG32 *(volatile unsigned int *) +#define REG16 *(volatile unsigned short *) +#define REG8 *(volatile unsigned char *) + +#define REG_GET32(addr) ( REG32(addr) ) /* Read 32 bits Register */ +#define REG_GET16(addr) ( REG16(addr) ) /* Read 16 bits Register */ +#define REG_GET8(addr) ( REG8(addr) ) /* Read 8 bits Register */ + +#define REG_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Register */ +#define REG_SET16(addr, val) ( REG16(addr) = (val) ) /* Write 16 bits Register */ +#define REG_SET8(addr, val) ( REG8(addr) = (val) ) /* Write 8 bits Register */ + +#define MEM_GET32(addr) ( REG32(addr) ) /* Read 32 bits Memory */ +#define MEM_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Memory */ + +/*#define USB_TIMEOUT 0x100*/ /*256*/ +/*#define USB_TEST_SUCCESS 1*/ +/*#define USB_TEST_FAIL 0*/ + +/* define the state of the USB device*/ +#define USBSTATE_ATTACHED 0x00 /* device attached to host*/ +#define USBSTATE_POWERED 0x01 /* device obtain power*/ +#define USBSTATE_DEFAULT 0x02 /* default working state*/ +#define USBSTATE_ADDRESS 0x04 /* device has get the address*/ +#define USBSTATE_CONFIGED 0x10 /* deivce has set the configuration*/ +#define USBSTATE_SUSPEND 0x20 /* No bus activity device goes to suspend */ + +#define UDC_TEST_J_STATE 1 +#define UDC_TEST_K_STATE 2 +#define UDC_TEST_SE0_NAK 3 +#define UDC_TEST_PACKET 4 +#define UDC_TEST_FRORCE_ENABLE 5 +#define UDC_TEST_EYE_PATTERN 6 +#define UDC_TEST_MODE_NOT_ENABLED 0 + +/*Define the USB register bit value*/ +/* USB device commmand/status register - 20*/ +#define USBREG_RUNCONTROLLER 0x01 /* set the controller run*/ +#define USBREG_RESETCONTROLLER 0x02 /* reset the device contrller*/ +#define USBREG_COMPLETEINT 0x04 /* the completion interrupt*/ +#define USBREG_BABBLEINT 0x08 /* the babble interrupt*/ +#define USBREG_BUSACTINT 0x10 /* the bus activity interrupt*/ +#define USBREG_TEST_J 0x20 /* set test J state*/ +#define USBREG_TEST_K 0x40 /* set test k state*/ +#define USBREG_SE0_NAK 0x60 /* set test SE0 and NAK*/ +#define USBREG_TESTPACKET 0x80 /* set device sending test packet*/ +#define USBREG_FORCEENABLE 0xA0 /* force port enable*/ +#define USBREG_TESTEYE 0xC0 /* Send test eye pattern packet*/ + +/* The device address register - 21*/ +#define DEVADDR_ADDRCHANGE 0x80 /* the address change bit for device address register*/ + +/* Device port control register - 22*/ +#define PORTCTRL_CONNECTSTATUS 0x01 /* current connection status*/ +#define PORTCTRL_CONNECTCHANGE 0x02 /* connection change bit*/ +#define PORTCTRL_SELFPOWER 0x04 /* the device is in the self power configuration*/ +#define PORTCTRL_FORCERESUME 0x08 /* force deivce to wake the host*/ +#define PORTCTRL_HIGHSPEEDMODE 0x10 /* device is in the high speed mode*/ +#define PORTCTRL_FULLSPEEDMODE 0x20 /* device is in the full speed mode*/ + +/* Device itnerrupt enable register - 23*/ +#define INTENABLE_DEVICERESET 0x01 /* this bit is set when the bus reset is completed*/ +#define INTENABLE_SUSPENDDETECT 0x02 /* device controller detect the suspend signal*/ +#define INTENABLE_RESUMEDETECT 0x04 /* device controller detect the resume signal*/ +#define INTENABLE_COMPLETEINTEN 0x10 /* enable completion interrupt*/ +#define INTENABLE_BABBLEINTEN 0x20 /* enable babble interrupt*/ +#define INTENABLE_BUSACTINTEN 0x40 /* enable bus activity interrupt*/ +#define INTENABLE_ALL 0x70 /* enable all interrupt */ +#define INTENABLE_FULLSPEEDONLY 0x80 /* force device to support full speed only*/ + +/* Control endpoint control - 24*/ +/* Bulk endpoint control - 28*/ +/* Interrupt endpoint control - 2C*/ +/* Bulk endpoint control - 0x310*/ +#define EP_RUN 0x01 /* run the enpoint DMA*/ +#define EP_ENABLEDMA 0x02 /* enable the DMA engine to run the schedule*/ +#define EP_DMALIGHTRESET 0x04 /* light reset the DMA engine*/ +#define EP_STALL 0x08 /* set the endpoint to stall*/ +#define EP_ACTIVE 0x10 /* the endpoint DMA is active*/ +#define EP_COMPLETEINT 0x20 /* endpoint transfer complete interrupt*/ +#define EP_BABBLE 0x40 /* endpoint babble interrupt*/ + +/* Control transfer descriptor status byte - 30*/ +#define CTRLXFER_XACTERR 0x01 /* trnasacion error of control transfer*/ +#define CTRLXFER_BABBLE 0x02 /* babbe error of control transfer*/ +#define CTRLXFER_SHORTPKT 0x04 /* shortpacket detect of control transfer*/ +#define CTRLXFER_ACTIVE 0x08 /* transfer active of control transfer*/ + +#define CTRLXFER_IN 0x08 /* I/O control bit 0 for OUT , 1 for In*/ +#define CTRLXFER_OUT 0x00 /**/ +#define CTRLXFER_CMDVALID 0x10 /* setup command is valid*/ +#define CTRLXFER_IOC 0x80 /* determine to gen interrupt for completion or not*/ +#define CTRLXFER_DATA1 0x80 /* for data_toggle 1*/ +#define CTRLXFER_DATA0 0x00 /* for data_toggle 0*/ + +/* Bulk endpoint transfer descriptor status - 34*/ +/* Bulk endpoint transfer descriptor status - 0x314 */ +#define BULKXFER_XACTERR 0x01 /* trnasacion error of bulk transfer*/ +#define BULKXFER_BABBLE 0x02 /* babbe error of bulk transfer*/ +#define BULKXFER_SHORTPKT 0X04 /* shortpacket detect of bulk transfer*/ +#define BULKXFER_ACTIVE 0x08 /* transfer active of bulk transfer*/ +#define BULKXFER_IN 0x10 /* I/O control bit 0 for OUT , 1 for In*/ +#define BULKXFER_OUT 0x00 +/*HP05_Begin*/ +#define BULKXFER_CBWBUF 0x20 /* enable CBW dedicated buffer*/ +/*HP05_End*/ +#define BULKXFER_IOC 0x80 /* determine to generate interrupt for completion or not*/ +#define BULKXFER_DATA1 0x80 /* for data_toggle 1*/ +#define BULKXFER_DATA0 0x00 /* for data_toggle 0*/ + +/* Interupt endpoint transfer descriptor - 33*/ +#define INTXFER_XACTERR 0x01 /* trnasacion error for interrupt transfer*/ +#define INTXFER_ACTIVE 0x02 /* transfer active*/ +#define INTXFER_IOC 0x04 /* determine to generate interrupt for completion or not*/ +#define INTXFER_DATA1 0x08 /* for data_toggle 1*/ +#define INTXFER_DATA0 0x00 /* for data_toggle 0*/ + +/*UDC 0x400 ~ 0x7FF*/ +struct UDC_REGISTER{ + UCHAR Reserved0[0x20]; /* 0x00~0x19 Reserved 0*/ + UCHAR CommandStatus; /* USB device commmand/status register - 20*/ + UCHAR DeviceAddr; /* The device address register - 21*/ + + UCHAR PortControl; /* Device port control register - 22*/ + UCHAR IntEnable; /* Device itnerrupt enable register - 23*/ + + UCHAR ControlEpControl; /* Control endpoint control - 24*/ + UCHAR ControlEpReserved; /* Control endpoint reserved byte - 25*/ + UCHAR ControlEpMaxLen; /* max length of control endpoint - 26*/ + UCHAR ControlEpEpNum; /* The control endpoint number - 27*/ + + UCHAR Bulk1EpControl; /* Bulk endpoint control - 28*/ + UCHAR Bulk1EpOutEpNum; /* Bulk out endpoint number - 29*/ + UCHAR Bulk1EpMaxLen; /* Bulk maximum length - 2A*/ + UCHAR Bulk1EpInEpNum; /* Bulk In endpoint number - 2B*/ + + UCHAR InterruptEpControl; /* Interrupt endpoint control - 2C*/ + UCHAR InterruptReserved; /* Interrupt endpoint reserved byte - 2D*/ + UCHAR InterruptEpMaxLen; /* Interrupt maximum transfer length - 2E*/ + UCHAR InterruptEpEpNum; /* interrupt endpoint number - 2F*/ + + UCHAR ControlDesStatus; /* Control transfer descriptor status byte - 30*/ + UCHAR ControlDesControl; /* Control transfer descriptor control byte - 31*/ + UCHAR ControlDesTbytes; /* Control transfer descriptor total bytes - 32*/ + + UCHAR InterruptDes; /* Interupt endpoint transfer descriptor - 33*/ + + UCHAR Bulk1DesStatus; /* Bulk endpoint transfer descriptor status - 34*/ + UCHAR Bulk1DesTbytes0; /* Bulk endpoint transfer descriptor control - 35*/ + UCHAR Bulk1DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 36*/ + UCHAR Bulk1DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 37*/ + + UCHAR MacToParameter; /* USB2.0 MAC timeout parameter register - 38*/ + UCHAR PhyMisc; /* PHY misc control register - 39*/ + UCHAR MiscControl0; /* Misc. control register 0 - 3A*/ + UCHAR MiscControl1; /* Misc. control register 1 - 3B*/ + UCHAR MiscControl2; /* Misc. control register 2 - 3C*/ + UCHAR MiscControl3; /* Misc. control register 3 - 3D*/ + UCHAR MACDelay; /* MAC receiver enable delay parameter - 3E*/ + UCHAR FunctionPatchEn; /* Function Patch Enable bits - 3F*/ + + UCHAR InterruptInBuf[32]; /* Interrupt In Endpoint Data Buffer - 40 ~ 5F (32 bytes) for CBW(31 bytes)*/ + + UCHAR Reserved1[0x2A0]; /* 0x060~0x2FF ; 0x2FF - 0x60 + 1 = 0x2A0 for Bulk Endpoint 01 02 DMA Source / Destination*/ + UCHAR SetupCommand[8]; /* 0x300~0x307 */ + UCHAR PHYControlBit; /* 0x308 Phy Control Bit */ + UCHAR Reserved2[2]; /* 0x309 ~ 0x30A*/ + UCHAR NewUSBPhyTestControl;/* 0x30B New USB 1.1 and USB 2.0 PHY test control bit*/ + UCHAR NewUSBPhyTestStatus; /* 0x30C New USB 1.1 and USB 2.0 PHY test status bit*/ + UCHAR SelfPowerConnect; /* 0x30D Debug pins for USBC side control bit*/ + + UCHAR Reserved3[2]; /* 0x30E ~ 0x30F*/ + + UCHAR Bulk2EpControl; /* Bulk endpoint control - 0x310*/ + UCHAR Bulk2EpOutEpNum; /* Bulk out endpoint number - 0x311*/ + UCHAR Bulk2EpMaxLen; /* Bulk maximum length - 0x312*/ + UCHAR Bulk2EpInEpNum; /* Bulk In endpoint number - 0x313*/ + + UCHAR Bulk2DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ + UCHAR Bulk2DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ + UCHAR Bulk2DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ + UCHAR Bulk2DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ + + UCHAR Bulk3EpControl; /* Bulk endpoint control - 0x310*/ + UCHAR Bulk3EpOutEpNum; /* Bulk out endpoint number - 0x311*/ + UCHAR Bulk3EpMaxLen; /* Bulk maximum length - 0x312*/ + UCHAR Bulk3EpInEpNum; /* Bulk In endpoint number - 0x313*/ + + UCHAR Bulk3DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ + UCHAR Bulk3DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ + UCHAR Bulk3DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ + UCHAR Bulk3DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ + + UCHAR Reserved4[0x20]; /*0x318 ~ 0x33F ; 0x33F - 0x318 + 1 = 0x28*/ + + UCHAR ControlDataBuf[64]; /*0x340~0x37F Control Endpoint Data Buffer */ +}__attribute__((packed)); + +/*DMA_Context_Control*/ +/*1:IF0-->peripheral 0:peripher-->IF0*/ +#define DMA_TRANS_OUT_DIR 0x00400000 +/*1:Run 0:Stop Scheduled*/ +#define DMA_RUN 0x00000080 + +/*DMA Interrupt Enable*/ +/*enable interfac 0 interrupt*/ +#define DMA_INTERRUPT_ENABLE0 0x00000001 +/*enable interfac 1 interrupt*/ +#define DMA_INTERRUPT_ENABLE1 0x00000002 +/*enable interfac 2 interrupt*/ +#define DMA_INTERRUPT_ENABLE2 0x00000010 + +/*enable interfac 0 status*/ +#define DMA_INTERRUPT_STATUS0 0x00000001 +/*enable interfac 1 status*/ +#define DMA_INTERRUPT_STATUS1 0x00000002 +/*enable interfac 2 status*/ +#define DMA_INTERRUPT_STATUS2 0x00000004 + +struct UDC_DMA_REG { + union { /*Rx00 - DMA Global Register (0x100~0x103)*/ + UINT DMA_Global; + struct { + UINT DMAConrollerEnable:1; + UINT Reserved0:7; + UINT SoftwareReset:1; + UINT SoftwareReset0:1; + UINT SoftwareReset1:1; + UINT SoftwareReset2:1; + UINT Reserved1:20; + } DMA_Global_Bits; + }; + + union { /*Rx04 - DMA Interrupt Enable (0x104~x107)*/ + UINT DMA_IER; + struct { + UINT DMAInterruptEnable0:1; + UINT DMAInterruptEnable1:1; + UINT Reserved:2; + UINT DMAInterruptEnable2:1; + UINT Reserved1:27; + } DMA_IER_Bits; + }; + + union { /*Rx08 - DMA Interrupt Status Register (0x108~0x10b)*/ + UINT DMA_ISR; + struct { + UINT InterruptStatus0:1; + UINT InterruptStatus1:1; + UINT InterruptStatus2:1; + UINT Reserved:29; + } DMA_ISR_Bits; + }; + + /*Interface 0*/ + union {/*Rx10c - DMA Memory-Descriptor Point Register dor Interdace 0 (0x10c~0x10f)*/ + UINT DMA_Descriptor_Point0; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point0_Bits; + }; + + union { /*Rx110 - DMA Residual Bytes Register for Interface 0 (Rx110~Rx103)*/ + UINT DMA_Residual_Bytes0; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes0_Bits; + }; + + /*Rx114 - DMA Data Address Register for Interface 0 (0x114~0x117)*/ + UINT DMA_Data_Addr0; + + union {/*Rx118 DMA Branch Address Register for INterface 0(0x118~0x11b)*/ + UINT DMA_Branch_Addr0; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr0_Bits; + }; + + union {/*Rx11c DMA command Pointer Register for Interrface 0(0x11c~0x11f)*/ + UINT Descriptor_Addr0; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr0_Bits; + }; + + union {/*Rx120 DMA Context Control Register for Interfaxe 0(0x120~0x123)*/ + UINT DMA_Context_Control0; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control0_Bis; + }; + + /*Interface 1*/ + union {/*Rx124 - DMA Memory-Descriptor Point Register dor Interdace 1 (0x124~0x127)*/ + UINT DMA_Descriptor_Point1; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point1_Bits; + }; + + union { /*Rx128 - DMA Residual Bytes Register for Interface 1 (Rx128~Rx12b)*/ + UINT DMA_Residual_Bytes1; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes1_Bits; + }; + + /*Rx12c - DMA Data Address Register for Interface 1 (0x12c~0x12f)*/ + UINT DMA_Data_Addr1; + + union {/*Rx130 DMA Branch Address Register for INterface 10(0x130~0x133)*/ + UINT DMA_Branch_Addr1; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr1_Bits; + }; + + union {/*Rx134 DMA command Pointer Register for Interrface 1(0x134~0x137)*/ + UINT Descriptor_Addr1; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr1_Bits; + }; + + union {/*Rx138DMA Context Control Register for Interfaxe 1(0x138~0x13b)*/ + UINT DMA_Context_Control1; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control1_Bis; + }; + + /*Interface 2*/ + union {/*Rx13c - DMA Memory-Descriptor Point Register dor Interdace 2 (0x10c~0x10f)*/ + UINT DMA_Descriptor_Point2; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point2_Bits; + }; + + union { /*Rx140 - DMA Residual Bytes Register for Interface 2 (Rx110~Rx103)*/ + UINT DMA_Residual_Bytes2; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes2_Bits; + }; + + /*Rx144 - DMA Data Address Register for Interface 2 (0x144~0x147)*/ + UINT DMA_Data_Addr2; + + union {/*Rx148 DMA Branch Address Register for INterface 2(0x148~0x14b)*/ + UINT DMA_Branch_Addr2; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr2_Bits; + }; + + union {/*Rx14c DMA command Pointer Register for Interrface 2(0x14c~0x14f)*/ + UINT Descriptor_Addr2; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr2_Bits; + }; + + union {/*Rx150 DMA Context Control Register for Interfaxe 2(0x150~0x153)*/ + UINT DMA_Context_Control2; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control2_Bis; + }; + +}__attribute__((packed)); + +#define DESCRIPTOT_TYPE_SHORT 0 +#define DESCRIPTOT_TYPE_LONG 1 +#define DESCRIPTOT_TYPE_MIX 2 + +#define TRANS_OUT 1 +#define TRANS_IN 0 + +#define DES_L_SIZE 0x10 +#define DES_S_SIZE 0x4 + + +/* + * PDMA Descriptor short + */ +struct _UDC_PDMA_DESC_S { + union { + UINT D_Word0; + struct { + UINT ReqCount:16; /* bit 0 -15 -Request count*/ + UINT i:1; /* bit 16 -interrupt*/ + UINT Reserved:13; + UINT Format:1; /* bit 30 -The descriptor format*/ + UINT End:1; /* bit 31-End flag of descriptor list*/ + } D_Word0_Bits; + }; + + UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ +}__attribute__((packed)); + +/* + * PDMA Descriptor long + */ + +struct _UDC_PDMA_DESC_L { + union { + UINT D_Word0; + struct { + UINT ReqCount:16; /* bit 0 -15-Request count*/ + UINT i:1; /* bit 16-interrupt*/ + UINT Reserved:13; + UINT Format:1; /* bit 30-The descriptor format*/ + UINT End:1; /* bit 31-End flag of descriptor list*/ + } D_Word0_Bits; + }; + + UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ + + union { + UINT Branch_addr; + struct { + UINT Reserved:2; + UINT BranchAddr:30; /* bit 31-2 -Descriptor Branch address*/ + } Branch_addr_Bits; + }; + + UINT Reserve0; +}__attribute__((packed)); + +/*Rx00 - UHDC Interrupt Status Register*/ +#define UHDC_INT_UDC 0x0300 +//#define UHDC_INT_UDC_DMA2 0x0400 +#define UHDC_INT_UDC_DMA1 0x0200 +#define UHDC_INT_UDC_CORE 0x0100 + +#ifdef OTGIP +/*UHDC Global Register Space : 0x7F0~0x7F7*/ +struct USB_GLOBAL_REG { + union { /*Rx00 - UHDC Interrupt Status Register*/ + USHORT UHDC_Interrupt_Status; + struct { + USHORT EHCIInt:1; /* [0] EHCI Interrupt bit*/ + USHORT UHCIInt:1; /* [1] UHCI Interrupt bit*/ + USHORT Reserved0:6; /* reserved for future use*/ + USHORT UDCCoreInt:1; /* [8] UDC Core Interrupt bit(IOC/Babble/Bus Activity)*/ + USHORT UDCDMA1Int:1; /* [9] DMA1 Interrupt bit (Bulk Transfer)*/ + USHORT UDCDMA2Int:1; /* [10] DMA2 Interrupt bit (Bulk Transfer)*/ + USHORT Reserved1:5; /* reserved for future use*/ + } UHDC_Interrupt_Status_Bits; + }; + + union { /*Rx01 - UHDC ID Status Register*/ + UCHAR UHDC_ID_Status; + struct { + UCHAR DualRoleID:1; /* Dual-Role USB Controller ID Value*/ + UCHAR Reserved:7; /* reserved for future use*/ + } UHDC_ID_Status_Bits; + }; + + union { /*Rx02 - UHDC Offchip Power Control Register*/ + UCHAR UHDC_OffChip_PowerControl; + struct { + UCHAR PowerSupplyMode:1; /* Power Supply Mode Select (1)SW mode (0)HW mode*/ + UCHAR PowerSupplySWEn:1; /* Power Supply SW Mode Enable bit */ + UCHAR Reserved:6; /* reserved for future use */ + } UHDC_OffChip_PowerControl_Bits; + }; + + union { /*Rx03 - UHDC Clock Reset Control Register*/ + USHORT UHDC_Clock_Reset_Control; + struct { + USHORT AHBClkGatingEn:1; /* [0] AHB clock Gating Enable bit*/ + USHORT HCSuspendClkGatingEn:1; /* [1] Host Controller Suspend Clock Gating Enable bit*/ + USHORT DCSuspendClkGatingEn:1; /* [2] Device Controller Suspend Clock Gating Enable bit*/ + USHORT DataReceivingClkGatingEn:1;/* [3] Controller Data-Receiving Clock Gating Enable bit*/ + USHORT Phy120MClkGatingEn:1; /* [4] Phy 120M Clock Gating Enable bit*/ + USHORT Phy60MClkGatingEn:1; /* [5] Phy 60M Clock Gating Enable bit*/ + USHORT Phy48MClkGatingEn:1; /* [6] Phy 48M Clock Gating Enable bit */ + USHORT Reserved0:1; /* [7] reserved for future use*/ + USHORT AHBResetGatingEn:1; /* [8] AHB Bus Reset Gating Enable bit*/ + USHORT PowerOnResetGatingEn:1; /* [9] Power-on Reset Gating Enable bit */ + USHORT Reserved1:6; /* [15:10] reserved for future use*/ + } UHDC_Clock_Reset_Control_Bits; + }; + + union { /*Rx04 - UHDC Pullup/Pulldown Control Register*/ + USHORT UHDC_Pull_Up_Down_Control; + struct { + USHORT PullUpDownSWControlEn:1; /* [0] Pullup/Pulldown SW Control Enable bit*/ + USHORT DPLinePullUpEn:1; /* [1] DP Line Pullup Enable bit*/ + USHORT DPLinePullDownEn:1; /* [2] DP Line Pulldown Enable bit*/ + USHORT DMLinePullDownEn:1; /* [3] DM Line Pulldown Enable bit*/ + USHORT HSTerminationRegisterEn:1; /* [4] High Speed Termination Register On bit*/ + USHORT Reserved1:11; /* [15:5] reserved for future use*/ + } UHDC_Pull_Up_Down_Control_Bits; + }; +}__attribute__((packed)); +#endif + +#define UDC_FULL_SPEED 0 +#define UDC_HIGH_SPEED 1 +/* Define the setup command buffer*/ + +#define MAX_TRANSFER_LENGTH 0x200 /* original is 0x20000, shift 16bits for minimum block size is 0x200*/ +/*HP04_End*/ + +/* Define the interrupt transfer buffer*/ +#define INTBUFFERSTART 0x308 /* the start byte of interrupt transfer buffer*/ +#define INTBUFFEREND 0x30F /* the last byte of interrupt transfer buffer*/ +#define INTBUFFERSIZE 0x08 /* the size of the interrupt transfer buffer*/ + +/* Define the control endpoint buffer*/ +#define CONTROLBUFFERSTART 0x340 /* the start byte of the control data buffer*/ +#define CONTROLBUFFEREND 0x37F /* the last byte of the control data buffer*/ +#define CONTROLBUFFERSIZE 0x40 /* the size of the control data buffer*/ + +/* Define the bulk transfer buffer*/ +#define BULKBUFFERSTART 0x800 /* the start byte of the bulk transfer buffer*/ +#define BULKBUFFEREND 0xFFF /* the last byte of the bulk transfer buffer*/ +#define BULKBUFFERSIZE 0x800 /* the size of the bulk transfer buffer*/ + +/* define the endpoint number for each endpoint*/ +#define BULKINEPNUM 0x01 +/*HP01_begin*/ +#define BULKOUTEPNUM 0x02 +/*HP01_End*/ +#define INTEPNUM 0x03 +#define MAXEPNUM 0x04 +/* define the structure of string table for default strings and vendor specified strings*/ + +/* define the IO state of USB to handle */ +#define IOSTATE_CBWIDLE 0x00 /* usb is idle and set the 8051 clock to stop*/ +#define IOSTATE_ACCEPTCBW 0x01 /* the usb accept a new CBW*/ +#define IOSTATE_DEVICEPREPAREIO 0x02 /* the state will call deivce startio to prepare IO*/ +#define IOSTATE_STARTIO 0x03 /* the CBW send to device to start IO operation*/ +#define IOSTATE_CSW 0x04 /* the state to send CSW back to host*/ +#define IOSTATE_CSWCOMPLETE 0x05 /* the CSW is returned, maybe need some more process*/ +#define IOSTATE_TIMEOUT 0x06 /* the IO is hang to long and it is timeout*/ +#define IOSTATE_FWDOWNLOAD 0x07 /* Download the new firmware.*/ +#define IOSTATE_WAITFORCBW 0x08 /* In this state, the controller is waiting for CBW*/ +#define IOSTATE_CSWIDLE 0x09 /* the idle state for wait for CSW complete, 8051 will stopped*/ + +/*VT3214 Define */ +/* define the state of Control endpoint*/ +#define CONTROLSTATE_SETUP 0x00 /* the control endpoint is in the Setup state*/ +#define CONTROLSTATE_DATA 0x01 /* the control endpoint is in the Data state*/ +#define CONTROLSTATE_STATUS 0x02 /* the control endpoint is in the Status state*/ + + +/* VT3300 PACK Size Defination*/ +#define UCE_MAX_DMA ((unsigned)64) +#define UIE_MAX_DMA ((unsigned)8) +#define UBE_MAX_DMA ((unsigned)0x20000) /* max length = 128K */ +#define EP0_FIFO_SIZE ((unsigned)64) +#define BULK_FIFO_SIZE ((unsigned)512) +#define INT_FIFO_SIZE ((unsigned)8) + +/* Define the setup command buffer*/ +typedef struct _SETUP_COMMAND +{ +unsigned char RequestType; /* the Request type of the SETUP command*/ +unsigned char Request; /* the Request code of the SETUP command*/ +unsigned char ValueLow; /* the lower value field of the SETUP command*/ +unsigned char ValueHigh; /* the higher value field of the SETUP command*/ +unsigned char IndexLow; /* the lower index field of the SETUP command*/ +unsigned char IndexHigh; /* the higher index field of the SETUP command*/ +unsigned char LengthLow; /* the lower length field of the SETUP command*/ +unsigned char LengthHigh; /* the higher length field of the SETUP command*/ +} SETUPCOMMAND, *PSETUPCOMMAND; + + + +struct vt8500_ep { + struct usb_ep ep; + struct list_head queue; + unsigned long irqs; + const struct usb_endpoint_descriptor *desc; + char name[14]; + u16 maxpacket; + u8 bEndpointAddress; + u8 bmAttributes; + unsigned double_buf:1; + unsigned stopped:1; + unsigned fnf:1; + unsigned has_dma:1; + unsigned toggle_bit:1; + unsigned stall:1; + unsigned rndis:1; + u8 ackwait; + /*u8 dma_channel;*/ + u32 dma_counter; + /*int lch;*/ + struct vt8500_udc *udc; + struct timer_list timer; + /*volatile u32 *reg_payload_addr;*/ + /*volatile u32 *reg_control_status;*/ + /*volatile u32 *reg_irp_descriptor;*/ + + /*volatile u32 temp_payload_addr;*/ + /*volatile u32 temp_control_status;*/ + + volatile u32 temp_buffer_address; + volatile u32 temp_dma_phy_address; + volatile u32 temp_buffer_address2; + volatile u32 temp_dma_phy_address2; + + /*volatile u32 temp_req_length;*/ + /*volatile u32 temp_irp_descriptor; */ + volatile u32 rndis_buffer_address; + volatile u32 rndis_dma_phy_address; + unsigned int rndis_buffer_length; + unsigned int rndis_buffer_alloc ; + + /*processing stall and clear stall.*/ + volatile u32 stall_more_processing; + volatile u32 temp_dcmd; + volatile u32 temp_dma_ccr; + volatile u32 temp_bulk_dma_addr; + volatile u32 ep_stall_toggle_bit; + volatile u32 ep_fifo_length; + +}__attribute__((packed)); + +struct vt8500_req { + struct usb_request req; + struct list_head queue; + unsigned dma_bytes; + struct vt8500_ep *ep; + struct list_head mem_list; /* sw qtd list */ + unsigned mapped:1; +}__attribute__((packed)); + + +struct vt8500_udc { + struct device *dev; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + spinlock_t lock; +// struct vt8500_ep ep[5]; + struct vt8500_ep ep[7];//gri + u16 devstat; + u16 ep0_in_status; + volatile u32 cbw_virtual_address; + /*volatile u32 ep3_virtual_address; */ + struct usb_phy *transceiver; + unsigned softconnect:1; + unsigned vbus_active:1; + unsigned ep0_pending:1; + unsigned ep0_in:1; + unsigned ep0_set_config:1; + unsigned ep0_reset_config:1; + unsigned ep0_setup:1; + unsigned ep0_status_0_byte:1; + unsigned usb_connect:1; + unsigned file_storage_set_halt:1; + unsigned bulk_out_dma_write_error:1; + unsigned int chip_version; + struct completion *done; + u8 setup_command[8]; + struct timer_list timer; +}__attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +//#define DEBUG +//#define VERBOSE + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_INFO "udc: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) +//#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + +#define USB_BULK_RESET_REQUEST 0xff +/*--------------------------------------------------------------------*/ + +/*static void vt8500_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp);*/ +/*static void vt8500_udc_csr(struct vt8500_udc *udc);*/ + +#endif /* __LINUX_USB_GADGET_VT8500_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/Kconfig b/ANDROID_3.4.5/drivers/usb/host/Kconfig index f788eb86..302bae2a 100644 --- a/ANDROID_3.4.5/drivers/usb/host/Kconfig +++ b/ANDROID_3.4.5/drivers/usb/host/Kconfig @@ -63,6 +63,21 @@ config USB_EHCI_HCD To compile this driver as a module, choose M here: the module will be called ehci-hcd. +#CharlesTu, for test mode # +config USB_EHCI_EHSET + bool "Embedded High-speed Host Electrical Test Support (EXPERIMENTAL)" + depends on USB_EHCI_HCD + default y + ---help--- + This option is only used if you are developing firmware for + an embedded device with a Hi-speed USB Host or OTG port. + + If you say Y here, software support for the Embedded High-speed + Host Electrical Tests will be added to the EHCI driver. This is + one of the tests performed during High-speed USB Host certification + testing. + + If you are at all unsure then say N here. config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators" depends on USB_EHCI_HCD diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c index bb73df65..dabd379f 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c +++ b/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c @@ -130,6 +130,10 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); /*-------------------------------------------------------------------------*/ +extern unsigned int usb_storage_id; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +unsigned int usb_param[2] = {0xff}; + static void timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) { @@ -599,6 +603,14 @@ static void ehci_stop (struct usb_hcd *hcd) ehci_readl(ehci, &ehci->regs->status)); } +int env_mos_gpio; +unsigned int env_active; +unsigned int env_port; +unsigned int env_bitmap; +unsigned int env_ctraddr; +unsigned int env_ocaddr; +unsigned int env_odaddr; + /* one-time init, only for memory state */ static int ehci_init(struct usb_hcd *hcd) { @@ -607,7 +619,14 @@ static int ehci_init(struct usb_hcd *hcd) int retval; u32 hcc_params; struct ehci_qh_hw *hw; - + char usb_env_name[] = "wmt.usb.param"; + char usb_env_val[20] = "0"; + int varlen = 20; + + char usb_resume_env_name[] = "wmt.gpo.usb"; + char usb_resume_env_val[80] = "0"; + int varlen_resume = 80; + spin_lock_init(&ehci->lock); /* @@ -720,7 +739,37 @@ static int ehci_init(struct usb_hcd *hcd) temp |= hird << 24; } ehci->command = temp; + + if(wmt_getsyspara(usb_env_name, usb_env_val, &varlen) == 0) { + sscanf(usb_env_val,"%X:%X", &usb_param[0],&usb_param[1]); + //printk("usb_param[0] =%x ,usb_param[1]=%x \n",usb_param[0],usb_param[1]); + if (usb_param[0] & 0x01) { + if(usb_param[1] <= 0x03 ) { + usb_storage_id = usb_param[1]+1; + //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id); + } else { + usb_storage_id = 2;// default port B + } + } else { + usb_storage_id=0; //disable + } + } + + if(wmt_getsyspara(usb_resume_env_name, usb_resume_env_val, &varlen_resume) == 0) { + sscanf(usb_resume_env_val,"%d:%X:%X:%X:%X:%X", &env_mos_gpio,&env_active,&env_bitmap,&env_ctraddr,&env_ocaddr,&env_odaddr); + + if (env_active) { + env_port = (env_active >> 4); + env_active &= 0x1; + env_ctraddr = ((env_ctraddr & 0xffffff) | 0xfe000000); + env_ocaddr = ((env_ocaddr & 0xffffff) | 0xfe000000); + env_odaddr = ((env_odaddr & 0xffffff) | 0xfe000000); + } + } else + env_active = 0; + printk("env_mos_gpio=%d env_active =%x ,env_port=%x env_bitmap=%x env_ctraddr=%x env_ocaddr=%x env_odaddr=%x \n",env_mos_gpio,env_active,env_port,env_bitmap,env_ctraddr,env_ocaddr,env_odaddr); + /* Accept arbitrarily long scatter-gather lists */ if (!(hcd->driver->flags & HCD_LOCAL_MEM)) hcd->self.sg_tablesize = ~0; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c index 38fe0762..714ca48b 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c +++ b/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c @@ -128,6 +128,9 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) return 0; } +extern char enable_ehci_wake; +extern char enable_ehci_disc_wakeup; + static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, bool suspending, bool do_wakeup) { @@ -171,10 +174,13 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, * If we are resuming the controller, set the wakeup flags. */ if (!suspending) { - if (t1 & PORT_CONNECT) - t2 |= PORT_WKOC_E | PORT_WKDISC_E; - else - t2 |= PORT_WKOC_E | PORT_WKCONN_E; + if (enable_ehci_wake && enable_ehci_disc_wakeup) { + if (t1 & PORT_CONNECT) + t2 |= PORT_WKOC_E | PORT_WKDISC_E; + else + t2 |= PORT_WKOC_E | PORT_WKCONN_E; + } else + t2 |= PORT_WKOC_E; } ehci_vdbg(ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); @@ -254,7 +260,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) if (t1 & PORT_OWNER) set_bit(port, &ehci->owned_ports); else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) { - t2 |= PORT_SUSPEND; + if (enable_ehci_wake) + t2 |= PORT_SUSPEND; + else + t2 &= ~PORT_PE;// CharlesTu, disable port set_bit(port, &ehci->bus_suspended); } @@ -265,10 +274,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) * condition happens here(connection change during bits * set), the port change detection will finally fix it. */ - if (t1 & PORT_CONNECT) - t2 |= PORT_WKOC_E | PORT_WKDISC_E; - else - t2 |= PORT_WKOC_E | PORT_WKCONN_E; + if (enable_ehci_wake && enable_ehci_disc_wakeup) { + if (t1 & PORT_CONNECT) + t2 |= PORT_WKOC_E | PORT_WKDISC_E; + else + t2 |= PORT_WKOC_E | PORT_WKCONN_E; + } else + t2 |= PORT_WKOC_E; } if (t1 != t2) { @@ -602,6 +614,16 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) * controller by the user. */ + /* + *CharlesTu,2009.08.17,patch Trancend 8GB usb device , + *copy and fast hot plug reset slowly issue. + *Due to Transcend 8GB device ,connect slowly and reset_done clear 0 + */ + /*if (!(temp & PORT_CONNECT))*/ + if (!(temp & (PORT_CONNECT|PORT_RESET))) + ehci->reset_done [i] = 0; + + if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend) || (ehci->reset_done[i] && time_after_eq( jiffies, ehci->reset_done[i]))) { @@ -611,6 +633,27 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [1] |= 1 << (i - 7); status = STS_PCD; } + /*CharlesTu,090415,patch usb card reader plug/unplug fastly + * port fail issue. Due to the port reset assert and not clear. + */ + if ((temp & PORT_RESET) + && time_after (jiffies, ehci->reset_done [i])) { + /*printk("port reset \n");*/ + /* force reset to complete */ + ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), + &ehci->regs->port_status [i]); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(ehci, + &ehci->regs->port_status [i], + PORT_RESET, 0, 750); + if (retval != 0) { + ehci_err (ehci, "port %d reset error %d\n", + i + 1, retval); + + } + } } /* FIXME autosuspend idle root hubs */ spin_unlock_irqrestore (&ehci->lock, flags); @@ -653,6 +696,190 @@ ehci_hub_descriptor ( } /*-------------------------------------------------------------------------*/ +/*{CharlesTu,2010.08.26, for test mode --------------------------------*/ +#ifdef CONFIG_USB_EHCI_EHSET + +static int +single_step_set_feature( struct usb_hcd *hcd, u8 port) +{ + struct usb_bus *bus = hcd_to_bus(hcd); + struct usb_device *udev; + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + struct list_head qtd_list; + struct list_head setup_list; + struct list_head data_list; + struct ehci_qtd *qtd; + struct urb urb; + struct usb_ctrlrequest setup_packet; + char data_buffer[USB_DT_DEVICE_SIZE]; + + ehci_info (ehci, "Testing SINGLE_STEP_SET_FEATURE\n"); + + if (bus == NULL) { + ehci_err (ehci, "EHSET: usb_bus pointer is NULL\n"); + return -EPIPE; + } + + udev = bus->root_hub; + if (udev == NULL) { + ehci_err (ehci, "EHSET: root_hub pointer is NULL\n"); + return -EPIPE; + } + /* Charles, modify for MVL5 */ + /*udev = udev->children[port - 1];*/ + udev = udev->children[port ]; + + if (udev == NULL) { + ehci_err (ehci, "EHSET: No test device found on port %d\n", + port); + return -EPIPE; + } + + setup_packet.bRequestType = USB_DIR_IN; + setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_packet.wValue = (USB_DT_DEVICE << 8); + setup_packet.wIndex = 0; + setup_packet.wLength = USB_DT_DEVICE_SIZE; + + INIT_LIST_HEAD (&qtd_list); + INIT_LIST_HEAD (&setup_list); + INIT_LIST_HEAD (&data_list); + + urb.transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb.dev = udev; + urb.pipe = usb_rcvctrlpipe(udev, 0); + /* Charles, modify for MVL5 */ + urb.hcpriv = udev->ep0.hcpriv; + /*urb.hcpriv = udev->ep0.hcpriv; */ + + urb.setup_packet = (char *)&setup_packet; + urb.transfer_buffer = data_buffer; + urb.transfer_flags = URB_HCD_DRIVER_TEST; + //spin_lock_init(&urb.lock); + + urb.setup_dma = dma_map_single( hcd->self.controller, + urb.setup_packet, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + urb.transfer_dma = dma_map_single ( + hcd->self.controller, + urb.transfer_buffer, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + + if (!urb.setup_dma || !urb.transfer_dma) { + ehci_err (ehci, "dma_map_single Failed\n"); + return -EBUSY; + } + + if (!qh_urb_transaction (ehci, &urb, &qtd_list, GFP_ATOMIC)) { + ehci_err (ehci, "qh_urb_transaction Failed\n"); + return -EBUSY; + } + + qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); + list_del_init (&qtd->qtd_list); + list_add (&qtd->qtd_list, &setup_list); + qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); + list_del_init (&qtd->qtd_list); + list_add (&qtd->qtd_list, &data_list); + qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); + list_del_init (&qtd->qtd_list); + ehci_qtd_free (ehci, qtd); + + ehci_info (ehci, "Sending SETUP PHASE\n"); + /* Charles, modify for MVL5 */ + //if (submit_async (ehci, &udev->ep0, &urb, &setup_list, GFP_ATOMIC)) { + if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) { + ehci_err (ehci, "Failed to queue up qtds\n"); + return -EBUSY; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(15000)); + urb.status = 0; + urb.actual_length = 0; + + ehci_info (ehci, "Sending DATA PHASE\n"); + /* Charles, modify for MVL5 */ + //if (submit_async (ehci, &udev->ep0, &urb, &data_list, GFP_ATOMIC)) { + + if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) { + + ehci_err (ehci, "Failed to queue up qtds\n"); + return -EBUSY; + } + + return 0; +} +static void stop_test(struct ehci_hcd *ehci) +{ + volatile unsigned int temp32 = 0; + //int ports = 0,i = 0; + + /*reset HC */ + temp32 = readl(&ehci->regs->command); + ehci_info(ehci, "command before set reset 0x%8.8x\n", temp32); + temp32 |= 0x00000002; + writel(temp32, &ehci->regs->command); + temp32 = readl (&ehci->regs->command); + ehci_info(ehci, "command after set reset 0x%8.8x\n", temp32); + while ((readl(&ehci->regs->command)) & 0x00000002) + ; + + /*set CF bit*/ + temp32 = readl(&ehci->regs->configured_flag); + ehci_info(ehci, "CF before set CF 0x%8.8x\n", temp32); + if (!temp32) + writel (FLAG_CF, &ehci->regs->configured_flag); + temp32 = readl(&ehci->regs->configured_flag); + while (!((readl(&ehci->regs->configured_flag)) & 0x00000001)) + ; + ehci_info(ehci, "CF after set CF 0x%8.8x\n", temp32); + + +} +#endif +/*CharlesTu}-------------------------------------------------------------*/ + +static int handshake_wmt (struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + u32 result1; + int usec_250; + + if (usec > 1000) + usec_250 = usec - 261; + else + usec_250 = usec; + + do { + result = ehci_readl(ehci, ptr); + result1 = result; + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay (1); + usec--; + if (usec == usec_250) { + ehci_writel(ehci, + result1 & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND), + ptr); +// printk("*2nd clear resume\n"); + } + } while (usec > 0); + return -ETIMEDOUT; +} + +extern unsigned int env_active; +extern unsigned int env_port; +extern unsigned int env_bitmap; +extern unsigned int env_ctraddr; +extern unsigned int env_ocaddr; +extern unsigned int env_odaddr; static int ehci_hub_control ( struct usb_hcd *hcd, @@ -670,7 +897,8 @@ static int ehci_hub_control ( u32 temp, temp1, status; unsigned long flags; int retval = 0; - unsigned selector; + unsigned selector=0; + u8 port_num = 0; //CharlesTu, for testmode /* * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. @@ -742,7 +970,8 @@ static int ehci_hub_control ( spin_lock_irqsave(&ehci->lock, flags); } /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); + //temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); + temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS | PORT_SUSPEND); ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); @@ -839,11 +1068,28 @@ static int ehci_hub_control ( /* stop resume signaling */ temp = ehci_readl(ehci, status_reg); +// ehci_writel(ehci, +// temp & ~(PORT_RWC_BITS | PORT_RESUME), +// status_reg); + if ((env_active) && (env_port == wIndex)) { + *((volatile unsigned char *)(env_ctraddr)) |= env_bitmap; + *((volatile unsigned char *)(env_ocaddr)) |= env_bitmap; + *((volatile unsigned char *)(env_odaddr)) |= env_bitmap; + } ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_RESUME), - status_reg); + temp & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND), + status_reg); clear_bit(wIndex, &ehci->resuming_ports); - retval = handshake(ehci, status_reg, + + udelay(1); + + if ((env_active) && (env_port == wIndex)) { + *((volatile unsigned char *)(env_odaddr)) &= (~env_bitmap); + } + +// retval = handshake(ehci, status_reg, +// PORT_RESUME, 0, 2000 /* 2msec */); + retval = handshake_wmt(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { ehci_err(ehci, @@ -984,7 +1230,12 @@ static int ehci_hub_control ( * mode if we have hostpc feature */ temp &= ~PORT_WKCONN_E; - temp |= PORT_WKDISC_E | PORT_WKOC_E; + + if (enable_ehci_wake && enable_ehci_disc_wakeup) + temp |= PORT_WKDISC_E | PORT_WKOC_E; + else + temp |= PORT_WKOC_E; + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); if (hostpc_reg) { spin_unlock_irqrestore(&ehci->lock, flags); @@ -1040,12 +1291,13 @@ static int ehci_hub_control ( * or else system reboot). See EHCI 2.3.9 and 4.14 for info * about the EHCI-specific stuff. */ +/* case USB_PORT_FEAT_TEST: if (!selector || selector > 5) goto error; ehci_quiesce(ehci); - /* Put all enabled ports into suspend */ + // Put all enabled ports into suspend while (ports--) { u32 __iomem *sreg = &ehci->regs->port_status[ports]; @@ -1060,6 +1312,59 @@ static int ehci_hub_control ( temp |= selector << 16; ehci_writel(ehci, temp, status_reg); break; +*/ + /*{CharlesTu, 2010.8.26, for test mode */ + case USB_PORT_FEAT_TEST: + ehci_info(ehci, "selector : %x\n ", selector); + //selector = (wIndex >> 8) & 0xff; + port_num = (wIndex) & 0xff; + ehci_info(ehci, "USB_PORT_FEAT_TEST : running test %x " + "on port %d\n", selector, port_num); + if (!selector || selector > 5) + ehci_info(ehci, "USB_PORT_FEAT_TEST 1: running test %x " + "on port %d\n", selector, port_num); + + switch (selector) { + case USB_PORT_TEST_J: + case USB_PORT_TEST_K: + case USB_PORT_TEST_SE0_NAK: + case USB_PORT_TEST_PACKET: + case USB_PORT_TEST_FORCE_ENABLE: + ehci_quiesce(ehci); + ehci_halt(ehci); +#ifdef CONFIG_USB_EHCI_EHSET + stop_test(ehci); +#endif + temp = ehci_readl(ehci, &ehci->regs->command); + temp &= 0xfffffffe; + writel(temp, &ehci->regs->command); + + temp = readl(&ehci->regs->port_status [(wIndex & 0x00ff)]); + temp &= 0xfff0ffff; + writel(temp, &ehci->regs->port_status[port_num]); + temp |= selector << 16; + writel(temp, &ehci->regs->port_status[port_num]); + break; +#ifdef CONFIG_USB_EHCI_EHSET + case USB_PORT_TEST_SINGLE_STEP_SET_FEATURE: + spin_unlock_irqrestore (&ehci->lock, flags); + if (single_step_set_feature(hcd, port_num)) { + spin_lock_irqsave (&ehci->lock, flags); + goto error; + } + spin_lock_irqsave (&ehci->lock, flags); + break; +#endif + + default: + goto error; + ehci_quiesce(ehci); + ehci_halt(ehci); + temp |= selector << 16; + writel (temp, &ehci->regs->port_status[port_num - 1]); + } + break; + /*CharlesTu} */ default: goto error; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c b/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c index 12348179..49726685 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c +++ b/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c @@ -27,6 +27,8 @@ /*-------------------------------------------------------------------------*/ +extern char enable_ehci_wake; + /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) { @@ -334,7 +336,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) struct ehci_hcd *ehci = hcd_to_ehci(hcd); unsigned long flags; int rc = 0; - + u16 pmc_enable = 0; if (time_before(jiffies, ehci->next_statechange)) msleep(10); @@ -352,7 +354,12 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) // could save FLADJ in case of Vaux power loss // ... we'd only use it to handle clock skew - + //CharlesTu,for PM high memory + if (enable_ehci_wake) { + pci_read_config_word(to_pci_dev(hcd->self.controller), 0x84, &pmc_enable); + pmc_enable |= 0x103; + pci_write_config_word(to_pci_dev(hcd->self.controller), 0x84, pmc_enable); + } return rc; } @@ -399,6 +406,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) * a '1' to the port switchover registers should have no effect if the * port was already switched over. */ + u16 pmc_enable = 0; + //CharlesTu,for PM high memory + if (enable_ehci_wake) { + pci_read_config_word(pdev, 0x84, &pmc_enable); + pmc_enable &= ~0x03; + pci_write_config_word(pdev, 0x84, pmc_enable); + } if (usb_is_intel_switchable_ehci(pdev)) ehci_enable_xhci_companion(); @@ -409,7 +423,11 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) /* Mark hardware accessible again as we are out of D3 state by now */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - + /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend + * when resume ehci hub activate ,type= HUB_RESET_RESUME + */ + if (!enable_ehci_wake) + usb_root_hub_lost_power(hcd->self.root_hub); /* If CF is still set and we aren't resuming from hibernation * then we maintained PCI Vaux power. * Just undo the effect of ehci_pci_suspend(). @@ -425,8 +443,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) ehci_readl(ehci, &ehci->regs->intr_enable); return 0; } - - usb_root_hub_lost_power(hcd->self.root_hub); + /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend*/ + if (enable_ehci_wake) + usb_root_hub_lost_power(hcd->self.root_hub); /* Else reset, to cope with power loss or flush-to-storage * style "resume" having let BIOS kick in during reboot. diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c b/ANDROID_3.4.5/drivers/usb/host/ehci-q.c index 36ca5077..9e11e38a 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c +++ b/ANDROID_3.4.5/drivers/usb/host/ehci-q.c @@ -286,7 +286,12 @@ __acquires(ehci->lock) status, urb->actual_length, urb->transfer_buffer_length); #endif - + /*{CharlesTu, 2008.12.26, for test mode */ +#ifdef CONFIG_USB_EHCI_EHSET + if (likely(urb->transfer_flags == URB_HCD_DRIVER_TEST)) + return; +#endif + /*CharlesTu}*/ /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c b/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c index a60679cb..757e3463 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c +++ b/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c @@ -655,7 +655,8 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) qh_put (qh); /* maybe turn off periodic schedule */ - return disable_periodic(ehci); + //return disable_periodic(ehci); + return 0; } static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) @@ -1767,7 +1768,7 @@ itd_complete ( ehci_urb_done(ehci, urb, 0); retval = true; urb = NULL; - (void) disable_periodic(ehci); + //(void) disable_periodic(ehci); gri ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { @@ -2163,7 +2164,7 @@ sitd_complete ( ehci_urb_done(ehci, urb, 0); retval = true; urb = NULL; - (void) disable_periodic(ehci); + //(void) disable_periodic(ehci);//gri ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci.h b/ANDROID_3.4.5/drivers/usb/host/ehci.h index 2694ed65..f04172ef 100644 --- a/ANDROID_3.4.5/drivers/usb/host/ehci.h +++ b/ANDROID_3.4.5/drivers/usb/host/ehci.h @@ -771,5 +771,26 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) #endif /* DEBUG */ /*-------------------------------------------------------------------------*/ - +/*{CharlesTu, 2010.08.26, for test mode */ + +static struct list_head * +qh_urb_transaction ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *head, + gfp_t flags +); + +static int submit_async ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) ; + +static inline void ehci_qtd_free ( + struct ehci_hcd *ehci, + struct ehci_qtd *qtd); + +/*CharlesTu}*/ #endif /* __LINUX_EHCI_HCD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c index df0828cb..2efade76 100644 --- a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c +++ b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c @@ -389,7 +389,7 @@ EXPORT_SYMBOL_GPL(uhci_reset_hc); */ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) { - u16 legsup; + //u16 legsup; unsigned int cmd, intr; /* @@ -402,16 +402,19 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) * * If any of these conditions are violated we do a complete reset. */ + #if 0 pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", __func__, legsup); goto reset_needed; } + #endif cmd = inw(base + UHCI_USBCMD); - if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || - !(cmd & UHCI_USBCMD_EGSM)) { +// if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || +// !(cmd & UHCI_USBCMD_EGSM)) { + if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_EGSM)) { dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", __func__, cmd); goto reset_needed; diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c index e4db3506..3e0d2a8c 100644 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c +++ b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c @@ -89,6 +89,8 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); static void wakeup_rh(struct uhci_hcd *uhci); static void uhci_get_current_frame_number(struct uhci_hcd *uhci); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + /* * Calculate the link pointer DMA value for the first Skeleton QH in a frame. */ @@ -338,6 +340,11 @@ __acquires(uhci->lock) uhci->RD_enable = !!int_enable; uhci_writew(uhci, int_enable, USBINTR); + //gri + uhci_writew(uhci, 0, USBCMD); + mb(); + while (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH)); + // uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD); mb(); udelay(5); @@ -855,7 +862,7 @@ static int __init uhci_hcd_init(void) int retval = -ENOMEM; if (usb_disabled()) - return -ENODEV; + return -ENODEV; printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n", ignore_oc ? ", overcurrent ignored" : ""); diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c index 768d5429..fb0da10f 100644 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c +++ b/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c @@ -98,9 +98,12 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, { int status; int i; + u16 tmp; + if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) { CLR_RH_PORTSTAT(SUSPEND_BITS); + wmb(); if (test_bit(port, &uhci->resuming_ports)) set_bit(port, &uhci->port_c_suspend); @@ -110,9 +113,13 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, * Experiments show that some controllers take longer, so * we'll poll for completion. */ for (i = 0; i < 10; ++i) { - if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS)) - break; udelay(1); + tmp = uhci_readw(uhci, port_addr); + //if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS)){ + //printk("uhci_finish_suspend 01\n"); + if (!(tmp & SUSPEND_BITS)){ + break; + } } } clear_bit(port, &uhci->resuming_ports); diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c b/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c index c300bd2f..2de5a93b 100644 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c +++ b/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c @@ -18,6 +18,7 @@ */ #include "pci-quirks.h" +#include <mach/hardware.h> /* * Make sure the controller is completely inactive, unable to @@ -162,11 +163,16 @@ static void uhci_shutdown(struct pci_dev *pdev) #ifdef CONFIG_PM +extern char enable_ehci_wake; +extern char enable_uhci0_wake; +extern char enable_uhci1_wake; + static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); int rc = 0; + u16 pmc_enable = 0; dev_dbg(uhci_dev(uhci), "%s\n", __func__); @@ -192,6 +198,12 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) pci_write_config_byte(pdev, USBRES_INTEL, USBPORT1EN | USBPORT2EN); } + //CharlesTu, for PM + if (((hcd->self.busnum == 2) && enable_uhci0_wake) || ((hcd->self.busnum == 3) && enable_uhci1_wake)){ + pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable); + pmc_enable |= 0x103; + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable); + } done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -203,7 +215,19 @@ done: static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - + u16 pmc_enable = 0; + /*CharlesTu,2009.08.30,patch uhci device disconnet irq nobody care issue + * Before clear D3 mode ,disable UHCI resume interrupt + * The right sequence: disconnect->wakeup->D0 mode->clear resume. + */ + if (enable_ehci_wake){ + REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x0304) &= ~0x02; + REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x1504) &= ~0x02; + + pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable); + pmc_enable &= ~0x03; + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable); + } dev_dbg(uhci_dev(uhci), "%s\n", __func__); /* Since we aren't in D3 any more, it's safe to set this flag diff --git a/ANDROID_3.4.5/drivers/usb/serial/Makefile b/ANDROID_3.4.5/drivers/usb/serial/Makefile index 07f198ee..d0bd3be2 100644 --- a/ANDROID_3.4.5/drivers/usb/serial/Makefile +++ b/ANDROID_3.4.5/drivers/usb/serial/Makefile @@ -62,3 +62,4 @@ obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o +obj-m += via_option.o diff --git a/ANDROID_3.4.5/drivers/usb/serial/option.c b/ANDROID_3.4.5/drivers/usb/serial/option.c index 49484b39..82d5ecf9 100644 --- a/ANDROID_3.4.5/drivers/usb/serial/option.c +++ b/ANDROID_3.4.5/drivers/usb/serial/option.c @@ -50,6 +50,11 @@ static int option_probe(struct usb_serial *serial, static void option_release(struct usb_serial *serial); static int option_send_setup(struct usb_serial_port *port); static void option_instat_callback(struct urb *urb); +/* VIA-Telecom CBP(Non-CDC version) IDs */ +#define VIATELECOM_VENDOR_ID 0x15EB +#define VIATELECOM_PRODUCT_ID 0x0001 +#define BORA9380_VENDOR_ID 0x16d8 +#define BORA9380_PRODUCT_ID 0x4000 /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 @@ -158,8 +163,10 @@ static void option_instat_callback(struct urb *urb); #define HUAWEI_PRODUCT_K4511 0x14CC #define HUAWEI_PRODUCT_ETS1220 0x1803 #define HUAWEI_PRODUCT_E353 0x1506 -#define HUAWEI_PRODUCT_E173S 0x1C05 - +//aron add-------- +#define HUAWEI_PRODUCT_E153 0x1446 +#define HUAWEI_PRODUCT_E173 0x1C05 +//---------- #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 #define QUANTA_PRODUCT_Q111 0xEA03 @@ -681,7 +688,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), @@ -704,6 +711,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E153) }, //aaron add + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173) },//aron add { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, @@ -1128,7 +1137,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2000, 0xff, 0xff, 0xff) }, //aron add. { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, @@ -1267,6 +1276,28 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, + { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) },/* VIA-Telecom CBP CDC Version*/ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, 0xff, 0xff, 0xff) }, /*huawei E173*/ + { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x1000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x6000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0xf00e, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0x1105, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */ + { USB_DEVICE(0x19f5, 0x9909) }, /*UW100 */ + { USB_DEVICE(0x19f5, 0x9013) }, /*UW100 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x0015, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1176, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, + { USB_DEVICE(BORA9380_VENDOR_ID, BORA9380_PRODUCT_ID) },/* ²¨ÀÖ9380*/ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14a8, 0xff, 0xff, 0xff) }, + + { USB_DEVICE(0x1c9e, 0x9605) }, /*a dongle without brand */ + { USB_DEVICE(0x231e, 0x0036) }, /*CYIT TD/GSM modem*/ + { USB_DEVICE(ZTE_VENDOR_ID, 0x1176) }, /*vodafone k3770-z*/ + { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1506) }, /*hw e1731*/ + { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1573) }, /*hw mu609*/ + { USB_DEVICE(0x1782, 0x0002) }, /*spectrum G3 3g modem*/
+ { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1c25) }, /*hw mu709*/ + { USB_DEVICE(0x2001, 0x7d01) }, /*dlink dwm156*/ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -1347,6 +1378,21 @@ static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, } return false; } +static int viatelecom_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); + int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + + /* VIA-Telecom CBP DTR format */ + return usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum, + NULL, 0, USB_CTRL_SET_TIMEOUT); + + +} + static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) @@ -1381,10 +1427,22 @@ static int option_probe(struct usb_serial *serial, serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) return -ENODEV; + + if(serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID){ + if(0!=(serial->dev->config->desc.bmAttributes&0x20)){ + usb_enable_autosuspend(serial->dev); + } + } + data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); if (!data) return -ENOMEM; - data->send_setup = option_send_setup; + + if ((serial->dev->descriptor.idVendor == BORA9380_VENDOR_ID && + serial->dev->descriptor.idProduct == BORA9380_PRODUCT_ID)) { + data->send_setup = viatelecom_send_setup; + } else + data->send_setup = option_send_setup; spin_lock_init(&data->susp_lock); data->private = (void *)id->driver_info; return 0; diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c b/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c index bcf26177..03c117c9 100644 --- a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c +++ b/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c @@ -93,16 +93,16 @@ struct usb_serial *usb_serial_get_by_index(unsigned index) } static struct usb_serial *get_free_serial(struct usb_serial *serial, - int num_ports, unsigned int *minor) + int num_ports, unsigned int *minor,int startIndex) { unsigned int i, j; int good_spot; dbg("%s %d", __func__, num_ports); + *minor = startIndex; - *minor = 0; mutex_lock(&table_lock); - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { + for (i = startIndex; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) continue; @@ -736,7 +736,7 @@ int usb_serial_probe(struct usb_interface *interface, int num_bulk_out = 0; int num_ports = 0; int max_endpoints; - + int startIndex = 0; mutex_lock(&table_lock); type = search_serial_device(interface); if (!type) { @@ -1066,8 +1066,10 @@ int usb_serial_probe(struct usb_interface *interface, * registered. */ serial->disconnected = 1; + if(!strcmp(type->driver.name,"pl2303")||!strcmp(type->driver.name,"ftdi_sio")||!strcmp(type->driver.name,"cp210x")) + startIndex = 5; - if (get_free_serial(serial, num_ports, &minor) == NULL) { + if (get_free_serial(serial, num_ports, &minor, startIndex) == NULL) { dev_err(&interface->dev, "No more free serial devices\n"); goto probe_error; } diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_option.c b/ANDROID_3.4.5/drivers/usb/serial/via_option.c new file mode 100755 index 00000000..2c8a84f3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/serial/via_option.c @@ -0,0 +1,1218 @@ +/* + USB Driver for GSM modems + + Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> + + This driver is free software; you can redistribute it and/or modify + it under the terms of Version 2 of the GNU General Public License as + published by the Free Software Foundation. + + Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org> + + History: see the git log. + + Work sponsored by: Sigos GmbH, Germany <info@sigos.de> + + This driver exists because the "normal" serial driver doesn't work too well + with GSM modems. Issues: + - data loss -- one single Receive URB is not nearly enough + - nonstandard flow (Option devices) control + - controlling the baud rate doesn't make sense + + This driver is named "option" because the most common device it's + used for is a PC-Card (with an internal OHCI-USB interface, behind + which the GSM interface sits), made by Option Inc. + + Some of the "one port" devices actually exhibit multiple USB instances + on the USB bus. This is not a bug, these ports are used for different + device features. +*/ + +#define DRIVER_VERSION "v0.7.2" +#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" +#define DRIVER_DESC "USB Driver for GSM modems" + +#include <linux/kernel.h> +#include <linux/jiffies.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/usb/rawbulk.h> +#include <linux/suspend.h> +#include "via_usb-wwan.h" +#include "via_usb_wwan.c" + +#if defined(CONFIG_VIATELECOM_SYNC_CBP) +#include <mach/viatel.h> +//#include "../drivers/usb/core/usb.h" +#endif + +/* Function prototypes */ +static int option_probe(struct usb_serial *serial, + const struct usb_device_id *id); +static void option_release(struct usb_serial *serial); +static int option_send_setup(struct usb_serial_port *port); +static void option_instat_callback(struct urb *urb); +/* VIA-Telecom CBP(Non-CDC version) IDs */ +struct wake_lock ets_wake_lock; +int ets_wake_lock_init = 0; +#define VIATELECOM_VENDOR_ID 0x15EB +#define VIATELECOM_PRODUCT_ID 0x0001 +#define BORA9380_VENDOR_ID 0x16d8 +#define BORA9380_PRODUCT_ID 0x4000 + +/* Vendor and product IDs */ +#define OPTION_VENDOR_ID 0x0AF0 +#define OPTION_PRODUCT_COLT 0x5000 +#define OPTION_PRODUCT_RICOLA 0x6000 +#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100 +#define OPTION_PRODUCT_RICOLA_QUAD 0x6200 +#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300 +#define OPTION_PRODUCT_RICOLA_NDIS 0x6050 +#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150 +#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250 +#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350 +#define OPTION_PRODUCT_COBRA 0x6500 +#define OPTION_PRODUCT_COBRA_BUS 0x6501 +#define OPTION_PRODUCT_VIPER 0x6600 +#define OPTION_PRODUCT_VIPER_BUS 0x6601 +#define OPTION_PRODUCT_GT_MAX_READY 0x6701 +#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721 +#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741 +#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761 +#define OPTION_PRODUCT_KOI_MODEM 0x6800 +#define OPTION_PRODUCT_SCORPION_MODEM 0x6901 +#define OPTION_PRODUCT_ETNA_MODEM 0x7001 +#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021 +#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041 +#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061 +#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 +#define OPTION_PRODUCT_GTM380_MODEM 0x7201 + +#define HUAWEI_VENDOR_ID 0x12D1 +#define HUAWEI_PRODUCT_E600 0x1001 +#define HUAWEI_PRODUCT_E220 0x1003 +#define HUAWEI_PRODUCT_E220BIS 0x1004 +#define HUAWEI_PRODUCT_E1401 0x1401 +#define HUAWEI_PRODUCT_E1402 0x1402 +#define HUAWEI_PRODUCT_E1403 0x1403 +#define HUAWEI_PRODUCT_E1404 0x1404 +#define HUAWEI_PRODUCT_E1405 0x1405 +#define HUAWEI_PRODUCT_E1406 0x1406 +#define HUAWEI_PRODUCT_E1407 0x1407 +#define HUAWEI_PRODUCT_E1408 0x1408 +#define HUAWEI_PRODUCT_E1409 0x1409 +#define HUAWEI_PRODUCT_E140A 0x140A +#define HUAWEI_PRODUCT_E140B 0x140B +#define HUAWEI_PRODUCT_E140C 0x140C +#define HUAWEI_PRODUCT_E140D 0x140D +#define HUAWEI_PRODUCT_E140E 0x140E +#define HUAWEI_PRODUCT_E140F 0x140F +#define HUAWEI_PRODUCT_E1410 0x1410 +#define HUAWEI_PRODUCT_E1411 0x1411 +#define HUAWEI_PRODUCT_E1412 0x1412 +#define HUAWEI_PRODUCT_E1413 0x1413 +#define HUAWEI_PRODUCT_E1414 0x1414 +#define HUAWEI_PRODUCT_E1415 0x1415 +#define HUAWEI_PRODUCT_E1416 0x1416 +#define HUAWEI_PRODUCT_E1417 0x1417 +#define HUAWEI_PRODUCT_E1418 0x1418 +#define HUAWEI_PRODUCT_E1419 0x1419 +#define HUAWEI_PRODUCT_E141A 0x141A +#define HUAWEI_PRODUCT_E141B 0x141B +#define HUAWEI_PRODUCT_E141C 0x141C +#define HUAWEI_PRODUCT_E141D 0x141D +#define HUAWEI_PRODUCT_E141E 0x141E +#define HUAWEI_PRODUCT_E141F 0x141F +#define HUAWEI_PRODUCT_E1420 0x1420 +#define HUAWEI_PRODUCT_E1421 0x1421 +#define HUAWEI_PRODUCT_E1422 0x1422 +#define HUAWEI_PRODUCT_E1423 0x1423 +#define HUAWEI_PRODUCT_E1424 0x1424 +#define HUAWEI_PRODUCT_E1425 0x1425 +#define HUAWEI_PRODUCT_E1426 0x1426 +#define HUAWEI_PRODUCT_E1427 0x1427 +#define HUAWEI_PRODUCT_E1428 0x1428 +#define HUAWEI_PRODUCT_E1429 0x1429 +#define HUAWEI_PRODUCT_E142A 0x142A +#define HUAWEI_PRODUCT_E142B 0x142B +#define HUAWEI_PRODUCT_E142C 0x142C +#define HUAWEI_PRODUCT_E142D 0x142D +#define HUAWEI_PRODUCT_E142E 0x142E +#define HUAWEI_PRODUCT_E142F 0x142F +#define HUAWEI_PRODUCT_E1430 0x1430 +#define HUAWEI_PRODUCT_E1431 0x1431 +#define HUAWEI_PRODUCT_E1432 0x1432 +#define HUAWEI_PRODUCT_E1433 0x1433 +#define HUAWEI_PRODUCT_E1434 0x1434 +#define HUAWEI_PRODUCT_E1435 0x1435 +#define HUAWEI_PRODUCT_E1436 0x1436 +#define HUAWEI_PRODUCT_E1437 0x1437 +#define HUAWEI_PRODUCT_E1438 0x1438 +#define HUAWEI_PRODUCT_E1439 0x1439 +#define HUAWEI_PRODUCT_E143A 0x143A +#define HUAWEI_PRODUCT_E143B 0x143B +#define HUAWEI_PRODUCT_E143C 0x143C +#define HUAWEI_PRODUCT_E143D 0x143D +#define HUAWEI_PRODUCT_E143E 0x143E +#define HUAWEI_PRODUCT_E143F 0x143F +#define HUAWEI_PRODUCT_K4505 0x1464 +#define HUAWEI_PRODUCT_K3765 0x1465 +#define HUAWEI_PRODUCT_E14AC 0x14AC +#define HUAWEI_PRODUCT_K3806 0x14AE +#define HUAWEI_PRODUCT_K4605 0x14C6 +#define HUAWEI_PRODUCT_K5005 0x14C8 +#define HUAWEI_PRODUCT_K3770 0x14C9 +#define HUAWEI_PRODUCT_K3771 0x14CA +#define HUAWEI_PRODUCT_K4510 0x14CB +#define HUAWEI_PRODUCT_K4511 0x14CC +#define HUAWEI_PRODUCT_ETS1220 0x1803 +#define HUAWEI_PRODUCT_E353 0x1506 +//aron add-------- +#define HUAWEI_PRODUCT_E153 0x1446 +#define HUAWEI_PRODUCT_E173 0x1C05 +//---------- +#define QUANTA_VENDOR_ID 0x0408 +#define QUANTA_PRODUCT_Q101 0xEA02 +#define QUANTA_PRODUCT_Q111 0xEA03 +#define QUANTA_PRODUCT_GLX 0xEA04 +#define QUANTA_PRODUCT_GKE 0xEA05 +#define QUANTA_PRODUCT_GLE 0xEA06 + +#define NOVATELWIRELESS_VENDOR_ID 0x1410 + +/* YISO PRODUCTS */ + +#define YISO_VENDOR_ID 0x0EAB +#define YISO_PRODUCT_U893 0xC893 + +/* + * NOVATEL WIRELESS PRODUCTS + * + * Note from Novatel Wireless: + * If your Novatel modem does not work on linux, don't + * change the option module, but check our website. If + * that does not help, contact ddeschepper@nvtl.com +*/ +/* MERLIN EVDO PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_V640 0x1100 +#define NOVATELWIRELESS_PRODUCT_V620 0x1110 +#define NOVATELWIRELESS_PRODUCT_V740 0x1120 +#define NOVATELWIRELESS_PRODUCT_V720 0x1130 + +/* MERLIN HSDPA/HSPA PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_U730 0x1400 +#define NOVATELWIRELESS_PRODUCT_U740 0x1410 +#define NOVATELWIRELESS_PRODUCT_U870 0x1420 +#define NOVATELWIRELESS_PRODUCT_XU870 0x1430 +#define NOVATELWIRELESS_PRODUCT_X950D 0x1450 + +/* EXPEDITE PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_EV620 0x2100 +#define NOVATELWIRELESS_PRODUCT_ES720 0x2110 +#define NOVATELWIRELESS_PRODUCT_E725 0x2120 +#define NOVATELWIRELESS_PRODUCT_ES620 0x2130 +#define NOVATELWIRELESS_PRODUCT_EU730 0x2400 +#define NOVATELWIRELESS_PRODUCT_EU740 0x2410 +#define NOVATELWIRELESS_PRODUCT_EU870D 0x2420 +/* OVATION PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_MC727 0x4100 +#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 +/* + * Note from Novatel Wireless: + * All PID in the 5xxx range are currently reserved for + * auto-install CDROMs, and should not be added to this + * module. + * + * #define NOVATELWIRELESS_PRODUCT_U727 0x5010 + * #define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 +*/ +#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 +#define NOVATELWIRELESS_PRODUCT_MC780 0x6010 +#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0x6000 +#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0x6001 +#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0x7000 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0x7001 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3 0x7003 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4 0x7004 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5 0x7005 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6 0x7006 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7 0x7007 +#define NOVATELWIRELESS_PRODUCT_MC996D 0x7030 +#define NOVATELWIRELESS_PRODUCT_MF3470 0x7041 +#define NOVATELWIRELESS_PRODUCT_MC547 0x7042 +#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0x8000 +#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 +#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 +#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 +#define NOVATELWIRELESS_PRODUCT_G1 0xA001 +#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 +#define NOVATELWIRELESS_PRODUCT_G2 0xA010 +#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 + +/* AMOI PRODUCTS */ +#define AMOI_VENDOR_ID 0x1614 +#define AMOI_PRODUCT_H01 0x0800 +#define AMOI_PRODUCT_H01A 0x7002 +#define AMOI_PRODUCT_H02 0x0802 +#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407 + +#define DELL_VENDOR_ID 0x413C + +/* Dell modems */ +#define DELL_PRODUCT_5700_MINICARD 0x8114 +#define DELL_PRODUCT_5500_MINICARD 0x8115 +#define DELL_PRODUCT_5505_MINICARD 0x8116 +#define DELL_PRODUCT_5700_EXPRESSCARD 0x8117 +#define DELL_PRODUCT_5510_EXPRESSCARD 0x8118 + +#define DELL_PRODUCT_5700_MINICARD_SPRINT 0x8128 +#define DELL_PRODUCT_5700_MINICARD_TELUS 0x8129 + +#define DELL_PRODUCT_5720_MINICARD_VZW 0x8133 +#define DELL_PRODUCT_5720_MINICARD_SPRINT 0x8134 +#define DELL_PRODUCT_5720_MINICARD_TELUS 0x8135 +#define DELL_PRODUCT_5520_MINICARD_CINGULAR 0x8136 +#define DELL_PRODUCT_5520_MINICARD_GENERIC_L 0x8137 +#define DELL_PRODUCT_5520_MINICARD_GENERIC_I 0x8138 + +#define DELL_PRODUCT_5730_MINICARD_SPRINT 0x8180 +#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 +#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 + +#define KYOCERA_VENDOR_ID 0x0c88 +#define KYOCERA_PRODUCT_KPC650 0x17da +#define KYOCERA_PRODUCT_KPC680 0x180a + +#define ANYDATA_VENDOR_ID 0x16d5 +#define ANYDATA_PRODUCT_ADU_620UW 0x6202 +#define ANYDATA_PRODUCT_ADU_E100A 0x6501 +#define ANYDATA_PRODUCT_ADU_500A 0x6502 + +#define AXESSTEL_VENDOR_ID 0x1726 +#define AXESSTEL_PRODUCT_MV110H 0x1000 + +#define BANDRICH_VENDOR_ID 0x1A8D +#define BANDRICH_PRODUCT_C100_1 0x1002 +#define BANDRICH_PRODUCT_C100_2 0x1003 +#define BANDRICH_PRODUCT_1004 0x1004 +#define BANDRICH_PRODUCT_1005 0x1005 +#define BANDRICH_PRODUCT_1006 0x1006 +#define BANDRICH_PRODUCT_1007 0x1007 +#define BANDRICH_PRODUCT_1008 0x1008 +#define BANDRICH_PRODUCT_1009 0x1009 +#define BANDRICH_PRODUCT_100A 0x100a + +#define BANDRICH_PRODUCT_100B 0x100b +#define BANDRICH_PRODUCT_100C 0x100c +#define BANDRICH_PRODUCT_100D 0x100d +#define BANDRICH_PRODUCT_100E 0x100e + +#define BANDRICH_PRODUCT_100F 0x100f +#define BANDRICH_PRODUCT_1010 0x1010 +#define BANDRICH_PRODUCT_1011 0x1011 +#define BANDRICH_PRODUCT_1012 0x1012 + +#define QUALCOMM_VENDOR_ID 0x05C6 + +#define CMOTECH_VENDOR_ID 0x16d8 +#define CMOTECH_PRODUCT_6008 0x6008 +#define CMOTECH_PRODUCT_6280 0x6280 + +#define TELIT_VENDOR_ID 0x1bc7 +#define TELIT_PRODUCT_UC864E 0x1003 +#define TELIT_PRODUCT_UC864G 0x1004 +#define TELIT_PRODUCT_CC864_DUAL 0x1005 +#define TELIT_PRODUCT_CC864_SINGLE 0x1006 +#define TELIT_PRODUCT_DE910_DUAL 0x1010 + +/* ZTE PRODUCTS */ +#define ZTE_VENDOR_ID 0x19d2 +#define ZTE_PRODUCT_MF622 0x0001 +#define ZTE_PRODUCT_MF628 0x0015 +#define ZTE_PRODUCT_MF626 0x0031 +#define ZTE_PRODUCT_CDMA_TECH 0xfffe +#define ZTE_PRODUCT_AC8710 0xfff1 +#define ZTE_PRODUCT_AC2726 0xfff5 +#define ZTE_PRODUCT_AC8710T 0xffff +#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_AD3812 0xffeb +#define ZTE_PRODUCT_MC2716 0xffed + +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_H10 0x4068 + +#define DLINK_VENDOR_ID 0x1186 +#define DLINK_PRODUCT_DWM_652 0x3e04 +#define DLINK_PRODUCT_DWM_652_U5 0xce16 +#define DLINK_PRODUCT_DWM_652_U5A 0xce1e + +#define QISDA_VENDOR_ID 0x1da5 +#define QISDA_PRODUCT_H21_4512 0x4512 +#define QISDA_PRODUCT_H21_4523 0x4523 +#define QISDA_PRODUCT_H20_4515 0x4515 +#define QISDA_PRODUCT_H20_4518 0x4518 +#define QISDA_PRODUCT_H20_4519 0x4519 + +/* TLAYTECH PRODUCTS */ +#define TLAYTECH_VENDOR_ID 0x20B9 +#define TLAYTECH_PRODUCT_TEU800 0x1682 + +/* TOSHIBA PRODUCTS */ +#define TOSHIBA_VENDOR_ID 0x0930 +#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 +#define TOSHIBA_PRODUCT_G450 0x0d45 + +#define ALINK_VENDOR_ID 0x1e0e +#define ALINK_PRODUCT_PH300 0x9100 +#define ALINK_PRODUCT_3GU 0x9200 + +/* ALCATEL PRODUCTS */ +#define ALCATEL_VENDOR_ID 0x1bbb +#define ALCATEL_PRODUCT_X060S_X200 0x0000 + +#define PIRELLI_VENDOR_ID 0x1266 +#define PIRELLI_PRODUCT_C100_1 0x1002 +#define PIRELLI_PRODUCT_C100_2 0x1003 +#define PIRELLI_PRODUCT_1004 0x1004 +#define PIRELLI_PRODUCT_1005 0x1005 +#define PIRELLI_PRODUCT_1006 0x1006 +#define PIRELLI_PRODUCT_1007 0x1007 +#define PIRELLI_PRODUCT_1008 0x1008 +#define PIRELLI_PRODUCT_1009 0x1009 +#define PIRELLI_PRODUCT_100A 0x100a +#define PIRELLI_PRODUCT_100B 0x100b +#define PIRELLI_PRODUCT_100C 0x100c +#define PIRELLI_PRODUCT_100D 0x100d +#define PIRELLI_PRODUCT_100E 0x100e +#define PIRELLI_PRODUCT_100F 0x100f +#define PIRELLI_PRODUCT_1011 0x1011 +#define PIRELLI_PRODUCT_1012 0x1012 + +/* Airplus products */ +#define AIRPLUS_VENDOR_ID 0x1011 +#define AIRPLUS_PRODUCT_MCD650 0x3198 + +/* Longcheer/Longsung vendor ID; makes whitelabel devices that + * many other vendors like 4G Systems, Alcatel, ChinaBird, + * Mobidata, etc sell under their own brand names. + */ +#define LONGCHEER_VENDOR_ID 0x1c9e + +/* 4G Systems products */ +/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick * + * It seems to contain a Qualcomm QSC6240/6290 chipset */ +#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 + +/* Zoom */ +#define ZOOM_PRODUCT_4597 0x9607 + +/* Haier products */ +#define HAIER_VENDOR_ID 0x201e +#define HAIER_PRODUCT_CE100 0x2009 + +/* Cinterion (formerly Siemens) products */ +#define SIEMENS_VENDOR_ID 0x0681 +#define CINTERION_VENDOR_ID 0x1e2d +#define CINTERION_PRODUCT_HC25_MDM 0x0047 +#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 +#define CINTERION_PRODUCT_HC28_MDM 0x004C +#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ +#define CINTERION_PRODUCT_EU3_E 0x0051 +#define CINTERION_PRODUCT_EU3_P 0x0052 +#define CINTERION_PRODUCT_PH8 0x0053 + +/* Olivetti products */ +#define OLIVETTI_VENDOR_ID 0x0b3c +#define OLIVETTI_PRODUCT_OLICARD100 0xc000 + +/* Celot products */ +#define CELOT_VENDOR_ID 0x211f +#define CELOT_PRODUCT_CT680M 0x6801 + +/* ONDA Communication vendor id */ +#define ONDA_VENDOR_ID 0x1ee8 + +/* ONDA MT825UP HSDPA 14.2 modem */ +#define ONDA_MT825UP 0x000b + +/* Samsung products */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_GT_B3730 0x6889 + +/* YUGA products www.yuga-info.com gavin.kx@qq.com */ +#define YUGA_VENDOR_ID 0x257A +#define YUGA_PRODUCT_CEM600 0x1601 +#define YUGA_PRODUCT_CEM610 0x1602 +#define YUGA_PRODUCT_CEM500 0x1603 +#define YUGA_PRODUCT_CEM510 0x1604 +#define YUGA_PRODUCT_CEM800 0x1605 +#define YUGA_PRODUCT_CEM900 0x1606 + +#define YUGA_PRODUCT_CEU818 0x1607 +#define YUGA_PRODUCT_CEU816 0x1608 +#define YUGA_PRODUCT_CEU828 0x1609 +#define YUGA_PRODUCT_CEU826 0x160A +#define YUGA_PRODUCT_CEU518 0x160B +#define YUGA_PRODUCT_CEU516 0x160C +#define YUGA_PRODUCT_CEU528 0x160D +#define YUGA_PRODUCT_CEU526 0x160F +#define YUGA_PRODUCT_CEU881 0x161F +#define YUGA_PRODUCT_CEU882 0x162F + +#define YUGA_PRODUCT_CWM600 0x2601 +#define YUGA_PRODUCT_CWM610 0x2602 +#define YUGA_PRODUCT_CWM500 0x2603 +#define YUGA_PRODUCT_CWM510 0x2604 +#define YUGA_PRODUCT_CWM800 0x2605 +#define YUGA_PRODUCT_CWM900 0x2606 + +#define YUGA_PRODUCT_CWU718 0x2607 +#define YUGA_PRODUCT_CWU716 0x2608 +#define YUGA_PRODUCT_CWU728 0x2609 +#define YUGA_PRODUCT_CWU726 0x260A +#define YUGA_PRODUCT_CWU518 0x260B +#define YUGA_PRODUCT_CWU516 0x260C +#define YUGA_PRODUCT_CWU528 0x260D +#define YUGA_PRODUCT_CWU581 0x260E +#define YUGA_PRODUCT_CWU526 0x260F +#define YUGA_PRODUCT_CWU582 0x261F +#define YUGA_PRODUCT_CWU583 0x262F + +#define YUGA_PRODUCT_CLM600 0x3601 +#define YUGA_PRODUCT_CLM610 0x3602 +#define YUGA_PRODUCT_CLM500 0x3603 +#define YUGA_PRODUCT_CLM510 0x3604 +#define YUGA_PRODUCT_CLM800 0x3605 +#define YUGA_PRODUCT_CLM900 0x3606 + +#define YUGA_PRODUCT_CLU718 0x3607 +#define YUGA_PRODUCT_CLU716 0x3608 +#define YUGA_PRODUCT_CLU728 0x3609 +#define YUGA_PRODUCT_CLU726 0x360A +#define YUGA_PRODUCT_CLU518 0x360B +#define YUGA_PRODUCT_CLU516 0x360C +#define YUGA_PRODUCT_CLU528 0x360D +#define YUGA_PRODUCT_CLU526 0x360F + +/* Viettel products */ +#define VIETTEL_VENDOR_ID 0x2262 +#define VIETTEL_PRODUCT_VT1000 0x0002 + +/* ZD Incorporated */ +#define ZD_VENDOR_ID 0x0685 +#define ZD_PRODUCT_7000 0x7000 + +/* LG products */ +#define LG_VENDOR_ID 0x1004 +#define LG_PRODUCT_L02C 0x618f + +/* MediaTek products */ +#define MEDIATEK_VENDOR_ID 0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 +#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM 0x7101 +#define MEDIATEK_PRODUCT_7208_2COM 0x7102 +#define MEDIATEK_PRODUCT_FP_1COM 0x0003 +#define MEDIATEK_PRODUCT_FP_2COM 0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 + +/* Cellient products */ +#define CELLIENT_VENDOR_ID 0x2692 +#define CELLIENT_PRODUCT_MEN200 0x9005 + +/* some devices interfaces need special handling due to a number of reasons */ +enum option_blacklist_reason { + OPTION_BLACKLIST_NONE = 0, + OPTION_BLACKLIST_SENDSETUP = 1, + OPTION_BLACKLIST_RESERVED_IF = 2 +}; + +#define MAX_BL_NUM 8 +struct option_blacklist_info { + /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */ + const unsigned long sendsetup; + /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */ + const unsigned long reserved; +}; + +static const struct option_blacklist_info four_g_w14_blacklist = { + .sendsetup = BIT(0) | BIT(1), +}; + +static const struct option_blacklist_info alcatel_x200_blacklist = { + .sendsetup = BIT(0) | BIT(1), +}; + +static const struct option_blacklist_info zte_0037_blacklist = { + .sendsetup = BIT(0) | BIT(1), +}; + +static const struct option_blacklist_info zte_k3765_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), + .reserved = BIT(4), +}; + +static const struct option_blacklist_info zte_ad3812_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), +}; + +static const struct option_blacklist_info zte_mc2718_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info zte_mc2716_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3), +}; + +static const struct option_blacklist_info huawei_cdc12_blacklist = { + .reserved = BIT(1) | BIT(2), +}; + +static const struct option_blacklist_info net_intf1_blacklist = { + .reserved = BIT(1), +}; + +static const struct option_blacklist_info net_intf2_blacklist = { + .reserved = BIT(2), +}; + +static const struct option_blacklist_info net_intf3_blacklist = { + .reserved = BIT(3), +}; + +static const struct option_blacklist_info net_intf4_blacklist = { + .reserved = BIT(4), +}; + +static const struct option_blacklist_info net_intf5_blacklist = { + .reserved = BIT(5), +}; + +static const struct option_blacklist_info zte_mf626_blacklist = { + .sendsetup = BIT(0) | BIT(1), + .reserved = BIT(4), +}; + +static const struct usb_device_id option_ids[] = { + { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) }, + { USB_DEVICE(0x201e, 0x1022) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, option_ids); + + +/* add rawbulk suspend support */ +static int usb_serial_option_suspend(struct usb_interface *intf, pm_message_t message) +{ + int rc = 0; + + rc = usb_serial_suspend(intf, message); + if(rc < 0) + { + err("usb_serial_suspend return error, errno=%d\n", rc); + return rc; + } +#ifdef CONFIG_USB_ANDROID_RAWBULK + return rawbulk_suspend_host_interface(intf->cur_altsetting->desc.bInterfaceNumber, message); +#else + return rc; +#endif +} + +static int usb_serial_option_resume(struct usb_interface *intf) +{ + int rc = 0; + + rc = usb_serial_resume(intf); + if(rc < 0) + { + err("usb_serial_resume return error, errno=%d\n", rc); + return rc; + } + +#ifdef CONFIG_USB_ANDROID_RAWBULK + return rawbulk_resume_host_interface(intf->cur_altsetting->desc.bInterfaceNumber); +#else + return rc; +#endif +} +/* End of temp added */ + +static int usb_serial_option_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void usb_serial_option_disconnect(struct usb_interface *interface); +static struct usb_driver option_driver = { + .name = "via_option", + .probe = usb_serial_option_probe, + .disconnect = usb_serial_option_disconnect, +#ifdef CONFIG_PM + .suspend = usb_serial_option_suspend, + .resume = usb_serial_option_resume, + .supports_autosuspend = 1, +#endif + .id_table = option_ids, +}; + +static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port + *port, const unsigned char *buf, int count); + + +/* The card has three separate interfaces, which the serial driver + * recognizes separately, thus num_port=1. + */ + +static struct usb_serial_driver option_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "via_option1", + }, + .description = "GSM modem (1-port)", + .id_table = option_ids, + .num_ports = 1, + .probe = option_probe, + .open = usb_wwan_open, + .close = usb_wwan_close, + .dtr_rts = usb_wwan_dtr_rts, + .write = usb_wwan_option_write, + .write_room = usb_wwan_write_room, + .chars_in_buffer = usb_wwan_chars_in_buffer, + .set_termios = usb_wwan_set_termios, + .tiocmget = usb_wwan_tiocmget, + .tiocmset = usb_wwan_tiocmset, + .ioctl = usb_wwan_ioctl, + .attach = usb_wwan_startup, + .disconnect = usb_wwan_disconnect, + .release = usb_wwan_release, + .read_int_callback = option_instat_callback, +#ifdef CONFIG_PM + .suspend = usb_wwan_suspend, + .resume = usb_wwan_resume, +#endif +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &option_1port_device, NULL +}; + +//static bool debug; + +//module_usb_serial_driver(option_driver, serial_drivers); + +static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, + const struct option_blacklist_info *blacklist) +{ + unsigned long num; + const unsigned long *intf_list; + + if (blacklist) { + if (reason == OPTION_BLACKLIST_SENDSETUP) + intf_list = &blacklist->sendsetup; + else if (reason == OPTION_BLACKLIST_RESERVED_IF) + intf_list = &blacklist->reserved; + else { + BUG_ON(reason); + return false; + } + + for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { + if (num == ifnum) + return true; + } + } + return false; +} + + +static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ +#ifdef CONFIG_USB_ANDROID_RAWBULK + int inception; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); + spin_lock_irq(&portdata->incept_lock); + inception = portdata->inception; + spin_unlock_irq(&portdata->incept_lock); + + if (inception) + return 0; +#endif + + return usb_wwan_write(tty, port, buf, count); +} + +#ifdef CONFIG_USB_ANDROID_RAWBULK +#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_AP2MODEM_VIATELECOM) +extern void ap_wake_modem(void); +extern void ap_sleep_modem(void); +#endif + +#ifdef CONFIG_VIATELECOM_SYNC_CBP +static int option_rawbulk_asc_notifier(int msg, void *data) { + int opened; + struct usb_serial *serial = data; + struct usb_serial_port *port = serial->port[0]; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); + struct usb_wwan_intf_private *intfdata = serial->private; + + spin_lock_irq(&intfdata->susp_lock); + opened = portdata->opened; + spin_unlock_irq(&intfdata->susp_lock); + + if (!opened && msg == ASC_NTF_RX_PREPARE) + asc_rx_confirm_ready(USB_RX_HD_NAME, 1); + return 0; +} +#endif + +static int option_rawbulk_intercept(struct usb_interface *interface, unsigned int flags) { + int rc = 0; + struct usb_serial *serial = usb_get_intfdata(interface); + struct usb_serial_port *port = serial->port[0]; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); + struct usb_wwan_intf_private *intfdata = serial->private; + int nif = interface->cur_altsetting->desc.bInterfaceNumber; + int enable = flags & RAWBULK_INCEPT_FLAG_ENABLE; + int opened; + int n; + + spin_lock_irq(&portdata->incept_lock); + if (portdata->inception == !!enable) { + spin_unlock_irq(&portdata->incept_lock); + return -ENOENT; + } + spin_unlock_irq(&portdata->incept_lock); + + spin_lock_irq(&intfdata->susp_lock); + opened = portdata->opened; + spin_unlock_irq(&intfdata->susp_lock); + + printk(KERN_DEBUG "rawbulk do %s on port %d (%s)\n", enable? "incept": + "unincept", port->number, opened? "opened": "not-in-use"); + + if (enable) { +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + struct asc_infor user = { + .notifier = option_rawbulk_asc_notifier, + .data = serial, + }; + snprintf(user.name, ASC_NAME_LEN, "%s%d", RAWBULK_RX_USER_NAME, nif); + asc_rx_add_user(USB_RX_HD_NAME, &user); + asc_tx_auto_ready(USB_TX_HD_NAME, 0); +#endif + +#ifdef CONFIG_PM + rc = usb_autopm_get_interface(interface); + if (rc < 0) + printk(KERN_ERR "incept failed while geting interface#%d\n", nif); +#endif + /* Stop reading/writing urbs */ + if (opened) { + if (!(flags & RAWBULK_INCEPT_FLAG_PUSH_WAY)) + for (n = 0; n < portdata->n_in_urb; n++) + usb_kill_urb(portdata->in_urbs[n]); + for (n = 0; n < portdata->n_out_urb; n++) + usb_kill_urb(portdata->out_urbs[n]); + } + /* Start urb for push-way */ + if (flags & RAWBULK_INCEPT_FLAG_PUSH_WAY) { + for (n = 0; n < portdata->n_in_urb; n ++) { + struct urb *urb = portdata->in_urbs[n]; + if (!urb || !urb->dev) + continue; + /* reset urb */ + usb_kill_urb(urb); + usb_clear_halt(urb->dev, urb->pipe); + rc = usb_submit_urb(urb, GFP_KERNEL); + if (rc < 0) + break; + } + if (rc < 0) + printk(KERN_ERR "incept %d while re-submitting " \ + "pushable urbs %d\n", nif, rc); + } + } else { +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + char asc_user[ASC_NAME_LEN]; +#endif + rc = usb_autopm_get_interface(interface); + if (rc < 0) + printk(KERN_ERR "unincept while get interface#%d\n", nif); + if (!intfdata->suspended && opened) { + for (n = 0; n < portdata->n_in_urb; n ++) { + struct urb *urb = portdata->in_urbs[n]; + if (!urb || !urb->dev) + continue; + /* reset urb */ + usb_kill_urb(urb); + usb_clear_halt(urb->dev, urb->pipe); + rc = usb_submit_urb(urb, GFP_KERNEL); + if (rc < 0) + break; + } + if (rc < 0) + printk(KERN_ERR "unincept %d while reseting " \ + "bulk IN urbs %d\n", nif, rc); + } +#ifdef CONFIG_PM + usb_autopm_put_interface(interface); +#endif +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + snprintf(asc_user, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, RAWBULK_RX_USER_NAME), nif); + asc_rx_del_user(asc_user); +#endif + } + + if (!rc) { + spin_lock_irq(&portdata->incept_lock); + portdata->inception = !!enable; + spin_unlock_irq(&portdata->incept_lock); + } else + printk(KERN_ERR "failed(%d) to %s inception on interface#%d\n", + rc, enable? "enable": "disable", nif); + + return rc; +} + +#endif + +int serial_ntcall(struct notifier_block *nb, unsigned long val, void *nodata) +{ + struct usb_wwan_intf_private *data = container_of(nb,struct usb_wwan_intf_private,pm_nb); + + switch (val) { + case PM_SUSPEND_PREPARE: + usb_disable_autosuspend(data->udev); + return NOTIFY_DONE; + case PM_POST_SUSPEND: + usb_enable_autosuspend(data->udev); + return NOTIFY_DONE; + } + return NOTIFY_DONE; +} + +static int viatelecom_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); + int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + + /* VIA-Telecom CBP DTR format */ + return usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum, + NULL, 0, USB_CTRL_SET_TIMEOUT); + + +} +static int option_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + struct usb_wwan_intf_private *data; + + /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ + if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && + serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && + serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) + return -ENODEV; + + /* Bandrich modem and AT command interface is 0xff */ + if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID || + serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) && + serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) + return -ENODEV; + + /* Don't bind reserved interfaces (like network ones) which often have + * the same class/subclass/protocol as the serial interfaces. Look at + * the Windows driver .INF files for reserved interface numbers. + */ + if (is_blacklisted( + serial->interface->cur_altsetting->desc.bInterfaceNumber, + OPTION_BLACKLIST_RESERVED_IF, + (const struct option_blacklist_info *) id->driver_info)) + return -ENODEV; + + /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ + if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && + serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 && + serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) + return -ENODEV; + + data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); + if (!data) + return -ENOMEM; + + + //kevin modify for viatel modem + data->send_setup = viatelecom_send_setup; + //data->send_setup = option_send_setup; + + spin_lock_init(&data->susp_lock); + data->private = (void *)id->driver_info; + return 0; +} + +static void option_release(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); + + usb_wwan_release(serial); + + kfree(priv); +} + +#define USB_CBP_TESTMODE_ENABLE 0x1 +#define USB_CBP_TESTMODE_QUERY 0x2 +#define USB_CBP_TESTMODE_UNSOLICTED 0x3 +static ssize_t option_port_testmode_show(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int rc; + struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev); + struct usb_device *udev = port0->serial->dev; + struct usb_interface *interface = port0->serial->interface; + int ifnum = interface->cur_altsetting->desc.bInterfaceNumber; + int feedback = -1; + rc = usb_autopm_get_interface(interface); + if (rc < 0) { + printk(KERN_ERR "failed to awake cp-usb when query testmode. %d\n", rc); + return -ENODEV; + } + rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_CBP_TESTMODE_QUERY, + USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 0, ifnum, &feedback, 2, USB_CTRL_GET_TIMEOUT * 5); + usb_autopm_put_interface(interface); + if ((feedback & 0xff) == 0x1) + return sprintf(buf, "%s", "enabled"); + if ((feedback & 0xff) == 0x0) + return sprintf(buf, "%s", "disabled"); + printk(KERN_ERR "connot query cp testmode %d, feedback %04x\n", rc, feedback & 0xffff); + return -EOPNOTSUPP; +} + +static ssize_t option_port_testmode_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + int rc = 0; + int enable = -1; + struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev); + struct usb_device *udev = port0->serial->dev; + struct usb_interface *interface = port0->serial->interface; + int ifnum = interface->cur_altsetting->desc.bInterfaceNumber; + + if (!strncmp(buf, "enable", 6)) + enable = 1; + else if (!strncmp(buf, "disable", 7)) + enable = 0; + if (enable >= 0) { + rc = usb_autopm_get_interface(interface); + if (rc < 0) { + printk(KERN_ERR "failed to awake cp-usb when set testmode. %d\n", rc); + return -ENODEV; + } + rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_CBP_TESTMODE_ENABLE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + enable, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); + usb_autopm_put_interface(interface); + if (rc < 0) { + printk(KERN_DEBUG "failed to sent testmode contorl msg %d\n", rc); + return rc; + } + } else if (!strncmp(buf, "unsolited", 9)) { + /* rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_CBP_TESTMODE_UNSOLICTED, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 0, ifnum, ¶m, sizeof(param), USB_CTRL_SET_TIMEOUT); */ + printk(KERN_DEBUG "unsolited test mode for cp does not supported yet.\n"); + } + + return count; +} + +static DEVICE_ATTR(testmode, S_IRUGO | S_IWUSR, + option_port_testmode_show, + option_port_testmode_store); + +static int usb_serial_option_probe(struct usb_interface *interface, + const struct usb_device_id *id) { + struct usb_serial *serial; + int ret = usb_serial_probe(interface, id); + if (ret < 0) + return ret; + +#ifdef CONFIG_USB_ANDROID_RAWBULK + ret = rawbulk_bind_host_interface(interface, option_rawbulk_intercept); + if (ret < 0) + return ret; +#endif + + + + + serial = usb_get_intfdata(interface); + return sysfs_create_file(&serial->port[0]->dev.kobj, + &dev_attr_testmode.attr); +} + +static void usb_serial_option_disconnect(struct usb_interface *interface) { + struct usb_serial *serial = usb_get_intfdata(interface); + struct usb_wwan_intf_private *data = serial->private; + + + + unregister_pm_notifier(&data->pm_nb); + + sysfs_remove_file(&serial->port[0]->dev.kobj, &dev_attr_testmode.attr); +#ifdef CONFIG_USB_ANDROID_RAWBULK + rawbulk_unbind_host_interface(interface); +#endif + + usb_serial_disconnect(interface); +} + + +static void option_instat_callback(struct urb *urb) +{ + int err; + int status = urb->status; + struct usb_serial_port *port = urb->context; + struct usb_wwan_port_private *portdata = + usb_get_serial_port_data(port); + + dbg("%s", __func__); + dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); + + if (status == 0) { + struct usb_ctrlrequest *req_pkt = + (struct usb_ctrlrequest *)urb->transfer_buffer; + + if (!req_pkt) { + dbg("%s: NULL req_pkt", __func__); + return; + } + if ((req_pkt->bRequestType == 0xA1) && + (req_pkt->bRequest == 0x20)) { + int old_dcd_state; + unsigned char signals = *((unsigned char *) + urb->transfer_buffer + + sizeof(struct usb_ctrlrequest)); + + dbg("%s: signal x%x", __func__, signals); + + old_dcd_state = portdata->dcd_state; + portdata->cts_state = 1; + portdata->dcd_state = ((signals & 0x01) ? 1 : 0); + portdata->dsr_state = ((signals & 0x02) ? 1 : 0); + portdata->ri_state = ((signals & 0x08) ? 1 : 0); + + if (old_dcd_state && !portdata->dcd_state) { + struct tty_struct *tty = + tty_port_tty_get(&port->port); + if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); + tty_kref_put(tty); + } + } else { + dbg("%s: type %x req %x", __func__, + req_pkt->bRequestType, req_pkt->bRequest); + } + } else + err("%s: error %d", __func__, status); + + /* Resubmit urb so we continue receiving IRQ data */ + if (status != -ESHUTDOWN && status != -ENOENT) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dbg("%s: resubmit intr urb failed. (%d)", + __func__, err); + } +} + +/** send RTS/DTR state to the port. + * + * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN + * CDC. +*/ +static int option_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_intf_private *intfdata = + (struct usb_wwan_intf_private *) serial->private; + struct usb_wwan_port_private *portdata; + int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + int val = 0; + dbg("%s", __func__); + + if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, + (struct option_blacklist_info *) intfdata->private)) { + dbg("No send_setup on blacklisted interface #%d\n", ifNum); + return -EIO; + } + + portdata = usb_get_serial_port_data(port); + + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); +} + + + + +static int __init via_option_init(void) +{ + int retval; + + + retval = usb_serial_register_drivers(&option_driver, serial_drivers); + if (retval) + goto failed_driver_register; + + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); + + + + wake_lock_init(&ets_wake_lock, WAKE_LOCK_SUSPEND, "ETS_Prevent_Suspend"); + usb_ap_sync_cbp_init(); + return 0; + +failed_driver_register: + + + return retval; +} + + +static void __exit via_option_exit (void) +{ + + wake_lock_destroy(&ets_wake_lock); + + usb_serial_deregister_drivers(&option_driver, serial_drivers); +} + + +module_init(via_option_init); +module_exit(via_option_exit); + + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +//module_param(debug, bool, S_IRUGO | S_IWUSR); +//MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h b/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h new file mode 100755 index 00000000..415b74c6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h @@ -0,0 +1,88 @@ +/* + * Definitions for USB serial mobile broadband cards + */ + +#ifndef __LINUX_USB_USB_WWAN +#define __LINUX_USB_USB_WWAN + +#define CONFIG_VIATELECOM_SYNC_CBP 1 +#define CONFIG_USB_ANDROID_RAWBULK 1 + + + +extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); +extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); +extern void usb_wwan_close(struct usb_serial_port *port); +extern int usb_wwan_startup(struct usb_serial *serial); +extern void usb_wwan_disconnect(struct usb_serial *serial); +extern void usb_wwan_release(struct usb_serial *serial); +extern int usb_wwan_write_room(struct tty_struct *tty); +extern void usb_wwan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old); +extern int usb_wwan_tiocmget(struct tty_struct *tty); +extern int usb_wwan_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear); +extern int usb_wwan_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg); +extern int usb_wwan_send_setup(struct usb_serial_port *port); +extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); +#ifdef CONFIG_PM +extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message); +extern int usb_wwan_resume(struct usb_serial *serial); +#endif + +/* per port private data */ + +#define N_IN_URB 8 +#define N_OUT_URB 16 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 4096 + +#define MAX_IN_URBS 16 +#define MAX_OUT_URBS 16 + +struct usb_wwan_intf_private { + spinlock_t susp_lock; + struct usb_device *udev; + struct notifier_block pm_nb; + unsigned int suspended:1; + int in_flight; + int (*send_setup) (struct usb_serial_port *port); + void *private; +}; + +struct usb_wwan_port_private { + /* Input endpoints and buffer for this port */ + unsigned int n_in_urb; + unsigned int in_buflen; + struct urb *in_urbs[MAX_IN_URBS]; + u8 *in_buffer[MAX_IN_URBS]; + /* Output endpoints and buffer for this port */ + unsigned int n_out_urb; + unsigned int out_buflen; + struct urb *out_urbs[MAX_OUT_URBS]; + u8 *out_buffer[MAX_OUT_URBS]; + unsigned long out_busy; /* Bit vector of URBs in use */ + int opened; + struct usb_anchor delayed; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[MAX_OUT_URBS]; + +#ifdef CONFIG_USB_ANDROID_RAWBULK + spinlock_t incept_lock; + unsigned int inception:1; +#endif +}; + +#endif /* __LINUX_USB_USB_WWAN */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c b/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c new file mode 100755 index 00000000..56c11455 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c @@ -0,0 +1,1013 @@ +/* + USB Driver layer for GSM modems + + Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> + + This driver is free software; you can redistribute it and/or modify + it under the terms of Version 2 of the GNU General Public License as + published by the Free Software Foundation. + + Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org> + + History: see the git log. + + Work sponsored by: Sigos GmbH, Germany <info@sigos.de> + + This driver exists because the "normal" serial driver doesn't work too well + with GSM modems. Issues: + - data loss -- one single Receive URB is not nearly enough + - controlling the baud rate doesn't make sense +*/ + +#define DRIVER_VERSION "v0.7.2" +#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" +#define DRIVER_DESC "USB Driver for GSM modems" + +#include <linux/kernel.h> +#include <linux/jiffies.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/serial.h> +#include <linux/wakelock.h> +#include "via_usb-wwan.h" + +#ifdef CONFIG_USB_ANDROID_RAWBULK +#include <linux/usb/rawbulk.h> +#endif + +#ifdef CONFIG_VIATELECOM_SYNC_CBP +#include <mach/viatel.h> +#define ASC_INTF_NUM (10) +atomic_t intf_pm_count[ASC_INTF_NUM]; + +#define EXPORT_SYMBOL(x) + + +static struct asc_config usb_tx_handle = { + .name = USB_TX_HD_NAME, + .gpio_wake = GPIO_VIATEL_USB_AP_WAKE_MDM, + .gpio_ready = GPIO_VIATEL_USB_MDM_RDY, + .polar = 1, +}; + +struct asc_config usb_rx_handle = { + .name = USB_RX_HD_NAME, + .gpio_wake = GPIO_VIATEL_USB_MDM_WAKE_AP, + .gpio_ready = GPIO_VIATEL_USB_AP_RDY, + .polar = 1, +}; + +static int usb_ap_sync_cbp_init(void) +{ + int i, ret = 0; + for(i = 0; i < ASC_INTF_NUM; i++){ + atomic_set(&intf_pm_count[i], 0); + } + asc_tx_register_handle(&usb_tx_handle); + asc_rx_register_handle(&usb_rx_handle); + return ret; +} + +//late_initcall(usb_ap_sync_cbp_init); + +static int cbp_usb_interface_notifier(int msg, void *data) + { + int index, ret = 0; + struct usb_interface * intf = (struct usb_interface *)data; + + if(!intf) { + printk(KERN_ERR "%s - usb find device interface error\n", __func__); + return -ENODEV; + } + + index = (int)intf->cur_altsetting->desc.bInterfaceNumber; + if(index < 0 || index > ASC_INTF_NUM){ + printk(KERN_ERR "%s - error interface index %d.\n", __func__, index); + return -ENODEV; + } + switch(msg){ + case ASC_NTF_RX_PREPARE: + //printk("%s:inft%d get cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index])); + if(!atomic_read(&intf_pm_count[index])){ + if(!usb_autopm_get_interface(intf)){ + atomic_set(&intf_pm_count[index], 1); + } + } + asc_rx_confirm_ready(USB_RX_HD_NAME, !ret); + break; + + case ASC_NTF_RX_POST: + //printk("%s:inft%d put cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index])); + if(atomic_read(&intf_pm_count[index])){ + usb_autopm_put_interface(intf); + atomic_set(&intf_pm_count[index], 0); + } + break; + default: + printk("%s unknow message %d\n", __FUNCTION__, msg); + } + + return ret; +} +static int cbp_usb_interface_add_user(struct usb_interface * intf) +{ + int index; + struct asc_infor user; + + if(!intf){ + return -EINVAL; + } + + index = (int)intf->cur_altsetting->desc.bInterfaceNumber; + memset(&user, 0, sizeof(user)); + user.notifier = cbp_usb_interface_notifier; + user.data = intf; + snprintf(user.name, ASC_NAME_LEN, "%s%d", USB_RX_USER_NAME, index); + return asc_rx_add_user(USB_RX_HD_NAME, &user); +} + +static void cbp_usb_interface_del_user(struct usb_interface * intf) +{ + int index; + char path[ASC_NAME_LEN]; + + if(!intf){ + return ; + } + + index = (int)intf->cur_altsetting->desc.bInterfaceNumber; + if(atomic_read(&intf_pm_count[index])){ + usb_autopm_put_interface_no_suspend(intf); + atomic_set(&intf_pm_count[index], 0); + } + memset(path, 0, ASC_NAME_LEN); + snprintf(path, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, USB_RX_USER_NAME), index); + return asc_rx_del_user(path); +} +#endif + +static int debug; +extern struct wake_lock ets_wake_lock; + +static unsigned int dump_mask = 0; +module_param(dump_mask, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_mask, "Set data dump mask for each interface"); + +static void usb_wwan_dump_data(struct usb_interface *interface, + const char *str, const unsigned char *data, int size) { + int i; + int no_chars = 0; + int n = interface->cur_altsetting->desc.bInterfaceNumber; + + if (!(dump_mask & (1 << n))) + return; + + printk(KERN_DEBUG "usb_wwan: dump on interface#%d, %s: len = %d, chars = \"", + n, str, size); + for (i = 0; i < size; ++i) { + char c = data[i]; + if (c > 0x20 && c < 0x7e) { + printk("%c", c); + } else { + printk("."); + no_chars ++; + } + } + printk("\", data = "); + for (i = 0; i < size; ++i) { + printk("%.2x ", data[i]); + if (i > 7) + break; + } + if (size < 8) { + printk("\n"); + return; + } else if (i < size - 8) { + printk("... "); + i = size - 8; + } + for (; i < size; ++i) + printk("%.2x ", data[i]); + printk("\n"); +} + +void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + + struct usb_wwan_intf_private *intfdata; + + dbg("%s", __func__); + + intfdata = port->serial->private; + + if (!intfdata->send_setup) + return; + + portdata = usb_get_serial_port_data(port); + mutex_lock(&serial->disc_mutex); + portdata->rts_state = on; + portdata->dtr_state = on; + if (serial->dev) + intfdata->send_setup(port); + mutex_unlock(&serial->disc_mutex); +} +EXPORT_SYMBOL(usb_wwan_dtr_rts); + +void usb_wwan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_wwan_intf_private *intfdata = port->serial->private; + + dbg("%s", __func__); + + /* Doesn't support option setting */ + tty_termios_copy_hw(tty->termios, old_termios); + + if (intfdata->send_setup) + intfdata->send_setup(port); +} +EXPORT_SYMBOL(usb_wwan_set_termios); + +int usb_wwan_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned int value; + struct usb_wwan_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + value = ((portdata->rts_state) ? TIOCM_RTS : 0) | + ((portdata->dtr_state) ? TIOCM_DTR : 0) | + ((portdata->cts_state) ? TIOCM_CTS : 0) | + ((portdata->dsr_state) ? TIOCM_DSR : 0) | + ((portdata->dcd_state) ? TIOCM_CAR : 0) | + ((portdata->ri_state) ? TIOCM_RNG : 0); + + return value; +} +EXPORT_SYMBOL(usb_wwan_tiocmget); + +int usb_wwan_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + + portdata = usb_get_serial_port_data(port); + intfdata = port->serial->private; + + if (!intfdata->send_setup) + return -EINVAL; + + /* FIXME: what locks portdata fields ? */ + if (set & TIOCM_RTS) + portdata->rts_state = 1; + if (set & TIOCM_DTR) + portdata->dtr_state = 1; + + if (clear & TIOCM_RTS) + portdata->rts_state = 0; + if (clear & TIOCM_DTR) + portdata->dtr_state = 0; + return intfdata->send_setup(port); +} +EXPORT_SYMBOL(usb_wwan_tiocmset); + +static int get_serial_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.line = port->serial->minor; + tmp.port = port->number; + tmp.baud_base = tty_get_baud_rate(port->port.tty); + tmp.close_delay = port->port.close_delay / 10; + tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + port->port.closing_wait / 10; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct usb_serial_port *port, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + unsigned int closing_wait, close_delay; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + + mutex_lock(&port->port.mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if ((close_delay != port->port.close_delay) || + (closing_wait != port->port.closing_wait)) + retval = -EPERM; + else + retval = -EOPNOTSUPP; + } else { + port->port.close_delay = close_delay; + port->port.closing_wait = closing_wait; + } + + mutex_unlock(&port->port.mutex); + return retval; +} + +int usb_wwan_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + + dbg("%s cmd 0x%04x", __func__, cmd); + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(port, + (struct serial_struct __user *) arg); + case TIOCSSERIAL: + return set_serial_info(port, + (struct serial_struct __user *) arg); + default: + break; + } + + dbg("%s arg not supported", __func__); + + return -ENOIOCTLCMD; +} +EXPORT_SYMBOL(usb_wwan_ioctl); + +/* Write */ +int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; + unsigned long flags; + + portdata = usb_get_serial_port_data(port); + intfdata = port->serial->private; + + dbg("%s: write (%d chars)", __func__, count); + +#ifdef CONFIG_VIATELECOM_SYNC_CBP + asc_tx_auto_ready(USB_TX_HD_NAME, 0); +#endif + + i = 0; + left = count; + for (i = 0; left > 0 && i < portdata->n_out_urb; i++) { + todo = left; + if (todo > portdata->out_buflen) + todo = portdata->out_buflen; + + this_urb = portdata->out_urbs[i]; + if (test_and_set_bit(i, &portdata->out_busy)) { + if (time_before(jiffies, + portdata->tx_start_time[i] + 10 * HZ)) + continue; + usb_unlink_urb(this_urb); + continue; + } + dbg("%s: endpoint %d buf %d", __func__, + usb_pipeendpoint(this_urb->pipe), i); + + err = usb_autopm_get_interface_async(port->serial->interface); + if (err < 0) + break; + + /* send the data */ + memcpy(this_urb->transfer_buffer, buf, todo); + this_urb->transfer_buffer_length = todo; + + spin_lock_irqsave(&intfdata->susp_lock, flags); + if (intfdata->suspended) { + usb_anchor_urb(this_urb, &portdata->delayed); + spin_unlock_irqrestore(&intfdata->susp_lock, flags); + } else { + intfdata->in_flight++; + spin_unlock_irqrestore(&intfdata->susp_lock, flags); + err = usb_submit_urb(this_urb, GFP_ATOMIC); + if (err) { + dbg("usb_submit_urb %p (write bulk) failed " + "(%d)", this_urb, err); + clear_bit(i, &portdata->out_busy); + spin_lock_irqsave(&intfdata->susp_lock, flags); + intfdata->in_flight--; + spin_unlock_irqrestore(&intfdata->susp_lock, + flags); + usb_autopm_put_interface_async(port->serial->interface); + break; + } + } + + portdata->tx_start_time[i] = jiffies; + buf += todo; + left -= todo; + } + + count -= left; + dbg("%s: wrote (did %d)", __func__, count); + return count; +} +EXPORT_SYMBOL(usb_wwan_write); + +static void usb_wwan_indat_callback(struct urb *urb) +{ + int err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int status = urb->status; + + dbg("%s: %p", __func__, urb); + + endpoint = usb_pipeendpoint(urb->pipe); + port = urb->context; + + if (status) { + dbg("%s: nonzero status: %d on endpoint %02x.", + __func__, status, endpoint); + } else { + int inception = 0; + struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); +#ifdef CONFIG_USB_ANDROID_RAWBULK + spin_lock(&portdata->incept_lock); + inception = portdata->inception; + spin_unlock(&portdata->incept_lock); +#endif + if (inception) { +#ifdef CONFIG_USB_ANDROID_RAWBULK + struct usb_interface *interface = port->serial->interface; + int tid = interface->cur_altsetting->desc.bInterfaceNumber; + err = rawbulk_push_upstream_buffer(tid, data, urb->actual_length); + if (err < 0) + printk(KERN_DEBUG "failed to push data to rawbulk(%d) %d\n", tid, err); +#endif + } else { + usb_wwan_dump_data(port->serial->interface, "from device", data, + urb->actual_length); + tty = tty_port_tty_get(&port->port); + if (tty) { + if (urb->actual_length) { + tty_insert_flip_string(tty, data, + urb->actual_length); + tty_flip_buffer_push(tty); + } else + dbg("%s: empty read urb received", __func__); + tty_kref_put(tty); + } + } + + /* Resubmit urb so we continue receiving */ + if (status != -ESHUTDOWN) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + if (err != -EPERM) { + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __func__, err); + /* busy also in error unless we are killed */ + usb_mark_last_busy(port->serial->dev); + } + } else { + usb_mark_last_busy(port->serial->dev); + } + } + + } +} + +static void usb_wwan_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + int i; + + dbg("%s", __func__); + + port = urb->context; + intfdata = port->serial->private; + usb_wwan_dump_data(port->serial->interface, urb->status < 0? + "failed sent to device": "to device", + urb->transfer_buffer, urb->transfer_buffer_length); + usb_serial_port_softint(port); + usb_autopm_put_interface_async(port->serial->interface); + portdata = usb_get_serial_port_data(port); + spin_lock(&intfdata->susp_lock); + intfdata->in_flight--; + spin_unlock(&intfdata->susp_lock); + + for (i = 0; i < portdata->n_out_urb; ++i) { + if (portdata->out_urbs[i] == urb) { + smp_mb__before_clear_bit(); + clear_bit(i, &portdata->out_busy); + break; + } + } +} + +int usb_wwan_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i = 0; i < portdata->n_out_urb; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && !test_bit(i, &portdata->out_busy)) + data_len += portdata->out_buflen; + } + + dbg("%s: %d", __func__, data_len); + return data_len; +} +EXPORT_SYMBOL(usb_wwan_write_room); + +int usb_wwan_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i = 0; i < portdata->n_out_urb; i++) { + this_urb = portdata->out_urbs[i]; + /* FIXME: This locking is insufficient as this_urb may + go unused during the test */ + if (this_urb && test_bit(i, &portdata->out_busy)) + data_len += this_urb->transfer_buffer_length; + } + dbg("%s: %d", __func__, data_len); + return data_len; +} +EXPORT_SYMBOL(usb_wwan_chars_in_buffer); + +static int port_to_infnum(struct usb_serial_port *port) +{ + struct usb_interface *interface = port->serial->interface; + int tid = interface->cur_altsetting->desc.bInterfaceNumber; + return tid; +} + +int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + intfdata = serial->private; + + dbg("%s", __func__); + +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + cbp_usb_interface_add_user(serial->interface); +#endif + + /* Start reading from the IN endpoint */ + for (i = 0; i < portdata->n_in_urb; i++) { + urb = portdata->in_urbs[i]; + if (!urb) + continue; + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + dbg("%s: submit urb %d failed (%d) %d", + __func__, i, err, urb->transfer_buffer_length); + } + } + + if (intfdata->send_setup) + intfdata->send_setup(port); + + serial->interface->needs_remote_wakeup = 0; + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 1; + spin_unlock_irq(&intfdata->susp_lock); + /* this balances a get in the generic USB serial code */ + if(port_to_infnum(port) == 1) + { + usb_autopm_get_interface(serial->interface); + wake_lock(&ets_wake_lock); + } + else + usb_autopm_put_interface(serial->interface); + + return 0; +} +EXPORT_SYMBOL(usb_wwan_open); + +void usb_wwan_close(struct usb_serial_port *port) +{ + int i; + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata = port->serial->private; + + dbg("%s", __func__); + portdata = usb_get_serial_port_data(port); + + if (serial->dev) { +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + cbp_usb_interface_del_user(serial->interface); +#endif + /* Stop reading/writing urbs */ + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); + + for (i = 0; i < portdata->n_in_urb; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < portdata->n_out_urb; i++) + usb_kill_urb(portdata->out_urbs[i]); + /* balancing - important as an error cannot be handled*/ + if(port_to_infnum(port) == 1) + { + usb_autopm_put_interface(serial->interface); + wake_unlock(&ets_wake_lock); + } + else + usb_autopm_get_interface_no_resume(serial->interface); + serial->interface->needs_remote_wakeup = 0; + } +} +EXPORT_SYMBOL(usb_wwan_close); + +/* Helper functions used by usb_wwan_setup_urbs */ +static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + void (*callback) (struct urb *)) +{ + struct urb *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ + if (urb == NULL) { + dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +/* Setup urbs */ +static void usb_wwan_setup_urbs(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ + for (j = 0; j < portdata->n_in_urb; ++j) { + portdata->in_urbs[j] = usb_wwan_setup_urb(serial, + port-> + bulk_in_endpointAddress, + USB_DIR_IN, + port, + portdata->in_buffer[j], + portdata->in_buflen, + usb_wwan_indat_callback); + } + + /* outdat endpoints */ + for (j = 0; j < portdata->n_out_urb; ++j) { + portdata->out_urbs[j] = usb_wwan_setup_urb(serial, + port-> + bulk_out_endpointAddress, + USB_DIR_OUT, + port, + portdata->out_buffer[j], + portdata->out_buflen, + usb_wwan_outdat_callback); + } + } +} + +static struct _via_cbp_port_init_params { + unsigned int n_in_urb; + unsigned int n_out_urb; + unsigned int in_buflen; + unsigned int out_buflen; +} _cbp_init_params[] = { + { 16, 16, 4096, 4096 }, /* Data Port */ + { 4, 4, 4096, 4096 }, /* ETS */ + { 1, 1, 4096, 4096 }, /* AT Channel */ + { 1, 1, 4096, 4096 }, /* PCV */ + { 1, 1, 4096, 4096 }, /* GPS */ + { }, +}; + +int usb_wwan_startup(struct usb_serial *serial) +{ + int i, j, err; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + u8 *buffer; + + dbg("%s", __func__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + int nr; + port = serial->port[i]; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", + __func__, i); + return 1; + } + init_usb_anchor(&portdata->delayed); + + //if (__le16_to_cpu(serial->dev->descriptor.idVendor) == 0x15eb && + // __le16_to_cpu(serial->dev->descriptor.idProduct) == 0x0001) { + nr = serial->interface->cur_altsetting->desc.bInterfaceNumber; + portdata->n_in_urb = min((int)_cbp_init_params[nr].n_in_urb, MAX_IN_URBS); + portdata->n_out_urb = min((int)_cbp_init_params[nr].n_out_urb, MAX_OUT_URBS); + portdata->in_buflen = _cbp_init_params[nr].in_buflen; + portdata->out_buflen = _cbp_init_params[nr].out_buflen; + //} else { + // portdata->n_in_urb = N_IN_URB; + // portdata->n_out_urb = N_OUT_URB; + // portdata->in_buflen = IN_BUFLEN; + // portdata->out_buflen = OUT_BUFLEN; + //} + + for (j = 0; j < portdata->n_in_urb; j++) { + buffer = (u8 *) __get_free_page(GFP_KERNEL); + if (!buffer) + goto bail_out_error; + portdata->in_buffer[j] = buffer; + portdata->in_buflen = PAGE_SIZE; + } + + for (j = 0; j < portdata->n_out_urb; j++) { + buffer = kmalloc(portdata->out_buflen, GFP_KERNEL); + if (!buffer) + goto bail_out_error2; + portdata->out_buffer[j] = buffer; + } + + usb_set_serial_port_data(port, portdata); + + if (!port->interrupt_in_urb) + continue; + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) + dbg("%s: submit irq_in urb failed %d", __func__, err); + } + usb_wwan_setup_urbs(serial); + return 0; + +bail_out_error2: + for (j = 0; j < portdata->n_out_urb; j++) + kfree(portdata->out_buffer[j]); +bail_out_error: + for (j = 0; j < portdata->n_in_urb; j++) + if (portdata->in_buffer[j]) + free_page((unsigned long)portdata->in_buffer[j]); + kfree(portdata); + return 1; +} +EXPORT_SYMBOL(usb_wwan_startup); + +static void stop_read_write_urbs(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + /* Stop reading/writing urbs */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + for (j = 0; j < portdata->n_in_urb; j++) + usb_kill_urb(portdata->in_urbs[j]); + for (j = 0; j < portdata->n_out_urb; j++) + usb_kill_urb(portdata->out_urbs[j]); + } +} + +void usb_wwan_disconnect(struct usb_serial *serial) +{ + dbg("%s", __func__); + stop_read_write_urbs(serial); +#if defined(CONFIG_VIATELECOM_SYNC_CBP) + cbp_usb_interface_del_user(serial->interface); +#endif +} +EXPORT_SYMBOL(usb_wwan_disconnect); + +void usb_wwan_release(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + dbg("%s", __func__); + + /* Now free them */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + for (j = 0; j < portdata->n_in_urb; j++) { + usb_free_urb(portdata->in_urbs[j]); + free_page((unsigned long) + portdata->in_buffer[j]); + portdata->in_urbs[j] = NULL; + } + for (j = 0; j < portdata->n_out_urb; j++) { + usb_free_urb(portdata->out_urbs[j]); + kfree(portdata->out_buffer[j]); + portdata->out_urbs[j] = NULL; + } + } + + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + kfree(usb_get_serial_port_data(port)); + } +} +EXPORT_SYMBOL(usb_wwan_release); + +#ifdef CONFIG_PM +int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct usb_wwan_intf_private *intfdata = serial->private; + int b; + + dbg("%s entered", __func__); + + if (PMSG_IS_AUTO(message)) { + spin_lock_irq(&intfdata->susp_lock); + b = intfdata->in_flight; + spin_unlock_irq(&intfdata->susp_lock); + + if (b) + return -EBUSY; + } + + spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 1; + spin_unlock_irq(&intfdata->susp_lock); + stop_read_write_urbs(serial); + + return 0; +} +EXPORT_SYMBOL(usb_wwan_suspend); + +static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) +{ + int i; + + for (i = 0; i < portdata->n_out_urb; i++) { + if (urb == portdata->out_urbs[i]) { + clear_bit(i, &portdata->out_busy); + break; + } + } +} + +static void play_delayed(struct usb_serial_port *port) +{ + struct usb_wwan_intf_private *data; + struct usb_wwan_port_private *portdata; + struct urb *urb; + int err; + + portdata = usb_get_serial_port_data(port); + data = port->serial->private; + while ((urb = usb_get_from_anchor(&portdata->delayed))) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (!err) { + data->in_flight++; + } else { + /* we have to throw away the rest */ + do { + unbusy_queued_urb(urb, portdata); + usb_autopm_put_interface_no_suspend(port->serial->interface); + } while ((urb = usb_get_from_anchor(&portdata->delayed))); + break; + } + } +} + +int usb_wwan_resume(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_intf_private *intfdata = serial->private; + struct usb_wwan_port_private *portdata; + struct urb *urb; + int err = 0; + + dbg("%s entered", __func__); + /* get the interrupt URBs resubmitted unconditionally */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + if (!port->interrupt_in_urb) { + dbg("%s: No interrupt URB for port %d", __func__, i); + continue; + } + err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); + dbg("Submitted interrupt URB for port %d (result %d)", i, err); + if (err < 0) { + err("%s: Error %d for interrupt URB of port%d", + __func__, err, i); + goto err_out; + } + } + + for (i = 0; i < serial->num_ports; i++) { + /* walk all ports */ + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* skip closed ports */ + spin_lock_irq(&intfdata->susp_lock); + if (!portdata->opened) { + spin_unlock_irq(&intfdata->susp_lock); + continue; + } + + for (j = 0; j < portdata->n_in_urb; j++) { + urb = portdata->in_urbs[j]; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) { + err("%s: Error %d for bulk URB %d", + __func__, err, i); + spin_unlock_irq(&intfdata->susp_lock); + goto err_out; + } + } + play_delayed(port); + spin_unlock_irq(&intfdata->susp_lock); + } + spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 0; + spin_unlock_irq(&intfdata->susp_lock); +err_out: + return err; +} +EXPORT_SYMBOL(usb_wwan_resume); +#endif + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/storage/usb.c b/ANDROID_3.4.5/drivers/usb/storage/usb.c index 2653e73d..95f5395a 100644 --- a/ANDROID_3.4.5/drivers/usb/storage/usb.c +++ b/ANDROID_3.4.5/drivers/usb/storage/usb.c @@ -78,7 +78,7 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); MODULE_LICENSE("GPL"); -static unsigned int delay_use = 1; +static unsigned int delay_use = 0;/*add by jay*/ module_param(delay_use, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); |