USB: serial gadget: simplify endpoint handling
[safe/jmp/linux-2.6] / drivers / usb / gadget / serial.c
index 65e084a..0829027 100644 (file)
  * This software is distributed under the terms of the GNU General
  * Public License ("GPL") as published by the Free Software Foundation,
  * either version 2 of that License or (at your option) any later version.
- *
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
-
-#include <linux/usb_ch9.h>
-#include <linux/usb_cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
-/* Wait Cond */
-
-#define __wait_cond_interruptible(wq, condition, lock, flags, ret)     \
-do {                                                                   \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       schedule();                                     \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible(wq, condition, lock, flags)            \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible(wq, condition, lock, flags,   \
-                                               __ret);                 \
-       __ret;                                                          \
-})
-
-#define __wait_cond_interruptible_timeout(wq, condition, lock, flags,  \
-                                               timeout, ret)           \
-do {                                                                   \
-       signed long __timeout = timeout;                                \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (__timeout == 0)                                     \
-                       break;                                          \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       __timeout = schedule_timeout(__timeout);        \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible_timeout(wq, condition, lock, flags,    \
-                                               timeout)                \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible_timeout(wq, condition, lock,  \
-                                               flags, timeout, __ret); \
-       __ret;                                                          \
-})
-
-
 /* Defines */
 
-#define GS_VERSION_STR                 "v2.0"
-#define GS_VERSION_NUM                 0x0200
+#define GS_VERSION_STR                 "v2.2"
+#define GS_VERSION_NUM                 0x0202
 
 #define GS_LONG_NAME                   "Gadget Serial"
 #define GS_SHORT_NAME                  "g_serial"
@@ -134,7 +40,11 @@ do {                                                                        \
 #define GS_MAJOR                       127
 #define GS_MINOR_START                 0
 
-#define GS_NUM_PORTS                   16
+/* REVISIT only one port is supported for now;
+ * see gs_{send,recv}_packet() ... no multiplexing,
+ * and no support for multiple ACM devices.
+ */
+#define GS_NUM_PORTS                   1
 
 #define GS_NUM_CONFIGS                 1
 #define GS_NO_CONFIG_ID                        0
@@ -158,35 +68,37 @@ do {                                                                       \
 
 #define GS_DEFAULT_USE_ACM             0
 
+/* 9600-8-N-1 ... matches init_termios.c_cflag and defaults
+ * expected by "usbser.sys" on MS-Windows.
+ */
 #define GS_DEFAULT_DTE_RATE            9600
 #define GS_DEFAULT_DATA_BITS           8
 #define GS_DEFAULT_PARITY              USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT         USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
-
-#define gs_debug(format, arg...) \
-       do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
-#define gs_debug_level(level, format, arg...) \
-       do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
-
 #else
+#define        debug 0
+#endif
 
 #define gs_debug(format, arg...) \
-       do { } while(0)
+       do { if (debug) pr_debug(format, ## arg); } while (0)
 #define gs_debug_level(level, format, arg...) \
-       do { } while(0)
+       do { if (debug >= level) pr_debug(format, ## arg); } while (0)
 
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -201,10 +113,6 @@ static int debug = 1;
 #define GS_NOTIFY_MAXPACKET            8
 
 
-/* Structures */
-
-struct gs_dev;
-
 /* circular buffer */
 struct gs_buf {
        unsigned int            buf_size;
@@ -213,23 +121,20 @@ struct gs_buf {
        char                    *buf_put;
 };
 
-/* list of requests */
-struct gs_req_entry {
-       struct list_head        re_entry;
-       struct usb_request      *re_req;
-};
-
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-       struct gs_dev           *port_dev;      /* pointer to device struct */
+       struct gs_dev           *port_dev;      /* pointer to device struct */
        struct tty_struct       *port_tty;      /* pointer to tty struct */
        spinlock_t              port_lock;
-       int                     port_num;
+       int                     port_num;
        int                     port_open_count;
        int                     port_in_use;    /* open/close in progress */
        wait_queue_head_t       port_write_wait;/* waiting to write */
        struct gs_buf           *port_write_buf;
-       struct usb_cdc_line_coding      port_line_coding;
+       struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
+       u16                     port_handshake_bits;
+#define RS232_RTS      (1 << 1)
+#define RS232_DTE      (1 << 0)
 };
 
 /* the device structure holds info for the USB device */
@@ -255,26 +160,7 @@ struct gs_dev {
 
 /* Functions */
 
-/* module */
-static int __init gs_module_init(void);
-static void __exit gs_module_exit(void);
-
-/* tty driver */
-static int gs_open(struct tty_struct *tty, struct file *file);
-static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
-       const unsigned char *buf, int count);
-static void gs_put_char(struct tty_struct *tty, unsigned char ch);
-static void gs_flush_chars(struct tty_struct *tty);
-static int gs_write_room(struct tty_struct *tty);
-static int gs_chars_in_buffer(struct tty_struct *tty);
-static void gs_throttle(struct tty_struct * tty);
-static void gs_unthrottle(struct tty_struct * tty);
-static void gs_break(struct tty_struct *tty, int break_state);
-static int  gs_ioctl(struct tty_struct *tty, struct file *file,
-       unsigned int cmd, unsigned long arg);
-static void gs_set_termios(struct tty_struct *tty, struct termios *old);
-
+/* tty driver internals */
 static int gs_send(struct gs_dev *dev);
 static int gs_send_packet(struct gs_dev *dev, char *packet,
        unsigned int size);
@@ -283,30 +169,16 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet,
 static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);
 static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);
 
-/* gadget driver */
-static int gs_bind(struct usb_gadget *gadget);
-static void gs_unbind(struct usb_gadget *gadget);
-static int gs_setup(struct usb_gadget *gadget,
-       const struct usb_ctrlrequest *ctrl);
-static int gs_setup_standard(struct usb_gadget *gadget,
-       const struct usb_ctrlrequest *ctrl);
-static int gs_setup_class(struct usb_gadget *gadget,
-       const struct usb_ctrlrequest *ctrl);
-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
-static void gs_disconnect(struct usb_gadget *gadget);
+/* gadget driver internals */
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
                u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
        gfp_t kmalloc_flags);
 static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
 
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
-       gfp_t kmalloc_flags);
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
-
 static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);
 static void gs_free_ports(struct gs_dev *dev);
 
@@ -321,65 +193,15 @@ static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf,
 static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
        unsigned int count);
 
-/* external functions */
-extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);
-
 
 /* Globals */
 
 static struct gs_dev *gs_device;
 
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_NOTIFY_NAME;
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
-static struct semaphore        gs_open_close_sem[GS_NUM_PORTS];
-
-static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
-static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
-
-static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
-
-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
-
-
-/* tty driver struct */
-static struct tty_operations gs_tty_ops = {
-       .open =                 gs_open,
-       .close =                gs_close,
-       .write =                gs_write,
-       .put_char =             gs_put_char,
-       .flush_chars =          gs_flush_chars,
-       .write_room =           gs_write_room,
-       .ioctl =                gs_ioctl,
-       .set_termios =          gs_set_termios,
-       .throttle =             gs_throttle,
-       .unthrottle =           gs_unthrottle,
-       .break_ctl =            gs_break,
-       .chars_in_buffer =      gs_chars_in_buffer,
-};
-static struct tty_driver *gs_tty_driver;
-
-/* gadget driver struct */
-static struct usb_gadget_driver gs_gadget_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       .speed =                USB_SPEED_HIGH,
-#else
-       .speed =                USB_SPEED_FULL,
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-       .function =             GS_LONG_NAME,
-       .bind =                 gs_bind,
-       .unbind =               gs_unbind,
-       .setup =                gs_setup,
-       .disconnect =           gs_disconnect,
-       .driver = {
-               .name =         GS_SHORT_NAME,
-               /* .shutdown = ... */
-               /* .suspend = ...  */
-               /* .resume = ...   */
-       },
-};
 
+/*-------------------------------------------------------------------------*/
 
 /* USB descriptors */
 
@@ -492,18 +314,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
 };
 
 static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-       .bLength =              sizeof(gs_call_mgmt_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
-       .bmCapabilities =       0,
-       .bDataInterface =       1,      /* index of data interface */
+       .bLength =              sizeof(gs_call_mgmt_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+       .bmCapabilities =       0,
+       .bDataInterface =       1,      /* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-       .bLength =              sizeof(gs_acm_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
-       .bmCapabilities =       0,
+       .bLength =              sizeof(gs_acm_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+       .bmCapabilities =       (1 << 1),
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -513,7 +335,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
        .bMasterInterface0 =    0,      /* index of control interface */
        .bSlaveInterface0 =     1,      /* index of data interface */
 };
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -559,7 +381,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
        NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -613,94 +434,36 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
        NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 
+/*-------------------------------------------------------------------------*/
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
 
+static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 module_param(read_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
 
+static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
 module_param(write_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
 
+static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
 module_param(write_buf_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
 
+static unsigned int use_acm = GS_DEFAULT_USE_ACM;
 module_param(use_acm, uint, S_IRUGO);
 MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
 
-module_init(gs_module_init);
-module_exit(gs_module_exit);
-
-/*
-*  gs_module_init
-*
-*  Register as a USB gadget driver and a tty driver.
-*/
-static int __init gs_module_init(void)
-{
-       int i;
-       int retval;
-
-       retval = usb_gadget_register_driver(&gs_gadget_driver);
-       if (retval) {
-               printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval);
-               return retval;
-       }
-
-       gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
-       if (!gs_tty_driver)
-               return -ENOMEM;
-       gs_tty_driver->owner = THIS_MODULE;
-       gs_tty_driver->driver_name = GS_SHORT_NAME;
-       gs_tty_driver->name = "ttygs";
-       gs_tty_driver->devfs_name = "usb/ttygs/";
-       gs_tty_driver->major = GS_MAJOR;
-       gs_tty_driver->minor_start = GS_MINOR_START;
-       gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
-       gs_tty_driver->init_termios = tty_std_termios;
-       gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       tty_set_operations(gs_tty_driver, &gs_tty_ops);
-
-       for (i=0; i < GS_NUM_PORTS; i++)
-               sema_init(&gs_open_close_sem[i], 1);
-
-       retval = tty_register_driver(gs_tty_driver);
-       if (retval) {
-               usb_gadget_unregister_driver(&gs_gadget_driver);
-               put_tty_driver(gs_tty_driver);
-               printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval);
-               return retval;
-       }
-
-       printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR);
-       return 0;
-}
-
-/*
-* gs_module_exit
-*
-* Unregister as a tty driver and a USB gadget driver.
-*/
-static void __exit gs_module_exit(void)
-{
-       tty_unregister_driver(gs_tty_driver);
-       put_tty_driver(gs_tty_driver);
-       usb_gadget_unregister_driver(&gs_gadget_driver);
-
-       printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR);
-}
+/*-------------------------------------------------------------------------*/
 
 /* TTY Driver */
 
@@ -714,7 +477,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        struct gs_port *port;
        struct gs_dev *dev;
        struct gs_buf *buf;
-       struct semaphore *sem;
+       struct mutex *mtx;
        int ret;
 
        port_num = tty->index;
@@ -722,7 +485,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
 
        if (port_num < 0 || port_num >= GS_NUM_PORTS) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
+               pr_err("gs_open: (%d,%p,%p) invalid port number\n",
                        port_num, tty, file);
                return -ENODEV;
        }
@@ -730,15 +493,14 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        dev = gs_device;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n",
+               pr_err("gs_open: (%d,%p,%p) NULL device pointer\n",
                        port_num, tty, file);
                return -ENODEV;
        }
 
-       sem = &gs_open_close_sem[port_num];
-       if (down_interruptible(sem)) {
-               printk(KERN_ERR
-               "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+       mtx = &gs_open_close_lock[port_num];
+       if (mutex_lock_interruptible(mtx)) {
+               pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
                        port_num, tty, file);
                return -ERESTARTSYS;
        }
@@ -746,8 +508,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        spin_lock_irqsave(&dev->dev_lock, flags);
 
        if (dev->dev_config == GS_NO_CONFIG_ID) {
-               printk(KERN_ERR
-                       "gs_open: (%d,%p,%p) device is not connected\n",
+               pr_err("gs_open: (%d,%p,%p) device is not connected\n",
                        port_num, tty, file);
                ret = -ENODEV;
                goto exit_unlock_dev;
@@ -756,7 +517,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        port = dev->dev_port[port_num];
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
+               pr_err("gs_open: (%d,%p,%p) NULL port pointer\n",
                        port_num, tty, file);
                ret = -ENODEV;
                goto exit_unlock_dev;
@@ -766,7 +527,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        spin_unlock(&dev->dev_lock);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
+               pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n",
                        port_num, tty, file);
                ret = -EIO;
                goto exit_unlock_port;
@@ -793,8 +554,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
                /* might have been disconnected while asleep, check */
                if (port->port_dev == NULL) {
-                       printk(KERN_ERR
-                               "gs_open: (%d,%p,%p) port disconnected (2)\n",
+                       pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
                        ret = -EIO;
@@ -802,7 +562,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                }
 
                if ((port->port_write_buf=buf) == NULL) {
-                       printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
+                       pr_err("gs_open: (%d,%p,%p) cannot allocate "
+                               "port write buffer\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
                        ret = -ENOMEM;
@@ -815,7 +576,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
        /* might have been disconnected while asleep, check */
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
+               pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n",
                        port_num, tty, file);
                port->port_in_use = 0;
                ret = -EIO;
@@ -833,12 +594,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
 exit_unlock_port:
        spin_unlock_irqrestore(&port->port_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 exit_unlock_dev:
        spin_unlock_irqrestore(&dev->dev_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 }
@@ -846,27 +607,36 @@ exit_unlock_dev:
 /*
  * gs_close
  */
+
+static int gs_write_finished_event_safely(struct gs_port *p)
+{
+       int cond;
+
+       spin_lock_irq(&(p)->port_lock);
+       cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf);
+       spin_unlock_irq(&(p)->port_lock);
+       return cond;
+}
+
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
-       unsigned long flags;
        struct gs_port *port = tty->driver_data;
-       struct semaphore *sem;
+       struct mutex *mtx;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_close: NULL port pointer\n");
+               pr_err("gs_close: NULL port pointer\n");
                return;
        }
 
        gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
 
-       sem = &gs_open_close_sem[port->port_num];
-       down(sem);
+       mtx = &gs_open_close_lock[port->port_num];
+       mutex_lock(mtx);
 
-       spin_lock_irqsave(&port->port_lock, flags);
+       spin_lock_irq(&port->port_lock);
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR
-                       "gs_close: (%d,%p,%p) port is already closed\n",
+               pr_err("gs_close: (%d,%p,%p) port is already closed\n",
                        port->port_num, tty, file);
                goto exit;
        }
@@ -890,12 +660,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        /* wait for write buffer to drain, or */
        /* at most GS_CLOSE_TIMEOUT seconds */
        if (gs_buf_data_avail(port->port_write_buf) > 0) {
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               wait_cond_interruptible_timeout(port->port_write_wait,
-               port->port_dev == NULL
-               || gs_buf_data_avail(port->port_write_buf) == 0,
-               &port->port_lock, flags, GS_CLOSE_TIMEOUT * HZ);
-               spin_lock_irqsave(&port->port_lock, flags);
+               spin_unlock_irq(&port->port_lock);
+               wait_event_interruptible_timeout(port->port_write_wait,
+                                       gs_write_finished_event_safely(port),
+                                       GS_CLOSE_TIMEOUT * HZ);
+               spin_lock_irq(&port->port_lock);
        }
 
        /* free disconnected port on final close */
@@ -915,8 +684,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
                port->port_num, tty, file);
 
 exit:
-       spin_unlock_irqrestore(&port->port_lock, flags);
-       up(sem);
+       spin_unlock_irq(&port->port_lock);
+       mutex_unlock(mtx);
 }
 
 /*
@@ -929,7 +698,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
        int ret;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_write: NULL port pointer\n");
+               pr_err("gs_write: NULL port pointer\n");
                return -EIO;
        }
 
@@ -942,14 +711,14 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
+               pr_err("gs_write: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                ret = -EIO;
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
+               pr_err("gs_write: (%d,%p) port is closed\n",
                        port->port_num, tty);
                ret = -EBADF;
                goto exit;
@@ -974,36 +743,39 @@ exit:
 /*
  * gs_put_char
  */
-static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
 {
        unsigned long flags;
        struct gs_port *port = tty->driver_data;
+       int ret = 0;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_put_char: NULL port pointer\n");
-               return;
+               pr_err("gs_put_char: NULL port pointer\n");
+               return 0;
        }
 
-       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+               port->port_num, tty, ch, __builtin_return_address(0));
 
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
+               pr_err("gs_put_char: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
+               pr_err("gs_put_char: (%d,%p) port is closed\n",
                        port->port_num, tty);
                goto exit;
        }
 
-       gs_buf_put(port->port_write_buf, &ch, 1);
+       ret = gs_buf_put(port->port_write_buf, &ch, 1);
 
 exit:
        spin_unlock_irqrestore(&port->port_lock, flags);
+       return ret;
 }
 
 /*
@@ -1015,7 +787,7 @@ static void gs_flush_chars(struct tty_struct *tty)
        struct gs_port *port = tty->driver_data;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_flush_chars: NULL port pointer\n");
+               pr_err("gs_flush_chars: NULL port pointer\n");
                return;
        }
 
@@ -1024,14 +796,13 @@ static void gs_flush_chars(struct tty_struct *tty)
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR
-                       "gs_flush_chars: (%d,%p) port is not connected\n",
+               pr_err("gs_flush_chars: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
+               pr_err("gs_flush_chars: (%d,%p) port is closed\n",
                        port->port_num, tty);
                goto exit;
        }
@@ -1129,7 +900,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
        struct gs_port *port = tty->driver_data;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_ioctl: NULL port pointer\n");
+               pr_err("gs_ioctl: NULL port pointer\n");
                return -EIO;
        }
 
@@ -1145,10 +916,27 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
 /*
  * gs_set_termios
  */
-static void gs_set_termios(struct tty_struct *tty, struct termios *old)
+static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
 }
 
+static const struct tty_operations gs_tty_ops = {
+       .open =                 gs_open,
+       .close =                gs_close,
+       .write =                gs_write,
+       .put_char =             gs_put_char,
+       .flush_chars =          gs_flush_chars,
+       .write_room =           gs_write_room,
+       .ioctl =                gs_ioctl,
+       .set_termios =          gs_set_termios,
+       .throttle =             gs_throttle,
+       .unthrottle =           gs_unthrottle,
+       .break_ctl =            gs_break,
+       .chars_in_buffer =      gs_chars_in_buffer,
+};
+
+/*-------------------------------------------------------------------------*/
+
 /*
 * gs_send
 *
@@ -1164,10 +952,9 @@ static int gs_send(struct gs_dev *dev)
        unsigned long flags;
        struct usb_ep *ep;
        struct usb_request *req;
-       struct gs_req_entry *req_entry;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_send: NULL device pointer\n");
+               pr_err("gs_send: NULL device pointer\n");
                return -ENODEV;
        }
 
@@ -1177,23 +964,28 @@ static int gs_send(struct gs_dev *dev)
 
        while(!list_empty(&dev->dev_req_list)) {
 
-               req_entry = list_entry(dev->dev_req_list.next,
-                       struct gs_req_entry, re_entry);
-
-               req = req_entry->re_req;
+               req = list_entry(dev->dev_req_list.next,
+                               struct usb_request, list);
 
                len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
                if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
-                       list_del(&req_entry->re_entry);
+                       gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+                                       "0x%2.2x 0x%2.2x ...\n", len,
+                                       *((unsigned char *)req->buf),
+                                       *((unsigned char *)req->buf+1),
+                                       *((unsigned char *)req->buf+2));
+                       list_del(&req->list);
                        req->length = len;
+                       spin_unlock_irqrestore(&dev->dev_lock, flags);
                        if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                               printk(KERN_ERR
+                               pr_err(
                                "gs_send: cannot queue read request, ret=%d\n",
                                        ret);
+                               spin_lock_irqsave(&dev->dev_lock, flags);
                                break;
                        }
+                       spin_lock_irqsave(&dev->dev_lock, flags);
                } else {
                        break;
                }
@@ -1228,9 +1020,7 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size)
        port = dev->dev_port[0];
 
        if (port == NULL) {
-               printk(KERN_ERR
-                       "gs_send_packet: port=%d, NULL port pointer\n",
-                       0);
+               pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0);
                return -EIO;
        }
 
@@ -1271,12 +1061,13 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
        unsigned int len;
        struct gs_port *port;
        int ret;
+       struct tty_struct *tty;
 
        /* TEMPORARY -- only port 0 is supported right now */
        port = dev->dev_port[0];
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n",
+               pr_err("gs_recv_packet: port=%d, NULL port pointer\n",
                        port->port_num);
                return -EIO;
        }
@@ -1284,40 +1075,36 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
        spin_lock(&port->port_lock);
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
+               pr_err("gs_recv_packet: port=%d, port is closed\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
        }
 
-       if (port->port_tty == NULL) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
+
+       tty = port->port_tty;
+
+       if (tty == NULL) {
+               pr_err("gs_recv_packet: port=%d, NULL tty pointer\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
        }
 
        if (port->port_tty->magic != TTY_MAGIC) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
+               pr_err("gs_recv_packet: port=%d, bad tty magic\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
        }
 
-       len = (unsigned int)(TTY_FLIPBUF_SIZE - port->port_tty->flip.count);
-       if (len < size)
-               size = len;
-
-       if (size > 0) {
-               memcpy(port->port_tty->flip.char_buf_ptr, packet, size);
-               port->port_tty->flip.char_buf_ptr += size;
-               port->port_tty->flip.count += size;
+       len = tty_buffer_request_room(tty, size);
+       if (len > 0) {
+               tty_insert_flip_string(tty, packet, len);
                tty_flip_buffer_push(port->port_tty);
                wake_up_interruptible(&port->port_tty->read_wait);
        }
-
        ret = 0;
-
 exit:
        spin_unlock(&port->port_lock);
        return ret;
@@ -1332,18 +1119,18 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
        struct gs_dev *dev = ep->driver_data;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_read_complete: NULL device pointer\n");
+               pr_err("gs_read_complete: NULL device pointer\n");
                return;
        }
 
        switch(req->status) {
        case 0:
-               /* normal completion */
+               /* normal completion */
                gs_recv_packet(dev, req->buf, req->actual);
 requeue:
                req->length = ep->maxpacket;
                if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                       printk(KERN_ERR
+                       pr_err(
                        "gs_read_complete: cannot queue read request, ret=%d\n",
                                ret);
                }
@@ -1357,7 +1144,7 @@ requeue:
 
        default:
                /* unexpected */
-               printk(KERN_ERR
+               pr_err(
                "gs_read_complete: unexpected status error, status=%d\n",
                        req->status);
                goto requeue;
@@ -1371,10 +1158,9 @@ requeue:
 static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct gs_dev *dev = ep->driver_data;
-       struct gs_req_entry *gs_req = req->context;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_write_complete: NULL device pointer\n");
+               pr_err("gs_write_complete: NULL device pointer\n");
                return;
        }
 
@@ -1382,14 +1168,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
        case 0:
                /* normal completion */
 requeue:
-               if (gs_req == NULL) {
-                       printk(KERN_ERR
-                               "gs_write_complete: NULL request pointer\n");
-                       return;
-               }
-
                spin_lock(&dev->dev_lock);
-               list_add(&gs_req->re_entry, &dev->dev_req_list);
+               list_add(&req->list, &dev->dev_req_list);
                spin_unlock(&dev->dev_lock);
 
                gs_send(dev);
@@ -1403,7 +1183,7 @@ requeue:
                break;
 
        default:
-               printk(KERN_ERR
+               pr_err(
                "gs_write_complete: unexpected status error, status=%d\n",
                        req->status);
                goto requeue;
@@ -1411,15 +1191,45 @@ requeue:
        }
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* Gadget Driver */
 
 /*
+ * gs_unbind
+ *
+ * Called on module unload.  Frees the control request and device
+ * structure.
+ */
+static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
+{
+       struct gs_dev *dev = get_gadget_data(gadget);
+
+       gs_device = NULL;
+
+       /* read/write requests already freed, only control request remains */
+       if (dev != NULL) {
+               if (dev->dev_ctrl_req != NULL) {
+                       gs_free_req(gadget->ep0, dev->dev_ctrl_req);
+                       dev->dev_ctrl_req = NULL;
+               }
+               gs_reset_config(dev);
+               gs_free_ports(dev);
+               kfree(dev);
+               set_gadget_data(gadget, NULL);
+       }
+
+       pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+               GS_VERSION_STR);
+}
+
+/*
  * gs_bind
  *
  * Called on module load.  Allocates and initializes the device
  * structure and a control request.
  */
-static int gs_bind(struct usb_gadget *gadget)
+static int __init gs_bind(struct usb_gadget *gadget)
 {
        int ret;
        struct usb_ep *ep;
@@ -1438,81 +1248,83 @@ static int gs_bind(struct usb_gadget *gadget)
                gs_device_desc.bcdDevice =
                                cpu_to_le16(GS_VERSION_NUM | gcnum);
        else {
-               printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
+               pr_warning("gs_bind: controller '%s' not recognized\n",
                        gadget->name);
                /* unrecognized, but safe unless bulk is REALLY quirky */
                gs_device_desc.bcdDevice =
                        __constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
        }
 
+       dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOMEM;
+
        usb_ep_autoconfig_reset(gadget);
 
        ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
        if (!ep)
                goto autoconf_fail;
-       EP_IN_NAME = ep->name;
-       ep->driver_data = ep;   /* claim the endpoint */
+       dev->dev_in_ep = ep;
+       ep->driver_data = dev;  /* claim the endpoint */
 
        ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
        if (!ep)
                goto autoconf_fail;
-       EP_OUT_NAME = ep->name;
-       ep->driver_data = ep;   /* claim the endpoint */
+       dev->dev_out_ep = ep;
+       ep->driver_data = dev;  /* claim the endpoint */
 
        if (use_acm) {
                ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
                if (!ep) {
-                       printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
+                       pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
                        goto autoconf_fail;
                }
                gs_device_desc.idProduct = __constant_cpu_to_le16(
                                                GS_CDC_PRODUCT_ID),
-               EP_NOTIFY_NAME = ep->name;
-               ep->driver_data = ep;   /* claim the endpoint */
+               dev->dev_notify_ep = ep;
+               ep->driver_data = dev;  /* claim the endpoint */
        }
 
        gs_device_desc.bDeviceClass = use_acm
                ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
        gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       gs_qualifier_desc.bDeviceClass = use_acm
-               ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-       /* assume ep0 uses the same packet size for both speeds */
-       gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-       /* assume endpoints are dual-speed */
-       gs_highspeed_notify_desc.bEndpointAddress =
-               gs_fullspeed_notify_desc.bEndpointAddress;
-       gs_highspeed_in_desc.bEndpointAddress =
-               gs_fullspeed_in_desc.bEndpointAddress;
-       gs_highspeed_out_desc.bEndpointAddress =
-               gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+       if (gadget_is_dualspeed(gadget)) {
+               gs_qualifier_desc.bDeviceClass = use_acm
+                       ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+               /* assume ep0 uses the same packet size for both speeds */
+               gs_qualifier_desc.bMaxPacketSize0 =
+                       gs_device_desc.bMaxPacketSize0;
+               /* assume endpoints are dual-speed */
+               gs_highspeed_notify_desc.bEndpointAddress =
+                       gs_fullspeed_notify_desc.bEndpointAddress;
+               gs_highspeed_in_desc.bEndpointAddress =
+                       gs_fullspeed_in_desc.bEndpointAddress;
+               gs_highspeed_out_desc.bEndpointAddress =
+                       gs_fullspeed_out_desc.bEndpointAddress;
+       }
 
        usb_gadget_set_selfpowered(gadget);
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
                gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
-       if (dev == NULL)
-               return -ENOMEM;
+       gs_device = dev;
 
        snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
-               system_utsname.sysname, system_utsname.release,
+               init_utsname()->sysname, init_utsname()->release,
                gadget->name);
 
-       memset(dev, 0, sizeof(struct gs_dev));
        dev->dev_gadget = gadget;
        spin_lock_init(&dev->dev_lock);
        INIT_LIST_HEAD(&dev->dev_req_list);
        set_gadget_data(gadget, dev);
 
        if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) {
-               printk(KERN_ERR "gs_bind: cannot allocate ports\n");
+               pr_err("gs_bind: cannot allocate ports\n");
                gs_unbind(gadget);
                return ret;
        }
@@ -1524,100 +1336,19 @@ static int gs_bind(struct usb_gadget *gadget)
                gs_unbind(gadget);
                return -ENOMEM;
        }
-       dev->dev_ctrl_req->complete = gs_setup_complete;
-
        gadget->ep0->driver_data = dev;
 
-       printk(KERN_INFO "gs_bind: %s %s bound\n",
+       pr_info("gs_bind: %s %s bound\n",
                GS_LONG_NAME, GS_VERSION_STR);
 
        return 0;
 
 autoconf_fail:
-       printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name);
+       kfree(dev);
+       pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
        return -ENODEV;
 }
 
-/*
- * gs_unbind
- *
- * Called on module unload.  Frees the control request and device
- * structure.
- */
-static void gs_unbind(struct usb_gadget *gadget)
-{
-       struct gs_dev *dev = get_gadget_data(gadget);
-
-       gs_device = NULL;
-
-       /* read/write requests already freed, only control request remains */
-       if (dev != NULL) {
-               if (dev->dev_ctrl_req != NULL) {
-                       gs_free_req(gadget->ep0, dev->dev_ctrl_req);
-                       dev->dev_ctrl_req = NULL;
-               }
-               gs_free_ports(dev);
-               kfree(dev);
-               set_gadget_data(gadget, NULL);
-       }
-
-       printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME,
-               GS_VERSION_STR);
-}
-
-/*
- * gs_setup
- *
- * Implements all the control endpoint functionality that's not
- * handled in hardware or the hardware driver.
- *
- * Returns the size of the data sent to the host, or a negative
- * error number.
- */
-static int gs_setup(struct usb_gadget *gadget,
-       const struct usb_ctrlrequest *ctrl)
-{
-       int ret = -EOPNOTSUPP;
-       struct gs_dev *dev = get_gadget_data(gadget);
-       struct usb_request *req = dev->dev_ctrl_req;
-       u16 wIndex = le16_to_cpu(ctrl->wIndex);
-       u16 wValue = le16_to_cpu(ctrl->wValue);
-       u16 wLength = le16_to_cpu(ctrl->wLength);
-
-       switch (ctrl->bRequestType & USB_TYPE_MASK) {
-       case USB_TYPE_STANDARD:
-               ret = gs_setup_standard(gadget,ctrl);
-               break;
-
-       case USB_TYPE_CLASS:
-               ret = gs_setup_class(gadget,ctrl);
-               break;
-
-       default:
-               printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
-                       ctrl->bRequestType, ctrl->bRequest,
-                       wValue, wIndex, wLength);
-               break;
-       }
-
-       /* respond with data transfer before status phase? */
-       if (ret >= 0) {
-               req->length = ret;
-               req->zero = ret < wLength
-                               && (ret % gadget->ep0->maxpacket) == 0;
-               ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-               if (ret < 0) {
-                       printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n",
-                               ret);
-                       req->status = 0;
-                       gs_setup_complete(gadget->ep0, req);
-               }
-       }
-
-       /* device either stalls (ret < 0) or reports success */
-       return ret;
-}
-
 static int gs_setup_standard(struct usb_gadget *gadget,
        const struct usb_ctrlrequest *ctrl)
 {
@@ -1640,9 +1371,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        memcpy(req->buf, &gs_device_desc, ret);
                        break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        ret = min(wLength,
                                (u16)sizeof(struct usb_qualifier_descriptor));
@@ -1650,14 +1380,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        /* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       ret = gs_build_config_buf(req->buf, gadget->speed,
+                       ret = gs_build_config_buf(req->buf, gadget,
                                wValue >> 8, wValue & 0xff,
-                               gadget->is_otg);
+                               gadget_is_otg(gadget));
                        if (ret >= 0)
                                ret = min(wLength, (u16)ret);
                        break;
@@ -1739,7 +1468,8 @@ set_interface_done:
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+               pr_err("gs_setup: unknown standard request, type=%02x, "
+                       "request=%02x, value=%04x, index=%04x, length=%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        wValue, wIndex, wLength);
                break;
@@ -1748,6 +1478,42 @@ set_interface_done:
        return ret;
 }
 
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+               struct usb_request *req)
+{
+       struct gs_dev *dev = ep->driver_data;
+       struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+       switch (req->status) {
+       case 0:
+               /* normal completion */
+               if (req->actual != sizeof(port->port_line_coding))
+                       usb_ep_set_halt(ep);
+               else if (port) {
+                       struct usb_cdc_line_coding      *value = req->buf;
+
+                       /* REVISIT:  we currently just remember this data.
+                        * If we change that, (a) validate it first, then
+                        * (b) update whatever hardware needs updating.
+                        */
+                       spin_lock(&port->port_lock);
+                       port->port_line_coding = *value;
+                       spin_unlock(&port->port_lock);
+               }
+               break;
+
+       case -ESHUTDOWN:
+               /* disconnect */
+               gs_free_req(ep, req);
+               break;
+
+       default:
+               /* unexpected */
+               break;
+       }
+       return;
+}
+
 static int gs_setup_class(struct usb_gadget *gadget,
        const struct usb_ctrlrequest *ctrl)
 {
@@ -1761,19 +1527,14 @@ static int gs_setup_class(struct usb_gadget *gadget,
 
        switch (ctrl->bRequest) {
        case USB_CDC_REQ_SET_LINE_CODING:
-               ret = min(wLength,
-                       (u16)sizeof(struct usb_cdc_line_coding));
-               if (port) {
-                       spin_lock(&port->port_lock);
-                       memcpy(&port->port_line_coding, req->buf, ret);
-                       spin_unlock(&port->port_lock);
-               }
+               if (wLength != sizeof(struct usb_cdc_line_coding))
+                       break;
+               ret = wLength;
+               req->complete = gs_setup_complete_set_line_coding;
                break;
 
        case USB_CDC_REQ_GET_LINE_CODING:
-               port = dev->dev_port[0];        /* ACM only has one port */
-               ret = min(wLength,
-                       (u16)sizeof(struct usb_cdc_line_coding));
+               ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
                if (port) {
                        spin_lock(&port->port_lock);
                        memcpy(req->buf, &port->port_line_coding, ret);
@@ -1782,11 +1543,30 @@ static int gs_setup_class(struct usb_gadget *gadget,
                break;
 
        case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+               if (wLength != 0)
+                       break;
                ret = 0;
+               if (port) {
+                       /* REVISIT:  we currently just remember this data.
+                        * If we change that, update whatever hardware needs
+                        * updating.
+                        */
+                       spin_lock(&port->port_lock);
+                       port->port_handshake_bits = wValue;
+                       spin_unlock(&port->port_lock);
+               }
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+               /* NOTE:  strictly speaking, we should accept AT-commands
+                * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+                * But our call management descriptor says we don't handle
+                * call management, so we should be able to get by without
+                * handling those "required" commands (except by stalling).
+                */
+               pr_err("gs_setup: unknown class request, "
+                               "type=%02x, request=%02x, value=%04x, "
+                               "index=%04x, length=%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        wValue, wIndex, wLength);
                break;
@@ -1801,12 +1581,69 @@ static int gs_setup_class(struct usb_gadget *gadget,
 static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
 {
        if (req->status || req->actual != req->length) {
-               printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n",
+               pr_err("gs_setup_complete: status error, status=%d, "
+                       "actual=%d, length=%d\n",
                        req->status, req->actual, req->length);
        }
 }
 
 /*
+ * gs_setup
+ *
+ * Implements all the control endpoint functionality that's not
+ * handled in hardware or the hardware driver.
+ *
+ * Returns the size of the data sent to the host, or a negative
+ * error number.
+ */
+static int gs_setup(struct usb_gadget *gadget,
+       const struct usb_ctrlrequest *ctrl)
+{
+       int             ret = -EOPNOTSUPP;
+       struct gs_dev   *dev = get_gadget_data(gadget);
+       struct usb_request *req = dev->dev_ctrl_req;
+       u16             wIndex = le16_to_cpu(ctrl->wIndex);
+       u16             wValue = le16_to_cpu(ctrl->wValue);
+       u16             wLength = le16_to_cpu(ctrl->wLength);
+
+       req->complete = gs_setup_complete;
+
+       switch (ctrl->bRequestType & USB_TYPE_MASK) {
+       case USB_TYPE_STANDARD:
+               ret = gs_setup_standard(gadget, ctrl);
+               break;
+
+       case USB_TYPE_CLASS:
+               ret = gs_setup_class(gadget, ctrl);
+               break;
+
+       default:
+               pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+                       "value=%04x, index=%04x, length=%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       wValue, wIndex, wLength);
+               break;
+       }
+
+       /* respond with data transfer before status phase? */
+       if (ret >= 0) {
+               req->length = ret;
+               req->zero = ret < wLength
+                               && (ret % gadget->ep0->maxpacket) == 0;
+               ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+               if (ret < 0) {
+                       pr_err("gs_setup: cannot queue response, ret=%d\n",
+                               ret);
+                       req->status = 0;
+                       gs_setup_complete(gadget->ep0, req);
+               }
+       }
+
+       /* device either stalls (ret < 0) or reports success */
+       return ret;
+}
+
+/*
  * gs_disconnect
  *
  * Called when the device is disconnected.  Frees the closed
@@ -1828,13 +1665,30 @@ static void gs_disconnect(struct usb_gadget *gadget)
 
        /* re-allocate ports for the next connection */
        if (gs_alloc_ports(dev, GFP_ATOMIC) != 0)
-               printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n");
+               pr_err("gs_disconnect: cannot re-allocate ports\n");
 
        spin_unlock_irqrestore(&dev->dev_lock, flags);
 
-       printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+       pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
 }
 
+static struct usb_gadget_driver gs_gadget_driver = {
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       .speed =                USB_SPEED_HIGH,
+#else
+       .speed =                USB_SPEED_FULL,
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
+       .function =             GS_LONG_NAME,
+       .bind =                 gs_bind,
+       .unbind =               gs_unbind,
+       .setup =                gs_setup,
+       .disconnect =           gs_disconnect,
+       .driver = {
+               .name =         GS_SHORT_NAME,
+               .owner =        THIS_MODULE,
+       },
+};
+
 /*
  * gs_set_config
  *
@@ -1850,12 +1704,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
        int ret = 0;
        struct usb_gadget *gadget = dev->dev_gadget;
        struct usb_ep *ep;
-       struct usb_endpoint_descriptor *ep_desc;
+       struct usb_endpoint_descriptor *out, *in, *notify;
        struct usb_request *req;
-       struct gs_req_entry *req_entry;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_set_config: NULL device pointer\n");
+               pr_err("gs_set_config: NULL device pointer\n");
                return 0;
        }
 
@@ -1870,97 +1723,74 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
        case GS_BULK_CONFIG_ID:
                if (use_acm)
                        return -EINVAL;
-               /* device specific optimizations */
-               if (gadget_is_net2280(gadget))
-                       net2280_set_fifo_mode(gadget, 1);
                break;
        case GS_ACM_CONFIG_ID:
                if (!use_acm)
                        return -EINVAL;
-               /* device specific optimizations */
-               if (gadget_is_net2280(gadget))
-                       net2280_set_fifo_mode(gadget, 1);
                break;
        default:
                return -EINVAL;
        }
 
-       dev->dev_config = config;
-
-       gadget_for_each_ep(ep, gadget) {
-
-               if (EP_NOTIFY_NAME
-               && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
+       in = choose_ep_desc(gadget,
+                       &gs_highspeed_in_desc,
+                       &gs_fullspeed_in_desc);
+       out = choose_ep_desc(gadget,
+                       &gs_highspeed_out_desc,
+                       &gs_fullspeed_out_desc);
+       notify = dev->dev_notify_ep
+               ? choose_ep_desc(gadget,
                                &gs_highspeed_notify_desc,
-                               &gs_fullspeed_notify_desc);
-                       ret = usb_ep_enable(ep,ep_desc);
-                       if (ret == 0) {
-                               ep->driver_data = dev;
-                               dev->dev_notify_ep = ep;
-                               dev->dev_notify_ep_desc = ep_desc;
-                       } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n",
-                                       ep->name, ret);
-                               goto exit_reset_config;
-                       }
-               }
-
-               else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
-                               &gs_highspeed_in_desc,
-                               &gs_fullspeed_in_desc);
-                       ret = usb_ep_enable(ep,ep_desc);
-                       if (ret == 0) {
-                               ep->driver_data = dev;
-                               dev->dev_in_ep = ep;
-                               dev->dev_in_ep_desc = ep_desc;
-                       } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
-                                       ep->name, ret);
-                               goto exit_reset_config;
-                       }
-               }
+                               &gs_fullspeed_notify_desc)
+               : NULL;
 
-               else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
-                               &gs_highspeed_out_desc,
-                               &gs_fullspeed_out_desc);
-                       ret = usb_ep_enable(ep,ep_desc);
-                       if (ret == 0) {
-                               ep->driver_data = dev;
-                               dev->dev_out_ep = ep;
-                               dev->dev_out_ep_desc = ep_desc;
-                       } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
-                                       ep->name, ret);
-                               goto exit_reset_config;
-                       }
-               }
+       ret = usb_ep_enable(dev->dev_in_ep, in);
+       if (ret == 0) {
+               dev->dev_in_ep_desc = in;
+       } else {
+               pr_debug("%s: cannot enable %s %s, ret=%d\n",
+                       __func__, "IN", dev->dev_in_ep->name, ret);
+               return ret;
+       }
 
+       ret = usb_ep_enable(dev->dev_out_ep, out);
+       if (ret == 0) {
+               dev->dev_out_ep_desc = out;
+       } else {
+               pr_debug("%s: cannot enable %s %s, ret=%d\n",
+                       __func__, "OUT", dev->dev_out_ep->name, ret);
+fail0:
+               usb_ep_disable(dev->dev_in_ep);
+               return ret;
        }
 
-       if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
-       || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
-               printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
-               ret = -ENODEV;
-               goto exit_reset_config;
+       if (notify) {
+               ret = usb_ep_enable(dev->dev_notify_ep, notify);
+               if (ret == 0) {
+                       dev->dev_notify_ep_desc = notify;
+               } else {
+                       pr_debug("%s: cannot enable %s %s, ret=%d\n",
+                               __func__, "NOTIFY",
+                               dev->dev_notify_ep->name, ret);
+                       usb_ep_disable(dev->dev_out_ep);
+                       goto fail0;
+               }
        }
 
+       dev->dev_config = config;
+
        /* allocate and queue read requests */
        ep = dev->dev_out_ep;
        for (i=0; i<read_q_size && ret == 0; i++) {
                if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
                        req->complete = gs_read_complete;
                        if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                               printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n",
-                                       ret);
+                               pr_err("gs_set_config: cannot queue read "
+                                       "request, ret=%d\n", ret);
                        }
                } else {
-                       printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
+                       pr_err("gs_set_config: cannot allocate "
+                                       "read requests\n");
                        ret = -ENOMEM;
                        goto exit_reset_config;
                }
@@ -1969,17 +1799,24 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
        /* allocate write requests, and put on free list */
        ep = dev->dev_in_ep;
        for (i=0; i<write_q_size; i++) {
-               if ((req_entry=gs_alloc_req_entry(ep, ep->maxpacket, GFP_ATOMIC))) {
-                       req_entry->re_req->complete = gs_write_complete;
-                       list_add(&req_entry->re_entry, &dev->dev_req_list);
+               req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+               if (req) {
+                       req->complete = gs_write_complete;
+                       list_add(&req->list, &dev->dev_req_list);
                } else {
-                       printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
+                       pr_err("gs_set_config: cannot allocate "
+                                       "write requests\n");
                        ret = -ENOMEM;
                        goto exit_reset_config;
                }
        }
 
-       printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
+       /* REVISIT the ACM mode should be able to actually *issue* some
+        * notifications, for at least serial state change events if
+        * not also for network connection; say so in bmCapabilities.
+        */
+
+       pr_info("gs_set_config: %s configured, %s speed %s config\n",
                GS_LONG_NAME,
                gadget->speed == USB_SPEED_HIGH ? "high" : "full",
                config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
@@ -2003,10 +1840,10 @@ exit_reset_config:
  */
 static void gs_reset_config(struct gs_dev *dev)
 {
-       struct gs_req_entry *req_entry;
+       struct usb_request *req;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_reset_config: NULL device pointer\n");
+               pr_err("gs_reset_config: NULL device pointer\n");
                return;
        }
 
@@ -2017,26 +1854,18 @@ static void gs_reset_config(struct gs_dev *dev)
 
        /* free write requests on the free list */
        while(!list_empty(&dev->dev_req_list)) {
-               req_entry = list_entry(dev->dev_req_list.next,
-                       struct gs_req_entry, re_entry);
-               list_del(&req_entry->re_entry);
-               gs_free_req_entry(dev->dev_in_ep, req_entry);
+               req = list_entry(dev->dev_req_list.next,
+                               struct usb_request, list);
+               list_del(&req->list);
+               gs_free_req(dev->dev_in_ep, req);
        }
 
        /* disable endpoints, forcing completion of pending i/o; */
        /* completion handlers free their requests in this case */
-       if (dev->dev_notify_ep) {
+       if (dev->dev_notify_ep)
                usb_ep_disable(dev->dev_notify_ep);
-               dev->dev_notify_ep = NULL;
-       }
-       if (dev->dev_in_ep) {
-               usb_ep_disable(dev->dev_in_ep);
-               dev->dev_in_ep = NULL;
-       }
-       if (dev->dev_out_ep) {
-               usb_ep_disable(dev->dev_out_ep);
-               dev->dev_out_ep = NULL;
-       }
+       usb_ep_disable(dev->dev_in_ep);
+       usb_ep_disable(dev->dev_out_ep);
 }
 
 /*
@@ -2045,11 +1874,11 @@ static void gs_reset_config(struct gs_dev *dev)
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
        u8 type, unsigned int index, int is_otg)
 {
        int len;
-       int high_speed;
+       int high_speed = 0;
        const struct usb_config_descriptor *config_desc;
        const struct usb_descriptor_header **function;
 
@@ -2057,20 +1886,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
                return -EINVAL;
 
        /* other speed switches high and full speed */
-       high_speed = (speed == USB_SPEED_HIGH);
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               high_speed = !high_speed;
+       if (gadget_is_dualspeed(g)) {
+               high_speed = (g->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       high_speed = !high_speed;
+       }
 
        if (use_acm) {
                config_desc = &gs_acm_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_acm_highspeed_function,
-                       gs_acm_fullspeed_function);
+               function = high_speed
+                       ? gs_acm_highspeed_function
+                       : gs_acm_fullspeed_function;
        } else {
                config_desc = &gs_bulk_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_bulk_highspeed_function,
-                       gs_bulk_fullspeed_function);
+               function = high_speed
+                       ? gs_bulk_highspeed_function
+                       : gs_bulk_fullspeed_function;
        }
 
        /* for now, don't advertise srp-only devices */
@@ -2128,46 +1959,6 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
 }
 
 /*
- * gs_alloc_req_entry
- *
- * Allocates a request and its buffer, using the given
- * endpoint, buffer len, and kmalloc flags.
- */
-static struct gs_req_entry *
-gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
-{
-       struct gs_req_entry     *req;
-
-       req = kmalloc(sizeof(struct gs_req_entry), kmalloc_flags);
-       if (req == NULL)
-               return NULL;
-
-       req->re_req = gs_alloc_req(ep, len, kmalloc_flags);
-       if (req->re_req == NULL) {
-               kfree(req);
-               return NULL;
-       }
-
-       req->re_req->context = req;
-
-       return req;
-}
-
-/*
- * gs_free_req_entry
- *
- * Frees a request and its buffer.
- */
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
-{
-       if (ep != NULL && req != NULL) {
-               if (req->re_req != NULL)
-                       gs_free_req(ep, req->re_req);
-               kfree(req);
-       }
-}
-
-/*
  * gs_alloc_ports
  *
  * Allocate all ports and set the gs_dev struct to point to them.
@@ -2184,10 +1975,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
                return -EIO;
 
        for (i=0; i<GS_NUM_PORTS; i++) {
-               if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
+               if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
                        return -ENOMEM;
 
-               memset(port, 0, sizeof(struct gs_port));
                port->port_dev = dev;
                port->port_num = i;
                port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
@@ -2237,8 +2027,7 @@ static void gs_free_ports(struct gs_dev *dev)
                                port->port_dev = NULL;
                                wake_up_interruptible(&port->port_write_wait);
                                if (port->port_tty) {
-                                       wake_up_interruptible(&port->port_tty->read_wait);
-                                       wake_up_interruptible(&port->port_tty->write_wait);
+                                       tty_hangup(port->port_tty);
                                }
                                spin_unlock_irqrestore(&port->port_lock, flags);
                        } else {
@@ -2250,6 +2039,8 @@ static void gs_free_ports(struct gs_dev *dev)
        }
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* Circular Buffer */
 
 /*
@@ -2264,7 +2055,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
        if (size == 0)
                return NULL;
 
-       gb = (struct gs_buf *)kmalloc(sizeof(struct gs_buf), kmalloc_flags);
+       gb = kmalloc(sizeof(struct gs_buf), kmalloc_flags);
        if (gb == NULL)
                return NULL;
 
@@ -2285,7 +2076,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
  *
  * Free the buffer and all associated memory.
  */
-void gs_buf_free(struct gs_buf *gb)
+static void gs_buf_free(struct gs_buf *gb)
 {
        if (gb) {
                kfree(gb->buf_buf);
@@ -2298,7 +2089,7 @@ void gs_buf_free(struct gs_buf *gb)
  *
  * Clear out all data in the circular buffer.
  */
-void gs_buf_clear(struct gs_buf *gb)
+static void gs_buf_clear(struct gs_buf *gb)
 {
        if (gb != NULL)
                gb->buf_get = gb->buf_put;
@@ -2311,7 +2102,7 @@ void gs_buf_clear(struct gs_buf *gb)
  * Return the number of bytes of data available in the circular
  * buffer.
  */
-unsigned int gs_buf_data_avail(struct gs_buf *gb)
+static unsigned int gs_buf_data_avail(struct gs_buf *gb)
 {
        if (gb != NULL)
                return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
@@ -2325,7 +2116,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb)
  * Return the number of bytes of space available in the circular
  * buffer.
  */
-unsigned int gs_buf_space_avail(struct gs_buf *gb)
+static unsigned int gs_buf_space_avail(struct gs_buf *gb)
 {
        if (gb != NULL)
                return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
@@ -2341,7 +2132,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb)
  *
  * Return the number of bytes copied.
  */
-unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
+static unsigned int
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
 {
        unsigned int len;
 
@@ -2379,7 +2171,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
  *
  * Return the number of bytes copied.
  */
-unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
+static unsigned int
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
 {
        unsigned int len;
 
@@ -2408,3 +2201,77 @@ unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
 
        return count;
 }
+
+/*-------------------------------------------------------------------------*/
+
+static struct tty_driver *gs_tty_driver;
+
+/*
+ *  gs_module_init
+ *
+ *  Register as a USB gadget driver and a tty driver.
+ */
+static int __init gs_module_init(void)
+{
+       int i;
+       int retval;
+
+       retval = usb_gadget_register_driver(&gs_gadget_driver);
+       if (retval) {
+               pr_err("gs_module_init: cannot register gadget driver, "
+                       "ret=%d\n", retval);
+               return retval;
+       }
+
+       gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
+       if (!gs_tty_driver)
+               return -ENOMEM;
+       gs_tty_driver->owner = THIS_MODULE;
+       gs_tty_driver->driver_name = GS_SHORT_NAME;
+       gs_tty_driver->name = "ttygs";
+       gs_tty_driver->major = GS_MAJOR;
+       gs_tty_driver->minor_start = GS_MINOR_START;
+       gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       gs_tty_driver->init_termios = tty_std_termios;
+       /* must match GS_DEFAULT_DTE_RATE and friends */
+       gs_tty_driver->init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       gs_tty_driver->init_termios.c_ispeed = GS_DEFAULT_DTE_RATE;
+       gs_tty_driver->init_termios.c_ospeed = GS_DEFAULT_DTE_RATE;
+       tty_set_operations(gs_tty_driver, &gs_tty_ops);
+
+       for (i = 0; i < GS_NUM_PORTS; i++)
+               mutex_init(&gs_open_close_lock[i]);
+
+       retval = tty_register_driver(gs_tty_driver);
+       if (retval) {
+               usb_gadget_unregister_driver(&gs_gadget_driver);
+               put_tty_driver(gs_tty_driver);
+               pr_err("gs_module_init: cannot register tty driver, "
+                               "ret=%d\n", retval);
+               return retval;
+       }
+
+       pr_info("gs_module_init: %s %s loaded\n",
+                       GS_LONG_NAME, GS_VERSION_STR);
+       return 0;
+}
+module_init(gs_module_init);
+
+/*
+ * gs_module_exit
+ *
+ * Unregister as a tty driver and a USB gadget driver.
+ */
+static void __exit gs_module_exit(void)
+{
+       tty_unregister_driver(gs_tty_driver);
+       put_tty_driver(gs_tty_driver);
+       usb_gadget_unregister_driver(&gs_gadget_driver);
+
+       pr_info("gs_module_exit: %s %s unloaded\n",
+                       GS_LONG_NAME, GS_VERSION_STR);
+}
+module_exit(gs_module_exit);