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/gadget | |
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/gadget')
19 files changed, 8742 insertions, 22 deletions
diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig index a04b3f57..21a5f4cd 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig +++ b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig @@ -135,6 +135,17 @@ choice # Integrated controllers # +config USB_GADGET_WMT + tristate "GADGET WMT" + select USB_GADGET_SELECTED + select USB_GADGET_DUALSPEED +# default USB_GADGET + +config USB_WMT + tristate "USB WMT" + depends on USB_GADGET_WMT +# default USB_GADGET + config USB_AT91 tristate "Atmel AT91 USB Device Port" depends on ARCH_AT91 @@ -540,8 +551,8 @@ config USB_GADGET_SUPERSPEED # USB Gadget Drivers # choice - tristate "USB Gadget Drivers" - default USB_ETH + boolean "USB Gadget Drivers" + default USB_G_ANDROID help A Linux "Gadget Driver" talks to the USB Peripheral Controller driver through the abstract "gadget" API. Some other operating diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Makefile b/ANDROID_3.4.5/drivers/usb/gadget/Makefile index b91866a6..8df55f44 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/Makefile +++ b/ANDROID_3.4.5/drivers/usb/gadget/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o +obj-$(CONFIG_USB_WMT) += udc_wmt.o # # USB gadget drivers @@ -73,3 +74,5 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_G_ANDROID) += g_android.o +obj-y += rawbulk.o +obj-y += rawbulk_transfer.o diff --git a/ANDROID_3.4.5/drivers/usb/gadget/android.c b/ANDROID_3.4.5/drivers/usb/gadget/android.c index 4e73bf1a..c5ce536a 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/android.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/android.c @@ -28,6 +28,8 @@ #include <linux/usb/composite.h> #include <linux/usb/gadget.h> +#include <linux/power/wmt_battery.h> + #include "gadget_chips.h" /* @@ -54,6 +56,7 @@ #include "f_rndis.c" #include "rndis.c" #include "u_ether.c" +#include "f_rawbulk.c" MODULE_AUTHOR("Mike Lockwood"); MODULE_DESCRIPTION("Android Composite USB Driver"); @@ -62,6 +65,9 @@ MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, char *varval); + /* Default vendor and product IDs, overridden by userspace */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 @@ -215,6 +221,7 @@ static void android_disable(struct android_dev *dev) /* Cancel pending control requests */ usb_ep_dequeue(cdev->gadget->ep0, cdev->req); usb_remove_config(cdev, &android_config_driver); + usb_ep_autoconfig_reset(cdev->gadget); } } @@ -917,6 +924,86 @@ static struct android_usb_function accessory_function = { .bind_config = accessory_function_bind_config, .ctrlrequest = accessory_function_ctrlrequest, }; +#define CONFIG_USB_ANDROID_RAWBULK 1 + +/* VIA Rawbulk functions */ +#ifdef CONFIG_USB_ANDROID_RAWBULK +static int rawbulk_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) +{ + return 0; +} + +static void rawbulk_function_cleanup(struct android_usb_function *f) +{ + ; +} + +static int rawbulk_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + char *i = f->name + strlen("via_"); + if (!strncmp(i, "modem", 5)) + return rawbulk_bind_config(c, RAWBULK_TID_MODEM); + else if (!strncmp(i, "ets", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_ETS); + else if (!strncmp(i, "atc", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_AT); + else if (!strncmp(i, "pcv", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_PCV); + else if (!strncmp(i, "gps", 3)) + return rawbulk_bind_config(c, RAWBULK_TID_GPS); + return -EINVAL; +} + +static int rawbulk_function_modem_ctrlrequest(struct android_usb_function *f, + struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *c) +{ + if ((c->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE && + (c->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { + struct rawbulk_function *fn = rawbulk_lookup_function(RAWBULK_TID_MODEM); + return rawbulk_function_setup(&fn->function, c); + } + return -1; +} + +static struct android_usb_function rawbulk_modem_function = { + .name = "via_modem", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, + .ctrlrequest = rawbulk_function_modem_ctrlrequest, +}; + +static struct android_usb_function rawbulk_ets_function = { + .name = "via_ets", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_atc_function = { + .name = "via_atc", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_pcv_function = { + .name = "via_pcv", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; + +static struct android_usb_function rawbulk_gps_function = { + .name = "via_gps", + .init = rawbulk_function_init, + .cleanup = rawbulk_function_cleanup, + .bind_config = rawbulk_function_bind_config, +}; +#endif /* CONFIG_USB_ANDROID_RAWBULK */ static int audio_source_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) @@ -990,6 +1077,11 @@ static struct android_usb_function *supported_functions[] = { &mass_storage_function, &accessory_function, &audio_source_function, + &rawbulk_modem_function, + &rawbulk_ets_function, + &rawbulk_atc_function, + &rawbulk_pcv_function, + &rawbulk_gps_function, NULL }; @@ -1356,6 +1448,23 @@ static void android_unbind_config(struct usb_configuration *c) android_unbind_enabled_functions(dev, c); } +unsigned char buf_android_serialno[32]; + +int get_android_serialno(void) +{ + int varlen =127; + int retval; + memset(buf_android_serialno,0,sizeof(buf_android_serialno)); + retval = wmt_getsyspara("androidboot.serialno", buf_android_serialno, &varlen); + if(!retval) + { + printk("androidboot.serialno=%s\n",buf_android_serialno); + return 0x0; + }else{ + printk("uboot variant androidboot.serialno do not exit\n"); + return -1; + } +} static int android_bind(struct usb_composite_dev *cdev) { @@ -1391,7 +1500,15 @@ static int android_bind(struct usb_composite_dev *cdev) /* Default strings - should be updated by userspace */ strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1); strncpy(product_string, "Android", sizeof(product_string) - 1); - strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); + + get_android_serialno(); + if(strlen(buf_android_serialno)==0){ + strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); + printk("buf_android_serialno is null\n"); + }else{ + strncpy(serial_string, buf_android_serialno, sizeof(serial_string) - 1); + printk("buf_android_serialno:%s\n",buf_android_serialno); + } id = usb_string_id(cdev); if (id < 0) @@ -1467,6 +1584,9 @@ android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) if (!dev->connected) { dev->connected = 1; schedule_work(&dev->work); +#if defined(CONFIG_BATTERY_WMT) + wmt_do_pc_connected(); +#endif } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) { schedule_work(&dev->work); @@ -1518,6 +1638,12 @@ static int android_create_device(struct android_dev *dev) return 0; } +/* provide usb connected state for charger */ +int wmt_is_pc_connected(void) +{ + return _android_dev ? _android_dev->connected : 0; +} +EXPORT_SYMBOL(wmt_is_pc_connected); static int __init init(void) { diff --git a/ANDROID_3.4.5/drivers/usb/gadget/composite.c b/ANDROID_3.4.5/drivers/usb/gadget/composite.c index 8f82fc0e..6cfe5f24 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/composite.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/composite.c @@ -798,6 +798,7 @@ static int unbind_config(struct usb_composite_dev *cdev, return 0; } +extern void wmt_cleanup_done_thread(int number); /** * usb_remove_config() - remove a configuration from a device. * @cdev: wraps the USB gadget @@ -811,16 +812,14 @@ int usb_remove_config(struct usb_composite_dev *cdev, struct usb_configuration *config) { unsigned long flags; - + //wmt_cleanup_done_thread(1); spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config == config) reset_config(cdev); list_del(&config->list); spin_unlock_irqrestore(&cdev->lock, flags); - return unbind_config(cdev, config); } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c index 51f3d42f..fc5eb804 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c @@ -280,6 +280,43 @@ struct usb_ep *usb_ep_autoconfig_ss( if (ep && ep_matches(gadget, ep, desc, ep_comp)) goto found_ep; + } else if (gadget_is_wmt (gadget)) { + //printk(KERN_INFO "usb_ep_autoconfig find wmt_gadget \n"); + if (USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep3in-int \n"); + ep = find_ep (gadget, "ep3in-int"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep3in-int \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_BULK == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); + ep = find_ep (gadget, "ep1in-bulk"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_BULK == type) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep2out-bulk \n"); + ep = find_ep (gadget, "ep2out-bulk"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep2out-bulk \n"); + goto found_ep; + } + } else if (USB_ENDPOINT_XFER_ISOC == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); + ep = find_ep (gadget, "ep4in-iso"); + if (ep && ep_matches (gadget, ep, desc, ep_comp)){ + //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); + goto found_ep; + } + } } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c index a244265c..bfb3a777 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c @@ -502,6 +502,7 @@ static int create_bulk_endpoints(struct acc_dev *dev, ep->driver_data = dev; /* claim the endpoint */ dev->ep_in = ep; +#if 0 ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); @@ -510,6 +511,7 @@ static int create_bulk_endpoints(struct acc_dev *dev, DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#endif ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { @@ -568,6 +570,10 @@ static ssize_t acc_read(struct file *fp, char __user *buf, ret = wait_event_interruptible(dev->read_wq, dev->online); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + goto done; } @@ -588,6 +594,10 @@ requeue_req: ret = wait_event_interruptible(dev->read_wq, dev->rx_done); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + usb_ep_dequeue(dev->ep_out, req); goto done; } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c index 1629ffb5..0eea2191 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c @@ -502,7 +502,8 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) dev->error = 1; wake_up(&dev->read_wq); - + extern void wmt_cleanup_done_thread(int number); + wmt_cleanup_done_thread(1); adb_request_free(dev->rx_req, dev->ep_out); while ((req = adb_req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c index cb8c162c..68c3d9f6 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c @@ -2691,6 +2691,8 @@ static int fsg_main_thread(void *common_) static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); +static DEVICE_ATTR(cdrom, 0644, fsg_show_cdrom, fsg_store_cdrom); + /****************************** FSG COMMON ******************************/ @@ -2815,7 +2817,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, rc = device_create_file(&curlun->dev, &dev_attr_nofua); if (rc) goto error_luns; - + rc = device_create_file(&curlun->dev, &dev_attr_cdrom); + if (rc) + goto error_luns; if (lcfg->filename) { rc = fsg_lun_open(curlun, lcfg->filename); if (rc) @@ -2947,6 +2951,7 @@ static void fsg_common_release(struct kref *ref) device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); + device_remove_file(&lun->dev, &dev_attr_cdrom); fsg_lun_close(lun); device_unregister(&lun->dev); } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c index 1638977a..6279bfb0 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c @@ -410,6 +410,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#if 0 ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); @@ -418,6 +419,7 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); ep->driver_data = dev; /* claim the endpoint */ dev->ep_out = ep; +#endif ep = usb_ep_autoconfig(cdev->gadget, intr_desc); if (!ep) { @@ -478,6 +480,10 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, dev->state != STATE_OFFLINE); if (ret < 0) { r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + goto done; } spin_lock_irq(&dev->lock); @@ -506,7 +512,11 @@ requeue_req: /* wait for a request to complete */ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); if (ret < 0) { - r = ret; + r = ret; + if (r == -ERESTARTSYS){ + r = -EIO; + } + usb_ep_dequeue(dev->ep_out, req); goto done; } @@ -1121,7 +1131,8 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) struct mtp_dev *dev = func_to_mtp(f); struct usb_request *req; int i; - + extern void wmt_cleanup_done_thread(int number); + wmt_cleanup_done_thread(1); while ((req = mtp_req_get(dev, &dev->tx_idle))) mtp_request_free(req, dev->ep_in); for (i = 0; i < RX_REQ_MAX; i++) @@ -1175,21 +1186,22 @@ static int mtp_function_set_alt(struct usb_function *f, return 0; } + static void mtp_function_disable(struct usb_function *f) { struct mtp_dev *dev = func_to_mtp(f); struct usb_composite_dev *cdev = dev->cdev; - DBG(cdev, "mtp_function_disable\n"); + printk("mtp_function_disable\n"); dev->state = STATE_OFFLINE; usb_ep_disable(dev->ep_in); usb_ep_disable(dev->ep_out); usb_ep_disable(dev->ep_intr); - +// wmt_cleanup_done_thread(1); /* readers may be blocked waiting for us to go online */ wake_up(&dev->read_wq); - VDBG(cdev, "%s disabled\n", dev->function.name); + printk("%s disabled\n", dev->function.name); } static int mtp_bind_config(struct usb_configuration *c, bool ptp_config) diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c new file mode 100755 index 00000000..92bce0fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c @@ -0,0 +1,322 @@ +/* + * Rawbulk Gadget Function Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" +#define DRIVER_VERSION "1.0.1" +#define DRIVER_NAME "usb_rawbulk" + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/wakelock.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + +#include <linux/usb/composite.h> +#include <linux/usb/rawbulk.h> +struct usb_composite_dev * wmt_cdev; +#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) + +static void simple_setup_complete(struct usb_ep *ep, + struct usb_request *req) { + ;//DO NOTHING +} + +unsigned int dump_mask = 0; +static int rawbulk_function_setup(struct usb_function *f, const struct + usb_ctrlrequest *ctrl) { + int rc; + struct rawbulk_function *fn = function_to_rawbulk(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + + if (rawbulk_transfer_state(fn->transfer_id) < 0) + return -EOPNOTSUPP; + + if (dump_mask & (1 << RAWBULK_TID_MODEM)) + printk(KERN_DEBUG "DUMP ctrl: bRequestType = %02X, bRequest = %02X, " \ + "wValue = %04X, wIndex = %04X, wLength = %d\n", + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, + ctrl->wLength); + + if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x02) { + /* Query CD109 Status */ + if (rawbulk_check_enable(fn)) + goto forwarding; + *(unsigned char *)req->buf = 0x02; /* Test!!! */ + req->length = 1; + req->complete = simple_setup_complete; + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0x01) { + /* Set/Clear DTR */ + if (rawbulk_check_enable(fn)) + goto forwarding; + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x04) { + /* Request CBP Product Name */ + req->length = sprintf(req->buf, "CBP_KUNLUN"); + req->zero = 0; + return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } + + return -EOPNOTSUPP; +forwarding: + rc = rawbulk_forward_ctrlrequest(ctrl); + if (rc < 0) { + printk(KERN_DEBUG "rawbulk forwarding failed %d\n", rc); + return rc; + } + return 256 + 999;//USB_GADGET_DELAYED_STATUS; +} + +static void rawbulk_auto_reconnect(int transfer_id) { + int rc; + struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); + if (!fn || fn->autoreconn == 0) + return; + + if (rawbulk_check_enable(fn) && fn->activated) { + printk(KERN_DEBUG "start %s again automatically.\n", fn->longname); + rc = rawbulk_start_transactions(transfer_id, fn->nups, + fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); + if (rc < 0) { + rawbulk_disable_function(fn); + rawbulk_tty_start_io(fn); + } + } +} + +static struct usb_ep *match_ep(struct usb_configuration *c, + struct rawbulk_function *fn, int in) { + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep; + struct usb_endpoint_descriptor *desc = + (struct usb_endpoint_descriptor *)(in? fn->fs_descs[BULKIN_DESC]: + fn->fs_descs[BULKOUT_DESC]); + return usb_ep_autoconfig(gadget, desc); +} + +static int rawbulk_function_bind(struct usb_configuration *c, struct + usb_function *f) { + int rc, ifnum; + struct rawbulk_function *fn = function_to_rawbulk(f); + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep_out, *ep_in; + + rc = usb_interface_id(c, f); + if (rc < 0) + return rc; + ifnum = rc; + + fn->interface.bInterfaceNumber = cpu_to_le16(ifnum); + + + + usb_ep_autoconfig_reset(c->cdev->gadget); //added by griffen + + + if (!(ep_out = match_ep(c, fn, 0))) { + printk(KERN_DEBUG "unfortunately, we could not find endpoint(OUT) for %s", + fn->longname); + return -ENOMEM; + } + + if (!(ep_in = match_ep(c, fn, 1))) { + printk(KERN_DEBUG "unfortunately, we could not find endpoint(IN) for %s", + fn->longname); + return -ENOMEM; + } + + ep_out->driver_data = fn; + ep_in->driver_data = fn; + fn->bulk_out = ep_out; + fn->bulk_in = ep_in; + + f->descriptors = usb_copy_descriptors(fn->fs_descs); + if (unlikely(!f->descriptors)) + return -ENOMEM; + + if (gadget_is_dualspeed(gadget)) { + fn->hs_bulkin_endpoint.bEndpointAddress = + fn->fs_bulkin_endpoint.bEndpointAddress; + fn->hs_bulkout_endpoint.bEndpointAddress = + fn->fs_bulkout_endpoint.bEndpointAddress; + f->hs_descriptors = usb_copy_descriptors(fn->hs_descs); + if (unlikely(!f->hs_descriptors)) { + usb_free_descriptors(f->descriptors); + return -ENOMEM; + } + } + + fn->cdev = c->cdev; + fn->activated = 0; + + /* + rc = rawbulk_register_tty(fn); + if (rc < 0) + printk(KERN_ERR "failed to register tty for %s\n", fn->longname); + */ + + return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in, + rawbulk_auto_reconnect); +} + +static void rawbulk_function_unbind(struct usb_configuration *c, struct + usb_function *f) { + struct rawbulk_function *fn = function_to_rawbulk(f); + + printk(KERN_DEBUG "%s - unbind %s.\n", __func__, fn->longname); + //rawbulk_unregister_tty(fn); + rawbulk_unbind_function(fn->transfer_id); +} + +static void do_activate(struct work_struct *data) { + struct rawbulk_function *fn = container_of(data, struct rawbulk_function, + activator); + int rc; + printk(KERN_DEBUG "%s rawbulk %s channel (enabled? %s).\n", + fn->activated? "activte": "detach", fn->shortname, + rawbulk_check_enable(fn)? "yes": "no"); + if (fn->activated) { /* enumerated */ + int ret; + ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_out); + if (ret) + return ; + + /* enabled endpoints */ + rc = usb_ep_enable(fn->bulk_out); + if (rc < 0) { + printk(KERN_ERR "failed to enable rawbulk %s %d\n", + fn->bulk_out->name, rc); + return; + } + + + ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_in); + if (ret) + return ; + + rc = usb_ep_enable(fn->bulk_in); + if (rc < 0) { + printk(KERN_ERR "failed to enable rawbulk %s %d\n", + fn->bulk_in->name, rc); + usb_ep_disable(fn->bulk_out); + return; + } + + /* start rawbulk if enabled */ + if (rawbulk_check_enable(fn)) { + wake_lock(&fn->keep_awake); + rc = rawbulk_start_transactions(fn->transfer_id, fn->nups, + fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); + if (rc < 0) + rawbulk_disable_function(fn); + } + + /* start tty io */ + rc = rawbulk_tty_alloc_request(fn); + if (rc < 0) + return; + if (!rawbulk_check_enable(fn)) + rawbulk_tty_start_io(fn); + } else { /* disconnect */ + if (rawbulk_check_enable(fn)) { + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* this in interrupt, but DTR need be set firstly then clear it + * */ + //control_dtr(0); + } + rawbulk_stop_transactions(fn->transfer_id); + /* keep the enable state, so we can enable again in next time */ + //set_enable_state(fn, 0); + wake_unlock(&fn->keep_awake); + } else + rawbulk_tty_stop_io(fn); + + rawbulk_tty_free_request(fn); + + usb_ep_disable(fn->bulk_out); + usb_ep_disable(fn->bulk_in); + + fn->bulk_out->driver_data = NULL; + fn->bulk_in->driver_data = NULL; + } +} + +static int rawbulk_function_setalt(struct usb_function *f, unsigned intf, + unsigned alt) { + struct rawbulk_function *fn = function_to_rawbulk(f); + fn->activated = 1; + schedule_work(&fn->activator); + return 0; +} + +static void rawbulk_function_disable(struct usb_function *f) { + struct rawbulk_function *fn = function_to_rawbulk(f); + fn->activated = 0; + schedule_work(&fn->activator); +} + +static int rawbulk_bind_config(struct usb_configuration *c, int transfer_id) { + int rc; + struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); + + printk(KERN_DEBUG "add %s to config.\n", fn->longname); + + if (!fn) + return -ENOMEM; + + if (fn->string_defs[0].id == 0) { + rc = usb_string_id(c->cdev); + if (rc < 0) + return rc; + fn->string_defs[0].id = rc; + fn->interface.iInterface = rc; + } + wmt_cdev = c->cdev; + + fn->function.name = fn->longname; + fn->function.setup = rawbulk_function_setup; + fn->function.bind = rawbulk_function_bind; + fn->function.unbind = rawbulk_function_unbind; + fn->function.set_alt = rawbulk_function_setalt; + fn->function.disable = rawbulk_function_disable; + + INIT_WORK(&fn->activator, do_activate); + + rc = usb_add_function(c, &fn->function); + if (rc < 0) + printk(KERN_DEBUG "%s - failed to config %d.\n", __func__, rc); + + return rc; +} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c index 3a6e5587..5a4fdbc7 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c @@ -458,7 +458,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) status, req->actual, req->length); // spin_unlock(&dev->lock); } - +extern bool get_rndis_initialized(void); static int rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -469,7 +469,8 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); - + if(!get_rndis_initialized()) + return; /* composite driver infrastructure handles everything except * CDC class messages; interface activation uses set_alt(). */ @@ -614,7 +615,7 @@ static void rndis_disable(struct usb_function *f) if (!rndis->notify->driver_data) return; - DBG(cdev, "rndis deactivated\n"); + printk("rndis deactivated\n"); rndis_uninit(rndis->config); gether_disconnect(&rndis->port); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h index a8855d0b..30fad3e8 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h +++ b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h @@ -26,6 +26,7 @@ * do that for you. */ #define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) +#define gadget_is_wmt(g) (!strcmp("wmotgdev", (g)->name)) #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) #define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) #define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) @@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x31; else if (gadget_is_dwc3(gadget)) return 0x32; + else if (gadget_is_wmt(gadget)) + return 0x33; return -ENOENT; } diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c new file mode 100755 index 00000000..5c027da4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c @@ -0,0 +1,1272 @@ +/* + * Rawbulk Gadget Function Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" +#define DRIVER_VERSION "1.0.1" +#define DRIVER_NAME "usb_rawbulk" + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/wakelock.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/types.h> +#include <linux/device.h> + +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + +#include <linux/usb/composite.h> +#include <linux/usb/rawbulk.h> + +#ifdef DEBUG +#define ldbg(f, a...) printk(KERN_DEBUG "%s - " f "\n", __func__, ##a) +#else +#define ldbg(...) {} +#endif + +/* sysfs attr idx assignment */ +enum _attr_idx { + ATTR_ENABLE = 0, /** enable switch for Rawbulk */ +#ifdef SUPPORT_LEGACY_CONTROL + ATTR_ENABLE_C, /** enable switch too, but for legacy */ +#endif + ATTR_AUTORECONN, /** enable to rebind cp when it reconnect */ + ATTR_STATISTICS, /** Rawbulk summary/statistics for one pipe */ + ATTR_NUPS, /** upstream transfers count */ + ATTR_NDOWNS, /** downstram transfers count */ + ATTR_UPSIZE, /** upstream buffer for each transaction */ + ATTR_DOWNSIZE, /** downstram buffer for each transaction */ + ATTR_SPLIT, /** split option for downstream */ + ATTR_PUSHABLE, /** set to use push-way for upstream */ + ATTR_DTR, /** DTR control, only for Data-Call port */ +}; + +/* USB gadget framework is not strong enough, and not be compatiable with some + * controller, such as musb. + * in musb driver, the usb_request's member list is used internally, but in some + * applications it used in function driver too. to avoid this, here we + * re-wrap the usb_request */ +struct usb_request_wrapper { + struct list_head list; + struct usb_request *request; + int length; + struct rawbulk_function *fn; + char buffer[0]; +}; + +static struct usb_request_wrapper *get_wrapper(struct usb_request *req) { + if (!req->buf) + return NULL; + return container_of(req->buf, struct usb_request_wrapper, buffer); +} + +/* Internal TTY functions/data */ +static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct + *tty); +static void rawbulk_tty_deactivate(struct tty_port *port); +static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct + *tty); +static void rawbulk_tty_cleanup(struct tty_struct *tty); +static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip); +static void rawbulk_tty_hangup(struct tty_struct *tty); +static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip); +static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count); +static int rawbulk_tty_write_room(struct tty_struct *tty); +static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty); +static void rawbulk_tty_throttle(struct tty_struct *tty); +static void rawbulk_tty_unthrottle(struct tty_struct *tty); +static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios + *old); +static int rawbulk_tty_tiocmget(struct tty_struct *tty); +static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); + +static struct tty_port_operations rawbulk_tty_port_ops = { + .activate = rawbulk_tty_activate, + .shutdown = rawbulk_tty_deactivate, +}; + +static struct tty_operations rawbulk_tty_ops = { + .open = rawbulk_tty_open, + .close = rawbulk_tty_close, + .write = rawbulk_tty_write, + .hangup = rawbulk_tty_hangup, + .write_room = rawbulk_tty_write_room, + .set_termios = rawbulk_tty_set_termios, + .throttle = rawbulk_tty_throttle, + .unthrottle = rawbulk_tty_unthrottle, + .chars_in_buffer = rawbulk_tty_chars_in_buffer, + .tiocmget = rawbulk_tty_tiocmget, + .tiocmset = rawbulk_tty_tiocmset, + .cleanup = rawbulk_tty_cleanup, + .install = rawbulk_tty_install, +}; + +struct tty_driver *rawbulk_tty_driver; + +struct rawbulk_function *prealloced_functions[_MAX_TID] = { NULL }; +struct rawbulk_function *rawbulk_lookup_function(int transfer_id) { + if (transfer_id >= 0 && transfer_id < _MAX_TID) + return prealloced_functions[transfer_id]; + return NULL; +} +EXPORT_SYMBOL_GPL(rawbulk_lookup_function); + +static struct rawbulk_function *lookup_by_tty_minor(int minor) { + int n; + struct rawbulk_function *fn; + for (n = 0; n < _MAX_TID; n ++) { + fn = prealloced_functions[n]; + if (fn->tty_minor == minor) + return fn; + } + return NULL; +} + +static inline int check_enable_state(struct rawbulk_function *fn) { + int enab; + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + enab = fn->enable? 1: 0; + spin_unlock_irqrestore(&fn->lock, flags); + return enab; +} + +int rawbulk_check_enable(struct rawbulk_function *fn) { + return check_enable_state(fn); +} +EXPORT_SYMBOL_GPL(rawbulk_check_enable); + +static inline int check_tty_opened(struct rawbulk_function *fn) { + int opened; + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + opened = fn->tty_opened? 1: 0; + spin_unlock_irqrestore(&fn->lock, flags); + return opened; +} + +static inline void set_enable_state(struct rawbulk_function *fn, int enab) { + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + fn->enable = !!enab; + spin_unlock_irqrestore(&fn->lock, flags); +} + +void rawbulk_disable_function(struct rawbulk_function *fn) { + set_enable_state(fn, 0); +} +EXPORT_SYMBOL_GPL(rawbulk_disable_function); + +static inline void set_tty_opened(struct rawbulk_function *fn, int opened) { + unsigned long flags; + spin_lock_irqsave(&fn->lock, flags); + fn->tty_opened = !!opened; + spin_unlock_irqrestore(&fn->lock, flags); +} + +#define port_to_rawbulk(p) container_of(p, struct rawbulk_function, port) +#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) + +static struct usb_request_wrapper *get_req(struct list_head *head, spinlock_t + *lock) { + unsigned long flags; + struct usb_request_wrapper *req = NULL; + spin_lock_irqsave(lock, flags); + if (!list_empty(head)) { + req = list_first_entry(head, struct usb_request_wrapper, list); + list_del(&req->list); + } + spin_unlock_irqrestore(lock, flags); + return req; +} + +static void put_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_add_tail(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static void move_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_move_tail(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static void insert_req(struct usb_request_wrapper *req, struct list_head *head, + spinlock_t *lock) { + unsigned long flags; + spin_lock_irqsave(lock, flags); + list_add(&req->list, head); + spin_unlock_irqrestore(lock, flags); +} + +static int control_dtr(int set) { + struct usb_ctrlrequest ctrl = { + .bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR, //0x40 + .bRequest = 0x01, + .wLength = 0, + .wIndex = 0, + }; + + ctrl.wValue = cpu_to_le16(!!set); + return rawbulk_forward_ctrlrequest(&ctrl); +} + +static void init_endpoint_desc(struct usb_endpoint_descriptor *epdesc, int in, + int maxpacksize) { + struct usb_endpoint_descriptor template = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }; + + *epdesc = template; + if (in) + epdesc->bEndpointAddress = USB_DIR_IN; + else + epdesc->bEndpointAddress = USB_DIR_OUT; + epdesc->wMaxPacketSize = cpu_to_le16(maxpacksize); +} + +static void init_interface_desc(struct usb_interface_descriptor *ifdesc) { + struct usb_interface_descriptor template = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff,//USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .iInterface = 0, + }; + + *ifdesc = template; +} + +static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute + *attr, char *buf); +static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count); + +static inline void add_device_attr(struct rawbulk_function *fn, int n, const char + *name, int mode) { + if (n < MAX_ATTRIBUTES) { + fn->attr[n].attr.name = name; + fn->attr[n].attr.mode = mode; + fn->attr[n].show = rawbulk_attr_show; + fn->attr[n].store = rawbulk_attr_store; + } +} + +static int which_attr(struct rawbulk_function *fn, struct device_attribute + *attr) { + int n; + for (n = 0; n < fn->max_attrs; n ++) { + if (attr == &fn->attr[n]) + return n; + } + return -1; +} + +static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute *attr, + char *buf) { + int n; + int idx; + int enab; + struct rawbulk_function *fn; + + for (n = 0; n < _MAX_TID; n ++) { + fn = rawbulk_lookup_function(n); + if (fn->dev == dev) { + idx = which_attr(fn, attr); + break; + } +#ifdef SUPPORT_LEGACY_CONTROL + if (!strcmp(attr->attr.name, fn->shortname)) { + idx = ATTR_ENABLE_C; + break; + } +#endif + } + + if (n == _MAX_TID) + return 0; + + enab = check_enable_state(fn); + switch (idx) { + case ATTR_ENABLE: + return sprintf(buf, "%d", enab); +#ifdef SUPPORT_LEGACY_CONTROL + case ATTR_ENABLE_C: + return sprintf(buf, "%s", enab? "gadget": "tty"); +#endif + case ATTR_AUTORECONN: + return sprintf(buf, "%d", fn->autoreconn); + case ATTR_STATISTICS: + return rawbulk_transfer_statistics(fn->transfer_id, buf); + case ATTR_NUPS: + return sprintf(buf, "%d", enab? fn->nups: -1); + case ATTR_NDOWNS: + return sprintf(buf, "%d", enab? fn->ndowns: -1); + case ATTR_UPSIZE: + return sprintf(buf, "%d", enab? fn->upsz: -1); + case ATTR_DOWNSIZE: + return sprintf(buf, "%d", enab? fn->downsz: -1); + case ATTR_SPLIT: + return sprintf(buf, "%d", enab? fn->splitsz: -1); + case ATTR_PUSHABLE: + return sprintf(buf, "%d", fn->pushable); + default: + break; + } + return 0; +} + +static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int n; + int rc = 0; + int idx = -1; + int nups; + int ndowns; + int upsz; + int downsz; + int splitsz; + int pushable; + struct rawbulk_function *fn; + + for (n = 0; n < _MAX_TID; n ++) { + fn = rawbulk_lookup_function(n); + if (fn->dev == dev) { + idx = which_attr(fn, attr); + break; + } +#ifdef SUPPORT_LEGACY_CONTROL + if (!strcmp(attr->attr.name, fn->shortname)) { + idx = ATTR_ENABLE_C; + break; + } +#endif + } + + if (idx < 0) { + printk(KERN_ERR "sorry, I cannot find rawbulk fn '%s'\n", attr->attr.name); + goto exit; + } + + nups = fn->nups; + ndowns = fn->ndowns; + upsz = fn->upsz; + downsz = fn->downsz; + splitsz = fn->splitsz; + pushable = fn->pushable; + + /* find out which attr(file) we write */ + +#ifdef SUPPORT_LEGACY_CONTROL + if (idx <= ATTR_ENABLE_C) +#else + if (idx == ATTR_ENABLE) +#endif + { + int enable; + if (idx == ATTR_ENABLE) { + enable = simple_strtoul(buf, NULL, 10); +#ifdef SUPPORT_LEGACY_CONTROL + } else if (idx == ATTR_ENABLE_C) { + if (!strncmp(buf, "tty", 3)) + enable = 0; + else if (!strncmp(buf, "gadget", 6)) + enable = 1; + else { + printk(KERN_ERR "invalid option(%s) for bypass, try again...\n", buf); + goto exit; + } +#endif /* SUPPORT_LEGACY_CONTROL */ + } else + goto exit; + + if (check_enable_state(fn) != (!!enable)) { + set_enable_state(fn, enable); + if (!!enable && fn->activated) { + printk(KERN_DEBUG "enable rawbulk %s channel, been activated? %s\n", + fn->shortname, fn->activated? "yes": "no"); + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* clear DTR to endup last session between AP and CP */ + control_dtr(1); + msleep(10); + control_dtr(0); + } + + /* Stop TTY i/o */ + rawbulk_tty_stop_io(fn); + + /* Start rawbulk transfer */ + wake_lock(&fn->keep_awake); + rc = rawbulk_start_transactions(fn->transfer_id, nups, + ndowns, upsz, downsz, splitsz, pushable); + if (rc < 0) { + set_enable_state(fn, !enable); + rawbulk_tty_start_io(fn); + } + } else { + /* Stop rawbulk transfer */ + printk(KERN_DEBUG "disable rawbulk %s channel, been activated? %s\n", + fn->shortname, fn->activated? "yes": "no"); + rawbulk_stop_transactions(fn->transfer_id); + if (fn->transfer_id == RAWBULK_TID_MODEM) { + /* clear DTR automatically when disable modem rawbulk */ + control_dtr(1); + msleep(10); + control_dtr(0); + } + wake_unlock(&fn->keep_awake); + + /* Start TTY i/o */ + rawbulk_tty_start_io(fn); + } + } + } else if (idx == ATTR_DTR) { + if (fn->transfer_id == RAWBULK_TID_MODEM) { + if (check_enable_state(fn)) + control_dtr(simple_strtoul(buf, NULL, 10)); + } + } else if (idx == ATTR_AUTORECONN) { + fn->autoreconn = !!simple_strtoul(buf, NULL, 10); + } else { + int val = simple_strtoul(buf, NULL, 10); + switch (idx) { + case ATTR_NUPS: nups = val; break; + case ATTR_NDOWNS: ndowns = val; break; + case ATTR_UPSIZE: upsz = val; break; + case ATTR_DOWNSIZE: downsz = val; break; + case ATTR_SPLIT: splitsz = val; break; + case ATTR_PUSHABLE: + pushable = !!val; + fn->pushable = pushable; + break; + default: goto exit; + } + + if (!check_enable_state(fn)) + goto exit; + + if (!fn->activated) + goto exit; + + rawbulk_stop_transactions(fn->transfer_id); + rc = rawbulk_start_transactions(fn->transfer_id, nups, ndowns, upsz, + downsz, splitsz, pushable); + if (rc >= 0) { + fn->nups = nups; + fn->ndowns = ndowns; + fn->upsz = upsz; + fn->downsz = downsz; + fn->splitsz = splitsz; + fn->pushable = pushable; + } else { + rawbulk_stop_transactions(fn->transfer_id); + wake_unlock(&fn->keep_awake); + set_enable_state(fn, 0); + } + } + +exit: + return count; +} + +static int rawbulk_create_files(struct rawbulk_function *fn) { + int n, rc; + for (n = 0; n < fn->max_attrs; n ++){ +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + rc = device_create_file(fn->dev, &fn->attr[n]); + if (rc < 0) { + while (--n >= 0) { +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + device_remove_file(fn->dev, &fn->attr[n]); + } + return rc; + } + } + return 0; +} + +static void rawbulk_remove_files(struct rawbulk_function *fn) { + int n = fn->max_attrs; + while (--n >= 0) { +#ifdef SUPPORT_LEGACY_CONTROL + if (n == ATTR_ENABLE_C) + continue; +#endif + device_remove_file(fn->dev, &fn->attr[n]); + } +} + +#define RAWBULK_TTY_MINORS 255 +static int tty_minors[RAWBULK_TTY_MINORS] = { 0 }; +static int alloc_tty_minor(struct rawbulk_function *fn) { + int n; + if (check_tty_opened(fn)) + printk(KERN_WARNING "ttyRB%d has opened yet %s has been disconnected\n", + fn->tty_minor, fn->longname); + for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { + if (tty_minors[n] == 0) { + tty_minors[n] = fn->transfer_id + 0x8000; + return n; + } + } + return -ENODEV; +} + +static void free_tty_minor(struct rawbulk_function *fn) { + int n; + struct tty_struct **ttys = rawbulk_tty_driver->ttys; + if (!check_tty_opened(fn)) + tty_minors[fn->tty_minor] = 0; + /* Clear the closed tty minors of this port */ + for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { + if ((tty_minors[n] == fn->transfer_id + 0x8000) && ttys[n]) { + struct tty_struct *tty = ttys[n]; + if (tty->count > 0) + continue; /* Keep the minor while tty is being used */ + if (test_bit(TTY_CLOSING, &tty->flags)) { + /* FIXME: Cannot close the tty_struct! */ + printk(KERN_DEBUG "cannot recycle the minor %d because " \ + "the TTY_CLOSING flags is still on\n", n); + continue; + } + tty_minors[n] = 0; + } + } +} + +int rawbulk_register_tty(struct rawbulk_function *fn) { + struct device *dev; + + spin_lock_init(&fn->tx_lock); + spin_lock_init(&fn->rx_lock); + INIT_LIST_HEAD(&fn->tx_free); + INIT_LIST_HEAD(&fn->rx_free); + INIT_LIST_HEAD(&fn->tx_inproc); + INIT_LIST_HEAD(&fn->rx_inproc); + INIT_LIST_HEAD(&fn->rx_throttled); + + fn->tty_minor = alloc_tty_minor(fn); + if (fn->tty_minor < 0) + return -ENODEV; + fn->tty_opened = 0; + fn->last_pushed = 0; + tty_port_init(&fn->port); + fn->port.ops = &rawbulk_tty_port_ops; + + /* Bring up the tty device */ + dev = tty_register_device(rawbulk_tty_driver, fn->tty_minor, fn->dev); + if (IS_ERR(dev)) + printk(KERN_ERR "Failed to attach ttyRB%d to %s device.\n", + fn->tty_minor, fn->longname); + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_register_tty); + +void rawbulk_unregister_tty(struct rawbulk_function *fn) { + tty_unregister_device(rawbulk_tty_driver, fn->tty_minor); + free_tty_minor(fn); +} +EXPORT_SYMBOL_GPL(rawbulk_unregister_tty); + +/******************************************************************************/ + +/* Call this after all request has detached! */ +void rawbulk_tty_free_request(struct rawbulk_function *fn) { + struct usb_request_wrapper *req; + + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + usb_ep_free_request(fn->bulk_out, req->request); + kfree(req); + } + + while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { + usb_ep_free_request(fn->bulk_in, req->request); + kfree(req); + } +} +EXPORT_SYMBOL_GPL(rawbulk_tty_free_request); + +static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req); +static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req); + +int rawbulk_tty_alloc_request(struct rawbulk_function *fn) { + int n; + struct usb_request_wrapper *req; + unsigned long flags; + + spin_lock_irqsave(&fn->lock, flags); + if (!fn->bulk_out || !fn->bulk_in) { + spin_unlock_irqrestore(&fn->lock, flags); + return -ENODEV; + } + spin_unlock_irqrestore(&fn->lock, flags); + + /* Allocate and init rx request */ + for (n = 0; n < MAX_TTY_RX; n ++) { + req = kmalloc(sizeof(struct usb_request_wrapper) + + MAX_TTY_RX_PACKAGE, GFP_KERNEL); + if (!req) + break; + + req->request = usb_ep_alloc_request(fn->bulk_out, GFP_KERNEL); + if (!req->request) { + kfree(req); + break; + } + + req->fn = fn; + INIT_LIST_HEAD(&req->list); + req->length = MAX_TTY_RX_PACKAGE; + req->request->buf = req->buffer; + req->request->length = MAX_TTY_RX_PACKAGE; + req->request->complete = rawbulk_tty_rx_complete; + put_req(req, &fn->rx_free, &fn->rx_lock); + } + + if (n < MAX_TTY_RX) { + /* free allocated request */ + rawbulk_tty_free_request(fn); + return -ENOMEM; + } + + /* Allocate and init tx request */ + for (n = 0; n < MAX_TTY_TX; n ++) { + req = kmalloc(sizeof(struct usb_request_wrapper) + + MAX_TTY_TX_PACKAGE, GFP_KERNEL); + if (!req) + break; + + req->request = usb_ep_alloc_request(fn->bulk_in, GFP_KERNEL); + if (!req->request) { + kfree(req); + break; + } + + req->fn = fn; + INIT_LIST_HEAD(&req->list); + req->length = MAX_TTY_TX_PACKAGE; + req->request->zero = 0; + req->request->buf = req->buffer; + req->request->complete = rawbulk_tty_tx_complete; + put_req(req, &fn->tx_free, &fn->tx_lock); + } + + if (n < MAX_TTY_TX) { + /* free allocated request */ + rawbulk_tty_free_request(fn); + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_alloc_request); + +int rawbulk_tty_stop_io(struct rawbulk_function *fn) { + struct usb_request_wrapper *req; + + if (!check_tty_opened(fn)) + return -ENODEV; + + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + } + + while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->tx_inproc, &fn->tx_lock); + usb_ep_dequeue(fn->bulk_in, req->request); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_stop_io); + +int rawbulk_tty_start_io(struct rawbulk_function *fn) { + int ret; + struct usb_request_wrapper *req; + + if (!check_tty_opened(fn)) + return -ENODEV; + + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->rx_free, &fn->rx_lock); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_tty_start_io); + +/* Complete the data send stage */ +static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req) { + struct usb_request_wrapper *r = get_wrapper(req); + struct rawbulk_function *fn = r->fn; + + move_req(r, &fn->tx_free, &fn->tx_lock); +} + +static void rawbulk_tty_push_data(struct rawbulk_function *fn) { + struct usb_request_wrapper *r; + struct tty_struct *tty; + + tty = tty_port_tty_get(&fn->port); + tty->minimum_to_wake = 1; /* wakeup to read even pushed only once */ + /* walk the throttled list, push all the data to TTY */ + while ((r = get_req(&fn->rx_throttled, &fn->rx_lock))) { + char *sbuf; + int push_count; + struct usb_request *req = r->request; + + if (req->status < 0) { + put_req(r, &fn->rx_free, &fn->rx_lock); + continue; + } + sbuf = req->buf + fn->last_pushed; + push_count = req->actual - fn->last_pushed; + if (push_count) { + int count = tty_insert_flip_string(tty, sbuf, push_count); + if (count < push_count) { + /* We met throttled again */ + fn->last_pushed += count; + if (count) + tty_flip_buffer_push(tty); + insert_req(r, &fn->rx_throttled, &fn->rx_lock); + break; + } + tty_flip_buffer_push(tty); + fn->last_pushed = 0; + } + put_req(r, &fn->rx_free, &fn->rx_lock); + } + tty_kref_put(tty); +} + +/* Recieve data from host */ +static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req) { + int ret; + struct usb_request_wrapper *r = get_wrapper(req); + struct rawbulk_function *fn = r->fn; + struct tty_struct *tty = fn->tty; + + if (req->status < 0 || !check_tty_opened(fn)) { + move_req(r, &fn->rx_free, &fn->rx_lock); + return; + } + + if (test_bit(TTY_THROTTLED, &tty->flags)) { + /* Give up to resubmitted the request */ + move_req(r, &fn->rx_free, &fn->rx_lock); + return; + } else { + /* Move the request to the throttled queue */ + move_req(r, &fn->rx_throttled, &fn->rx_lock); + /* Start to push data */ + rawbulk_tty_push_data(fn); + } + + /* Re-queue the request again */ + while ((r = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(r, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, r->request, GFP_ATOMIC); + if (ret < 0) { + move_req(r, &fn->rx_free, &fn->rx_lock); + break; + } + } +} + +/* Start to queue request on BULK OUT endpoint, when tty is try to open */ +static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct + *tty) { + struct rawbulk_function *fn = port_to_rawbulk(port); + /* Low latency for tty */ + tty->low_latency = 1; + tty->termios->c_cc[VMIN] = 1; + return rawbulk_tty_start_io(fn); +} + +static void rawbulk_tty_deactivate(struct tty_port *port) { + struct usb_request_wrapper *req; + struct rawbulk_function *fn = port_to_rawbulk(port); + + /* This is a little different from stop_io */ + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + + while ((req = get_req(&fn->rx_throttled, &fn->rx_lock))) + put_req(req, &fn->rx_free, &fn->rx_lock); + + while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { + put_req(req, &fn->tx_inproc, &fn->tx_lock); + usb_ep_dequeue(fn->bulk_in, req->request); + } +} + +static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count) { + int ret; + int submitted = 0; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return -EBUSY; + + /* Get new request(s) that freed, fill it, queue it to the endpoint */ + while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { + int length = count - submitted; + if (length <= 0) { + put_req(req, &fn->tx_free, &fn->tx_lock); + break; + } + if (length > MAX_TTY_TX_PACKAGE) + length = MAX_TTY_TX_PACKAGE; + memcpy(req->buffer, buf + submitted, length); + req->request->length = length; + put_req(req, &fn->tx_inproc, &fn->tx_lock); + ret = usb_ep_queue(fn->bulk_in, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->tx_free, &fn->tx_lock); + return ret; + } + submitted += length; + } + + return submitted; +} + +static int rawbulk_tty_write_room(struct tty_struct *tty) { + int room = 0; + unsigned long flags; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return 0; + + spin_lock_irqsave(&fn->tx_lock, flags); + list_for_each_entry(req, &fn->tx_free, list) + room += req->length; + spin_unlock_irqrestore(&fn->tx_lock, flags); + + return room; +} + +static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty) { + int chars = 0; + unsigned long flags; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + if (check_enable_state(fn)) + return 0; + + spin_lock_irqsave(&fn->rx_lock, flags); + list_for_each_entry(req, &fn->rx_throttled, list) { + if (req->request->status < 0) + continue; + chars += req->request->actual; + } + chars -= fn->last_pushed; + spin_unlock_irqrestore(&fn->rx_lock, flags); + + return chars; +} + +static void rawbulk_tty_throttle(struct tty_struct *tty) { + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + /* Stop the processing requests */ + while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { + if (req->request->status == -EINPROGRESS) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + usb_ep_dequeue(fn->bulk_out, req->request); + } + } +} + +static void rawbulk_tty_unthrottle(struct tty_struct *tty) { + int ret; + struct usb_request_wrapper *req; + struct rawbulk_function *fn = tty->driver_data; + + /* Try to push the throttled requests' data to TTY */ + rawbulk_tty_push_data(fn); + + /* Restart the free requests */ + while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { + put_req(req, &fn->rx_inproc, &fn->rx_lock); + ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); + if (ret < 0) { + move_req(req, &fn->rx_free, &fn->rx_lock); + break; + } + } +} + +static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios + *old) { + //struct rawbulk_function *fn = tty->driver_data; +} + +static int rawbulk_tty_tiocmget(struct tty_struct *tty) { + //struct rawbulk_function *fn = tty->driver_data; + return 0; +} + +static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear) { + //struct rawbulk_function *fn = tty->driver_data; + return 0; +} + +static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct + *tty) { + int ret = 0; + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + + if (!fn) + return -ENODEV; + + ret = tty_init_termios(tty); + if (ret < 0) + return ret; + + tty->driver_data = fn; + fn->tty = tty; + + /* Final install (we use the default method) */ + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[tty->index] = tty; + return ret; +} + +static void rawbulk_tty_cleanup(struct tty_struct *tty) { + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + tty->driver_data = NULL; + if (fn) + fn->tty = NULL; +} + +static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip) { + int ret; + struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); + + if (!fn) + return -ENODEV; + + tty->driver_data = fn; + fn->tty = tty; + + if (check_enable_state(fn)) + return -EBUSY; + + if (check_tty_opened(fn)) + return -EBUSY; + + set_tty_opened(fn, 1); + + ret = tty_port_open(&fn->port, tty, flip); + if (ret < 0) + return ret; + return 0; +} + +static void rawbulk_tty_hangup(struct tty_struct *tty) { + struct rawbulk_function *fn = tty->driver_data; + if (!fn) + return; + tty_port_hangup(&fn->port); +} + +static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip) { + struct rawbulk_function *fn = tty->driver_data; + if (!fn) + return; + set_tty_opened(fn, 0); + tty_port_close(&fn->port, tty, flip); +} + +static __init int rawbulk_tty_init(void) { + int ret; + struct tty_driver *drv = alloc_tty_driver(_MAX_TID); + if (!drv) + return -ENOMEM; + + drv->owner = THIS_MODULE; + drv->driver_name = "rawbulkport"; + drv->name = "ttyRB";//prefix + drv->type = TTY_DRIVER_TYPE_SERIAL; + drv->subtype = SERIAL_TYPE_NORMAL; + drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + drv->init_termios = tty_std_termios; + drv->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + drv->init_termios.c_lflag = 0; + drv->init_termios.c_ispeed = 9600; + drv->init_termios.c_ospeed = 9600; + + tty_set_operations(drv, &rawbulk_tty_ops); + + ret = tty_register_driver(drv); + if (ret < 0) { + put_tty_driver(drv); + } else + rawbulk_tty_driver = drv; + return ret; +} + +/******************************************************************************/ +static struct class *rawbulk_class; + +static struct _function_init_stuff { + const char *longname; + const char *shortname; + const char *iString; + unsigned int ep_maxpkg; + unsigned int nups; + unsigned int ndowns; + unsigned int upsz; + unsigned int downsz; + unsigned int splitsz; + bool autoreconn; + bool pushable; +} _init_params[] = { + {"rawbulk-modem", "data", "Modem Port", 64, 16, 16, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-ets", "ets", "ETS Port", 512, 4, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-at", "atc", "AT Channel", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-pcv", "pcv", "PCM Voice", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + {"rawbulk-gps", "gps", "LBS GPS Port", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, + { }, /* End of configurations */ +}; + +static __init struct rawbulk_function *rawbulk_alloc_function(int transfer_id) { + int rc; + struct rawbulk_function *fn; + struct _function_init_stuff *_init = &_init_params[transfer_id]; + + if (transfer_id == _MAX_TID) + return NULL; + + fn = kzalloc(sizeof *fn, GFP_KERNEL); + if (IS_ERR(fn)) + return NULL; + + /* init default features of rawbulk functions */ + fn->longname = _init->longname; + fn->shortname = _init->shortname; + fn->string_defs[0].s = _init->iString; + fn->nups = _init->nups; + fn->ndowns = _init->ndowns; + fn->upsz = _init->upsz; + fn->downsz = _init->downsz; + fn->splitsz = _init->splitsz; + fn->autoreconn = _init->autoreconn; + fn->pushable = _init->pushable; + + fn->tty_minor = -1; + /* init descriptors */ + init_interface_desc(&fn->interface); + init_endpoint_desc(&fn->fs_bulkin_endpoint, 1, _init->ep_maxpkg); + init_endpoint_desc(&fn->hs_bulkin_endpoint, 1, _init->ep_maxpkg); + init_endpoint_desc(&fn->fs_bulkout_endpoint, 0, _init->ep_maxpkg); + init_endpoint_desc(&fn->hs_bulkout_endpoint, 0, _init->ep_maxpkg); + + fn->fs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; + fn->fs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkin_endpoint; + fn->fs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkout_endpoint; + + fn->hs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; + fn->hs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkin_endpoint; + fn->hs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkout_endpoint; + + fn->string_table.language = 0x0409; + fn->string_table.strings = fn->string_defs; + fn->strings[0] = &fn->string_table; + fn->strings[1] = NULL; + + fn->transfer_id = transfer_id; + + /* init function callbacks */ + fn->function.strings = fn->strings; + fn->function.descriptors = fn->fs_descs; + fn->function.hs_descriptors = fn->hs_descs; + + /* init device attributes */ + add_device_attr(fn, ATTR_ENABLE, "enable", 0755); +#ifdef SUPPORT_LEGACY_CONTROL + add_device_attr(fn, ATTR_ENABLE_C, fn->shortname, 0755); +#endif + add_device_attr(fn, ATTR_AUTORECONN, "autoreconn", 0755); + add_device_attr(fn, ATTR_STATISTICS, "statistics", 0644); + add_device_attr(fn, ATTR_NUPS, "nups", 0755); + add_device_attr(fn, ATTR_NDOWNS, "ndowns", 0755); + add_device_attr(fn, ATTR_UPSIZE, "ups_size", 0755); + add_device_attr(fn, ATTR_DOWNSIZE, "downs_size", 0755); + add_device_attr(fn, ATTR_SPLIT, "split_size", 0755); + add_device_attr(fn, ATTR_PUSHABLE, "pushable", 0755); + + fn->max_attrs = ATTR_PUSHABLE + 1; + + if (transfer_id == RAWBULK_TID_MODEM) { + // printk(" kevin chagnge dtr for 200 for cts, disable usb est bypass \n"); + add_device_attr(fn, ATTR_DTR, "dtr", 0200); + fn->max_attrs ++; + } + + fn->dev = device_create(rawbulk_class, NULL, MKDEV(0, + fn->transfer_id), NULL, fn->shortname); + if (IS_ERR(fn->dev)) { + kfree(fn); + return NULL; + } + + rc = rawbulk_create_files(fn); + if (rc < 0) { + device_destroy(rawbulk_class, fn->dev->devt); + kfree(fn); + return NULL; + } + + spin_lock_init(&fn->lock); + wake_lock_init(&fn->keep_awake, WAKE_LOCK_SUSPEND, fn->longname); + return fn; +} + +static void rawbulk_destory_function(struct rawbulk_function *fn) { + if (!fn) + return; + wake_lock_destroy(&fn->keep_awake); + rawbulk_remove_files(fn); + device_destroy(rawbulk_class, fn->dev->devt); + kfree(fn); +} + +#ifdef SUPPORT_LEGACY_CONTROL +static struct attribute *legacy_sysfs[_MAX_TID + 1] = { NULL }; +static struct attribute_group legacy_sysfs_group = { + .attrs = legacy_sysfs, +}; +struct kobject *legacy_sysfs_stuff; +#endif /* SUPPORT_LEGACY_CONTROL */ + +static int __init init(void) { + int n; + int rc = 0; + + printk(KERN_INFO "rawbulk functions init.\n"); + + rawbulk_class = class_create(THIS_MODULE, "usb_rawbulk"); + if (IS_ERR(rawbulk_class)) + return PTR_ERR(rawbulk_class); + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_function *fn = rawbulk_alloc_function(n); + if (IS_ERR(fn)) { + while (n --) + rawbulk_destory_function(prealloced_functions[n]); + rc = PTR_ERR(fn); + break; + } + prealloced_functions[n] = fn; +#ifdef SUPPORT_LEGACY_CONTROL + legacy_sysfs[n] = &fn->attr[ATTR_ENABLE_C].attr; +#endif + } + + if (rc < 0) { + class_destroy(rawbulk_class); + return rc; + } + +#ifdef SUPPORT_LEGACY_CONTROL + /* make compatiable with old bypass sysfs access */ + legacy_sysfs_stuff = kobject_create_and_add("usb_bypass", NULL); + if (legacy_sysfs_stuff) { + rc = sysfs_create_group(legacy_sysfs_stuff, &legacy_sysfs_group); + if (rc < 0) + printk(KERN_ERR "failed to create legacy bypass sys-stuff, but continue...\n"); + } +#endif /* SUPPORT_LEGACY_CONTROL */ + + rc = rawbulk_tty_init(); + if (rc < 0) { + printk(KERN_ERR "failed to init rawbulk tty driver.\n"); + return rc; + } + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_function *fn = prealloced_functions[n]; + rc = rawbulk_register_tty(fn); + if (rc < 0) { + printk(KERN_ERR "fatal error: we cannot create ttyRB%d for %s\n", + n, fn->longname); + return rc; + } + } + + return 0; +} + +module_init(init); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c new file mode 100755 index 00000000..70ec5be1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c @@ -0,0 +1,1372 @@ +/* + * Rawbulk Driver from VIA Telecom + * + * Copyright (C) 2011 VIA Telecom, Inc. + * Author: Karfield Chen (kfchen@via-telecom.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/* + * Rawbulk is transfer performer between CBP host driver and Gadget driver + * + * 1 rawbulk transfer can be consist by serval upstream and/or downstream + * transactions. + * + * upstream: CBP Driver ---> Gadget IN + * downstream: Gadget OUT ---> CBP Driver + * + * upstream flowchart: + * + * -x-> usb_submit_urb -> complete -> usb_ep_queue -> complete -, + * | | + * `----------------------(control)----------------------------' + * + * downstream flowchart: + * + * -x-> usb_ep_queue -> complete -> usb_submit_urb -> complete -, + * | | + * `----------------------(control)----------------------------' + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#define DRIVER_AUTHOR "Karfield Chen <kfchen@via-telecom.com>" +#define DRIVER_DESC "Rawbulk Driver - perform bypass for Kunlun" +#define DRIVER_VERSION "1.0.3" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/usb/rawbulk.h> +#include <linux/moduleparam.h> + +#ifdef VERBOSE_DEBUG +#define ldbg(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args) +#define tdbg(t, fmt, args...) \ + printk(KERN_DEBUG "Rawbulk %s: " fmt "\n", t->name, ##args) +#else +#define ldbg(args...) +#define tdbg(args...) +#endif + +#define lerr(fmt, args...) \ + printk(KERN_ERR "%s: " fmt "\n", __func__, ##args) +#define terr(t, fmt, args...) \ + printk(KERN_ERR "Rawbulk [%s]:" fmt "\n", t->name, ##args) + +#define FREE_STALLED 1 +#define FREE_IDLED 2 +#define FREE_RETRIVING 4 +#define FREE_ALL (FREE_STALLED | FREE_IDLED | FREE_RETRIVING) + +#define STOP_UPSTREAM 0x1 +#define STOP_DOWNSTREAM 0x2 + +struct rawbulk_transfer { + enum transfer_id id; + spinlock_t lock; + int control; + struct usb_anchor submitted; + struct usb_function *function; + struct usb_interface *interface; + struct mutex mutex; /* protection for API calling */ + rawbulk_autoreconn_callback_t autoreconn; + rawbulk_intercept_t inceptor; + spinlock_t suspend_lock; + int suspended; + struct { + int ntrans; + struct list_head transactions; + struct usb_ep *ep; + struct usb_host_endpoint *host_ep; + } upstream, downstream; +}; + +static inline int get_epnum(struct usb_host_endpoint *ep) { + return (int)(ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); +} + +static inline int get_maxpacksize(struct usb_host_endpoint *ep) { + return (int)(le16_to_cpu(ep->desc.wMaxPacketSize)); +} + + +#define MAX_RESPONSE 32 +struct rawbulk_transfer_model { + struct usb_device *udev; + struct usb_composite_dev *cdev; + char ctrl_response[MAX_RESPONSE]; + struct usb_ctrlrequest forward_dr; + struct urb *forwarding_urb; + struct rawbulk_transfer transfer[_MAX_TID]; +}; +static struct rawbulk_transfer_model *rawbulk; + +static struct rawbulk_transfer *id_to_transfer(int transfer_id) { + if (transfer_id < 0 || transfer_id >= _MAX_TID) + return NULL; + return &rawbulk->transfer[transfer_id]; +} + +/* + * upstream + */ + +#define UPSTREAM_STAT_FREE 0 +#define UPSTREAM_STAT_RETRIEVING 1 +#define UPSTREAM_STAT_UPLOADING 2 + +struct upstream_transaction { + int state; + int stalled; + char name[32]; + struct list_head tlist; + struct delayed_work delayed; + struct rawbulk_transfer *transfer; + struct usb_request *req; + struct urb *urb; + int buffer_length; + unsigned char *buffer; +}; + +static void upstream_delayed_work(struct work_struct *work); +static struct upstream_transaction * +alloc_upstream_transaction(struct rawbulk_transfer *transfer, int bufsz, int pushable) +{ + struct upstream_transaction *t; + + if (bufsz < get_maxpacksize(transfer->upstream.host_ep)) + return NULL; + if (bufsz < PAGE_SIZE || bufsz % PAGE_SIZE != 0) + return NULL; + + t = kzalloc(sizeof *t, GFP_KERNEL); + if (!t) + return NULL; + + t->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(bufsz)); + if (!t->buffer) { + kfree(t); + return NULL; + } + + t->buffer_length = bufsz; + + t->req = usb_ep_alloc_request(transfer->upstream.ep, GFP_KERNEL); + if (!t->req) + goto failto_alloc_usb_request; + + if (!pushable) { + t->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!t->urb) + goto failto_alloc_urb; + } + + t->name[0] = 0; + sprintf(t->name, "U%d (H:ep%din, G:%s)", transfer->upstream.ntrans, + get_epnum(transfer->upstream.host_ep), + transfer->upstream.ep->name); + + INIT_LIST_HEAD(&t->tlist); + list_add_tail(&t->tlist, &transfer->upstream.transactions); + transfer->upstream.ntrans ++; + t->transfer = transfer; + + INIT_DELAYED_WORK(&t->delayed, upstream_delayed_work); + t->state = UPSTREAM_STAT_FREE; + return t; + +failto_alloc_urb: + usb_ep_free_request(transfer->upstream.ep, t->req); +failto_alloc_usb_request: + free_page((unsigned long)t->buffer); + kfree(t); + return NULL; +} + +static void free_upstream_transaction(struct rawbulk_transfer *transfer, int option) { + struct list_head *p, *n; + list_for_each_safe(p, n, &transfer->upstream.transactions) { + struct upstream_transaction *t = list_entry(p, struct + upstream_transaction, tlist); + + if ((option & FREE_RETRIVING) && + (t->state == UPSTREAM_STAT_RETRIEVING)) { + if (t->urb) usb_unlink_urb(t->urb); + goto free; + } + + if ((option & FREE_STALLED) && t->stalled) + goto free; + + if ((option & FREE_IDLED) && (t->state == UPSTREAM_STAT_FREE)) + goto free; + + continue; +free: + list_del(p); + if (t->urb) + usb_free_urb(t->urb); + usb_ep_free_request(transfer->upstream.ep, t->req); + free_page((unsigned long)t->buffer); + kfree(t); + + transfer->upstream.ntrans --; + } +} + +static void upstream_second_stage(struct urb *urb); +static void upstream_final_stage(struct usb_ep *ep, struct usb_request + *req); + +static int start_upstream(struct upstream_transaction *t, gfp_t mem_flags) { + int rc; + unsigned long flags; + struct rawbulk_transfer *transfer = t->transfer; + + spin_lock_irqsave(&transfer->lock, flags); + if (transfer->control & STOP_UPSTREAM) { + spin_unlock_irqrestore(&transfer->lock, flags); + cancel_delayed_work(&t->delayed); + t->state = UPSTREAM_STAT_FREE; + t->stalled = 1; + return -EPIPE; + } + spin_unlock_irqrestore(&transfer->lock, flags); + + t->stalled = 0; + t->state = UPSTREAM_STAT_FREE; + + usb_fill_bulk_urb(t->urb, rawbulk->udev, + usb_rcvbulkpipe(rawbulk->udev, + get_epnum(transfer->upstream.host_ep)), + t->buffer, t->buffer_length, + upstream_second_stage, t); + usb_anchor_urb(t->urb, &transfer->submitted); + + rc = usb_submit_urb(t->urb, mem_flags); + usb_mark_last_busy(rawbulk->udev); + if (rc < 0) { + terr(t, "fail to submit urb %d", rc); + /* FIXME: if we met the host is suspending yet, we may add re-submit + * this urb in a ashman thread. so what is a ashman? this can deal any + * error that occur in this driver, and maintain the driver's health, I + * will complete this code in future, here we just stall the transaction + */ + t->stalled = 1; + usb_unanchor_urb(t->urb); + } + + t->state = UPSTREAM_STAT_RETRIEVING; + return rc; +} + +static void upstream_delayed_work(struct work_struct *work) { + int rc; + int stop; + unsigned long flags; + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct upstream_transaction *t = container_of (work, struct + upstream_transaction, delayed.work); + struct rawbulk_transfer *transfer = t->transfer; + + spin_lock_irqsave(&transfer->lock, flags); + stop = !!(transfer->control & STOP_UPSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + rc = start_upstream(t, GFP_ATOMIC); + if (rc < 0 && !stop) + schedule_delayed_work(dw, HZ); +} + +static unsigned int dump_mask = 0; +module_param(dump_mask, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_mask, "Set data dump mask for each transfers"); + +static inline void dump_data(struct rawbulk_transfer *trans, + const char *str, const unsigned char *data, int size) { + int i; + int no_chars = 0; + + if (!(dump_mask & (1 << trans->id))) + return; + + printk(KERN_DEBUG "DUMP tid = %d, %s: len = %d, chars = \"", + trans->id, str, size); + for (i = 0; i < size; ++i) { + char c = data[i]; + if (c > 0x20 && c < 0x7e) { + printk("%c", c); + } else { + printk("."); + no_chars ++; + } + } + printk("\", data = "); + for (i = 0; i < size; ++i) { + printk("%.2x ", data[i]); + if (i > 7) + break; + } + if (size < 8) { + printk("\n"); + return; + } else if (i < size - 8) { + printk("... "); + i = size - 8; + } + for (; i < size; ++i) + printk("%.2x ", data[i]); + printk("\n"); +} + +static void upstream_second_stage(struct urb *urb) { + int rc; + struct upstream_transaction *t = urb->context; + struct rawbulk_transfer *transfer = t->transfer; + struct usb_request *req = t->req; + + if (urb->status < 0) { + if (urb->status == -ECONNRESET) { + terr(t, "usb-device connection reset!"); + return; + } + printk("WTF?! %s failed %d\n", __func__, urb->status); + /* start again atomatically */ + rc = start_upstream(t, GFP_ATOMIC); +#if 0 + if (rc < 0) + schedule_delayed_work(&t->delayed, HZ); +#endif + return; + } + + dump_data(transfer, "upstream", t->buffer, urb->actual_length); + /* allow zero-length package to pass + if (!urb->actual_length) { + terr(t, "urb actual_length 0"); + start_upstream(t, GFP_ATOMIC); + return; + } + */ + + req->status = 0; + req->context = t; + req->buf = urb->transfer_buffer; + req->length = urb->actual_length; + req->complete = upstream_final_stage; + if (urb->actual_length == 0) + req->zero = 1; + else + req->zero = 0; + + t->state = UPSTREAM_STAT_UPLOADING; + rc = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); + if (rc < 0) { + terr(t, "fail to queue request, %d", rc); + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; + } +} + +static void upstream_final_stage(struct usb_ep *ep, + struct usb_request *req) { + struct upstream_transaction *t = req->context; + + t->state = UPSTREAM_STAT_FREE; + + if (req->status < 0) { + if (req->status != -ECONNRESET) + terr(t, "req status %d", req->status); + if (req->status == -ESHUTDOWN) { + t->stalled = 1; + return; + } + } + + if (!req->actual) + terr(t, "req actual 0"); + + if (t->urb) + start_upstream(t, GFP_ATOMIC); +} + +static void stop_upstream(struct upstream_transaction *t) { + struct rawbulk_transfer *transfer = t->transfer; + if (t->state == UPSTREAM_STAT_RETRIEVING) { + cancel_delayed_work(&t->delayed); + if (t->urb) + usb_unlink_urb(t->urb); + } else if (t->state == UPSTREAM_STAT_UPLOADING) { + usb_ep_dequeue(transfer->upstream.ep, t->req); + } + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; +} + +int rawbulk_push_upstream_buffer(int transfer_id, const void *buffer, + unsigned int length) { + int ret = -ENOENT; + struct upstream_transaction *t; + struct rawbulk_transfer *transfer; + struct usb_request *req; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + /* search for free transfer */ + mutex_lock(&transfer->mutex); + list_for_each_entry(t, &transfer->upstream.transactions, tlist) { + if (t && t->state != UPSTREAM_STAT_UPLOADING) { + ret = 0; + break; + } + } + mutex_unlock(&transfer->mutex); + if (ret < 0) { + terr(t, "no entry for transfer %d while pushing!\n", transfer_id); + return ret; + } + req = t->req; + if (!req) + return -EINVAL; + + /* copy the buffer */ + memcpy(t->buffer, buffer, length); + dump_data(transfer, "pushing up", t->buffer, length); + + req->status = 0; + req->length = length; + req->buf = t->buffer; + req->complete = upstream_final_stage; + req->zero = (length > 0)? 0: 1; + + t->state = UPSTREAM_STAT_UPLOADING; + ret = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); + if (ret < 0) { + terr(t, "fail to queue request, %d", ret); + t->stalled = 1; + t->state = UPSTREAM_STAT_FREE; + return ret; + } + return 0; +} +EXPORT_SYMBOL_GPL(rawbulk_push_upstream_buffer); + +/* + * downstream + */ + +#define MAX_SPLIT_LIMITED 64 + +#define DOWNSTREAM_STAT_FREE 0 +#define DOWNSTREAM_STAT_RETRIEVING 1 +#define DOWNSTREAM_STAT_DOWNLOADING 2 + +struct downstream_transaction { + int state; + int stalled; + char name[32]; + struct list_head tlist; + struct rawbulk_transfer *transfer; + struct usb_request *req; + int nurb; + struct urb *urb[MAX_SPLIT_LIMITED]; + int urb_length; + int buffer_length; + unsigned char buffer[0]; +}; + +static void downstream_second_stage(struct usb_ep *ep, + struct usb_request *req); +static void downstream_final_stage(struct urb *urb); + +static struct downstream_transaction *alloc_downstream_transaction( + struct rawbulk_transfer *transfer, int bufsz, int urbsz) { + int n = 0; + struct downstream_transaction *t; + int maxurbs = bufsz / urbsz; + + if (urbsz < get_maxpacksize(transfer->downstream.host_ep)) + return NULL; + + if (maxurbs > MAX_SPLIT_LIMITED) + return NULL; + + t = kzalloc(sizeof *t + bufsz * sizeof(unsigned char), GFP_KERNEL); + if (!t) + return NULL; + + t->buffer_length = bufsz; + t->urb_length = urbsz; + + t->req = usb_ep_alloc_request(transfer->downstream.ep, GFP_KERNEL); + if (!t->req) + goto failto_alloc_usb_request; + + for (n = 0; n < maxurbs; n ++) { + t->urb[n] = usb_alloc_urb(0, GFP_KERNEL); + if (!t->urb[n]) + goto failto_alloc_urb; + } + t->nurb = 0; + + t->name[0] = 0; + sprintf(t->name, "D%d (G:%s, H:ep%dout)", transfer->downstream.ntrans, + transfer->downstream.ep->name, + get_epnum(transfer->downstream.host_ep)); + + INIT_LIST_HEAD(&t->tlist); + list_add_tail(&t->tlist, &transfer->downstream.transactions); + transfer->downstream.ntrans ++; + t->transfer = transfer; + + t->state = DOWNSTREAM_STAT_FREE; + return t; + +failto_alloc_urb: + while (n --) + usb_free_urb(t->urb[n]); + usb_ep_free_request(transfer->downstream.ep, t->req); +failto_alloc_usb_request: + kfree(t); + return NULL; +} + +static void free_downstream_transaction(struct rawbulk_transfer *transfer, int option) { + int i; + int maxurbs; + struct list_head *p, *n; + list_for_each_safe(p, n, &transfer->downstream.transactions) { + struct downstream_transaction *t = list_entry(p, struct + downstream_transaction, tlist); + + if ((option & FREE_STALLED) && t->stalled) + goto free; + + if ((option & FREE_IDLED) && (t->state == DOWNSTREAM_STAT_FREE)) + goto free; + + if ((option & FREE_RETRIVING) && + (t->state == DOWNSTREAM_STAT_RETRIEVING)) { + usb_ep_dequeue(transfer->downstream.ep, t->req); + goto free; + } + + continue; +free: + list_del(p); + maxurbs = t->buffer_length / t->urb_length; + for (i = 0; i < maxurbs; i ++) + usb_free_urb(t->urb[i]); + usb_ep_free_request(transfer->downstream.ep, t->req); + kfree(t); + + transfer->downstream.ntrans --; + } +} + +static int start_downstream(struct downstream_transaction *t) { + int rc; + unsigned long flags; + struct rawbulk_transfer *transfer = t->transfer; + struct usb_request *req = t->req; + + spin_lock_irqsave(&transfer->lock, flags); + if (transfer->control & STOP_DOWNSTREAM) { + spin_unlock_irqrestore(&transfer->lock, flags); + t->state = DOWNSTREAM_STAT_FREE; + t->stalled = 1; + return -EPIPE; + } + spin_unlock_irqrestore(&transfer->lock, flags); + + t->stalled = 0; + t->state = DOWNSTREAM_STAT_FREE; + + req->buf = t->buffer; + req->length = t->buffer_length; + req->complete = downstream_second_stage; + + rc = usb_ep_queue(transfer->downstream.ep, req, GFP_ATOMIC); + if (rc < 0) { + terr(t, "fail to queue request, %d", rc); + t->stalled = 1; + return rc; + } + + t->state = DOWNSTREAM_STAT_RETRIEVING; + return 0; +} + +static void downstream_second_stage(struct usb_ep *ep, + struct usb_request *req) { + int n = 0; + void *next_buf = req->buf; + int data_length = req->actual; + struct downstream_transaction *t = container_of(req->buf, + struct downstream_transaction, buffer); + struct rawbulk_transfer *transfer = t->transfer; + + if (req->status) { + if (req->status != -ECONNRESET) + terr(t, "req status %d", req->status); + if (req->status == -ESHUTDOWN ||req->status == -ECONNRESET ) + t->stalled = 1; + else + start_downstream(t); + return; + } + + dump_data(transfer, "downstream", t->buffer, req->actual); + /* + if (!data_length) { + terr(t, "req actual 0"); + start_downstream(t); + return; + } + */ + + /* split recieved data into servral urb size less than maxpacket of cbp + * endpoint */ + do { + int rc; + struct urb *urb = t->urb[n]; + int tsize = (data_length > t->urb_length)? t->urb_length: + data_length; + + urb->status = 0; + usb_fill_bulk_urb(urb, rawbulk->udev, + usb_sndbulkpipe(rawbulk->udev, + get_epnum(transfer->downstream.host_ep)), + next_buf, tsize, downstream_final_stage, t); + usb_anchor_urb(urb, &transfer->submitted); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + usb_mark_last_busy(rawbulk->udev); + if (rc < 0) { + terr(t, "fail to submit urb %d, n %d", rc, n); + usb_unanchor_urb(urb); + break; + } + + data_length -= tsize; + next_buf += tsize; + n ++; + } while (data_length > 0); + + t->nurb = n; + t->state = DOWNSTREAM_STAT_DOWNLOADING; +} + +static void downstream_final_stage(struct urb *urb) { + int n; + int actual_total = 0; + struct downstream_transaction *t = urb->context; + + if (urb->status < 0) { + printk("WTF?! - %s failed %d\n", __func__, urb->status); + } + + /* check the condition, re-queue usb_request on gadget ep again if possible */ + for (n = 0; n < t->nurb; n ++) { + int status = t->urb[n]->status; + + if (status == -EINPROGRESS) + return; + + if (!status) + actual_total += t->urb[n]->actual_length; + } + + if (actual_total < t->req->actual) { + terr(t, "requested %d actual %d", t->req->actual, actual_total); + t->stalled = 1; + return; + } + + /* completely transfered over, we can start next transfer now */ + start_downstream(t); +} + +static void stop_downstream(struct downstream_transaction *t) { + int n; + struct rawbulk_transfer *transfer = t->transfer; + int maxurbs = t->buffer_length / t->urb_length; + + if (t->state == DOWNSTREAM_STAT_RETRIEVING) { + usb_ep_dequeue(transfer->downstream.ep, t->req); + } else if (t->state == DOWNSTREAM_STAT_DOWNLOADING) { + for (n = 0; n < maxurbs; n ++) + usb_unlink_urb(t->urb[n]); + } + + t->stalled = 1; +} + +/* + * Ctrlrequest forwarding + */ + +static void response_complete(struct usb_ep *ep, struct usb_request *req) { + if (req->status < 0) + ldbg("feedback error %d\n", req->status); +} + +static void forward_ctrl_complete(struct urb *urb) { + struct usb_composite_dev *cdev = urb->context; + if (!cdev) + return; + + if (urb->status >= 0) { + struct usb_request *req = cdev->req; + if (urb->pipe & USB_DIR_IN) { + memcpy(req->buf, urb->transfer_buffer, urb->actual_length); + req->zero = 0; + req->length = urb->actual_length; + req->complete = response_complete; + ldbg("cp echo: len %d data[0] %02x", req->length, *((char *)req->buf)); + usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } else /* Finish the status stage */ + usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } +} + +int rawbulk_forward_ctrlrequest(const struct usb_ctrlrequest *ctrl) { + struct usb_device *dev; + struct urb *urb; + + ldbg("req_type %02x req %02x value %04x index %04x len %d", + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, + ctrl->wLength); + + dev = rawbulk->udev; + if (!dev) { + return -ENODEV; + } + + rawbulk->forward_dr.bRequestType = ctrl->bRequestType; + rawbulk->forward_dr.bRequest = ctrl->bRequest; + rawbulk->forward_dr.wValue = ctrl->wValue; + //rawbulk->forward_dr.wIndex = ctrl->wIndex; + rawbulk->forward_dr.wIndex = 0;//MODEM DATA PORT + rawbulk->forward_dr.wLength = ctrl->wLength; + + if (!rawbulk->forwarding_urb) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + rawbulk->forwarding_urb = urb; + } else + urb = rawbulk->forwarding_urb; + + if (ctrl->bRequestType & USB_DIR_IN) + usb_fill_control_urb(urb, dev, + usb_rcvctrlpipe(dev, 0), + (unsigned char *)&rawbulk->forward_dr, + rawbulk->ctrl_response, + __le16_to_cpu(ctrl->wLength), + forward_ctrl_complete, + rawbulk->cdev); + else + usb_fill_control_urb(urb, dev, + usb_sndctrlpipe(dev, 0), + (unsigned char *)&rawbulk->forward_dr, + NULL, 0, + forward_ctrl_complete, + rawbulk->cdev); + + return usb_submit_urb(urb, GFP_ATOMIC); +} + +EXPORT_SYMBOL_GPL(rawbulk_forward_ctrlrequest); + +int rawbulk_start_transactions(int transfer_id, int nups, int ndowns, int upsz, + int downsz, int splitsz, int pushable) { + int n; + int rc; + unsigned long flags = 0; + int suspended; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + if (!rawbulk->cdev || !rawbulk->udev) + return -ENODEV; + + if (!transfer->function || !transfer->interface) + return -ENODEV; + + ldbg("start transactions on id %d, nups %d ndowns %d upsz %d downsz %d split %d pushable %d\n", + transfer_id, nups, ndowns, upsz, downsz, splitsz, pushable); + + mutex_lock(&transfer->mutex); + + /* stop host transfer 1stly */ + if (transfer->inceptor) + transfer->inceptor(transfer->interface, pushable? + (RAWBULK_INCEPT_FLAG_ENABLE | RAWBULK_INCEPT_FLAG_PUSH_WAY): + RAWBULK_INCEPT_FLAG_ENABLE); + + /* Make upstream buffer larger than the pusher */ + if (pushable && (upsz < 4096)) + upsz = 4096; + + for (n = 0; n < nups; n ++) { + upstream = alloc_upstream_transaction(transfer, upsz, pushable); + if (!upstream) { + rc = -ENOMEM; + ldbg("fail to allocate upstream transaction n %d", n); + goto failto_alloc_upstream; + } + } + + for (n = 0; n < ndowns; n ++) { + downstream = alloc_downstream_transaction(transfer, downsz, splitsz); + if (!downstream) { + rc = -ENOMEM; + ldbg("fail to allocate downstream transaction n %d", n); + goto failto_alloc_downstream; + } + } + + spin_lock_irqsave(&transfer->suspend_lock, flags); + suspended = transfer->suspended; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + if (suspended) { + ldbg("interface %d is sleeping", transfer_id); + mutex_unlock(&transfer->mutex); + return 0; + } + + transfer->control &= ~STOP_UPSTREAM; + if (!pushable) { + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d\n", upstream->name, rc); + goto failto_start_upstream; + } + } + } + } + + transfer->control &= ~STOP_DOWNSTREAM; + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d\n", downstream->name, rc); + goto failto_start_downstream; + } + } + } + + mutex_unlock(&transfer->mutex); + return 0; + +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); +failto_alloc_downstream: + free_downstream_transaction(transfer, FREE_ALL); +failto_alloc_upstream: + free_upstream_transaction(transfer, FREE_ALL); + /* recover host transfer */ + if (transfer->inceptor) + transfer->inceptor(transfer->interface, 0); + mutex_unlock(&transfer->mutex); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_start_transactions); + +void rawbulk_stop_transactions(int transfer_id) { + unsigned long flags; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + mutex_lock(&transfer->mutex); + spin_lock_irqsave(&transfer->lock, flags); + transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + free_upstream_transaction(transfer, FREE_ALL); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); + free_downstream_transaction(transfer, FREE_ALL); + if (transfer->inceptor) + transfer->inceptor(transfer->interface, 0); + mutex_unlock(&transfer->mutex); +} + +EXPORT_SYMBOL_GPL(rawbulk_stop_transactions); + +int rawbulk_halt_transactions(int transfer_id) { + unsigned long flags; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + spin_lock_irqsave(&transfer->lock, flags); + transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); + spin_unlock_irqrestore(&transfer->lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_halt_transactions); + +int rawbulk_resume_transactions(int transfer_id) { + int rc; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + if (!rawbulk->cdev || !rawbulk->udev) + return -ENODEV; + + if (!transfer->function || !transfer->interface) + return -ENODEV; + + transfer->control &= ~STOP_UPSTREAM; + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d", upstream->name, rc); + goto failto_start_upstream; + } + } + } + + transfer->control &= ~STOP_DOWNSTREAM; + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d", downstream->name, rc); + goto failto_start_downstream; + } + } + } + return 0; + +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_resume_transactions); + +int rawbulk_transfer_state(int transfer_id) { + int stalled = 1; + int count = 0; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + if (!rawbulk->udev || !rawbulk->cdev) + return -ENODEV; + + if (!transfer->interface || !transfer->function) + return -EIO; + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (!upstream->stalled) + stalled = 0; + count ++; + } + + if (stalled || count == 0) + return -EACCES; + + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (!downstream->stalled) + stalled = 0; + count ++; + } + if (stalled || count == 0) + return -EACCES; + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_transfer_state); + +static char *state2string(int state, int upstream) { + if (upstream) { + switch (state) { + case UPSTREAM_STAT_FREE: + return "FREE"; + case UPSTREAM_STAT_RETRIEVING: + return "RETRIEVING"; + case UPSTREAM_STAT_UPLOADING: + return "UPLOADING"; + default: + return "UNKNOW"; + } + } else { + switch (state) { + case DOWNSTREAM_STAT_FREE: + return "FREE"; + case DOWNSTREAM_STAT_RETRIEVING: + return "RETRIEVING"; + case DOWNSTREAM_STAT_DOWNLOADING: + return "DOWNLOADING"; + default: + return "UNKNOW"; + } + } +} + +int rawbulk_transfer_statistics(int transfer_id, char *buf) { + char *pbuf = buf; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return sprintf(pbuf, "-ENODEV, id %d\n", transfer_id); + + pbuf += sprintf(pbuf, "rawbulk statistics:\n"); + if (rawbulk->udev) + pbuf += sprintf(pbuf, " host device: %d-%d\n", rawbulk->udev->bus->busnum, + rawbulk->udev->devnum); + else + pbuf += sprintf(pbuf, " host device: -ENODEV\n"); + if (rawbulk->cdev && rawbulk->cdev->config) + pbuf += sprintf(pbuf, " gadget device: %s\n", + rawbulk->cdev->config->label); + else + pbuf += sprintf(pbuf, " gadget device: -ENODEV\n"); + pbuf += sprintf(pbuf, " upstreams (total %d transactions)\n", + transfer->upstream.ntrans); + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + pbuf += sprintf(pbuf, " %s state: %s", upstream->name, + state2string(upstream->state, 1)); + pbuf += sprintf(pbuf, ", maxbuf: %d bytes", upstream->buffer_length); + if (upstream->stalled) + pbuf += sprintf(pbuf, " (stalled!)"); + pbuf += sprintf(pbuf, "\n"); + } + pbuf += sprintf(pbuf, " downstreams (total %d transactions)\n", + transfer->downstream.ntrans); + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + pbuf += sprintf(pbuf, " %s state: %s", downstream->name, + state2string(downstream->state, 0)); + pbuf += sprintf(pbuf, ", maxbuf: %d bytes", downstream->buffer_length); + if (downstream->state == DOWNSTREAM_STAT_DOWNLOADING) + pbuf += sprintf(pbuf, ", spliting: %d urbs(%d bytes)", downstream->nurb, + downstream->urb_length); + if (downstream->stalled) + pbuf += sprintf(pbuf, " (stalled!)"); + pbuf += sprintf(pbuf, "\n"); + } + pbuf += sprintf(pbuf, "\n"); + return (int)(pbuf - buf); +} + +EXPORT_SYMBOL_GPL(rawbulk_transfer_statistics); + +int rawbulk_bind_function(int transfer_id, struct usb_function *function, struct + usb_ep *bulk_out, struct usb_ep *bulk_in, + rawbulk_autoreconn_callback_t autoreconn_callback) { + struct rawbulk_transfer *transfer; + + if (!function || !bulk_out || !bulk_in) + return -EINVAL; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + transfer->downstream.ep = bulk_out; + transfer->upstream.ep = bulk_in; + transfer->function = function; + rawbulk->cdev = function->config->cdev; + + transfer->autoreconn = autoreconn_callback; + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_bind_function); + +void rawbulk_unbind_function(int transfer_id) { + int n; + int no_functions = 1; + struct rawbulk_transfer *transfer; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + rawbulk_stop_transactions(transfer_id); + transfer->downstream.ep = NULL; + transfer->upstream.ep = NULL; + transfer->function = NULL; + + for (n = 0; n < _MAX_TID; n ++) { + if (!!rawbulk->transfer[n].function) + no_functions = 0; + } + + if (no_functions) + rawbulk->cdev = NULL; +} + +EXPORT_SYMBOL_GPL(rawbulk_unbind_function); + +int rawbulk_bind_host_interface(struct usb_interface *interface, + rawbulk_intercept_t inceptor) { + int n; + int transfer_id; + struct rawbulk_transfer *transfer; + struct usb_device *udev; + + if (!interface || !inceptor) + return -EINVAL; + + transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -ENODEV; + + udev = interface_to_usbdev(interface); + if (!udev) + return -ENODEV; + + if (!rawbulk->udev) { + rawbulk->udev = udev; + } + + /* search host bulk ep for up/downstreams */ + for (n = 0; n < interface->cur_altsetting->desc.bNumEndpoints; n++) { + struct usb_host_endpoint *endpoint = + &interface->cur_altsetting->endpoint[n]; + if (usb_endpoint_is_bulk_out(&endpoint->desc)) + transfer->upstream.host_ep = endpoint; + if (usb_endpoint_is_bulk_in(&endpoint->desc)) + transfer->downstream.host_ep = endpoint; + } + + if (!transfer->upstream.host_ep || !transfer->downstream.host_ep) { + lerr("endpoints do not match bulk pair that needed\n"); + return -EINVAL; + } + + transfer->interface = interface; + transfer->inceptor = inceptor; + + if (transfer->autoreconn) + transfer->autoreconn(transfer->id); + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_bind_host_interface); + +void rawbulk_unbind_host_interface(struct usb_interface *interface) { + int n; + int no_interfaces = 1; + struct rawbulk_transfer *transfer; + int transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return; + + rawbulk_stop_transactions(transfer_id); + transfer->upstream.host_ep = NULL; + transfer->downstream.host_ep = NULL; + transfer->interface = NULL; + transfer->inceptor = NULL; + + for (n = 0; n < _MAX_TID; n ++) { + if(!!rawbulk->transfer[n].interface) + no_interfaces = 0; + } + + if (no_interfaces) { + usb_kill_urb(rawbulk->forwarding_urb); + usb_free_urb(rawbulk->forwarding_urb); + rawbulk->forwarding_urb = NULL; + rawbulk->udev = NULL; + } +} + +EXPORT_SYMBOL_GPL(rawbulk_unbind_host_interface); + +int rawbulk_suspend_host_interface(int transfer_id, pm_message_t message) { + unsigned long flags = 0; + struct rawbulk_transfer *transfer; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + spin_lock_irqsave(&transfer->suspend_lock, flags); + transfer->suspended = 1; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(rawbulk_suspend_host_interface); + +int rawbulk_resume_host_interface(int transfer_id) { + int rc; + unsigned long flags = 0; + struct rawbulk_transfer *transfer; + struct upstream_transaction *upstream; + struct downstream_transaction *downstream; + + transfer = id_to_transfer(transfer_id); + if (!transfer) + return -EINVAL; + + spin_lock_irqsave(&transfer->suspend_lock, flags); + transfer->suspended = 0; + spin_unlock_irqrestore(&transfer->suspend_lock, flags); + + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { + if (upstream->stalled) { + transfer->control &= ~STOP_UPSTREAM; + /* restart transaction again */ + ldbg("restart upstream: %s", upstream->name); + stop_upstream(upstream); + rc = start_upstream(upstream, GFP_KERNEL); + if (rc < 0) { + ldbg("fail to start upstream %s rc %d", upstream->name, rc); + goto failto_start_upstream; + } + } + } + + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { + if (downstream->stalled) { + transfer->control &= ~STOP_DOWNSTREAM; + ldbg("restart downstream: %s", downstream->name); + stop_downstream(downstream); + rc = start_downstream(downstream); + if (rc < 0) { + ldbg("fail to start downstream %s rc %d", downstream->name, rc); + goto failto_start_downstream; + } + } + } + + return 0; +failto_start_downstream: + list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) + stop_downstream(downstream); +failto_start_upstream: + list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) + stop_upstream(upstream); + return rc; +} + +EXPORT_SYMBOL_GPL(rawbulk_resume_host_interface); + +static __init int rawbulk_init(void) { + int n; + + rawbulk = kzalloc(sizeof *rawbulk, GFP_KERNEL); + if (!rawbulk) + return -ENOMEM; + + for (n = 0; n < _MAX_TID; n ++) { + struct rawbulk_transfer *t = &rawbulk->transfer[n]; + + t->id = n; + INIT_LIST_HEAD(&t->upstream.transactions); + INIT_LIST_HEAD(&t->downstream.transactions); + + mutex_init(&t->mutex); + spin_lock_init(&t->lock); + spin_lock_init(&t->suspend_lock); + t->suspended = 0; + t->control = STOP_UPSTREAM | STOP_DOWNSTREAM; + + init_usb_anchor(&t->submitted); + } + + return 0; +} + +fs_initcall (rawbulk_init); + +static __exit void rawbulk_exit(void) { + int n; + for (n = 0; n < _MAX_TID; n ++) + rawbulk_stop_transactions(n); + + if (rawbulk->forwarding_urb) { + usb_kill_urb(rawbulk->forwarding_urb); + usb_free_urb(rawbulk->forwarding_urb); + rawbulk->forwarding_urb = NULL; + } + + kfree(rawbulk); +} + +module_exit (rawbulk_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c index 0cb21218..953439d4 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c @@ -1203,3 +1203,7 @@ void rndis_exit(void) } #endif } +bool get_rndis_initialized(void) +{ + return rndis_initialized; +}
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c index 8081ca3a..88e9c0ef 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c @@ -813,6 +813,14 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, return rc; } +static ssize_t fsg_show_cdrom(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%d\n", curlun->cdrom); +} + static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -898,3 +906,33 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, up_write(filesem); return (rc < 0 ? rc : count); } + +static ssize_t fsg_store_cdrom(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t rc; + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + unsigned cdrom; + + rc = kstrtouint(buf, 2, &cdrom); + if (rc) + return rc; + + /* + * Allow the write-enable status to change only while the + * backing file is closed. + */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { + curlun->cdrom = cdrom; + LDBG(curlun, "cdrom status set to %d\n", curlun->cdrom); + rc = count; + } + up_read(filesem); + return rc; +} + diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c index c8702c8e..59ac7227 100644 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c +++ b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c @@ -457,7 +457,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; - + unsigned long flags; switch (req->status) { default: dev->net->stats.tx_errors++; @@ -471,9 +471,11 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) } dev->net->stats.tx_packets++; - spin_lock(&dev->req_lock); + //spin_lock(&dev->req_lock); + spin_lock_irqsave(&dev->req_lock, flags); list_add(&req->list, &dev->tx_reqs); - spin_unlock(&dev->req_lock); + //spin_unlock(&dev->req_lock); + spin_unlock_irqrestore(&dev->req_lock, flags); dev_kfree_skb_any(skb); atomic_dec(&dev->tx_qlen); @@ -703,7 +705,7 @@ module_param(dev_addr, charp, S_IRUGO); MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); /* this address is invisible to ifconfig */ -static char *host_addr; +static char *host_addr="02:50:e6:a8:b8:63"; module_param(host_addr, charp, S_IRUGO); MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); @@ -938,7 +940,7 @@ fail0: return ERR_PTR(result); return dev->net; } - +extern void wmt_cleanup_done_thread(int number); /** * gether_disconnect - notify network layer that USB link is inactive * @link: the USB link, on which gether_connect() was called @@ -955,7 +957,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; - + unsigned long flags; WARN_ON(!dev); if (!dev) return; @@ -970,6 +972,7 @@ void gether_disconnect(struct gether *link) * and forget about the endpoints. */ usb_ep_disable(link->in_ep); + wmt_cleanup_done_thread(1); spin_lock(&dev->req_lock); while (!list_empty(&dev->tx_reqs)) { req = container_of(dev->tx_reqs.next, @@ -985,6 +988,7 @@ void gether_disconnect(struct gether *link) link->in_ep->desc = NULL; usb_ep_disable(link->out_ep); + wmt_cleanup_done_thread(1); spin_lock(&dev->req_lock); while (!list_empty(&dev->rx_reqs)) { req = container_of(dev->rx_reqs.next, diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c new file mode 100755 index 00000000..c239e3d8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c @@ -0,0 +1,4699 @@ +/* + * wmt_udc.c -- for WonderMedia Technology udc + * + * Copyright (C) 2007 VIA Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef DEBUG +#undef VERBOSE + +#include <generated/autoconf.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/mm.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/suspend.h> + + + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> +#include <asm/mach-types.h> +#include <linux/usb/composite.h> + +#include "udc_wmt.h" + +#define USE_BULK3_TO_INTERRUPT //gri + +//#define FULL_SPEED_ONLY +/*#define HW_BUG_HIGH_SPEED_PHY*/ +#undef USB_TRACE + +/* bulk DMA seems to be behaving for both IN and OUT */ +#define USE_DMA + +/*#define DEBUG_UDC_ISR_TIMER*/ +#undef DEBUG_UDC_ISR_TIMER + +/*#define RNDIS_INFO_DEBUG_BULK_OUT*/ +#undef RNDIS_INFO_DEBUG_BULK_OUT + +/*#define RNDIS_INFO_DEBUG_BULK_IN*/ +#undef RNDIS_INFO_DEBUG_BULK_IN + +/*#define MSC_COMPLIANCE_TEST*/ +#undef MSC_COMPLIANCE_TEST + +/*#define UDC_A1_SELF_POWER_ENABLE*/ + +/*-----------------------------------------------------------------------------*/ + +#define DRIVER_DESC "VIA UDC driver" +#define DRIVER_VERSION "3 December 2007" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +static unsigned fifo_mode; + +static unsigned fiq_using = 0; + +/* "modprobe vt8500_udc fifo_mode=42", or else as a kernel + * boot parameter "vt8500_udc:fifo_mode=42" + */ + +module_param(fifo_mode, uint, 0); +MODULE_PARM_DESC(fifo_mode, "endpoint setup (0 == default)"); + +static bool use_dma = 1; + +module_param(use_dma, bool, 0); +MODULE_PARM_DESC(use_dma, "enable/disable DMA"); + +static const char driver_name[] = "wmotgdev";/*"wmt_udc";*/ +static const char driver_desc[] = DRIVER_DESC; + +static DEFINE_SEMAPHORE(wmt_udc_sem); +static int f_ep3_used = 0; + +static struct vt8500_udc *udc; +static struct device *pDMADescLI, *pDMADescSI; +static struct device *pDMADescLO, *pDMADescSO; + +static struct device *pDMADescL2I, *pDMADescS2I; + +dma_addr_t UdcPdmaPhyAddrLI, UdcPdmaPhyAddrSI; +static UINT UdcPdmaVirAddrLI, UdcPdmaVirAddrSI; +dma_addr_t UdcPdmaPhyAddrLO, UdcPdmaPhyAddrSO; +static UINT UdcPdmaVirAddrLO, UdcPdmaVirAddrSO; + +dma_addr_t UdcPdmaPhyAddrL2I, UdcPdmaPhyAddrS2I; +static UINT UdcPdmaVirAddrL2I, UdcPdmaVirAddrS2I; + +dma_addr_t UdcRndisEp1PhyAddr, UdcRndisEp2PhyAddr, UdcRndisEp3PhyAddr; +static UINT UdcRndisEp1VirAddr, UdcRndisEp2VirAddr, UdcRndisEp3VirAddr; + +#ifdef OTGIP +static struct USB_GLOBAL_REG *pGlobalReg; +#endif +/*static struct UDC_REGISTER *udc_reg;*/ + +static volatile struct UDC_REGISTER *pDevReg; +static volatile struct UDC_DMA_REG *pUdcDmaReg; + +PSETUPCOMMAND pSetupCommand; +UCHAR *pSetupCommandBuf; +UCHAR *SetupBuf; +UCHAR *IntBuf; + +UCHAR ControlState; /* the state the control pipe*/ +UCHAR USBState; +UCHAR TestMode; + +/* Basic Define*/ +//#define REG32 *(volatile unsigned int *) +//#define REG_GET32(addr) (REG32(addr)) /* Read 32 bits Register */ + +static unsigned long irq_flags;//gri + +volatile unsigned char *pUSBMiscControlRegister5; + +unsigned int interrupt_transfer_size; + +static void wmt_pdma_reset(void); +static void wmt_pdma0_reset(void); +static void wmt_pdma1_reset(void); + +#ifdef USE_BULK3_TO_INTERRUPT +static void wmt_pdma2_reset(void); +#endif + +/* 1 : storage */ +static unsigned int gadget_connect=0; +//static unsigned int first_mount=0; + + +struct work_struct online_thread; +struct work_struct offline_thread; +struct work_struct done_thread; +struct work_struct chkiso_thread; + + + +struct list_head done_main_list; +spinlock_t gri_lock; +static unsigned long gri_flags;//gri + +static unsigned int b_pullup=0; + +void run_chkiso (struct work_struct *work); + +static inline unsigned int wmt_ost_counter(void) +{ + OSTC_VAL |= OSTC_RDREQ; + while (OSTA_VAL & OSTA_RCA) + ; + + return (u32)OSCR_VAL; +} + +static inline void wmt_ost2_set_match(u32 new_match) +{ + /* check if can write OS Timer2 match register nows */ + while (OSTA_VAL & OSTA_MWA2) + ; + + OSM2_VAL = new_match; +} + +void wmt_enable_fiq(unsigned int how_many_us) +{ + unsigned int cnt = 0; + + cnt = wmt_ost_counter(); + cnt += (3*how_many_us); + wmt_ost2_set_match(cnt); + OSTI_VAL |= OSTI_E2; +} + +void wmt_disable_fiq(void) +{ + OSTI_VAL &= ~OSTI_E2; +} + +static irqreturn_t +test_fiq_handler(int irq, void *_udc)//, struct pt_regs *r) +{ + OSTS_VAL = OSTI_E2; + + //printk("i am test_fiq_handler\n"); + + run_chkiso(NULL); + return IRQ_HANDLED; +} + +void initial_test_fiq(void) +{ + //int ret = -1; + int status = -ENODEV; + + printk("\n\n\ninitial_test_fiq\n\n"); + // set fiq + + OSTS_VAL = OSTI_E2; + OSTI_VAL &= ~OSTI_E2; +#if 0 + fhandler.fiq = test_fiq_handler; + fhandler.resume = test_fiq_resume; + ret = fiq_wmt_register_handler(&fhandler); + if (ret) { + pr_err("%s: could not install fiq handler ( %d )\n", __func__, ret); + return; + } + + //use OST2 to test + + enable_fiq(70); +#else + status = request_irq(IRQ_OST2, test_fiq_handler, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_DISABLED), driver_name, udc);//gri + if (status != 0) { + ERR("**** can't get irq %d, err %d\n", + IRQ_OST2, status); + } else + INFO("**** wmt_udc_probe - request_irq(0x%02X) pass!\n", IRQ_OST2); +#endif +} + +/** + * + * Run these two functions to execute shell script to mount / umount storage + * + */ +#if 0 +static int run_online(void) +{ + kobject_uevent(&udc->dev->kobj, 2); + return 0; +} +#endif +void wmt_cleanup_done_thread(int number); +static void run_offline (struct work_struct *work) +{ + if ((udc->driver) && b_pullup){ +// printk(KERN_INFO "disconnect\n"); //gri + udc->driver->disconnect(&udc->gadget); + } +// return 0; +} + +static void run_done (struct work_struct *work) +{ + struct vt8500_req * req; + + spin_lock_irqsave(&gri_lock, gri_flags); +// printk(KERN_INFO "d1\n"); //gri + while (!list_empty(&done_main_list)){ +// printk(KERN_INFO "d3\n"); //gri + req = list_entry(done_main_list.next, struct vt8500_req, mem_list); + list_del_init(&req->mem_list); + spin_unlock_irqrestore(&gri_lock, gri_flags); + req->req.complete(&req->ep->ep, &req->req); + spin_lock_irqsave(&gri_lock, gri_flags); + } +// printk(KERN_INFO "d2\n"); //gri + spin_unlock_irqrestore(&gri_lock, gri_flags); +// return 0; +} + +void dma_irq(u8 addr); +void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req); +void iso_prepare_0byte(void); +void run_chkiso (struct work_struct *work) +{ + spin_lock_irqsave(&udc->lock, irq_flags); + if (!fiq_using) { + //printk("iso fail\n"); + spin_unlock_irqrestore(&udc->lock, irq_flags); + return; + } + + //do { + //schedule(); + if (pDevReg->Bulk3DesStatus & BULKXFER_XACTERR) { + { + struct vt8500_ep *ep; + struct vt8500_req *req; + /*u32 temp32;*/ + /*u32 i;*/ + + ep = &udc->ep[4]; + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + //printk("iso h q\n"); + next_in_dma(ep, req); + } else { + //printk("no q\n"); + wmt_disable_fiq(); + fiq_using = 0; + wmt_pdma2_reset(); + iso_prepare_0byte(); + } + } + //printk("iso hit\n"); + //break; + } else { + wmt_enable_fiq(300); + //printk("iso hit miss\n"); + } + //} while (1); + spin_unlock_irqrestore(&udc->lock, irq_flags); +} + +enum schedule_work_action +{ + action_done, action_off_line, action_chkiso +}; + +static void run_script(enum schedule_work_action dwAction) +{ + + if (dwAction == action_done){//8 + schedule_work(&done_thread); + }else if (dwAction == action_off_line){//7 + schedule_work(&offline_thread); + }else if (dwAction == action_chkiso){//7 + schedule_work(&chkiso_thread); + }else { + } + +} + + +void udc_device_dump_register(void) +{ + volatile unsigned int address; + volatile unsigned char temp8; + int i; + + for (i = 0x20; i <= 0x3F; i++) { /*0x20~0x3F (0x3F-0x20 + 1) /4 = 8 DWORD*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + for (i = 0x308; i <= 0x30D; i++) { /*0x308~0x30D*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + for (i = 0x310; i <= 0x317; i++) { /*0x310~0x317*/ + address = (USB_UDC_REG_BASE + i); + temp8 = REG_GET8(address); + + INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); + } + + INFO("[UDC Device] Dump Reigster PASS!\n"); + +} /*void udc_device_dump_register(void)*/ + +void udc_bulk_dma_dump_register(void) +{ + volatile unsigned int temp32; + int i; + + for (i = 0; i <= 0x10; i++) { /*0x100 ~ 0x113 (0x113 - 0x100 + 1) = 0x14 /4 = 5*/ + temp32 = REG_GET32(USB_UDC_DMA_REG_BASE + i*4); + INFO("[UDC Bulk DMA] Offset[0x%8.8X] = 0x%8.8X \n", (USB_UDC_DMA_REG_BASE + i*4), temp32); + } + INFO("[UDC Bulk DMAD] Dump Reigster PASS!\n"); + +} /*void udc_bulk_dma_dump_register(void)*/ + +void wmt_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp) +{ + struct vt8500_ep *ep; + /*u32 epn_rxtx = 0;*/ + /*U8 temp_adr;*/ + + VDBG("wmt_ep_setup_csr()\n"); + + /* OUT endpoints first, then IN*/ + + ep = &udc->ep[addr & 0x7f]; + + VDBG("wmt_ep_setup()\n"); + + /* OUT endpoints first, then IN*/ + ep = &udc->ep[addr & 0x7f]; + + if (type == USB_ENDPOINT_XFER_CONTROL) { + /*pDevReg->ControlEpControl;*/ + pDevReg->ControlEpReserved = 0; + pDevReg->ControlEpMaxLen = (maxp & 0xFF); + pDevReg->ControlEpEpNum = 0; + } else if (type == USB_ENDPOINT_XFER_BULK) { + if (addr & USB_DIR_IN) { + /*pDevReg->Bulk1EpControl;*/ + pDevReg->Bulk1EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk1EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk1EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } else { + /*pDevReg->Bulk2EpControl;*/ + pDevReg->Bulk2EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk2EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk2EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } + } else if (type == USB_ENDPOINT_XFER_INT) { +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + + pDevReg->InterruptReserved = (0x85 & 0x7f) << 4; + pDevReg->InterruptEpMaxLen = (8 & 0xFF); /* Interrupt maximum transfer length - 2E*/ + pDevReg->InterruptEpEpNum = (((0x85 & 0x7f) << 4) | ((8 & 0x700) >> 8)); +#else + /*pDevReg->InterruptEpControl; // Interrupt endpoint control - 2C*/ + /* Interrupt endpoint reserved byte - 2D*/ + pDevReg->InterruptReserved = (addr & 0x7f) << 4; + pDevReg->InterruptEpMaxLen = (maxp & 0xFF); /* Interrupt maximum transfer length - 2E*/ + pDevReg->InterruptEpEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); +#endif + } else if (type == USB_ENDPOINT_XFER_ISOC) { + pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; + pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); + pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); + } + + /*Setting address pointer ...*/ + wmb(); + VDBG("wmt_ep_setup_csr() - %s addr %02x maxp %d\n", + name, addr, maxp); + + ep->toggle_bit = 0; + ep->ep.maxpacket = maxp; +} /*tatic void wmt_ep_setup_csr()*/ + +static int wmt_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_udc *udc; + + u16 maxp; + + DBG("wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); + printk(KERN_INFO "gri wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); + + /* catch various bogus parameters*/ + if (!_ep || !desc || (ep->desc && ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC)) + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep->maxpacket < usb_endpoint_maxp(desc)) { + VDBG("ep->bEndpointAddress = 0x%08X\n", ep->bEndpointAddress); + VDBG("desc->bEndpointAddres = 0x%08X\n", desc->bEndpointAddress); + VDBG("ep->maxpacket =0x%08X\n", ep->maxpacket); + VDBG("desc->wMaxPacketSize =0x%08X\n", desc->wMaxPacketSize); + VDBG("_ep =0x%08X\n", (unsigned int)_ep); + VDBG("desc =0x%08X\n", (unsigned int)desc); + VDBG("ep->desc =0x%08X\n", (unsigned int)ep->desc); + + /*DBG("%s, bad ep or descriptor\n", __FUNCTION__);*/ + return -EINVAL; + } + + maxp = usb_endpoint_maxp(desc); + + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK) + && (usb_endpoint_maxp(desc) > ep->maxpacket + || !desc->wMaxPacketSize)) { + DBG("[wmt_ep_enable]bad %s maxpacket\n", _ep->name); + return -ERANGE; + } + +#if 1 + if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC + && desc->bInterval != 1)) { + /* hardware wants period = 1; USB allows 2^(Interval-1) */ + DBG("%s, unsupported ISO period %dms\n", _ep->name, + 1 << (desc->bInterval - 1)); + return -EDOM; + } + +#if 0 + /* xfer types must match, except that interrupt ~= bulk*/ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DBG("[wmt_ep_enable], %s type mismatch\n", _ep->name); + printk("[wmt_ep_enable], %s type mismatch\n", _ep->name); + return -EINVAL; + } +#endif +#endif + + udc = ep->udc; + + spin_lock_irqsave(&udc->lock, irq_flags); + + ep->desc = desc; + ep->irqs = 0; + ep->stopped = 0; + ep->ep.maxpacket = maxp; + + ep->has_dma = 1; + ep->ackwait = 0; + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); + wmb(); + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 1:/*Bulk In*/ + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, maxp); + wmb(); + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 2:/*Bulk Out*/ + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, maxp); + wmb(); + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + if (f_ep3_used == 4) + return -ERANGE; + f_ep3_used = 3; + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); + wmb(); + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); + wmb(); + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif + break; + + case 4:/*iso in*/ + if (f_ep3_used == 3) + return -ERANGE; + f_ep3_used = 4; + wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISOC, 384); + wmb(); + + wmt_pdma2_reset(); + iso_prepare_0byte(); + + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; + break; + + } + wmb(); + spin_unlock_irqrestore(&udc->lock, irq_flags); + VDBG("%s enabled\n", _ep->name); +// printk(KERN_INFO "gri enabled %s\n", ep ? ep->ep.name : NULL); + + return 0; +} /*static int wmt_ep_enable()*/ + +static void nuke(struct vt8500_ep *, int status); + +static int wmt_ep_disable(struct usb_ep *_ep) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); +// unsigned long flags; + + DBG("wmt_ep_disable() %s\n", ep ? ep->ep.name : NULL); + + if (!_ep || !ep->desc) { + DBG("[wmt_ep_disable], %s not enabled\n", + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + ep->desc = 0; + nuke(ep, -ESHUTDOWN); + ep->ep.maxpacket = ep->maxpacket; + ep->has_dma = 0; + + del_timer(&ep->timer); + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xFC; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl &= 0xFC; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xFC; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + if (f_ep3_used == 3) + f_ep3_used = 0; + pDevReg->Bulk3EpControl &= 0xFC; +#else + pDevReg->InterruptEpControl &= 0xFC; +#endif + break; + + case 4:/*Iso In*/ + if (f_ep3_used == 4) + f_ep3_used = 0; + pDevReg->Bulk3EpControl &= 0xFC; + fiq_using = 0; + break; + } + wmb(); + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + VDBG("%s disabled\n", _ep->name); + return 0; +} /*static int wmt_ep_disable()*/ + + +static struct usb_request * +wmt_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct vt8500_req *req; + struct vt8500_ep *ep = NULL; + +// DBG("gri wmt_alloc_request() %s\n", ep->name); + + ep = container_of(_ep, struct vt8500_ep, ep); +// printk(KERN_INFO "gri wmt_alloc_request() %s\n", ep->name); +// if ((ep->bEndpointAddress & 0x7F) > 4) +// return NULL; + + + /*if(ep->bEndpointAddress == 3)*/ + /* INFO("wmt_alloc_request() %s\n", ep->name);*/ + + req = kmalloc(sizeof *req, gfp_flags); + if (req) { + memset(req, 0, sizeof *req); + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD(&req->queue); + } + return &req->req;/*struct usb_request for file_storage.o*/ +} /*wmt_alloc_request()*/ + +static void +wmt_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vt8500_req *req = container_of(_req, struct vt8500_req, req); + struct vt8500_ep *ep = NULL; + + DBG("wmt_free_request() %s\n", ep->name); + ep = container_of(_ep, struct vt8500_ep, ep); + + /*if(ep->bEndpointAddress == 3)*/ + /* INFO("wmt_free_request() %s\n", ep->name);*/ + + if (_req) + kfree(req); +} /*wmt_free_request()*/ + +/*EP0 - Control 256 bytes*/ +/*EP2,3 Bulk In/Out 16384 bytes (16K)*/ +/*file_storeage.c - req->buf*/ +/*struct usb_request req;*/ +static void wmt_pdma_init(struct device *dev); + + +static void ep0_status(struct vt8500_udc *udc) +{ + struct vt8500_ep *ep; + + ep = &udc->ep[0]; + + if (udc->ep0_in) { /*OUT STATUS*/ + if (udc->ep0_status_0_byte == 1) { + udc->ep0_status_0_byte = 0; + + /* the data phase is OUT*/ + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_STATUS; + } /*if(udc->ep0_status_0_byte == 1)*/ + } else { /*IN STATUS*/ + if (udc->ep0_status_0_byte == 1) { + udc->ep0_status_0_byte = 0; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA0; + + pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; /* zero length*/ + pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_STATUS; + } /*if(udc->ep0_status_0_byte == 1)*/ + } + +} /*static void ep0_status(struct vt8500_udc *udc)*/ + + +static void +done(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ + unsigned stopped = ep->stopped; + + DBG("done() %s\n", ep ? ep->ep.name : NULL); + + list_del_init(&req->queue); + + /*#define EINPROGRESS 115*/ /* Operation now in progress */ + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else { + if (status != 0) + status = req->req.status; + } + + DBG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback*/ + ep->stopped = 1; + + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + req->req.complete(&ep->ep, &req->req); + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + if ((ep->bEndpointAddress & 0x7F) == 0)/*Control*/ + { + if (req->req.actual != 0) { + ep->udc->ep0_status_0_byte = 1; + } + } +#if 0 + else + printk("**done() %s\n", ep ? ep->ep.name : NULL); +#endif + + ep->stopped = stopped; + +} /*done(struct vt8500_ep *ep, struct vt8500_req *req, int status)*/ + +static u32 dma_src_len(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*dma_addr_t end;*/ + /*U32 ep_trans_len;*/ + unsigned start = 0 , end = 0; + u32 temp32 = 0; + + start = req->req.length; + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control In*/ + end = (pDevReg->ControlDesTbytes & 0x7F); + temp32 = (ep->ep_fifo_length - end); + return temp32; + } else if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ + end = (pDevReg->Bulk1DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk1DesTbytes1 << 8; + end |= pDevReg->Bulk1DesTbytes0; + } else if ((ep->bEndpointAddress & 0x7F) == 3)/*Interrupt In*/ + { +#ifdef USE_BULK3_TO_INTERRUPT + end = (pDevReg->Bulk3DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk3DesTbytes1 << 8; + end |= pDevReg->Bulk3DesTbytes0; +#else + start = req->dma_bytes; + end = (pDevReg->InterruptDes >> 4); +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4)/*Iso In*/ + { + end = 0; + } + + temp32 = (start - end); + return temp32; +} /*static u32 dma_src_len()*/ + +static u32 dma_dest_len(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*dma_addr_t end;*/ + unsigned start = 0 , end = 0; + u32 temp32 = 0; + + start = req->req.length; + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control Out*/ + end = (pDevReg->ControlDesTbytes & 0x7F); + temp32 = (ep->ep_fifo_length - end); + return temp32; + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + end = (pDevReg->Bulk2DesTbytes2 & 0x03) << 16; + end |= pDevReg->Bulk2DesTbytes1 << 8; + end |= pDevReg->Bulk2DesTbytes0; + } + + temp32 = (start - end); + return temp32; +} /*static u32 dma_dest_len()*/ + +/* Each USB transfer request using DMA maps to one or more DMA transfers. + * When DMA completion isn't request completion, the UDC continues with + * the next DMA transfer for that USB transfer. + */ + +static void wmt_udc_pdma_des_prepare(unsigned int size, unsigned int dma_phy + , unsigned char des_type, unsigned char channel, int is_bulk) +{ + unsigned int res_size = size; + volatile unsigned int trans_dma_phy = dma_phy, des_phy_addr = 0, des_vir_addr = 0; + unsigned int cut_size = 0x40; + + switch (des_type) { + case DESCRIPTOT_TYPE_SHORT: + { + struct _UDC_PDMA_DESC_S *pDMADescS; + + if (channel == TRANS_OUT) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrSO; + des_vir_addr = UdcPdmaVirAddrSO; + pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; + } else if (channel == TRANS_IN) { + if (is_bulk) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrSI; + des_vir_addr = UdcPdmaVirAddrSI; + pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; + } + else { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrS2I; + des_vir_addr = UdcPdmaVirAddrS2I; + pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; + } + } else + DBG("!! wrong channel %d\n", channel); + + while (res_size) { + pDMADescS = (struct _UDC_PDMA_DESC_S *) des_vir_addr; + + pDMADescS->Data_Addr = trans_dma_phy; + pDMADescS->D_Word0_Bits.Format = 0; + +// if (res_size <= 65535) { + if (res_size <= 32767) { + pDMADescS->D_Word0_Bits.i = 1; + pDMADescS->D_Word0_Bits.End = 1; + pDMADescS->D_Word0_Bits.ReqCount = res_size; + + res_size -= res_size; + } else { + pDMADescS->D_Word0_Bits.i = 0; + pDMADescS->D_Word0_Bits.End = 0; + pDMADescS->D_Word0_Bits.ReqCount = 0x8000 - cut_size; + + res_size -= 0x8000; + des_vir_addr += (unsigned int)DES_S_SIZE; + trans_dma_phy += (unsigned int)0x8000; + } + } + break; + } + + case DESCRIPTOT_TYPE_LONG: + { + struct _UDC_PDMA_DESC_L *pDMADescL; + + if (channel == TRANS_OUT) { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrLO; + des_vir_addr = UdcPdmaVirAddrLO; + pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; + +// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", +// pUdcDmaReg->DMA_Descriptor_Point1); //gri + +// printk(KERN_INFO "des_vir_addr=0x%08X", +// des_vir_addr); //gri + + } else if (channel == TRANS_IN) { + if (is_bulk){ + des_phy_addr = (unsigned int) UdcPdmaPhyAddrLI; + des_vir_addr = UdcPdmaVirAddrLI; + pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; + + // printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", + // pUdcDmaReg->DMA_Descriptor_Point0); //gri + +// printk(KERN_INFO "des_vir_addr=0x%08X", +// des_vir_addr); //gri + } + else { + des_phy_addr = (unsigned int) UdcPdmaPhyAddrL2I; + des_vir_addr = UdcPdmaVirAddrL2I; + pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); + cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; + +// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point2=0x%08X", +// pUdcDmaReg->DMA_Descriptor_Point2); //gri + +// printk(KERN_INFO "des_vir_addr 2 =0x%08X", +// des_vir_addr); //gri + } + + } else + DBG("!! wrong channel %d\n", channel); + + memset((void *)des_vir_addr, 0, 0x100); + + while (res_size) { + pDMADescL = (struct _UDC_PDMA_DESC_L *) des_vir_addr; + + pDMADescL->Data_Addr = trans_dma_phy; + pDMADescL->D_Word0_Bits.Format = 1; + +// if (res_size <= 65535) { + if (res_size <= 32767) { + pDMADescL->D_Word0_Bits.i = 1; + pDMADescL->D_Word0_Bits.End = 1; + pDMADescL->Branch_addr = 0; + pDMADescL->D_Word0_Bits.ReqCount = res_size; + + res_size -= res_size; + } else { + pDMADescL->D_Word0_Bits.i = 0; + pDMADescL->D_Word0_Bits.End = 0; + pDMADescL->Branch_addr = des_vir_addr + (unsigned int)DES_L_SIZE; + pDMADescL->D_Word0_Bits.ReqCount = 0x8000 - cut_size; + + res_size -= 0x8000; + des_vir_addr += (unsigned int)DES_L_SIZE; + trans_dma_phy += (unsigned int)0x8000; + } + } + +#if 0 + if (channel == TRANS_IN) { + if (!is_bulk) { + printk(KERN_INFO "pDMADescL(0x%08X)\n", + des_vir_addr); //gri + printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri + printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri + printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri + } + else { + printk(KERN_INFO "pDMADescL(0x%08X)\n", + des_vir_addr); //gri + printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri + printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri + printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri + } + } +#endif + + break; + } + + case DESCRIPTOT_TYPE_MIX: + break; + default: + break; + } + + //wmb(); +} /*wmt_udc_pdma_des_prepare*/ + +void iso_prepare_0byte(void) +{ + unsigned char ubulk3tmp; + + ubulk3tmp = pDevReg->Bulk3EpControl; + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3DesStatus = 0; + pDevReg->Bulk3DesTbytes2 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes0 = 0; + + pDevReg->Bulk3EpControl = ubulk3tmp; + + /* set endpoint data toggle*/ + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + //wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + +} +void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req) +{ + u32 temp32; + u32 dma_ccr = 0; + unsigned int length; + u32 dcmd; + u32 buf; + int is_in, i; + u8 *pctrlbuf; +#ifndef USE_BULK3_TO_INTERRUPT + u8 *pintbuf; +#endif + +// printk(KERN_INFO "next_in_dma s\n"); //gri + + dcmd = length = req->req.length - req->req.actual;/*wmt_ep_queue() : req->req.actual = 0*/ + buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); + + is_in = 1;/*ep->bEndpointAddress & USB_DIR_IN;*/ + + DBG("next_in_dma() %s\n", ep ? ep->ep.name : NULL); + +#ifdef RNDIS_INFO_DEBUG_BULK_IN + if ((ep->bEndpointAddress & 0x7F) == 1) + INFO("next_in_dma() %s\n", ep ? ep->ep.name : NULL); +#endif + + if (((ep->bEndpointAddress & 0x7F) == 1) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +printk(KERN_INFO "rndis xxxxx %d\n",req->req.length); + + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp1VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp1PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (((ep->bEndpointAddress & 0x7F) == 3) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } +#endif + + if (((ep->bEndpointAddress & 0x7F) == 4) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + + } + + if (((ep->bEndpointAddress & 0x7F) == 1) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { + //void *retval; + //dma_addr_t dma; + +printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (((ep->bEndpointAddress & 0x7F) == 3) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { + //void *retval; + //dma_addr_t dma; + +//printk(KERN_INFO "rndis 3 ooooobb %d\n",req->req.length); + } +#endif + + if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control*/ + ep->ep_fifo_length = 0; + + if (length >= 64) + length = 64; + + ep->ep_fifo_length = length; + pctrlbuf = (u8 *)(req->req.buf + req->req.actual); + + for (i = 0; i < length; i++) + SetupBuf[i] = pctrlbuf[i]; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = length | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = length | CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_DATA; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } else if (((ep->bEndpointAddress & 0x7F) == 1)) {/*Bulk In*/ + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk1EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + if (ep->toggle_bit) + pDevReg->Bulk1DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ + else + pDevReg->Bulk1DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk1DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk1EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control0 = dma_ccr; + + wmb(); + pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; + } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk3EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + if (ep->toggle_bit) + pDevReg->Bulk3DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ + else + pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + //dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + dma_ccr |= DMA_RUN; + + wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; +#else + +//printk(KERN_INFO "udc interrupt\n"); + + if (dcmd > INT_FIFO_SIZE) + dcmd = INT_FIFO_SIZE; + interrupt_transfer_size = dcmd; + + pintbuf = (u8 *)(req->req.buf);/* + req->req.actual);*/ + + for (i = req->req.actual; i < (req->req.actual + dcmd); i++) + IntBuf[(i-req->req.actual)] = pintbuf[i]; + + pDevReg->InterruptDes = 0x00; + pDevReg->InterruptDes = (dcmd << 4); + + if (ep->toggle_bit) + pDevReg->InterruptDes |= INTXFER_DATA1; + else + pDevReg->InterruptDes &= 0xF7; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + pDevReg->InterruptDes |= INTXFER_IOC; + wmb(); + pDevReg->InterruptDes |= INTXFER_ACTIVE; +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ + + unsigned char tmp; + + tmp = pDevReg->Bulk3EpControl; + + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3EpControl = tmp; + + wmt_pdma2_reset(); + + ep->stall_more_processing = 0; + + //printk(KERN_INFO "next_in_dma 4 %d %d %d\n", length, req->req.length,req->req.actual); //gri + //printk(KERN_INFO "next_in_dma 4\n"); //gri + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk3EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + + if (ep->rndis == 1) { + memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + } else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (is_in) { + pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ + + pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); + } /*if(is_in)*/ + + if (pDevReg->Bulk3EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + + /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ + ep->toggle_bit = 0; + + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + //dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + +// wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + + dma_ccr |= DMA_RUN; + +// wmb(); + if (dcmd) /* PDMA can not support 0 byte transfer*/ + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; + +// wmb(); + + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + fiq_using = 1; + + wmt_enable_fiq(300); + //run_script(action_chkiso); + } + + DBG("req->req.dma 0x%08X \n", req->req.dma); + +#ifdef MSC_COMPLIANCE_TEST + INFO("req->req.dma 0x%08X \n", req->req.dma); +#endif + + req->dma_bytes = dcmd;//length; + +#if 0 + if (((ep->bEndpointAddress & 0x7F) == 3) || ((ep->bEndpointAddress & 0x7F) == 4)) { + printk(KERN_INFO "next_in_dma 3 e\n"); //gri + printk(KERN_INFO "Bulk3EpInEpNum =0x%2.2x\n", pDevReg->Bulk3EpInEpNum); //gri + printk(KERN_INFO "Bulk3EpMaxLen =0x%2.2x\n", pDevReg->Bulk3EpMaxLen); //gri + printk(KERN_INFO "Bulk3EpOutEpNum =0x%2.2x\n", pDevReg->Bulk3EpOutEpNum); //gri + printk(KERN_INFO "Bulk3EpControl =0x%2.2x\n", pDevReg->Bulk3EpControl); //gri + + printk(KERN_INFO "Bulk3DesTbytes2 =0x%2.2x\n", pDevReg->Bulk3DesTbytes2); //gri + printk(KERN_INFO "Bulk3DesTbytes1 =0x%2.2x\n", pDevReg->Bulk3DesTbytes1); //gri + printk(KERN_INFO "Bulk3DesTbytes0 =0x%2.2x\n", pDevReg->Bulk3DesTbytes0); //gri + printk(KERN_INFO "Bulk3DesStatus =0x%2.2x\n", pDevReg->Bulk3DesStatus); //gri + + printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point2); //gri + printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes2); //gri + printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr2); //gri + printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr2); //gri + printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr2); //gri + printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control2); //gri + + } + else if ((ep->bEndpointAddress & 0x7F) == 1) { + printk(KERN_INFO "next_in_dma 1 e\n"); //gri + printk(KERN_INFO "Bulk1EpInEpNum =0x%2.2x\n", pDevReg->Bulk1EpInEpNum); //gri + printk(KERN_INFO "Bulk1EpMaxLen =0x%2.2x\n", pDevReg->Bulk1EpMaxLen); //gri + printk(KERN_INFO "Bulk1EpOutEpNum =0x%2.2x\n", pDevReg->Bulk1EpOutEpNum); //gri + printk(KERN_INFO "Bulk1EpControl =0x%2.2x\n", pDevReg->Bulk1EpControl); //gri + + printk(KERN_INFO "Bulk1DesTbytes2 =0x%2.2x\n", pDevReg->Bulk1DesTbytes2); //gri + printk(KERN_INFO "Bulk1DesTbytes1 =0x%2.2x\n", pDevReg->Bulk1DesTbytes1); //gri + printk(KERN_INFO "Bulk1DesTbytes0 =0x%2.2x\n", pDevReg->Bulk1DesTbytes0); //gri + printk(KERN_INFO "Bulk1DesStatus =0x%2.2x\n", pDevReg->Bulk1DesStatus); //gri + + printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point0); //gri + printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes0); //gri + printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr0); //gri + printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr0); //gri + printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr0); //gri + printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control0); //gri + } +#endif + +} /*static void next_in_dma()*/ + +static void finish_in_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ +// printk(KERN_INFO "finish_in_dma()s\n"); //gri + + DBG("finish_in_dma() %s\n", ep ? ep->ep.name : NULL); + + if (status == 0) { /* Normal complete!*/ +#ifdef USE_BULK3_TO_INTERRUPT + req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ +#else +// if ((ep->bEndpointAddress & 0x7F) == 3) +// req->req.actual += interrupt_transfer_size; +// else + if ((ep->bEndpointAddress & 0x7F) != 3) + req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ +#endif + + /* return if this request needs to send data or zlp*/ + if (req->req.actual < req->req.length) + return; + + if (req->req.zero + && req->dma_bytes != 0 + && (req->req.actual % ep->maxpacket) == 0) + return; + + } else + req->req.actual += dma_src_len(ep, req); + +#ifdef RNDIS_INFO_DEBUG_BULK_IN + if ((ep->bEndpointAddress & 0x7F) == 1) + INFO("finish_in_dma()e %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", + ep ? ep->ep.name : NULL, req->req.actual, req->req.length); +#endif + + done(ep, req, status); + +//printk(KERN_INFO "finish_in_dma() %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", +//ep ? ep->ep.name : NULL, req->req.actual, req->req.length); //gri + + +} /*static void finish_in_dma()*/ + +static void next_out_dma(struct vt8500_ep *ep, struct vt8500_req *req) +{ + /*unsigned packets;*/ + u32 dma_ccr = 0; + u32 dcmd; + u32 buf; + int is_in; + +// printk(KERN_INFO "next_out_dma s\n"); //gri + + is_in = 0;/*ep->bEndpointAddress & USB_DIR_IN;*/ + +#ifdef RNDIS_INFO_DEBUG_BULK_OUT + if (ep->bEndpointAddress == 2) + INFO("next_out_dma() %s\n", ep ? ep->ep.name : NULL); +#endif + + DBG("next_out_dma() %s\n", ep ? ep->ep.name : NULL); + + dcmd = req->dma_bytes = req->req.length - req->req.actual; + buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); + + if ((ep->bEndpointAddress == 2) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { + unsigned int dma_length = 65536; + +printk(KERN_INFO "rndis ooooo %d\n",req->req.length); + if (ep->rndis_buffer_alloc == 0) { + + ep->rndis_buffer_address = (unsigned int)UdcRndisEp2VirAddr; + ep->rndis_dma_phy_address = (u32)UdcRndisEp2PhyAddr; + ep->rndis_buffer_length = dma_length; + ep->rndis_buffer_alloc = 1; + } + ep->rndis = 1; + } + if ((ep->bEndpointAddress == 2) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { +// void *retval; +// dma_addr_t dma; + +printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); +#if 0 + dma_free_coherent (ep->udc->dev, + ep->rndis_buffer_length, + (void *)ep->rndis_buffer_address, (dma_addr_t)ep->rndis_dma_phy_address); + + retval = dma_alloc_coherent(ep->udc->dev, + req->req.length, &dma, GFP_ATOMIC); + + ep->rndis_buffer_address = (unsigned int)retval; + ep->rndis_dma_phy_address = (u32)dma; + ep->rndis_buffer_length = req->req.length; + ep->rndis = 1; +#endif + } + + if (ep->bEndpointAddress == 0) {/*Control*/ + ep->ep_fifo_length = 0; + + if (dcmd >= 64) + dcmd = 64; + + ep->ep_fifo_length = dcmd; + + if (ep->toggle_bit) + pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA1; + else + pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA0; + + pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; + wmb(); + pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; + ControlState = CONTROLSTATE_DATA; + + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + ep->stall_more_processing = 0; + +// printk(KERN_INFO "next_out_dma %d %d %d\n", req->dma_bytes, req->req.length,req->req.actual); //gri + + /*if(req->dma_bytes == 64)*/ + ep->udc->cbw_virtual_address = (((u32)req->req.buf + req->req.actual) & 0xFFFFFFFC); + + if (dcmd > UBE_MAX_DMA) + dcmd = UBE_MAX_DMA; + + if (pDevReg->Bulk2EpControl & EP_STALL) { + ep->stall_more_processing = 1; + ep->temp_dcmd = dcmd; + } + /* Set Address*/ + if (ep->rndis == 1) + wmt_udc_pdma_des_prepare(dcmd, + ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), + DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + else + wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->temp_bulk_dma_addr = buf; + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->temp_dma_ccr = dma_ccr; + + /* DMA Global Controller Reg*/ + /* DMA Controller Enable +*/ + /* DMA Global Interrupt Enable(if any TC, error, or abort status in any channels occurs)*/ + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= (dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = (dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->toggle_bit) + pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; + else + pDevReg->Bulk2DesTbytes2 &= 0x3F;/*BULKXFER_DATA0;*/ + + pDevReg->Bulk2DesStatus = BULKXFER_IOC;/*| BULKXFER_IN;*/ + + if (pDevReg->Bulk2EpControl & EP_STALL) + ep->ep_stall_toggle_bit = ep->toggle_bit; + + dma_ccr = 0; + dma_ccr = DMA_RUN; + if (!is_in) + dma_ccr |= DMA_TRANS_OUT_DIR; + + wmb(); + pUdcDmaReg->DMA_Context_Control1 = dma_ccr; + wmb(); + pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; + /*udc_device_dump_register();*/ + } + + VDBG("req->req.dma 0x%08X \n", req->req.dma); + +//printk(KERN_INFO "next_out_dma e\n"); //gri + +} /*static void next_out_dma()*/ + +static void +finish_out_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) +{ + u16 count; + u8 temp8; + u32 temp32; + /*u8 bulk_dma_csr;*/ + +// printk(KERN_INFO "finish_out_dma s\n"); //gri + + DBG("finish_out_dma() %s\n", ep ? ep->ep.name : NULL); + + count = dma_dest_len(ep, req); + + if (ep->bEndpointAddress == 0) {/*Control*/ + u8 *pctrlbuf; + int i; + + pctrlbuf = (u8 *)(req->req.buf + req->req.actual); + for (i = 0; i < count; i++) + pctrlbuf[i] = SetupBuf[i]; + + /*INFO("finish_out_dma() %s\n", ep ? ep->ep.name : NULL);*/ + /*dump_bulk_buffer((req->req.buf + req->req.actual), count);*/ + } + + count += req->req.actual; + + if (count <= req->req.length) + req->req.actual = count; + + if (ep->bEndpointAddress == 0) {/*Control*/ + if (req->req.actual < req->req.length) { + temp8 = pDevReg->ControlDesStatus; + + if ((temp8 & CTRLXFER_SHORTPKT) == 0) + return; /*Continue...*/ + } + } else if (ep->bEndpointAddress == 2) { + + if (pDevReg->Bulk2DesTbytes2 & 0x80) + ep->toggle_bit= 1; + else + ep->toggle_bit= 0; + +// while((pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0xf) && +// (pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0x5)); + +// printk(KERN_INFO "finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", +// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);//gri + // INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", + // ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); + + + { + { + unsigned int gri_t_d; + unsigned int gri_count=0; + unsigned int dma_count; + do{ + gri_t_d=pUdcDmaReg->DMA_ISR ; + gri_t_d &= 0x2; + gri_count++; + if (gri_count & 0x10){ + gri_count=0; +// printk(KERN_INFO "pUdcDmaReg->DMA_Context_Control1 0x%08x\n", &(pUdcDmaReg->DMA_Context_Control1)); + printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); + dma_count = req->req.length - pUdcDmaReg->DMA_Residual_Bytes1_Bits.ResidualBytes; +// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); + if (pUdcDmaReg->DMA_Context_Control1_Bis.Run == 0) + break; + if ((count == dma_count) || (count == 0)){ +// printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); +// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); +// while(1); + pUdcDmaReg->DMA_Context_Control1_Bis.Run = 0; + break; + } + } + }while(!gri_t_d); + } + } + + + if (req->req.actual < req->req.length) { + DBG("finish_out_dma() req->actual < req->req.length\n"); + temp8 = pDevReg->Bulk2DesStatus; + + if ((temp8 & BULKXFER_SHORTPKT) == 0) + return; /*Continue...*/ + else { /*Short Package.*/ + pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; + wmb(); + + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) + ; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + wmb(); + } + } + } + /* rx completion*/ + /*UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);*/ + +//#ifdef RNDIS_INFO_DEBUG_BULK_OUT +// if (ep->bEndpointAddress == 2) +// INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", +// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); +//#endif + + /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ + + if ((ep->bEndpointAddress == 2) && (ep->rndis == 1)) { + memcpy((void *)((u32)req->req.buf), (void *)((u32)ep->rndis_buffer_address), req->req.actual); + + #ifdef RNDIS_INFO_DEBUG_BULK_OUT + /*if ((req->req.actual % 4 == 3))// && (b_message == 0))*/ + /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ + #endif +#if 0 + if ((req->req.length == 1600) || (req->req.length == 2048)) {/*F.S. [1600] : H.S. [2048]*/ + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else + INFO("Different Length for Bulk Out (%08d) Toggle Bit would Error\n" + , req->req.length); +#else +#if 0 + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } +#endif + +#endif + } else { +#if 1 + if (ep->bEndpointAddress == 0){ + /*GigaHsu-B 2008.5.15 : Add this caculate toggle from next_out_dma() : + fixed sideshow gadget issue.*/ + if (req->req.length > ep->maxpacket) { + /*ex : 512 /64 = 8 8 % 2 = 0*/ + temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; + ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); + } else { + if (ep->toggle_bit == 0) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + } + } +#endif + + /*GigaHsu-E 2008.5.15*/ + } + + done(ep, req, status); + +//printk(KERN_INFO "finish_out_dma e\n"); //gri + +} /*finish_out_dma()*/ + +void dma_irq(u8 addr) +{ + struct vt8500_ep *ep; + struct vt8500_req *req; + /*u32 temp32;*/ + /*u32 i;*/ + + ep = &udc->ep[addr & 0x7f]; + + if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ + + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->Bulk1EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_in_dma(ep, req); + } + } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ + + /* OUT dma: rx from host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_out_dma(ep, req, 0); + } + + while (pDevReg->Bulk2EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_out_dma(ep, req); + } + } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ + +#ifdef USE_BULK3_TO_INTERRUPT + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->Bulk3EpControl & EP_COMPLETEINT) + ; + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_in_dma(ep, req); + } +#else + /* IN dma: tx to host*/ + while (pDevReg->InterruptEpControl & EP_COMPLETEINT) + ; + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + req->req.actual += dma_src_len(ep, req); + if (req->req.actual < req->req.length) + next_in_dma(ep, req); + else + finish_in_dma(ep, req, 0); + } + +// if (!list_empty(&ep->queue)) { +// req = container_of(ep->queue.next, struct vt8500_req, queue); +// next_in_dma(ep, req); +// } +#endif + } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ + + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_in_dma(ep, req, 0); + } + } + +} /*static void dma_irq()*/ + + +static void pullup_enable(struct vt8500_udc *udc) +{ + INFO("gri pullup_enable()\n"); + b_pullup = 1; + /*Enable port control's FSM to enable 1.5k pull-up on D+.*/ + //pDevReg->PhyMisc &= 0x0F;/*Hardware auto-mode*/ + pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + wmb(); + /*pDevReg->PhyMisc |= 0x50;*/ + +} /*static void pullup_enable()*/ + + + +/*-------------------------------------------------------------------------*/ +/*file_storage.c ep0_queue() - control*/ +/*file_storage.c start_transfer() - bulk*/ +static int +wmt_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_req *req = container_of(_req, struct vt8500_req, req); + /*struct vt8500_udc *udc;*/ +// unsigned long flags; + unsigned char empty_data = 0; + + DBG("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); +// INFO("gri wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); + +// if ((ep->bEndpointAddress & 0x7F) > 4) +// return -EINVAL; + +#ifdef RNDIS_INFO_DEBUG_BULK_OUT + if ((ep->bEndpointAddress == 3))/* || ((ep->bEndpointAddress & 0x7F) == 2))*/ + INFO("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); +#endif + + /* catch various bogus parameters*/ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { + DBG("[wmt_ep_queue], bad params\n"); + return -EINVAL; + } + if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + DBG("[wmt_ep_queue], bad ep\n"); + return -EINVAL; + } + +//#ifdef RNDIS_INFO_DEBUG_BULK_OUT +// if ((ep->bEndpointAddress == 2))/* || ((ep->bEndpointAddress & 0x7F) == 1))*/ +// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", +// ep->ep.name, _req, _req->length, _req->buf); +//#endif + +//#ifdef MSC_COMPLIANCE_TEST +// if ((ep->bEndpointAddress & 0x7F) == 1) +// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", +// ep->ep.name, _req, _req->length, _req->buf); +//#endif + + DBG("wmt_ep_queue() %s queue req %p, len %d buf %p\n", + ep->ep.name, _req, _req->length, _req->buf); + + spin_lock_irqsave(&udc->lock, irq_flags); + + req->req.status = -EINPROGRESS; + req->req.actual = 0; + + /* maybe kickstart non-iso i/o queues*/ + + if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { + int is_in; + + if (ep->bEndpointAddress == 0) { + if (!udc->ep0_pending || !list_empty(&ep->queue)) { + spin_unlock_irqrestore(&udc->lock, irq_flags); + return -EL2HLT; + } + + /* empty DATA stage?*/ + is_in = udc->ep0_in; + + if (!req->req.length) { /*status 0 bytes*/ + + udc->ep0_status_0_byte = 1; + ep0_status(udc); + + /* cleanup*/ + udc->ep0_pending = 0; + done(ep, req, 0); + empty_data = 1; + } + + if (req->req.length) { + udc->bulk_out_dma_write_error = 0; + (is_in ? next_in_dma : next_out_dma)(ep, req); + } + } else { + is_in = ep->bEndpointAddress & USB_DIR_IN; + + if (req != 0){ + list_add_tail(&req->queue, &ep->queue); + empty_data = 1; + } +// else +// { +// printk(KERN_INFO "xxx %x %x\n",req,empty_data); //gri +// } + /*if (!ep->has_dma)*/ + /* use_ep(ep, UDC_EP_SEL);*/ + /* if ISO: SOF IRQs must be enabled/disabled!*/ + if (((ep->bEndpointAddress & 0x7F) != 4) || (!fiq_using)) + (is_in ? next_in_dma : next_out_dma)(ep, req); +#if 0 + else + printk("gri w_e_q() 01 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); +#endif + } + } + /* irq handler advances the queue*/ +#if 0 + if ((ep->bEndpointAddress & 0x7F) == 4) + printk("gri w_e_q() 02 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); +#endif + + if ((req != 0) && (empty_data == 0)) + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&udc->lock, irq_flags); + + return 0; +} /*wmt_ep_queue()*/ + +void ep1_cancel_tx(struct vt8500_ep *ep) +{ + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk1EpControl & 0xE3; + pDevReg->Bulk1DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk1DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk1DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk1DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk1DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk1EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk1EpControl = bctrl0; + + wmt_pdma0_reset(); + wmb(); +} + +void ep2_cancel_tx(struct vt8500_ep *ep) +{ + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk2EpControl & 0xE3; + pDevReg->Bulk2DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk2DesTbytes2 & 0x80; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk2DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk2DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk2DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk2EpControl = bctrl0; + + wmt_pdma1_reset(); + wmb(); +} + +void ep3_cancel_tx(struct vt8500_ep *ep) +{ +#ifdef USE_BULK3_TO_INTERRUPT + unsigned char btmp; + unsigned char bctrl0; + + bctrl0 = pDevReg->Bulk3EpControl & 0xE3; + pDevReg->Bulk3DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk3DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk3EpControl = bctrl0; + + wmt_pdma2_reset(); + wmb(); +#else + unsigned char tmp0, tmp1, tmp2, tmp3; + + pDevReg->InterruptDes = 0x00; + wmb(); + tmp0 = InterruptEpControl; + tmp1 = InterruptReserved; + tmp2 = InterruptEpMaxLen; + tmp3 = InterruptEpEpNum; + InterruptEpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->InterruptEpControl & EP_DMALIGHTRESET); + InterruptEpControl = tmp0; + InterruptReserved = tmp1; + InterruptEpMaxLen = tmp2; + InterruptEpEpNum = tmp3; + wmb(); +#endif +} + +void ep4_cancel_tx(struct vt8500_ep *ep) +{ + + unsigned char btmp; + unsigned char bctrl0; + + fiq_using = 0; + + bctrl0 = pDevReg->Bulk3EpControl & 0xE3; + pDevReg->Bulk3DesStatus &= 0xF0; + + ep->stall_more_processing = 0; + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + btmp = pDevReg->Bulk3DesTbytes2 & 0x40; + + if (btmp) + ep->toggle_bit = 1; + else + ep->toggle_bit = 0; + + if (ep->toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + wmb(); + pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; + wmb(); + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); + pDevReg->Bulk3EpControl = bctrl0; + + wmt_pdma2_reset(); + wmb(); +} + +static int wmt_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); + struct vt8500_req *req; + int is_in; +// unsigned long flags; + + if (!_ep || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + DBG("wmt_ep_dequeue() %s\n", ep ? ep->ep.name : NULL); + /* make sure it's actually queued on this endpoint*/ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + return -EINVAL; + } + + + if (((ep->bEndpointAddress & 0x7F) != 0) && ep->queue.next == &req->queue) { + + if (ep->bEndpointAddress == 1){ + ep1_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 2){ + ep2_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 3){ + ep3_cancel_tx(ep); + } + else if (ep->bEndpointAddress == 4){ + ep4_cancel_tx(ep); + } + } + + done(ep, req, -ECONNRESET); + + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + is_in = ep->bEndpointAddress & USB_DIR_IN; + (is_in ? next_in_dma : next_out_dma)(ep, req); + } + + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + return 0; +} /*static int wmt_ep_dequeue()*/ + +/*-------------------------------------------------------------------------*/ + +static int wmt_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); +// unsigned long flags; + int status = -EOPNOTSUPP; + + spin_lock_irqsave(&ep->udc->lock, irq_flags); + + ep->toggle_bit = 0; /*patch CLEAR_FEATURE ENDPOINT_HALT*/ + DBG("wmt_ep_set_halt() %s\n", ep ? ep->ep.name : NULL); + + if (value) { + u8 temp32bytes[31]; + + memset(temp32bytes, 0, 31); + temp32bytes[0] = 0xEF; + temp32bytes[1] = 0xBE; + temp32bytes[2] = 0xAD; + temp32bytes[3] = 0xDE; + + /*usb_ep_set_halt() - value == 1 stall*/ + + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl |= EP_STALL; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl |= EP_STALL; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl |= EP_STALL; + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl |= EP_STALL; +#else + pDevReg->InterruptEpControl |= EP_STALL; +#endif + break; + + case 4:/*Iso In*/ + pDevReg->Bulk3EpControl |= EP_STALL; + break; + } + + ep->stall = 1; + /*DBG("wmt_ep_set_halt(1) HALT CSR(0x%08X)\n", *ep->reg_control_status);*/ + status = 0; + + if (memcmp(temp32bytes, (void *)ep->udc->cbw_virtual_address, 4) == 0) + udc->file_storage_set_halt = 1; /*forbid to CLEAR FEATURE*/ + } else {/*usb_ep_clear_halt - value == 0 reset*/ + + /**ep->reg_control_status &= 0xFFFFFFFB;*/ + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xF7; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl &= 0xF7; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xF7; + break; + + case 3:/*Interrupt In*/ + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl &= 0xF7; +#else + pDevReg->InterruptEpControl &= 0xF7; +#endif + break; + + case 4:/*Iso In*/ + pDevReg->Bulk3EpControl &= 0xF7; + break; + } + + ep->stall = 0; + status = 0; + udc->file_storage_set_halt = 0; + } + + VDBG("%s %s halt stat %d\n", ep->ep.name, + value ? "set" : "clear", status); + wmb(); + spin_unlock_irqrestore(&ep->udc->lock, irq_flags); + + return status; +} /*static int wmt_ep_set_halt()*/ + +static struct usb_ep_ops wmt_ep_ops = { + .enable = wmt_ep_enable, + .disable = wmt_ep_disable, + + .alloc_request = wmt_alloc_request, + .free_request = wmt_free_request, + +// .alloc_buffer = wmt_alloc_buffer, +// .free_buffer = wmt_free_buffer, + + .queue = wmt_ep_queue, + .dequeue = wmt_ep_dequeue, + + .set_halt = wmt_ep_set_halt, + + /* fifo_status ... report bytes in fifo*/ + /* fifo_flush ... flush fifo*/ +}; + +#if 0 +static void +wmt_udc_csr(struct vt8500_udc *udc) +{ + /* abolish any previous hardware state*/ + + DBG("wmt_udc_csr()\n"); + + if (udc->gadget.speed == USB_SPEED_FULL) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); + } else if (udc->gadget.speed == USB_SPEED_HIGH) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); + } else if (udc->gadget.speed == USB_SPEED_UNKNOWN) { + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); + } + //wmt_ep_setup_csr("ep3in""-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif +} /*wmt_udc_csr(void)*/ +#endif + +static int wmt_get_frame(struct usb_gadget *gadget) +{ + DBG("wmt_get_frame()\n"); + return 0; +} + +static int wmt_wakeup(struct usb_gadget *gadget) +{ + /*struct vt8500_udc *udc;*/ + /*unsigned long flags;*/ + int retval = 0; + DBG("wmt_wakeup()\n"); +/* + udc = container_of(gadget, struct vt8500_udc, gadget); + + spin_lock_irqsave(&udc->lock, irq_flags); + if (udc->devstat & UDC_SUS) { + // NOTE: OTG spec erratum says that OTG devices may + // issue wakeups without host enable. + // + if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { + DBG("remote wakeup...\n"); + UDC_SYSCON2_REG = UDC_RMT_WKP; + retval = 0; + } + + // NOTE: non-OTG systems may use SRP TOO... + } else if (!(udc->devstat & UDC_ATT)) { + if (udc->transceiver) + retval = otg_start_srp(udc->transceiver->otg); + } + spin_unlock_irqrestore(&udc->lock, irq_flags); +*/ + return retval; +} + +static int +wmt_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + DBG("wmt_set_selfpowered()\n"); +/* struct vt8500_udc *udc; + unsigned long flags; + u16 syscon1; + + udc = container_of(gadget, struct vt8500_udc, gadget); + spin_lock_irqsave(&udc->lock, irq_flags); + syscon1 = UDC_SYSCON1_REG; + if (is_selfpowered) + syscon1 |= UDC_SELF_PWR; + else + syscon1 &= ~UDC_SELF_PWR; + UDC_SYSCON1_REG = syscon1; + spin_unlock_irqrestore(&udc->lock, irq_flags); +*/ + return 0; +} + + +void reset_ep(void) +{ +#if 1 + wmt_disable_fiq(); + fiq_using = 0; + + pDevReg->Bulk1EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk2EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) + ; + + pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; + while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) + ; +#else + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; +#endif + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; + + /* enable DMA and run the control endpoint*/ + wmb(); + + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; +#if 0 + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif +#endif + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + wmb(); + pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + wmb(); + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + /*status = wmt_udc_setup(odev, xceiv);*/ + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); +#if 1 + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); +#if 0 +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif +#endif +#endif +} + +void reset_udc(void) +{ +/* if (!((*(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254))&0x00000080))*/ +/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) |= 0x00000080;*/ /*DPM needed*/ + +pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + wmb(); + + if ((*(volatile unsigned char *)(USB_IP_BASE + 0x249))&0x04) { + *(volatile unsigned char*)(USB_IP_BASE + 0x249)&= ~0x04; + mdelay(1); + } + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ + /* reset Bulk descriptor control*/ + wmb(); + + f_ep3_used = 0; + reset_ep(); + + pDevReg->SelfPowerConnect |= 0x10;//Neil + wmb(); + /* enable all interrupt*/ +#ifdef FULL_SPEED_ONLY + pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ +#else + pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ +#endif + wmb(); + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl = CTRLXFER_IOC; +/*Neil_080731*/ +/* pullup_disable here and enable in /arch/arm/kernel/apm.c:395 + apm_ioctl() to patch issue signal fail when resume when recive*/ +/* set_configuration time out.*/ +/* pullup_enable(udc);//usb_gadget_probe_driver()*/ + wmb(); + wmt_pdma_reset(); + +// pullup_enable(udc); +// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ +/* pullup_disable(udc);*/ +/*Neil_080731*/ + +} + + +/* +static int can_pullup(struct vt8500_udc *udc) +{ + return udc->driver && udc->softconnect && udc->vbus_active; +} +*/ +static void pullup_disable(struct vt8500_udc *udc) +{ + INFO("pullup_disable()\n"); + /*Hold port control's FSM from enter device mode.*/ + //pDevReg->PhyMisc &= 0x0F; + //pDevReg->PhyMisc |= 0x10; + pDevReg->FunctionPatchEn &= (~0x20); /* HW attach process evaluation enable bit*/ + wmb(); + gadget_connect=0; + + f_ep3_used = 0; + reset_ep(); + wmt_pdma_reset(); + + +} /*static void pullup_disable()*/ + +/* + * Called by whatever detects VBUS sessions: external transceiver + * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. + */ +static int wmt_vbus_session(struct usb_gadget *gadget, int is_active) +{ + DBG("wmt_vbus_session()\n"); + return 0; +} + +static int wmt_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + DBG("wmt_vbus_draw()\n"); + return -EOPNOTSUPP; +} + +static int wmt_pullup(struct usb_gadget *gadget, int is_on) +{ + struct vt8500_udc *udc; +// unsigned long flags; + + DBG("wmt_pullup()\n"); + + udc = container_of(gadget, struct vt8500_udc, gadget); + down(&wmt_udc_sem); + spin_lock_irqsave(&udc->lock, irq_flags); + udc->softconnect = (is_on != 0); +// if (can_pullup(udc)) + + if (udc->softconnect) + pullup_enable(udc); + else { + pullup_disable(udc); + //run_script(action_off_line); + } + spin_unlock_irqrestore(&udc->lock, irq_flags); + up(&wmt_udc_sem); + + return 0; +} + +void get_udc_sem (void) +{ + down(&wmt_udc_sem); +} + +void release_udc_sem (void) +{ + up(&wmt_udc_sem); +} + +static int wmt_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int wmt_udc_stop(struct usb_gadget_driver *driver); + +static struct usb_gadget_ops wmt_gadget_ops = { + .get_frame = wmt_get_frame, + .wakeup = wmt_wakeup, + .set_selfpowered = wmt_set_selfpowered, + .vbus_session = wmt_vbus_session, + .vbus_draw = wmt_vbus_draw, + .pullup = wmt_pullup, + .start = wmt_udc_start, + .stop = wmt_udc_stop, +}; + +/* dequeue ALL requests; caller holds udc->lock */ +static void nuke(struct vt8500_ep *ep, int status) +{ + struct vt8500_req *req; + + DBG("nuke()\n"); + ep->stopped = 1; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct vt8500_req, queue); + done(ep, req, status); + } +} /*void nuke()*/ + +/* caller holds udc->lock */ +static void udc_quiesce(struct vt8500_udc *udc) +{ + struct vt8500_ep *ep; + DBG("udc_quiesce()\n"); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->ep[0], -ESHUTDOWN); + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) + nuke(ep, -ESHUTDOWN); +} /*void udc_quiesce()*/ + +/* +static void update_otg(struct vt8500_udc *udc) +{ + u16 devstat; + + if (!udc->gadget.is_otg) + return; + + if (OTG_CTRL_REG & OTG_ID) + devstat = UDC_DEVSTAT_REG; + else + devstat = 0; + + udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); + udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); + udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); + + // Enable HNP early, avoiding races on suspend irq path. + // ASSUMES OTG state machine B_BUS_REQ input is true. + // + if (udc->gadget.b_hnp_enable) + OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ) + & ~OTG_PULLUP; + +}//static void update_otg() +*/ + + +/* define the prepare result codes*/ +#define RESPOK 0 +#define RESPFAIL 1 +u16 Control_Length; /* the length of transfer for current control transfer*/ +u16 Configure_Length; + + +/*UDC_IS_SETUP_INT*/ +static void udc_control_prepare_data_resp(void)/*(struct vt8500_udc *udc, u32 udc_irq_src)*/ +{ + struct vt8500_ep *ep0 = &udc->ep[0]; + struct vt8500_req *req = 0; + /*UCHAR Result = RESPFAIL;*/ + /*unsigned char CurXferLength = 0;*/ + /*unsigned char Control_Length = 0;*/ + int i; + u8 test_mode_enable = 0; + + Configure_Length = 0; + + /*ep0->irqs++;*/ + DBG("ep0_irq()\n"); + ep0->toggle_bit = 1; + + if (!list_empty(&ep0->queue)) + req = container_of(ep0->queue.next, struct vt8500_req, queue); + + /* SETUP starts all control transfers*/ + { + union u { + u8 bytes[8]; + struct usb_ctrlrequest r; + } u; + int status = -EINVAL; + struct vt8500_ep *ep = &udc->ep[0]; + int ep0_status_phase_0_byte = 0; + + nuke(ep0, 0); + /* read the (latest) SETUP message*/ + for (i = 0; i <= 7; i++) + u.bytes[i] = pSetupCommandBuf[i]; + + le32_to_cpus(&u.r.wValue); + le32_to_cpus(&u.r.wIndex); + le32_to_cpus(&u.r.wLength); + + /* Delegate almost all control requests to the gadget driver,*/ + /* except for a handful of ch9 status/feature requests that*/ + /* hardware doesn't autodecode _and_ the gadget API hides.*/ + /**/ + udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; + udc->ep0_set_config = 0; + udc->ep0_pending = 1; + udc->ep0_in_status = 0; + + ep0->stopped = 0; + ep0->ackwait = 0; + + if ((u.r.bRequestType & USB_RECIP_OTHER) == USB_RECIP_OTHER) {/*USB_RECIP_OTHER(0x03)*/ + status = 0; + + /*INFO("ep0_irq() setup command[0]=(0x%08X)\n",u.dword[0]);*/ + /*INFO("ep0_irq() setup command[1]=(0x%08X)\n",u.dword[1]);*/ + /*INFO("ep0_irq() address(%08X)", udc_reg->AddressControl);*/ + goto delegate; + } + + switch (u.r.bRequest) { + case USB_REQ_SET_CONFIGURATION: + /* udc needs to know when ep != 0 is valid*/ + /*SETUP 00.09 v0001 i0000 l0000*/ + if (u.r.bRequestType != USB_RECIP_DEVICE)/*USB_RECIP_DEVICE(0x00)*/ + goto delegate; + if (u.r.wLength != 0) + goto do_stall; + udc->ep0_set_config = 1; + udc->ep0_reset_config = (u.r.wValue == 0); + VDBG("set config %d\n", u.r.wValue); + + if (u.r.wValue == 0) + USBState = USBSTATE_ADDRESS; + else + USBState = USBSTATE_CONFIGED; + /* update udc NOW since gadget driver may start*/ + /* queueing requests immediately; clear config*/ + /* later if it fails the request.*/ + /**/ + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + + status = 0; + goto delegate; + + /* Giga Hsu : 2007.6.6 This would cause set interface status 0 + return to fast and cause bulk endpoint in out error*/ + case USB_REQ_SET_INTERFACE: + + VDBG("set interface %d\n", u.r.wValue); + status = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + goto delegate; + /*break;*/ + + case USB_REQ_CLEAR_FEATURE: + /* clear endpoint halt*/ + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + + if (u.r.wValue != USB_ENDPOINT_HALT + || u.r.wLength != 0) + goto do_stall; + + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep != ep0) { + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) + goto do_stall; + + if (udc->file_storage_set_halt == 0) { + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl &= 0xF7; + break; + + case 1:/*Bulk In*/ + + pDevReg->Bulk1EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma0_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk1DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk1DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk1DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk1DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk1DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk1DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control0 = dma_ccr; //neil + wmb(); + pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; + } + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl &= 0xF7; + + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + ep->stall_more_processing = 0; + wmt_pdma1_reset(); + // wmt_pdma_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); + /* DMA Global Controller Reg*/ + /* DMA Controller Enable +*/ + /* DMA Global Interrupt Enable(if any TC, error, + or abort status in any channels occurs)*/ + + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk2DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk2DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk2DesTbytes0 = + ep->temp_dcmd & 0xFF; + + if (ep->ep_stall_toggle_bit) + pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; + else + pDevReg->Bulk2DesTbytes2 &= 0x3F; + + pDevReg->Bulk2DesStatus = BULKXFER_IOC; + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + + /*udc_bulk_dma_dump_register();*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + dma_ccr |= DMA_TRANS_OUT_DIR; + wmb(); + pUdcDmaReg->DMA_Context_Control1 = dma_ccr; + wmb(); + pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; + } + break; + + case 3:/*Interrupt In*/ +#ifdef USE_BULK3_TO_INTERRUPT +/*Bulk In*/ + + pDevReg->Bulk3EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma2_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + } + +#else +/*Interrupt In*/ + pDevReg->InterruptEpControl &= 0xF7; +#endif + break; + + case 4:/*Iso In*/ + + pDevReg->Bulk3EpControl &= 0xF7; + #ifdef MSC_COMPLIANCE_TEST + udc_bulk_dma_dump_register(); + udc_device_dump_register(); + #endif + if (ep->stall_more_processing == 1) { + u32 dma_ccr = 0; + + ep->stall_more_processing = 0; + wmt_pdma2_reset(); + wmt_udc_pdma_des_prepare(ep->temp_dcmd, + ep->temp_bulk_dma_addr, + DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); + + pDevReg->Bulk3DesStatus = 0x00; + pDevReg->Bulk3DesTbytes2 |= + (ep->temp_dcmd >> 16) & 0x3; + pDevReg->Bulk3DesTbytes1 = + (ep->temp_dcmd >> 8) & 0xFF; + pDevReg->Bulk3DesTbytes0 = + ep->temp_dcmd & 0xFF; + + /* set endpoint data toggle*/ + if (ep->ep_stall_toggle_bit) { + /* BULKXFER_DATA1;*/ + pDevReg->Bulk3DesTbytes2 |= 0x40; + } else { + /*(~BULKXFER_DATA1);*/ + pDevReg->Bulk3DesTbytes2 &= 0xBF; + } + + pDevReg->Bulk3DesStatus = + (BULKXFER_IOC | BULKXFER_IN); + + /* DMA Channel Control Reg*/ + /* Software Request + Channel Enable*/ + dma_ccr = 0; + dma_ccr = DMA_RUN; + wmb(); + pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil + wmb(); + pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; + } + + break; + + } + + ep->stall = 0; + ep->stopped = 0; + /**ep->reg_irp_descriptor = ep->temp_irp_descriptor;*/ + } + } /*if (ep != ep0)*/ + + ep0_status_phase_0_byte = 1; + VDBG("%s halt cleared by host\n", ep->name); + /*goto ep0out_status_stage;*/ + status = 0; + udc->ep0_pending = 0; + /*break;*/ + goto delegate; + + case USB_REQ_SET_FEATURE: + /* set endpoint halt*/ + + if ((u.r.wValue == USB_DEVICE_TEST_MODE)) {/*(USBState == USBSTATE_DEFAULT) &&*/ + TestMode = (UCHAR)(u.r.wIndex >> 8); + test_mode_enable = 1; + INFO("USB_REQ_SET_FEATURE - TestMode (0x%02X)\n", TestMode); + + /*ControlState = CONTROLSTATE_STATUS;*/ + ep0_status_phase_0_byte = 1; + status = 0; + break; + } + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) + goto do_stall; + + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) + goto do_stall; + + wmb(); + switch ((ep->bEndpointAddress & 0x7F)) { + case 0:/*Control In/Out*/ + pDevReg->ControlEpControl |= EP_STALL; + break; + + case 1:/*Bulk In*/ + pDevReg->Bulk1EpControl |= EP_STALL; + break; + + case 2:/*Bulk Out*/ + pDevReg->Bulk2EpControl |= EP_STALL; + break; + + case 3: +#ifdef USE_BULK3_TO_INTERRUPT + /*Bulk Out*/ + pDevReg->Bulk3EpControl |= EP_STALL; +#else + /*Interrupt In*/ + pDevReg->InterruptEpControl |= EP_STALL; +#endif + break; + + case 4: + /*Bulk Out*/ + pDevReg->Bulk3EpControl |= EP_STALL; + break; + } + wmb(); + ep->stall = 1; + ep->stopped = 1; + + ep0_status_phase_0_byte = 1; + /*use_ep(ep, 0);*/ + /* can't halt if fifo isn't empty...*/ + /*UDC_CTRL_REG = UDC_CLR_EP;*/ + /*UDC_CTRL_REG = UDC_SET_HALT;*/ + VDBG("%s halted by host\n", ep->name); + /*ep0out_status_stage:*/ + status = 0; + + udc->ep0_pending = 0; + /*break;*/ + goto delegate; + + case USB_REQ_GET_STATUS: + /* return interface status. if we were pedantic,*/ + /* we'd detect non-existent interfaces, and stall.*/ + /**/ + + if (u.r.bRequestType == (USB_DIR_IN|USB_RECIP_ENDPOINT)) { + ep = &udc->ep[u.r.wIndex & 0xf]; + + if (ep->stall == 1) { + udc->ep0_in_status = 0x01; + + /*GgiaHsu-B 2007.08.10 : patch HW Bug : + MSC Compliance Test : Error Recovery Items.*/ + ep = &udc->ep[3]; + if ((udc->file_storage_set_halt == 1) && (ep->stall == 1)) + ep->stall = 1; + /*GgiaHsu-E 2007.08.10 : + --------------------------------------------*/ + + ep = &udc->ep[0]; + ep->stall = 0; + } else + udc->ep0_in_status = 0x00; + + VDBG("GET_STATUS, interface wIndex(0x%02X) ep0_in_status(0x%04X)\n" + , u.r.wIndex, udc->ep0_in_status); + } else + udc->ep0_in_status = 0x00; + + /* return two zero bytes*/ + status = 0; + + /* next, status stage*/ + goto delegate; + break; + + case USB_REQ_SET_ADDRESS: + if (u.r.bRequestType == USB_RECIP_DEVICE) { /*USB_RECIP_DEVICE(0x00)*/ + if (USBState == USBSTATE_DEFAULT) { + if (u.r.wValue != 0) + USBState = USBSTATE_ADDRESS; + } else if (USBState == USBSTATE_ADDRESS) { + if (u.r.wValue == 0) + USBState = USBSTATE_DEFAULT; + } + + pDevReg->DeviceAddr |= (DEVADDR_ADDRCHANGE | u.r.wValue); + VDBG("USB_REQ_SET_ADDRESS 0x%03d\n", u.r.wValue); + ControlState = CONTROLSTATE_STATUS; + ep0_status_phase_0_byte = 1; + status = 0; + } + break; + + case USB_BULK_RESET_REQUEST: + + VDBG("USB_BULK_RESET_REQUEST\n"); + udc->file_storage_set_halt = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + status = 0; + + goto delegate; + /*break;*/ + + default: +delegate: + VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + /* + // The gadget driver may return an error here, + // causing an immediate protocol stall. + // + // Else it must issue a response, either queueing a + // response buffer for the DATA stage, or halting ep0 + // (causing a protocol stall, not a real halt). A + // zero length buffer means no DATA stage. + // + // It's fine to issue that response after the setup() + // call returns, and this IRQ was handled. + // + */ + udc->ep0_setup = 1; + + spin_unlock_irqrestore(&udc->lock, irq_flags); + /*usb gadget driver prepare setup data phase(control in)*/ + status = udc->driver->setup(&udc->gadget, &u.r); /*usb_gadget_driver->setup()*/ + spin_lock_irqsave(&udc->lock, irq_flags); + udc->ep0_setup = 0; + } /*switch (u.r.bRequest)*/ + + if (ep0_status_phase_0_byte == 1) {/* && (udc->ep[0].stall==0))*/ + udc->ep0_status_0_byte = 1; + if (test_mode_enable == 1) + ep0_status(udc); + } + + if (status < 0) { +do_stall: + /* ep = &udc->ep[0];*/ + /**ep->reg_control_status |= UDC_EP0_STALL;*/ + /* fail in the command parsing*/ + pDevReg->ControlEpControl |= EP_STALL; /* stall the pipe*/ + wmb(); + ControlState = CONTROLSTATE_SETUP; /* go back to setup state*/ + + ep->stall = 1; + DBG("Setup Command STALL : req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, status); + + udc->ep0_pending = 0; + } /*if (status < 0)*/ + } /*if (udc_irq_src & UDC_IS_SETUP_INT)*/ +} /*udc_control_prepare_data_resp()*/ + +#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) + +static void devstate_irq(struct vt8500_udc *udc, u32 port0_status) +{ + udc->usb_connect = 0; + + if (pDevReg->IntEnable & INTENABLE_DEVICERESET) { + /*vt3357 hw issue : clear all device register.*/ + /*payload & address needs re-set again...*/ + pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; + VDBG("devstate_irq() - Global Reset...\n"); +//printk("[devstate_irq]0xd8009834 = 0x%8.8x\n",*(volatile unsigned int *)(USB_IP_BASE+0x2034)); + + if (udc->driver) { + udc->gadget.speed = USB_SPEED_UNKNOWN; +// ppudc = udc; +// run_script(action_off_line); +// udc->driver->disconnect(&udc->gadget); + } + + udc->ep0_set_config = 0; + pDevReg->Bulk1DesStatus = 0; + + udc->ep[0].toggle_bit = 0; + udc->ep[1].toggle_bit = 0; + udc->ep[2].toggle_bit = 0; + udc->ep[3].toggle_bit = 0; + udc->ep[4].toggle_bit = 0; + udc->ep[5].toggle_bit = 0;//gri + udc->ep[6].toggle_bit = 0;//gri + + + udc->ep[0].rndis = 0; + udc->ep[1].rndis = 0; + udc->ep[2].rndis = 0; + udc->ep[3].rndis = 0; + udc->ep[4].rndis = 0; + udc->ep[5].rndis = 0;//gri + udc->ep[6].rndis = 0;//gri + + udc->file_storage_set_halt = 0; + udc->bulk_out_dma_write_error = 0; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + wmt_pdma_reset(); + + gadget_connect=0; + /*vt8500_usb_device_reg_dump();*/ + + } /*if (pDevReg->IntEnable & INTENABLE_DEVICERESET)*/ + + if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT) { + VDBG("devstate_irq() - Global Suspend...\n"); + pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; + + + + } /*if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT)*/ + + if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT) { + pDevReg->IntEnable |= INTENABLE_RESUMEDETECT; + VDBG("devstate_irq() - Global Resume...\n"); + + } /*if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT)*/ + +/*#ifdef UDC_A1_SELF_POWER_ENABLE*/ + /* USB Bus Connection Change*/ + /* clear connection change event*/ + if (pDevReg->PortControl & PORTCTRL_SELFPOWER)/* Device port control register - 22)*/ + if (pDevReg->PortControl & PORTCTRL_CONNECTCHANGE)/* Device port control register - 22)*/ + pDevReg->PortControl |= PORTCTRL_CONNECTCHANGE;/* 0x02 // connection change bit*/ + +/*#endif*/ + + if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { + udc->gadget.speed = USB_SPEED_FULL; + udc->usb_connect = 1; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + VDBG("devstate_irq() - full speed host connect...\n"); + } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ + + if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { + udc->gadget.speed = USB_SPEED_HIGH; + udc->usb_connect = 1; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + VDBG("devstate_irq() - high speed host connect...\n"); + } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ + +} /*static void devstate_irq()*/ + +void USB_ControlXferComplete(void) +{ + struct vt8500_ep *ep; + struct vt8500_req *req; + + ep = &udc->ep[0]; + /* when ever a setup received, the Control state will reset*/ + /* check for the valid bit of the contol descriptor*/ + /*DBG("USB_ControlXferComplete()\n");*/ + if (pDevReg->ControlDesControl & CTRLXFER_CMDVALID) { + ep->toggle_bit = 1; + if (udc->usb_connect == 0) { + if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { + udc->gadget.speed = USB_SPEED_FULL; + udc->usb_connect = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + //wmt_udc_csr(udc); + VDBG("devstate_irq() - full speed host connect...\n"); + USBState = USBSTATE_DEFAULT; + } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ + + if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { + udc->gadget.speed = USB_SPEED_HIGH; + udc->usb_connect = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; + /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ + /*after host controller connected.*/ + //wmt_udc_csr(udc); + VDBG("devstate_irq() - high speed host connect...\n"); + USBState = USBSTATE_DEFAULT; + } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ + } + /* HP11_Begin*/ + /* clear the command valid bit*/ + /* pDevReg->ControlDesControl |= CTRLXFER_CMDVALID;*/ + /* always clear control stall when SETUP received*/ + pDevReg->ControlEpControl &= 0x17; /* clear the stall*/ + wmb(); + ControlState = CONTROLSTATE_DATA; + udc_control_prepare_data_resp(); /*processing SETUP command ...*/ + pDevReg->ControlDesControl &= 0xEF;/*(~CTRLXFER_CMDVALID);*/ + wmb(); + /*HP11_End*/ + return; + } + + if (udc->ep0_in) { + /* IN dma: tx to host*/ + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + VDBG("dma_irq : finish_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); + finish_in_dma(ep, req, 0); + } + + while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ + ; + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + VDBG("dma_irq : next_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); + next_in_dma(ep, req); + } + } else {/*ep0 out*/ + /* OUT dma: rx from host*/ + if (!list_empty(&ep->queue)) { + req = container_of(ep->queue.next, struct vt8500_req, queue); + finish_out_dma(ep, req, 0); + } + + while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ + ; + if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ + req = container_of(ep->queue.next, struct vt8500_req, queue); + next_out_dma(ep, req); + } + } + +} /*void USB_ControlXferComplete(void)*/ +static irqreturn_t +wmt_udc_dma_irq(int irq, void *_udc)//, struct pt_regs *r) +{ + irqreturn_t status = IRQ_NONE; + u32 bulk_dma_csr; + + bulk_dma_csr = pUdcDmaReg->DMA_ISR; + /*printk("[udc_dma_isr]dma int_sts = 0x%8.8x\n",pUdcDmaReg->DMA_ISR);*/ + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS0) { + /* printk("[udc_dma_isr]channel0 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control0);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS0; + status = IRQ_HANDLED; + } + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS1) { + /* printk("[udc_dma_isr]channel1 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control1);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS1; + status = IRQ_HANDLED; + } + + if (bulk_dma_csr & DMA_INTERRUPT_STATUS2) { + /* printk("[udc_dma_isr]channel2 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control2);*/ + pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS2; + //printk("iso dma hit\n"); + dma_irq(0x84); + status = IRQ_HANDLED; + } + return status; +} + +static irqreturn_t +wmt_udc_irq(int irq, void *_udc)//, struct pt_regs *r) +{ + struct vt8500_udc *udc = _udc; + u32 udc_irq_src; + irqreturn_t status = IRQ_NONE; +// unsigned long flags; +#ifdef OTGIP + u32 global_irq_src; +#endif + /*u32 i;*/ + + spin_lock_irqsave(&udc->lock, irq_flags); + + DBG("wmt_udc_irq()\n"); + +#ifdef OTGIP + /*Global Interrupt Status*/ + global_irq_src = pGlobalReg->UHDC_Interrupt_Status; + + if (global_irq_src & UHDC_INT_UDC) {/*UDC Core + UDC DMA1 + UDC DMA2 */ + if (global_irq_src & UHDC_INT_UDC_CORE) {/*UDC Core*/ +#endif + /*connection interrupt*/ + if (pDevReg->SelfPowerConnect & 0x02) { + //struct usb_gadget_driver *driver = udc->driver; + + if (pDevReg->SelfPowerConnect & 0x01) //connect + { +// wmt_pdma_reset(); +reset_udc(); +//pullup_enable(udc); + } + else {//disconnct +// spin_unlock_irqrestore(&udc->lock, irq_flags); +// if (udc->driver) +// udc->driver->disconnect(&udc->gadget); +// ppudc = udc; + printk(KERN_INFO "disconnect 1\n"); //gri + run_script(action_off_line); + gadget_connect=0; + +// pullup_disable(udc); + + } + + status = IRQ_HANDLED; + pDevReg->SelfPowerConnect |= 0x02; + } + wmb(); + /* Device Global Interrupt Pending Status*/ + udc_irq_src = pDevReg->CommandStatus; + + /* Device state change (usb ch9 stuff)*/ + if (udc_irq_src & USBREG_BUSACTINT) {/* the bus activity interrupt occured*/ + /*caused by Port 0 Statsu Change*/ + devstate_irq(_udc, udc_irq_src); + status = IRQ_HANDLED; + pDevReg->CommandStatus |= USBREG_BUSACTINT; + wmb(); + } + + if (udc_irq_src & USBREG_BABBLEINT) {/* the Babble interrupt ocuured*/ + /* check for Control endpoint for BABBLE error*/ + if (pDevReg->ControlEpControl & EP_BABBLE) { + /* the Control endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->ControlEpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP0 Babble Detect!\n"); + udc->ep[0].stopped = 1; + udc->ep[0].stall = 1; + } + + if (pDevReg->Bulk1EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk1EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP1 Babble Detect!\n"); + udc->ep[1].stopped = 1; + udc->ep[1].stall = 1; + } + + if (pDevReg->Bulk2EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk2EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP2 Babble Detect!\n"); + udc->ep[2].stopped = 1; + udc->ep[2].stall = 1; + } + + if (pDevReg->Bulk3EpControl & EP_BABBLE) { + /* the Bulk endpoint is encounted the babble error*/ + /* stall the endpoint and clear the babble condition*/ + pDevReg->Bulk3EpControl |= (EP_BABBLE + EP_STALL); + INFO("vt8430_udc_irq() - EP3 Babble Detect!\n"); + udc->ep[3].stopped = 1; + udc->ep[3].stall = 1; + } + wmb(); + status = IRQ_HANDLED; + } + + if (udc_irq_src & USBREG_COMPLETEINT) {/* the complete inerrupt occured*/ + if (pDevReg->ControlEpControl & EP_COMPLETEINT) { + /* the control transfer complete event*/ + pDevReg->ControlEpControl |= EP_COMPLETEINT; /* clear the event*/ + wmb(); + USB_ControlXferComplete(); +#if 0 + gadget_connect=1; +#endif + + } + + if (pDevReg->Bulk1EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk1EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 1 DMA()\n");*/ + dma_irq(0x81); +#if 1 + gadget_connect=1; +#endif + } + + if (pDevReg->Bulk2EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk2EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 2 DMA()\n");*/ + dma_irq(2); +#if 1 + gadget_connect=1; +#endif + } + +#ifdef USE_BULK3_TO_INTERRUPT + if (pDevReg->Bulk3EpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->Bulk3EpControl |= EP_COMPLETEINT; + wmb(); + /*DBG("USB_Bulk 3 DMA()\n");*/ + dma_irq(0x83); +#if 1 + gadget_connect=1; +#endif + } +#else + if (pDevReg->InterruptEpControl & EP_COMPLETEINT) { + /* the bulk transfer complete event*/ + pDevReg->InterruptEpControl |= EP_COMPLETEINT; + /*DBG("USB_INT 3 DMA()\n");*/ + if (f_ep3_used == 3) + dma_irq(0x83); +#if 1 + gadget_connect=1; +#endif + } +#endif + status = IRQ_HANDLED; + } + + if (udc->ep0_status_0_byte == 1)/* && (udc_ep[0].stall==0))*/ + ep0_status(udc); + + if (ControlState == CONTROLSTATE_STATUS) { + /* checking for test mode*/ + if (TestMode != 0x00) { +#if 0 + pDevReg->CommandStatus &= 0x1F; + wmb(); + pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) + ; + /* HW attach process evaluation enable bit*/ +#if 0 + pDevReg->FunctionPatchEn |= 0x20; + /* Device port control register - 22*/ + pDevReg->PortControl |= PORTCTRL_SELFPOWER; + wmb(); +#else + pullup_enable(udc); + pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + wmb(); + //msleep(1000); +#endif +#endif + wmb(); + udelay(1000); + /*GigaHsu 2008.1.26 : Don't set RUN bit while TestMode enable*/ + /* setting the test mode*/ + switch (TestMode) { + case UDC_TEST_MODE_NOT_ENABLED:/*0*/ + INFO("UDC_TEST_MODE_NOT_ENABLED (0x%02X)\n", TestMode); + break; + + case UDC_TEST_J_STATE:/*1*/ + pDevReg->CommandStatus = USBREG_TEST_J; + INFO("UDC_TEST_J_STATE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_K_STATE:/*2*/ + pDevReg->CommandStatus = USBREG_TEST_K; + INFO("UDC_TEST_K_STATE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_SE0_NAK:/*3*/ + pDevReg->CommandStatus = USBREG_SE0_NAK; + INFO("UDC_TEST_SE0_NAK wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_PACKET:/*4*/ + pDevReg->CommandStatus = USBREG_TESTPACKET; + INFO("UDC_TEST_PACKET wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_FRORCE_ENABLE:/*5*/ + pDevReg->CommandStatus = USBREG_FORCEENABLE; + INFO("UDC_TEST_FRORCE_ENABLE wIndex(0x%02X)\n", TestMode); + break; + + case UDC_TEST_EYE_PATTERN:/*6*/ + pDevReg->CommandStatus = USBREG_TESTEYE; + INFO("UDC_TEST_EYE_PATTERN wIndex(0x%02X)\n", TestMode); + break; + } /*switch(TestMode)*/ + + INFO("UDC - CommandStatus(0x%02X)\n", pDevReg->CommandStatus); + /* stop the 8051*/ + /*ChipTopRegister.Config |= CT_STOP8051;*/ + } + ControlState = CONTROLSTATE_SETUP; /* go back SETUP state*/ + } +#ifdef OTGIP + } + + global_irq_src = pGlobalReg->UHDC_Interrupt_Status; + if (global_irq_src & UHDC_INT_UDC_DMA1)/*UDC Bulk DMA 1*/ + status = wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + +// if (global_irq_src & UHDC_INT_UDC_DMA2)/*UDC Bulk DMA 1*/ +// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + +// if (global_irq_src & UHDC_INT_UDC_DMA3)/*UDC Bulk DMA 1*/ +// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); + + } +#endif + spin_unlock_irqrestore(&udc->lock, irq_flags); + //printk("udc s =0x%x\n",pGlobalReg->UHDC_Interrupt_Status); + + return status; +} /*wmt_udc_irq()*/ + +/* workaround for seemingly-lost IRQs for RX ACKs... */ +#define PIO_OUT_TIMEOUT (jiffies + HZ/3) + +#ifdef DEBUG_UDC_ISR_TIMER +static void wmt_udc_softirq(unsigned long _udc) +{ + struct vt8500_udc *udc = (void *) _udc; + /*unsigned long flags;*/ + struct pt_regs r; + + INFO("wmt_udc_softirq()\n"); + wmt_udc_irq(UDC_IRQ_USB, udc, &r); + mod_timer(&udc->timer, PIO_OUT_TIMEOUT); + +} +#endif + +static void __init wmt_ep_setup(char *name, u8 addr, u8 type, unsigned maxp); + +static int wmt_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) + +{ + int status = -ENODEV; + struct vt8500_ep *ep; +// unsigned long flags; + + DBG("wmt_udc_start()\n"); + + /* basic sanity tests */ + if (!udc) + return -ENODEV; + if (!driver + /* FIXME if otg, check: driver->is_otg*/ + || driver->max_speed < USB_SPEED_FULL + || !bind +// || !driver->unbind + || !driver->setup){ +// printk(KERN_INFO "gri usb_gadget_probe_driver f2\n"); +// printk(KERN_INFO "gri driver=%x driver->speed=%x driver->bind=%x driver->unbind=%x driver->setup=%x\n", +// (unsigned int)driver,(unsigned int)driver->speed,(unsigned int)driver->bind,(unsigned int)driver->unbind,(unsigned int)driver->setup); + return -EINVAL; + } + + spin_lock_irqsave(&udc->lock, irq_flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, irq_flags); + return -EBUSY; + } + + /* reset state */ + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + ep->irqs = 0; + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) + continue; + /*use_ep(ep, 0);*/ + /*UDC_CTRL_REG = UDC_SET_HALT;*/ + } + udc->ep0_pending = 0; + udc->ep0_status_0_byte = 0; + udc->ep[0].irqs = 0; + udc->softconnect = 1; + udc->file_storage_set_halt = 0; + /* hook up the driver */ + driver->driver.bus = 0; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, irq_flags); + + status = bind(&udc->gadget); + spin_lock_irqsave(&udc->lock, irq_flags); +printk(KERN_INFO "bind to %s --> %d\n", driver->driver.name, status); + + if (status) { + /* %s -> g_file_storage*/ + DBG("bind to %s --> %d\n", driver->driver.name, status); +// printk(KERN_INFO "gri usb_gadget_probe_driver %d\n", status); + udc->gadget.dev.driver = 0; + udc->driver = 0; + goto done; + } + + DBG("bound to driver %s\n", driver->driver.name);/*udc: bound to driver g_file_storage*/ + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + + *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ + wmb(); +#if 0 + /* reset Bulk descriptor control*/ + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk1EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk2EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + while (pDevReg->Bulk3EpControl & EP_ACTIVE) + ; /* wait the DMA stopped*/ + + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; + + /* enable DMA and run the control endpoint*/ + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif +#endif + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + + + pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ + wmb(); + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + wmb(); + + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); +#if 0 + wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); + wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); +#ifdef USE_BULK3_TO_INTERRUPT + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); +#else + wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); +#endif + wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISO, 384); +#endif + + /* enable all interrupt*/ +#ifdef FULL_SPEED_ONLY + pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ +#else + pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ +#endif + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl = CTRLXFER_IOC; + wmt_pdma_reset();/*NeilChen*/ + +// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ + +#ifdef DEBUG_UDC_ISR_TIMER + init_timer(&udc->timer); + udc->timer.function = wmt_udc_softirq; + udc->timer.data = (unsigned long) udc; + add_timer(&udc->timer); +#endif + +done: + spin_unlock_irqrestore(&udc->lock, irq_flags); + return status; +} /*int wmt_udc_start ()*/ + +static int wmt_udc_stop(struct usb_gadget_driver *driver) +{ +// unsigned long flags; + int status = -ENODEV; + + if (!udc) + return -ENODEV; + if (!driver || driver != udc->driver) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, irq_flags); + udc_quiesce(udc); + spin_unlock_irqrestore(&udc->lock, irq_flags); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = 0; + udc->driver = 0; + + pDevReg->IntEnable &= 0x8F;/*INTENABLE_ALL(0x70)*/ + /* set IOC on the Setup decscriptor to accept the Setup request*/ + pDevReg->ControlDesControl &= 0x7F;/*CTRLXFER_IOC;*/ + + if (udc->transceiver) + (void) otg_set_peripheral(udc->transceiver->otg, NULL); + else { + pullup_disable(udc); +// pDevReg->FunctionPatchEn &= ~0x20; + } + + if (TestMode != 0x00) { + pDevReg->CommandStatus &= 0x1F; + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + *pUSBMiscControlRegister5 = 0x00;/* USB PHY in power down & USB in reset*/ + + INFO("usb_gadget_unregister_driver() RESET_UDC OK!\n"); + TestMode = 0; + } + + DBG("unregistered driver '%s'\n", driver->driver.name); + return status; +} /*int wmt_udc_stop ()*/ + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_vt8500_PROC + +#include <linux/seq_file.h> + +static const char proc_filename[] = "driver/udc"; + +#define FOURBITS "%s%s%s%s" +#define EIGHTBITS FOURBITS FOURBITS + +static void proc_ep_show(struct seq_file *s, struct vt8500_ep *ep) +{ + +} /*proc_ep_show()*/ + + +static char *trx_mode(unsigned m) +{ + switch (m) { + case 3: + case 0: return "6wire"; + case 1: return "4wire"; + case 2: return "3wire"; + default: return "unknown"; + } +} + +static int proc_udc_show(struct seq_file *s, void *_) +{ + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, 0); +} + +static struct file_operations proc_ops = { + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_proc_file(void) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry(proc_filename, 0, NULL); + if (pde) + pde->proc_fops = &proc_ops; +} + +static void remove_proc_file(void) +{ + remove_proc_entry(proc_filename, 0); +} + +#else + +static inline void create_proc_file(void) {} +static inline void remove_proc_file(void) {} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* Before this controller can enumerate, we need to pick an endpoint + * configuration, or "fifo_mode" That involves allocating 2KB of packet + * buffer space among the endpoints we'll be operating. + */ +static void __init +wmt_ep_setup(char *name, u8 addr, u8 type, + unsigned maxp) +{ + struct vt8500_ep *ep; + + VDBG("wmt_ep_setup()\n"); + + /* OUT endpoints first, then IN*/ + ep = &udc->ep[addr & 0x7f]; + + VDBG("wmt_ep_setup() - %s addr %02x maxp %d\n", + name, addr, maxp); + + strlcpy(ep->name, name, sizeof ep->name); + INIT_LIST_HEAD(&ep->queue); + ep->bEndpointAddress = addr; + ep->bmAttributes = type; + ep->double_buf = 0;/*dbuf;*/ + ep->udc = udc; + ep->toggle_bit = 0; + ep->ep.name = ep->name; + ep->ep.ops = &wmt_ep_ops;/*struct usb_ep_ops*/ + ep->ep.maxpacket = ep->maxpacket = maxp; + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + + /*return buf;*/ +} /*wmt_ep_setup()*/ + +static void wmt_udc_release(struct device *dev) +{ + DBG("wmt_udc_release()\n"); + complete(udc->done); + kfree(udc); + udc = 0; +} /*wmt_udc_release()*/ + +static int __init +wmt_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) +{ + DBG("wmt_udc_setup()\n"); + udc = kmalloc(sizeof *udc, GFP_KERNEL); + + if (!udc) + return -ENOMEM; + + memset(udc, 0, sizeof *udc); + spin_lock_init(&udc->lock); + + spin_lock_init(&gri_lock); + + sema_init(&wmt_udc_sem, 1); + + udc->gadget.ops = &wmt_gadget_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + INIT_LIST_HEAD(&udc->gadget.ep_list); + /*INIT_LIST_HEAD(&udc->iso);*/ + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.name = driver_name; + + device_initialize(&udc->gadget.dev); + //strcpy(udc->gadget.dev.bus_id, "gadget"); + dev_set_name(&udc->gadget.dev, "gadget"); + udc->gadget.dev.release = wmt_udc_release; + udc->transceiver = NULL; + /* ep0 is special; put it right after the SETUP buffer*/ + wmt_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); + + list_del_init(&udc->ep[0].ep.ep_list); + +#if 1 +#if 1 +#define VT8430_BULK_EP(name, addr) \ + wmt_ep_setup(name "-bulk", addr, \ + USB_ENDPOINT_XFER_BULK, 512); + +/*usb_ch9.h*/ +/*#define USB_DIR_OUT 0 *//* to device */ +/*#define USB_DIR_IN 0x80 *//* to host */ +#define VT8430_INT_EP(name, addr, maxp) \ + wmt_ep_setup(name "-int", addr, \ + USB_ENDPOINT_XFER_INT, maxp); + +#define VT8430_ISO_EP(name, addr, maxp) \ + wmt_ep_setup(name "-iso", addr, \ + USB_ENDPOINT_XFER_ISOC, maxp); +#endif + + VT8430_BULK_EP("ep1in", USB_DIR_IN | 1); + VT8430_BULK_EP("ep2out", USB_DIR_OUT | 2); +#ifdef USE_BULK3_TO_INTERRUPT + VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 512); +#else + VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 8); +#endif + VT8430_ISO_EP("ep4in", USB_DIR_IN | 4, 512); +#endif + udc->ep[0].rndis_buffer_alloc = 0; + udc->ep[1].rndis_buffer_alloc = 0; + udc->ep[2].rndis_buffer_alloc = 0; + udc->ep[3].rndis_buffer_alloc = 0; + udc->ep[4].rndis_buffer_alloc = 0; + udc->ep[5].rndis_buffer_alloc = 0;//gri + udc->ep[6].rndis_buffer_alloc = 0;//gri + + /*INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);*/ + return 0; +} /*wmt_udc_setup()*/ + +static void wmt_pdma_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + +static void wmt_pdma0_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset0 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset0)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + + +static void wmt_pdma1_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset1 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset1)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ + +#ifdef USE_BULK3_TO_INTERRUPT +static void wmt_pdma2_reset(void) +{ + + if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + + pUdcDmaReg->DMA_Global_Bits.SoftwareReset2 = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset2)/*wait reset complete*/ + ; + + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; + wmb(); + /*descriptor initial*/ + +} /*wmt_pdma_init*/ +#endif + + +/*static void wmt_pdma_init(struct device *dev)*/ +static void wmt_pdma_init(struct device *dev) +{ + UdcRndisEp1VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp1PhyAddr), GFP_KERNEL|GFP_ATOMIC); + UdcRndisEp2VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp2PhyAddr), GFP_KERNEL|GFP_ATOMIC); + UdcRndisEp3VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp3PhyAddr), GFP_KERNEL|GFP_ATOMIC); + + UdcPdmaVirAddrLI = (unsigned int) dma_alloc_coherent(pDMADescLI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLI), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrSI = (unsigned int) dma_alloc_coherent(pDMADescSI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSI), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrLO = (unsigned int) dma_alloc_coherent(pDMADescLO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLO), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrSO = (unsigned int) dma_alloc_coherent(pDMADescSO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSO), GFP_KERNEL|GFP_ATOMIC); + +#ifdef USE_BULK3_TO_INTERRUPT + UdcPdmaVirAddrL2I = (unsigned int) dma_alloc_coherent(pDMADescL2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrL2I), GFP_KERNEL|GFP_ATOMIC); + UdcPdmaVirAddrS2I = (unsigned int) dma_alloc_coherent(pDMADescS2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrS2I), GFP_KERNEL|GFP_ATOMIC); +#endif + + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; + wmb(); + while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ + ; + pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; + + pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; + pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; + +#ifdef USE_BULK3_TO_INTERRUPT + pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; + pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; +#endif + wmb(); + +} /*wmt_pdma_init*/ + +/*static int __init wmt_udc_probe(struct device *dev)*/ +static int __init wmt_udc_probe(struct platform_device *pdev) +{ +/* struct platform_device *odev = to_platform_device(dev);*/ + struct device *dev = &pdev->dev; + int status = -ENODEV; + struct usb_phy *xceiv = 0; + + DBG("wmt_udc_probe()\n"); + + /*UDC Register Space 0x400~0x7EF*/ + + INIT_LIST_HEAD (&done_main_list); + + b_pullup = 0; + + pDevReg = (struct UDC_REGISTER *)USB_UDC_REG_BASE; + pUdcDmaReg = (struct UDC_DMA_REG *)USB_UDC_DMA_REG_BASE; + pSetupCommand = (PSETUPCOMMAND)(USB_UDC_REG_BASE + 0x300); + pSetupCommandBuf = (unsigned char *)(USB_UDC_REG_BASE + 0x300); + SetupBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x340); + IntBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x40); + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + +#ifdef OTGIP + /*UHDC Global Register Space 0x7F0~0x7F7*/ + pGlobalReg = (struct USB_GLOBAL_REG *) USB_GLOBAL_REG_BASE; +#endif + + *pUSBMiscControlRegister5 = 0x01; + pDevReg->CommandStatus &= 0x1F; + pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; + wmb(); + while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) + ; + + wmt_pdma_init(dev); + + pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk1DesStatus = 0x00; + pDevReg->Bulk2DesStatus = 0x00; + + pDevReg->Bulk1DesTbytes0 = 0; + pDevReg->Bulk1DesTbytes1 = 0; + pDevReg->Bulk1DesTbytes2 = 0; + + pDevReg->Bulk2DesTbytes0 = 0; + pDevReg->Bulk2DesTbytes1 = 0; + pDevReg->Bulk2DesTbytes2 = 0; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ + wmb(); + while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ + ; + pDevReg->Bulk3DesStatus = 0x00; + + pDevReg->Bulk3DesTbytes0 = 0; + pDevReg->Bulk3DesTbytes1 = 0; + pDevReg->Bulk3DesTbytes2 = 0; +#endif + + /* enable DMA and run the control endpoint*/ + wmb(); + pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; + /* enable DMA and run the bulk endpoint*/ + pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; + pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; + +#ifdef USE_BULK3_TO_INTERRUPT + pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; +#else + pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; +#endif + wmb(); + /* enable DMA and run the interrupt endpoint*/ + /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ + /* run the USB controller*/ + pDevReg->MiscControl3 = 0x3d; + + /* HW attach process evaluation enable bit For WM3426 and after project*/ + /*pDevReg->FunctionPatchEn |= 0x20;*/ +#ifdef HW_BUG_HIGH_SPEED_PHY + pDevReg->MiscControl0 &= ~0x80; +#endif + pDevReg->MiscControl0 |= 0x02; + wmb(); + pDevReg->CommandStatus = USBREG_RUNCONTROLLER; + + ControlState = CONTROLSTATE_SETUP; + USBState = USBSTATE_DEFAULT; + TestMode = 0; + + status = wmt_udc_setup(pdev, xceiv); + if (status) + goto cleanup0; + + xceiv = 0; + + /*udc->chip_version = tmp8;*/ + /* "udc" is now valid*/ + pullup_disable(udc); + + udc->gadget.is_otg = 0;/*(config->otg != 0);*/ + udc->dev = dev; + udc->gadget.max_speed = USB_SPEED_HIGH;; + udc->ep0_status_0_byte = 0; + udc->usb_connect = 0; + /* USB general purpose IRQ: ep0, state changes, dma, etc*/ + status = request_irq(UDC_IRQ_USB, wmt_udc_irq, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);//gri + pDevReg->SelfPowerConnect |= 0x10;//Neil + +#ifndef OTGIP + status = request_irq(UDC_IRQ_DMA, wmt_udc_dma_irq, +// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); +// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); + (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); +#endif + /*SA_SAMPLE_RANDOM, driver_name, udc);*/ + if (status != 0) { + ERR("can't get irq %d, err %d\n", + UDC_IRQ_USB, status); + goto cleanup1; + } else + INFO("wmt_udc_probe - request_irq(0x%02X) pass!\n", UDC_IRQ_USB); + + create_proc_file(); + status = device_add(&udc->gadget.dev); + if (status) + goto cleanup4; + + status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + initial_test_fiq(); + if (!status) + return 0; + +cleanup4: + remove_proc_file(); + +/*cleanup2:*/ + free_irq(UDC_IRQ_USB, udc); + INFO("wmt_udc_probe - free_irq(0x%02X)?\n", UDC_IRQ_USB); +cleanup1: + kfree(udc); + udc = 0; + +cleanup0: + if (xceiv) + usb_put_transceiver(xceiv); + /*release_mem_region(odev->resource[0].start,*/ + /* odev->resource[0].end - odev->resource[0].start + 1);*/ + return status; + +} /*wmt_udc_probe()*/ + +static int __exit wmt_udc_remove(struct platform_device *pdev) +{ + /*struct platform_device *odev = to_platform_device(dev);*/ + DECLARE_COMPLETION(done); + DBG("wmt_udc_remove()\n"); + + if (!udc) + return -ENODEV; + + udc->done = &done; + + pullup_disable(udc); + if (udc->transceiver) { + usb_put_transceiver(udc->transceiver); + udc->transceiver = 0; + } + /*UDC_SYSCON1_REG = 0;*/ + + remove_proc_file(); + + free_irq(UDC_IRQ_USB, udc); + + device_unregister(&udc->gadget.dev); + wait_for_completion(&done); + + return 0; +} /*wmt_udc_remove()*/ + +/* suspend/resume/wakeup from sysfs (echo > power/state) */ + +static int +wmt_udc_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) +{ + + + if (event == PM_SUSPEND_PREPARE) { + if (udc->driver){ + run_script(action_off_line); + } + gadget_connect=0; + down(&wmt_udc_sem); + pullup_disable(udc); + up(&wmt_udc_sem); + } + else if (event == PM_POST_SUSPEND) { + + down(&wmt_udc_sem); + pullup_enable(udc); + up(&wmt_udc_sem); + + wmt_wakeup(&udc->gadget); + } + + return NOTIFY_OK; +} + + +static struct notifier_block wmt_udc_pm_notifier = { + .notifier_call = wmt_udc_pm_notify, +}; + + + + +static int wmt_udc_suspend(struct platform_device *pdev, pm_message_t state) +{ + DBG("wmt_udc_suspend()\n"); + printk(KERN_INFO "wmt_udc_suspend\n"); //gri +#if 0 + if (udc->driver){ + run_script(action_off_line); + } + gadget_connect=0; + run_script(action_mount); +#endif + pDevReg->CommandStatus &= 0x1F; + + pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); + /**pUSBMiscControlRegister5 = 0x02;// USB PHY in power down & USB in reset*/ + *pUSBMiscControlRegister5 = 0x00;/*USB in reset*/ + wmb(); + + TestMode = 0; +#if 0 + down(&wmt_udc_sem); + pullup_disable(udc); + up(&wmt_udc_sem); +#endif + +/* if ((state == 3) && (level == 3))*/ +/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) &= ~0x00000080;*/ /*DPM needed*/ + *(volatile unsigned char*)(USB_IP_BASE + 0x249) |= 0x04; + + return 0; + +} /*wmt_udc_suspend()*/ + +static int wmt_udc_resume(struct platform_device *pdev) +{ +#if 0 + DBG("wmt_udc_resume()\n"); + printk(KERN_INFO "wmt_udc_resume\n"); //gri + down(&wmt_udc_sem); + reset_udc(); + pullup_enable(udc); + up(&wmt_udc_sem); + + return wmt_wakeup(&udc->gadget); +#endif + reset_udc(); + return 0; + +} /*wmt_udc_resume()*/ + +/*-------------------------------------------------------------------------*/ + +static struct platform_driver udc_driver = { + .driver.name = (char *) driver_name, + .probe = wmt_udc_probe, + .remove = __exit_p(wmt_udc_remove), + .suspend = wmt_udc_suspend, + .resume = wmt_udc_resume, +}; + +static struct resource wmt_udc_resources[] = { + [0] = { + .start = (USB_IP_BASE + 0x2000), + .end = (USB_IP_BASE + 0x2400), + .flags = IORESOURCE_MEM, + }, +}; +static u64 wmt_udc_dma_mask = 0xFFFFF000; + +static struct platform_device wmt_udc_device = { + .name = (char *) driver_name, + .id = 0, + .dev = { + .dma_mask = &wmt_udc_dma_mask, + .coherent_dma_mask = ~0, + }, + .num_resources = ARRAY_SIZE(wmt_udc_resources), + .resource = wmt_udc_resources, +}; + +void wmt_cleanup_done_thread(int number) +{ + unsigned long flags; + struct usb_composite_dev *cdev = get_gadget_data(&(udc->gadget)); +#if 1 + if(number == 1) + { + if(in_interrupt()) + return; + if(spin_is_locked(&cdev->lock)){ + //local_irq_save(flags); + spin_unlock(&cdev->lock); + //local_irq_enable(); + //schedule_work(&done_thread); + flush_work_sync(&done_thread); + //local_irq_restore(flags); + spin_lock(&cdev->lock); + }else{ + flush_work_sync(&done_thread); + } + //wmt_ep_disable(&udc->ep[0]); + spin_lock_irqsave(&udc->lock, flags); + nuke(&udc->ep[0],ESHUTDOWN); + spin_unlock_irqrestore(&udc->lock, flags); + }else if(number == 2) + { + }else{ + //flush_work_sync(&mount_thread); + printk("erro parameter:%s\n",__func__); + } +#endif +} +EXPORT_SYMBOL(wmt_cleanup_done_thread); + +static int __init udc_init(void) +{ + INFO("%s, version: " DRIVER_VERSION + "%s\n", driver_desc, + use_dma ? " (dma)" : ""); + + DBG("udc_init()\n"); + +//INIT_WORK(&online_thread, run_online); +INIT_WORK(&offline_thread, run_offline); +INIT_WORK(&done_thread, run_done); +INIT_WORK(&chkiso_thread, run_chkiso); + +platform_device_register(&wmt_udc_device); + + register_pm_notifier(&wmt_udc_pm_notifier); + + return platform_driver_register(&udc_driver); +} /*udc_init()*/ + +module_init(udc_init); + +static void __exit udc_exit(void) +{ + DBG("udc_exit()\n"); + //driver_unregister(&udc_driver); + platform_driver_unregister(&udc_driver); + platform_device_unregister(&wmt_udc_device); +} /*udc_exit()*/ + +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h new file mode 100755 index 00000000..c566f3cd --- /dev/null +++ b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h @@ -0,0 +1,801 @@ +/* + * wmt_udc.c -- for WonderMedia Technology udc + * + * Copyright (C) 2007 VIA Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_USB_GADGET_VT8500_H +#define __LINUX_USB_GADGET_VT8500_H + +#include <linux/types.h> +/*#include <stdio.h>*/ +/*#include <stdlib.h>*/ +/*#include <string.h>*/ +#include <mach/hardware.h> +#include <asm/irq.h> + +#define OTGIP + +#define UINT volatile unsigned int +#define USHORT volatile unsigned short +#define UCHAR volatile unsigned char +#define ULL volatile unsigned long long + +#define UDC_IRQ_USB IRQ_UHDC + +#ifndef OTGIP +#define UDC_IRQ_DMA 2 +#endif +/*#define DWORD volatile unsigned long*/ +/*#define WORD volatile unsigned short*/ +/*#define BYTE volatile unsigned char*/ +#define USB_IP_BASE USB20_HOST_DEVICE_CFG_BASE_ADDR +/*UDC Register Space 0x400~0x7EF*/ +#define USB_UDC_REG_BASE (USB_IP_BASE + 0x400) +/*Bulk Endpoint DMA Register Space 0x100*/ +#define USB_UDC_DMA_REG_BASE (USB_IP_BASE + 0x500) +#ifdef OTGIP +/*UHDC Global Register Space 0x7F0~0x7F7*/ +#define USB_GLOBAL_REG_BASE (USB_IP_BASE + 0x7f0) +#endif + +#define UDC_REG(offset) REG32_PTR(USB_UDC_REG_BASE + offset) + +#define OTG_HOST_MEM_BASE 0x01400000/*20MB*/ + +#define USB_EP0_CTRL_DMA_BASE OTG_HOST_MEM_BASE /*64 bytes*/ +#define USB_EP1_BULK_IN_DMA_BASE 0x01400040/*OTG_HOST_MEM_BASE + 64 */ /*64B +64KB*/ +#define USB_EP2_BULK_OUT_DMA_BASE 0x01410040/*OTG_HOST_MEM_BASE + 65536*/ /* ~ END*/ +#define USB_DOWNLOAD_KERNEL_RAM_ADDR USB_EP2_BULK_OUT_DMA_BASE + +/* Basic Define*/ +#define REG32 *(volatile unsigned int *) +#define REG16 *(volatile unsigned short *) +#define REG8 *(volatile unsigned char *) + +#define REG_GET32(addr) ( REG32(addr) ) /* Read 32 bits Register */ +#define REG_GET16(addr) ( REG16(addr) ) /* Read 16 bits Register */ +#define REG_GET8(addr) ( REG8(addr) ) /* Read 8 bits Register */ + +#define REG_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Register */ +#define REG_SET16(addr, val) ( REG16(addr) = (val) ) /* Write 16 bits Register */ +#define REG_SET8(addr, val) ( REG8(addr) = (val) ) /* Write 8 bits Register */ + +#define MEM_GET32(addr) ( REG32(addr) ) /* Read 32 bits Memory */ +#define MEM_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Memory */ + +/*#define USB_TIMEOUT 0x100*/ /*256*/ +/*#define USB_TEST_SUCCESS 1*/ +/*#define USB_TEST_FAIL 0*/ + +/* define the state of the USB device*/ +#define USBSTATE_ATTACHED 0x00 /* device attached to host*/ +#define USBSTATE_POWERED 0x01 /* device obtain power*/ +#define USBSTATE_DEFAULT 0x02 /* default working state*/ +#define USBSTATE_ADDRESS 0x04 /* device has get the address*/ +#define USBSTATE_CONFIGED 0x10 /* deivce has set the configuration*/ +#define USBSTATE_SUSPEND 0x20 /* No bus activity device goes to suspend */ + +#define UDC_TEST_J_STATE 1 +#define UDC_TEST_K_STATE 2 +#define UDC_TEST_SE0_NAK 3 +#define UDC_TEST_PACKET 4 +#define UDC_TEST_FRORCE_ENABLE 5 +#define UDC_TEST_EYE_PATTERN 6 +#define UDC_TEST_MODE_NOT_ENABLED 0 + +/*Define the USB register bit value*/ +/* USB device commmand/status register - 20*/ +#define USBREG_RUNCONTROLLER 0x01 /* set the controller run*/ +#define USBREG_RESETCONTROLLER 0x02 /* reset the device contrller*/ +#define USBREG_COMPLETEINT 0x04 /* the completion interrupt*/ +#define USBREG_BABBLEINT 0x08 /* the babble interrupt*/ +#define USBREG_BUSACTINT 0x10 /* the bus activity interrupt*/ +#define USBREG_TEST_J 0x20 /* set test J state*/ +#define USBREG_TEST_K 0x40 /* set test k state*/ +#define USBREG_SE0_NAK 0x60 /* set test SE0 and NAK*/ +#define USBREG_TESTPACKET 0x80 /* set device sending test packet*/ +#define USBREG_FORCEENABLE 0xA0 /* force port enable*/ +#define USBREG_TESTEYE 0xC0 /* Send test eye pattern packet*/ + +/* The device address register - 21*/ +#define DEVADDR_ADDRCHANGE 0x80 /* the address change bit for device address register*/ + +/* Device port control register - 22*/ +#define PORTCTRL_CONNECTSTATUS 0x01 /* current connection status*/ +#define PORTCTRL_CONNECTCHANGE 0x02 /* connection change bit*/ +#define PORTCTRL_SELFPOWER 0x04 /* the device is in the self power configuration*/ +#define PORTCTRL_FORCERESUME 0x08 /* force deivce to wake the host*/ +#define PORTCTRL_HIGHSPEEDMODE 0x10 /* device is in the high speed mode*/ +#define PORTCTRL_FULLSPEEDMODE 0x20 /* device is in the full speed mode*/ + +/* Device itnerrupt enable register - 23*/ +#define INTENABLE_DEVICERESET 0x01 /* this bit is set when the bus reset is completed*/ +#define INTENABLE_SUSPENDDETECT 0x02 /* device controller detect the suspend signal*/ +#define INTENABLE_RESUMEDETECT 0x04 /* device controller detect the resume signal*/ +#define INTENABLE_COMPLETEINTEN 0x10 /* enable completion interrupt*/ +#define INTENABLE_BABBLEINTEN 0x20 /* enable babble interrupt*/ +#define INTENABLE_BUSACTINTEN 0x40 /* enable bus activity interrupt*/ +#define INTENABLE_ALL 0x70 /* enable all interrupt */ +#define INTENABLE_FULLSPEEDONLY 0x80 /* force device to support full speed only*/ + +/* Control endpoint control - 24*/ +/* Bulk endpoint control - 28*/ +/* Interrupt endpoint control - 2C*/ +/* Bulk endpoint control - 0x310*/ +#define EP_RUN 0x01 /* run the enpoint DMA*/ +#define EP_ENABLEDMA 0x02 /* enable the DMA engine to run the schedule*/ +#define EP_DMALIGHTRESET 0x04 /* light reset the DMA engine*/ +#define EP_STALL 0x08 /* set the endpoint to stall*/ +#define EP_ACTIVE 0x10 /* the endpoint DMA is active*/ +#define EP_COMPLETEINT 0x20 /* endpoint transfer complete interrupt*/ +#define EP_BABBLE 0x40 /* endpoint babble interrupt*/ + +/* Control transfer descriptor status byte - 30*/ +#define CTRLXFER_XACTERR 0x01 /* trnasacion error of control transfer*/ +#define CTRLXFER_BABBLE 0x02 /* babbe error of control transfer*/ +#define CTRLXFER_SHORTPKT 0x04 /* shortpacket detect of control transfer*/ +#define CTRLXFER_ACTIVE 0x08 /* transfer active of control transfer*/ + +#define CTRLXFER_IN 0x08 /* I/O control bit 0 for OUT , 1 for In*/ +#define CTRLXFER_OUT 0x00 /**/ +#define CTRLXFER_CMDVALID 0x10 /* setup command is valid*/ +#define CTRLXFER_IOC 0x80 /* determine to gen interrupt for completion or not*/ +#define CTRLXFER_DATA1 0x80 /* for data_toggle 1*/ +#define CTRLXFER_DATA0 0x00 /* for data_toggle 0*/ + +/* Bulk endpoint transfer descriptor status - 34*/ +/* Bulk endpoint transfer descriptor status - 0x314 */ +#define BULKXFER_XACTERR 0x01 /* trnasacion error of bulk transfer*/ +#define BULKXFER_BABBLE 0x02 /* babbe error of bulk transfer*/ +#define BULKXFER_SHORTPKT 0X04 /* shortpacket detect of bulk transfer*/ +#define BULKXFER_ACTIVE 0x08 /* transfer active of bulk transfer*/ +#define BULKXFER_IN 0x10 /* I/O control bit 0 for OUT , 1 for In*/ +#define BULKXFER_OUT 0x00 +/*HP05_Begin*/ +#define BULKXFER_CBWBUF 0x20 /* enable CBW dedicated buffer*/ +/*HP05_End*/ +#define BULKXFER_IOC 0x80 /* determine to generate interrupt for completion or not*/ +#define BULKXFER_DATA1 0x80 /* for data_toggle 1*/ +#define BULKXFER_DATA0 0x00 /* for data_toggle 0*/ + +/* Interupt endpoint transfer descriptor - 33*/ +#define INTXFER_XACTERR 0x01 /* trnasacion error for interrupt transfer*/ +#define INTXFER_ACTIVE 0x02 /* transfer active*/ +#define INTXFER_IOC 0x04 /* determine to generate interrupt for completion or not*/ +#define INTXFER_DATA1 0x08 /* for data_toggle 1*/ +#define INTXFER_DATA0 0x00 /* for data_toggle 0*/ + +/*UDC 0x400 ~ 0x7FF*/ +struct UDC_REGISTER{ + UCHAR Reserved0[0x20]; /* 0x00~0x19 Reserved 0*/ + UCHAR CommandStatus; /* USB device commmand/status register - 20*/ + UCHAR DeviceAddr; /* The device address register - 21*/ + + UCHAR PortControl; /* Device port control register - 22*/ + UCHAR IntEnable; /* Device itnerrupt enable register - 23*/ + + UCHAR ControlEpControl; /* Control endpoint control - 24*/ + UCHAR ControlEpReserved; /* Control endpoint reserved byte - 25*/ + UCHAR ControlEpMaxLen; /* max length of control endpoint - 26*/ + UCHAR ControlEpEpNum; /* The control endpoint number - 27*/ + + UCHAR Bulk1EpControl; /* Bulk endpoint control - 28*/ + UCHAR Bulk1EpOutEpNum; /* Bulk out endpoint number - 29*/ + UCHAR Bulk1EpMaxLen; /* Bulk maximum length - 2A*/ + UCHAR Bulk1EpInEpNum; /* Bulk In endpoint number - 2B*/ + + UCHAR InterruptEpControl; /* Interrupt endpoint control - 2C*/ + UCHAR InterruptReserved; /* Interrupt endpoint reserved byte - 2D*/ + UCHAR InterruptEpMaxLen; /* Interrupt maximum transfer length - 2E*/ + UCHAR InterruptEpEpNum; /* interrupt endpoint number - 2F*/ + + UCHAR ControlDesStatus; /* Control transfer descriptor status byte - 30*/ + UCHAR ControlDesControl; /* Control transfer descriptor control byte - 31*/ + UCHAR ControlDesTbytes; /* Control transfer descriptor total bytes - 32*/ + + UCHAR InterruptDes; /* Interupt endpoint transfer descriptor - 33*/ + + UCHAR Bulk1DesStatus; /* Bulk endpoint transfer descriptor status - 34*/ + UCHAR Bulk1DesTbytes0; /* Bulk endpoint transfer descriptor control - 35*/ + UCHAR Bulk1DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 36*/ + UCHAR Bulk1DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 37*/ + + UCHAR MacToParameter; /* USB2.0 MAC timeout parameter register - 38*/ + UCHAR PhyMisc; /* PHY misc control register - 39*/ + UCHAR MiscControl0; /* Misc. control register 0 - 3A*/ + UCHAR MiscControl1; /* Misc. control register 1 - 3B*/ + UCHAR MiscControl2; /* Misc. control register 2 - 3C*/ + UCHAR MiscControl3; /* Misc. control register 3 - 3D*/ + UCHAR MACDelay; /* MAC receiver enable delay parameter - 3E*/ + UCHAR FunctionPatchEn; /* Function Patch Enable bits - 3F*/ + + UCHAR InterruptInBuf[32]; /* Interrupt In Endpoint Data Buffer - 40 ~ 5F (32 bytes) for CBW(31 bytes)*/ + + UCHAR Reserved1[0x2A0]; /* 0x060~0x2FF ; 0x2FF - 0x60 + 1 = 0x2A0 for Bulk Endpoint 01 02 DMA Source / Destination*/ + UCHAR SetupCommand[8]; /* 0x300~0x307 */ + UCHAR PHYControlBit; /* 0x308 Phy Control Bit */ + UCHAR Reserved2[2]; /* 0x309 ~ 0x30A*/ + UCHAR NewUSBPhyTestControl;/* 0x30B New USB 1.1 and USB 2.0 PHY test control bit*/ + UCHAR NewUSBPhyTestStatus; /* 0x30C New USB 1.1 and USB 2.0 PHY test status bit*/ + UCHAR SelfPowerConnect; /* 0x30D Debug pins for USBC side control bit*/ + + UCHAR Reserved3[2]; /* 0x30E ~ 0x30F*/ + + UCHAR Bulk2EpControl; /* Bulk endpoint control - 0x310*/ + UCHAR Bulk2EpOutEpNum; /* Bulk out endpoint number - 0x311*/ + UCHAR Bulk2EpMaxLen; /* Bulk maximum length - 0x312*/ + UCHAR Bulk2EpInEpNum; /* Bulk In endpoint number - 0x313*/ + + UCHAR Bulk2DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ + UCHAR Bulk2DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ + UCHAR Bulk2DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ + UCHAR Bulk2DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ + + UCHAR Bulk3EpControl; /* Bulk endpoint control - 0x310*/ + UCHAR Bulk3EpOutEpNum; /* Bulk out endpoint number - 0x311*/ + UCHAR Bulk3EpMaxLen; /* Bulk maximum length - 0x312*/ + UCHAR Bulk3EpInEpNum; /* Bulk In endpoint number - 0x313*/ + + UCHAR Bulk3DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ + UCHAR Bulk3DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ + UCHAR Bulk3DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ + UCHAR Bulk3DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ + + UCHAR Reserved4[0x20]; /*0x318 ~ 0x33F ; 0x33F - 0x318 + 1 = 0x28*/ + + UCHAR ControlDataBuf[64]; /*0x340~0x37F Control Endpoint Data Buffer */ +}__attribute__((packed)); + +/*DMA_Context_Control*/ +/*1:IF0-->peripheral 0:peripher-->IF0*/ +#define DMA_TRANS_OUT_DIR 0x00400000 +/*1:Run 0:Stop Scheduled*/ +#define DMA_RUN 0x00000080 + +/*DMA Interrupt Enable*/ +/*enable interfac 0 interrupt*/ +#define DMA_INTERRUPT_ENABLE0 0x00000001 +/*enable interfac 1 interrupt*/ +#define DMA_INTERRUPT_ENABLE1 0x00000002 +/*enable interfac 2 interrupt*/ +#define DMA_INTERRUPT_ENABLE2 0x00000010 + +/*enable interfac 0 status*/ +#define DMA_INTERRUPT_STATUS0 0x00000001 +/*enable interfac 1 status*/ +#define DMA_INTERRUPT_STATUS1 0x00000002 +/*enable interfac 2 status*/ +#define DMA_INTERRUPT_STATUS2 0x00000004 + +struct UDC_DMA_REG { + union { /*Rx00 - DMA Global Register (0x100~0x103)*/ + UINT DMA_Global; + struct { + UINT DMAConrollerEnable:1; + UINT Reserved0:7; + UINT SoftwareReset:1; + UINT SoftwareReset0:1; + UINT SoftwareReset1:1; + UINT SoftwareReset2:1; + UINT Reserved1:20; + } DMA_Global_Bits; + }; + + union { /*Rx04 - DMA Interrupt Enable (0x104~x107)*/ + UINT DMA_IER; + struct { + UINT DMAInterruptEnable0:1; + UINT DMAInterruptEnable1:1; + UINT Reserved:2; + UINT DMAInterruptEnable2:1; + UINT Reserved1:27; + } DMA_IER_Bits; + }; + + union { /*Rx08 - DMA Interrupt Status Register (0x108~0x10b)*/ + UINT DMA_ISR; + struct { + UINT InterruptStatus0:1; + UINT InterruptStatus1:1; + UINT InterruptStatus2:1; + UINT Reserved:29; + } DMA_ISR_Bits; + }; + + /*Interface 0*/ + union {/*Rx10c - DMA Memory-Descriptor Point Register dor Interdace 0 (0x10c~0x10f)*/ + UINT DMA_Descriptor_Point0; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point0_Bits; + }; + + union { /*Rx110 - DMA Residual Bytes Register for Interface 0 (Rx110~Rx103)*/ + UINT DMA_Residual_Bytes0; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes0_Bits; + }; + + /*Rx114 - DMA Data Address Register for Interface 0 (0x114~0x117)*/ + UINT DMA_Data_Addr0; + + union {/*Rx118 DMA Branch Address Register for INterface 0(0x118~0x11b)*/ + UINT DMA_Branch_Addr0; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr0_Bits; + }; + + union {/*Rx11c DMA command Pointer Register for Interrface 0(0x11c~0x11f)*/ + UINT Descriptor_Addr0; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr0_Bits; + }; + + union {/*Rx120 DMA Context Control Register for Interfaxe 0(0x120~0x123)*/ + UINT DMA_Context_Control0; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control0_Bis; + }; + + /*Interface 1*/ + union {/*Rx124 - DMA Memory-Descriptor Point Register dor Interdace 1 (0x124~0x127)*/ + UINT DMA_Descriptor_Point1; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point1_Bits; + }; + + union { /*Rx128 - DMA Residual Bytes Register for Interface 1 (Rx128~Rx12b)*/ + UINT DMA_Residual_Bytes1; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes1_Bits; + }; + + /*Rx12c - DMA Data Address Register for Interface 1 (0x12c~0x12f)*/ + UINT DMA_Data_Addr1; + + union {/*Rx130 DMA Branch Address Register for INterface 10(0x130~0x133)*/ + UINT DMA_Branch_Addr1; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr1_Bits; + }; + + union {/*Rx134 DMA command Pointer Register for Interrface 1(0x134~0x137)*/ + UINT Descriptor_Addr1; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr1_Bits; + }; + + union {/*Rx138DMA Context Control Register for Interfaxe 1(0x138~0x13b)*/ + UINT DMA_Context_Control1; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control1_Bis; + }; + + /*Interface 2*/ + union {/*Rx13c - DMA Memory-Descriptor Point Register dor Interdace 2 (0x10c~0x10f)*/ + UINT DMA_Descriptor_Point2; + struct { + UINT Reserved:2; + UINT DesBaseAddr:30; + } DMA_Descriptor_Point2_Bits; + }; + + union { /*Rx140 - DMA Residual Bytes Register for Interface 2 (Rx110~Rx103)*/ + UINT DMA_Residual_Bytes2; + struct { + UINT ResidualBytes:16; + UINT IntEn:1; + UINT Reseved:13; + UINT Format:1; + UINT End:1; + } DMA_Residual_Bytes2_Bits; + }; + + /*Rx144 - DMA Data Address Register for Interface 2 (0x144~0x147)*/ + UINT DMA_Data_Addr2; + + union {/*Rx148 DMA Branch Address Register for INterface 2(0x148~0x14b)*/ + UINT DMA_Branch_Addr2; + struct { + UINT Reserved:4; + UINT BranchDesxriptorAddress:28; + } DMA_Branch_Addr2_Bits; + }; + + union {/*Rx14c DMA command Pointer Register for Interrface 2(0x14c~0x14f)*/ + UINT Descriptor_Addr2; + struct { + UINT Reserved:4; + UINT DescriptorAddr:28; + } Descriptor_Addr2_Bits; + }; + + union {/*Rx150 DMA Context Control Register for Interfaxe 2(0x150~0x153)*/ + UINT DMA_Context_Control2; + struct { + UINT EventCode:4; + UINT Reserved0:3; + UINT Run:1; + UINT Active:1; + UINT P0Cmpl:1; + UINT Reserved1:2; + UINT Prot:4; + UINT Reserved2:6; + UINT TransDir:1; + UINT Reserved3:9; + } DMA_Context_Control2_Bis; + }; + +}__attribute__((packed)); + +#define DESCRIPTOT_TYPE_SHORT 0 +#define DESCRIPTOT_TYPE_LONG 1 +#define DESCRIPTOT_TYPE_MIX 2 + +#define TRANS_OUT 1 +#define TRANS_IN 0 + +#define DES_L_SIZE 0x10 +#define DES_S_SIZE 0x4 + + +/* + * PDMA Descriptor short + */ +struct _UDC_PDMA_DESC_S { + union { + UINT D_Word0; + struct { + UINT ReqCount:16; /* bit 0 -15 -Request count*/ + UINT i:1; /* bit 16 -interrupt*/ + UINT Reserved:13; + UINT Format:1; /* bit 30 -The descriptor format*/ + UINT End:1; /* bit 31-End flag of descriptor list*/ + } D_Word0_Bits; + }; + + UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ +}__attribute__((packed)); + +/* + * PDMA Descriptor long + */ + +struct _UDC_PDMA_DESC_L { + union { + UINT D_Word0; + struct { + UINT ReqCount:16; /* bit 0 -15-Request count*/ + UINT i:1; /* bit 16-interrupt*/ + UINT Reserved:13; + UINT Format:1; /* bit 30-The descriptor format*/ + UINT End:1; /* bit 31-End flag of descriptor list*/ + } D_Word0_Bits; + }; + + UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ + + union { + UINT Branch_addr; + struct { + UINT Reserved:2; + UINT BranchAddr:30; /* bit 31-2 -Descriptor Branch address*/ + } Branch_addr_Bits; + }; + + UINT Reserve0; +}__attribute__((packed)); + +/*Rx00 - UHDC Interrupt Status Register*/ +#define UHDC_INT_UDC 0x0300 +//#define UHDC_INT_UDC_DMA2 0x0400 +#define UHDC_INT_UDC_DMA1 0x0200 +#define UHDC_INT_UDC_CORE 0x0100 + +#ifdef OTGIP +/*UHDC Global Register Space : 0x7F0~0x7F7*/ +struct USB_GLOBAL_REG { + union { /*Rx00 - UHDC Interrupt Status Register*/ + USHORT UHDC_Interrupt_Status; + struct { + USHORT EHCIInt:1; /* [0] EHCI Interrupt bit*/ + USHORT UHCIInt:1; /* [1] UHCI Interrupt bit*/ + USHORT Reserved0:6; /* reserved for future use*/ + USHORT UDCCoreInt:1; /* [8] UDC Core Interrupt bit(IOC/Babble/Bus Activity)*/ + USHORT UDCDMA1Int:1; /* [9] DMA1 Interrupt bit (Bulk Transfer)*/ + USHORT UDCDMA2Int:1; /* [10] DMA2 Interrupt bit (Bulk Transfer)*/ + USHORT Reserved1:5; /* reserved for future use*/ + } UHDC_Interrupt_Status_Bits; + }; + + union { /*Rx01 - UHDC ID Status Register*/ + UCHAR UHDC_ID_Status; + struct { + UCHAR DualRoleID:1; /* Dual-Role USB Controller ID Value*/ + UCHAR Reserved:7; /* reserved for future use*/ + } UHDC_ID_Status_Bits; + }; + + union { /*Rx02 - UHDC Offchip Power Control Register*/ + UCHAR UHDC_OffChip_PowerControl; + struct { + UCHAR PowerSupplyMode:1; /* Power Supply Mode Select (1)SW mode (0)HW mode*/ + UCHAR PowerSupplySWEn:1; /* Power Supply SW Mode Enable bit */ + UCHAR Reserved:6; /* reserved for future use */ + } UHDC_OffChip_PowerControl_Bits; + }; + + union { /*Rx03 - UHDC Clock Reset Control Register*/ + USHORT UHDC_Clock_Reset_Control; + struct { + USHORT AHBClkGatingEn:1; /* [0] AHB clock Gating Enable bit*/ + USHORT HCSuspendClkGatingEn:1; /* [1] Host Controller Suspend Clock Gating Enable bit*/ + USHORT DCSuspendClkGatingEn:1; /* [2] Device Controller Suspend Clock Gating Enable bit*/ + USHORT DataReceivingClkGatingEn:1;/* [3] Controller Data-Receiving Clock Gating Enable bit*/ + USHORT Phy120MClkGatingEn:1; /* [4] Phy 120M Clock Gating Enable bit*/ + USHORT Phy60MClkGatingEn:1; /* [5] Phy 60M Clock Gating Enable bit*/ + USHORT Phy48MClkGatingEn:1; /* [6] Phy 48M Clock Gating Enable bit */ + USHORT Reserved0:1; /* [7] reserved for future use*/ + USHORT AHBResetGatingEn:1; /* [8] AHB Bus Reset Gating Enable bit*/ + USHORT PowerOnResetGatingEn:1; /* [9] Power-on Reset Gating Enable bit */ + USHORT Reserved1:6; /* [15:10] reserved for future use*/ + } UHDC_Clock_Reset_Control_Bits; + }; + + union { /*Rx04 - UHDC Pullup/Pulldown Control Register*/ + USHORT UHDC_Pull_Up_Down_Control; + struct { + USHORT PullUpDownSWControlEn:1; /* [0] Pullup/Pulldown SW Control Enable bit*/ + USHORT DPLinePullUpEn:1; /* [1] DP Line Pullup Enable bit*/ + USHORT DPLinePullDownEn:1; /* [2] DP Line Pulldown Enable bit*/ + USHORT DMLinePullDownEn:1; /* [3] DM Line Pulldown Enable bit*/ + USHORT HSTerminationRegisterEn:1; /* [4] High Speed Termination Register On bit*/ + USHORT Reserved1:11; /* [15:5] reserved for future use*/ + } UHDC_Pull_Up_Down_Control_Bits; + }; +}__attribute__((packed)); +#endif + +#define UDC_FULL_SPEED 0 +#define UDC_HIGH_SPEED 1 +/* Define the setup command buffer*/ + +#define MAX_TRANSFER_LENGTH 0x200 /* original is 0x20000, shift 16bits for minimum block size is 0x200*/ +/*HP04_End*/ + +/* Define the interrupt transfer buffer*/ +#define INTBUFFERSTART 0x308 /* the start byte of interrupt transfer buffer*/ +#define INTBUFFEREND 0x30F /* the last byte of interrupt transfer buffer*/ +#define INTBUFFERSIZE 0x08 /* the size of the interrupt transfer buffer*/ + +/* Define the control endpoint buffer*/ +#define CONTROLBUFFERSTART 0x340 /* the start byte of the control data buffer*/ +#define CONTROLBUFFEREND 0x37F /* the last byte of the control data buffer*/ +#define CONTROLBUFFERSIZE 0x40 /* the size of the control data buffer*/ + +/* Define the bulk transfer buffer*/ +#define BULKBUFFERSTART 0x800 /* the start byte of the bulk transfer buffer*/ +#define BULKBUFFEREND 0xFFF /* the last byte of the bulk transfer buffer*/ +#define BULKBUFFERSIZE 0x800 /* the size of the bulk transfer buffer*/ + +/* define the endpoint number for each endpoint*/ +#define BULKINEPNUM 0x01 +/*HP01_begin*/ +#define BULKOUTEPNUM 0x02 +/*HP01_End*/ +#define INTEPNUM 0x03 +#define MAXEPNUM 0x04 +/* define the structure of string table for default strings and vendor specified strings*/ + +/* define the IO state of USB to handle */ +#define IOSTATE_CBWIDLE 0x00 /* usb is idle and set the 8051 clock to stop*/ +#define IOSTATE_ACCEPTCBW 0x01 /* the usb accept a new CBW*/ +#define IOSTATE_DEVICEPREPAREIO 0x02 /* the state will call deivce startio to prepare IO*/ +#define IOSTATE_STARTIO 0x03 /* the CBW send to device to start IO operation*/ +#define IOSTATE_CSW 0x04 /* the state to send CSW back to host*/ +#define IOSTATE_CSWCOMPLETE 0x05 /* the CSW is returned, maybe need some more process*/ +#define IOSTATE_TIMEOUT 0x06 /* the IO is hang to long and it is timeout*/ +#define IOSTATE_FWDOWNLOAD 0x07 /* Download the new firmware.*/ +#define IOSTATE_WAITFORCBW 0x08 /* In this state, the controller is waiting for CBW*/ +#define IOSTATE_CSWIDLE 0x09 /* the idle state for wait for CSW complete, 8051 will stopped*/ + +/*VT3214 Define */ +/* define the state of Control endpoint*/ +#define CONTROLSTATE_SETUP 0x00 /* the control endpoint is in the Setup state*/ +#define CONTROLSTATE_DATA 0x01 /* the control endpoint is in the Data state*/ +#define CONTROLSTATE_STATUS 0x02 /* the control endpoint is in the Status state*/ + + +/* VT3300 PACK Size Defination*/ +#define UCE_MAX_DMA ((unsigned)64) +#define UIE_MAX_DMA ((unsigned)8) +#define UBE_MAX_DMA ((unsigned)0x20000) /* max length = 128K */ +#define EP0_FIFO_SIZE ((unsigned)64) +#define BULK_FIFO_SIZE ((unsigned)512) +#define INT_FIFO_SIZE ((unsigned)8) + +/* Define the setup command buffer*/ +typedef struct _SETUP_COMMAND +{ +unsigned char RequestType; /* the Request type of the SETUP command*/ +unsigned char Request; /* the Request code of the SETUP command*/ +unsigned char ValueLow; /* the lower value field of the SETUP command*/ +unsigned char ValueHigh; /* the higher value field of the SETUP command*/ +unsigned char IndexLow; /* the lower index field of the SETUP command*/ +unsigned char IndexHigh; /* the higher index field of the SETUP command*/ +unsigned char LengthLow; /* the lower length field of the SETUP command*/ +unsigned char LengthHigh; /* the higher length field of the SETUP command*/ +} SETUPCOMMAND, *PSETUPCOMMAND; + + + +struct vt8500_ep { + struct usb_ep ep; + struct list_head queue; + unsigned long irqs; + const struct usb_endpoint_descriptor *desc; + char name[14]; + u16 maxpacket; + u8 bEndpointAddress; + u8 bmAttributes; + unsigned double_buf:1; + unsigned stopped:1; + unsigned fnf:1; + unsigned has_dma:1; + unsigned toggle_bit:1; + unsigned stall:1; + unsigned rndis:1; + u8 ackwait; + /*u8 dma_channel;*/ + u32 dma_counter; + /*int lch;*/ + struct vt8500_udc *udc; + struct timer_list timer; + /*volatile u32 *reg_payload_addr;*/ + /*volatile u32 *reg_control_status;*/ + /*volatile u32 *reg_irp_descriptor;*/ + + /*volatile u32 temp_payload_addr;*/ + /*volatile u32 temp_control_status;*/ + + volatile u32 temp_buffer_address; + volatile u32 temp_dma_phy_address; + volatile u32 temp_buffer_address2; + volatile u32 temp_dma_phy_address2; + + /*volatile u32 temp_req_length;*/ + /*volatile u32 temp_irp_descriptor; */ + volatile u32 rndis_buffer_address; + volatile u32 rndis_dma_phy_address; + unsigned int rndis_buffer_length; + unsigned int rndis_buffer_alloc ; + + /*processing stall and clear stall.*/ + volatile u32 stall_more_processing; + volatile u32 temp_dcmd; + volatile u32 temp_dma_ccr; + volatile u32 temp_bulk_dma_addr; + volatile u32 ep_stall_toggle_bit; + volatile u32 ep_fifo_length; + +}__attribute__((packed)); + +struct vt8500_req { + struct usb_request req; + struct list_head queue; + unsigned dma_bytes; + struct vt8500_ep *ep; + struct list_head mem_list; /* sw qtd list */ + unsigned mapped:1; +}__attribute__((packed)); + + +struct vt8500_udc { + struct device *dev; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + spinlock_t lock; +// struct vt8500_ep ep[5]; + struct vt8500_ep ep[7];//gri + u16 devstat; + u16 ep0_in_status; + volatile u32 cbw_virtual_address; + /*volatile u32 ep3_virtual_address; */ + struct usb_phy *transceiver; + unsigned softconnect:1; + unsigned vbus_active:1; + unsigned ep0_pending:1; + unsigned ep0_in:1; + unsigned ep0_set_config:1; + unsigned ep0_reset_config:1; + unsigned ep0_setup:1; + unsigned ep0_status_0_byte:1; + unsigned usb_connect:1; + unsigned file_storage_set_halt:1; + unsigned bulk_out_dma_write_error:1; + unsigned int chip_version; + struct completion *done; + u8 setup_command[8]; + struct timer_list timer; +}__attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +//#define DEBUG +//#define VERBOSE + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_INFO "udc: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) +//#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + +#define USB_BULK_RESET_REQUEST 0xff +/*--------------------------------------------------------------------*/ + +/*static void vt8500_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp);*/ +/*static void vt8500_udc_csr(struct vt8500_udc *udc);*/ + +#endif /* __LINUX_USB_GADGET_VT8500_H */ |