Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / gadget / serial.c
index bd13911..b992546 100644 (file)
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/uts.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
 #include <linux/wait.h>
-#include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <asm/uaccess.h>
 
 #include <linux/usb_ch9.h>
+#include <linux/usb_cdc.h>
 #include <linux/usb_gadget.h>
 
+#include "gadget_chips.h"
+
 
 /* Wait Cond */
 
@@ -124,8 +125,8 @@ do {                                                                        \
 
 /* Defines */
 
-#define GS_VERSION_STR                 "v0.1"
-#define GS_VERSION_NUM                 0x0001
+#define GS_VERSION_STR                 "v2.0"
+#define GS_VERSION_NUM                 0x0200
 
 #define GS_LONG_NAME                   "Gadget Serial"
 #define GS_SHORT_NAME                  "g_serial"
@@ -137,13 +138,13 @@ do {                                                                      \
 
 #define GS_NUM_CONFIGS                 1
 #define GS_NO_CONFIG_ID                        0
-#define GS_BULK_CONFIG_ID              2
-
-#define GS_NUM_INTERFACES              1
-#define GS_INTERFACE_ID                        0
-#define GS_ALT_INTERFACE_ID            0
+#define GS_BULK_CONFIG_ID              1
+#define GS_ACM_CONFIG_ID               2
 
-#define GS_NUM_ENDPOINTS               2
+#define GS_MAX_NUM_INTERFACES          2
+#define GS_BULK_INTERFACE_ID           0
+#define GS_CONTROL_INTERFACE_ID                0
+#define GS_DATA_INTERFACE_ID           1
 
 #define GS_MAX_DESC_LEN                        256
 
@@ -155,10 +156,23 @@ do {                                                                      \
 
 #define GS_CLOSE_TIMEOUT               15
 
-/* debug macro */
-#if G_SERIAL_DEBUG
+#define GS_DEFAULT_USE_ACM             0
+
+#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 */
 
-static int debug = G_SERIAL_DEBUG;
+/* debug settings */
+#ifdef GS_DEBUG
+static int debug = 1;
 
 #define gs_debug(format, arg...) \
        do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
@@ -172,161 +186,19 @@ static int debug = G_SERIAL_DEBUG;
 #define gs_debug_level(level, format, arg...) \
        do { } while(0)
 
-#endif /* G_SERIAL_DEBUG */
-
-
-/* USB Controllers */
-
-/*
- * NetChip 2280, PCI based.
- *
- * This has half a dozen configurable endpoints, four with dedicated
- * DMA channels to manage their FIFOs.  It supports high speed.
- * Those endpoints can be arranged in any desired configuration.
- */
-#ifdef CONFIG_USB_GADGET_NET2280
-#define CHIP                           "net2280"
-#define EP0_MAXPACKET                  64
-static const char EP_OUT_NAME[] =      "ep-a";
-#define EP_OUT_NUM                     2
-static const char EP_IN_NAME[] =       "ep-b";
-#define EP_IN_NUM                      2
-#define HIGHSPEED
-#define SELFPOWER                      USB_CONFIG_ATT_SELFPOWER
-
-extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);
-
-static inline void hw_optimize(struct usb_gadget *gadget)
-{
-       /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets
-        * for highspeed bulk) because we're not using ep-c/ep-d.
-        */
-       net2280_set_fifo_mode (gadget, 1);
-}
-#endif
-
-
-/*
- * Dummy_hcd, software-based loopback controller.
- *
- * This imitates the abilities of the NetChip 2280, so we will use
- * the same configuration.
- */
-#ifdef CONFIG_USB_GADGET_DUMMY_HCD
-#define CHIP                           "dummy"
-#define EP0_MAXPACKET                  64
-static const char EP_OUT_NAME[] =      "ep-a";
-#define EP_OUT_NUM                     2
-static const char EP_IN_NAME[] =       "ep-b";
-#define EP_IN_NUM                      2
-#define HIGHSPEED
-#define SELFPOWER                      USB_CONFIG_ATT_SELFPOWER
-
-/* no hw optimizations to apply */
-#define hw_optimize(g)                 do {} while (0)
-#endif
-
-
-/*
- * PXA-2xx UDC:  widely used in second gen Linux-capable PDAs.
- *
- * This has fifteen fixed-function full speed endpoints, and it
- * can support all USB transfer types.
- *
- * These supports three or four configurations, with fixed numbers.
- * The hardware interprets SET_INTERFACE, net effect is that you
- * can't use altsettings or reset the interfaces independently.
- * So stick to a single interface.
- */
-#ifdef CONFIG_USB_GADGET_PXA2XX
-#define CHIP                           "pxa2xx"
-#define EP0_MAXPACKET                  16
-static const char EP_OUT_NAME[] =      "ep2out-bulk";
-#define EP_OUT_NUM                     2
-static const char EP_IN_NAME[] =       "ep1in-bulk";
-#define EP_IN_NUM                      1
-#define SELFPOWER                      USB_CONFIG_ATT_SELFPOWER
-
-/* no hw optimizations to apply */
-#define hw_optimize(g)                 do {} while (0)
-#endif
-
-
-/*
- * SA-1100 UDC:  widely used in first gen Linux-capable PDAs.
- *
- * This has only two fixed function endpoints, which can only
- * be used for bulk (or interrupt) transfers.  (Plus control.)
- *
- * Since it can't flush its TX fifos without disabling the UDC,
- * the current configuration or altsettings can't change except
- * in special situations.  So this is a case of "choose it right
- * during enumeration" ...
- */
-#ifdef CONFIG_USB_GADGET_SA1100
-#define CHIP                           "sa1100"
-#define EP0_MAXPACKET                  8
-static const char EP_OUT_NAME[] =      "ep1out-bulk";
-#define EP_OUT_NUM                     1
-static const char EP_IN_NAME [] =      "ep2in-bulk";
-#define EP_IN_NUM                      2
-#define SELFPOWER                      USB_CONFIG_ATT_SELFPOWER
-
-/* no hw optimizations to apply */
-#define hw_optimize(g)                 do {} while (0)
-#endif
-
-
-/*
- * Toshiba TC86C001 ("Goku-S") UDC
- *
- * This has three semi-configurable full speed bulk/interrupt endpoints.
- */
-#ifdef CONFIG_USB_GADGET_GOKU
-#define CHIP                           "goku"
-#define DRIVER_VERSION_NUM             0x0116
-#define EP0_MAXPACKET                  8
-static const char EP_OUT_NAME [] =     "ep1-bulk";
-#define EP_OUT_NUM                     1
-static const char EP_IN_NAME [] =      "ep2-bulk";
-#define EP_IN_NUM                      2
-#define SELFPOWER                      USB_CONFIG_ATT_SELFPOWER
-
-/* no hw optimizations to apply */
-#define hw_optimize(g)                 do {} while (0)
-#endif
-
-/*
- * USB Controller Defaults
- */
-#ifndef EP0_MAXPACKET
-#error Configure some USB peripheral controller for g_serial!
-#endif
-
-#ifndef SELFPOWER
-/* default: say we rely on bus power */
-#define SELFPOWER                      0
-/* else value must be USB_CONFIG_ATT_SELFPOWER */
-#endif
-
-#ifndef        MAX_USB_POWER
-/* any hub supports this steady state bus power consumption */
-#define MAX_USB_POWER                  100     /* mA */
-#endif
-
-#ifndef        WAKEUP
-/* default: this driver won't do remote wakeup */
-#define WAKEUP                         0
-/* else value must be USB_CONFIG_ATT_WAKEUP */
-#endif
+#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
-#define GS_VENDOR_ID   0x0525          /* NetChip */
-#define GS_PRODUCT_ID  0xa4a6          /* Linux-USB Serial Gadget */
+#define GS_VENDOR_ID                   0x0525  /* NetChip */
+#define GS_PRODUCT_ID                  0xa4a6  /* Linux-USB Serial Gadget */
+#define GS_CDC_PRODUCT_ID              0xa4a7  /* ... as CDC-ACM */
+
+#define GS_LOG2_NOTIFY_INTERVAL                5       /* 1 << 5 == 32 msec */
+#define GS_NOTIFY_MAXPACKET            8
 
 
 /* Structures */
@@ -357,6 +229,7 @@ struct gs_port {
        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;
 };
 
 /* the device structure holds info for the USB device */
@@ -364,8 +237,15 @@ struct gs_dev {
        struct usb_gadget       *dev_gadget;    /* gadget device pointer */
        spinlock_t              dev_lock;       /* lock for set/reset config */
        int                     dev_config;     /* configuration number */
+       struct usb_ep           *dev_notify_ep; /* address of notify endpoint */
        struct usb_ep           *dev_in_ep;     /* address of in endpoint */
        struct usb_ep           *dev_out_ep;    /* address of out endpoint */
+       struct usb_endpoint_descriptor          /* descriptor of notify ep */
+                               *dev_notify_ep_desc;
+       struct usb_endpoint_descriptor          /* descriptor of in endpoint */
+                               *dev_in_ep_desc;
+       struct usb_endpoint_descriptor          /* descriptor of out endpoint */
+                               *dev_out_ep_desc;
        struct usb_request      *dev_ctrl_req;  /* control request */
        struct list_head        dev_req_list;   /* list of write requests */
        int                     dev_sched_port; /* round robin port scheduled */
@@ -382,7 +262,7 @@ 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, int from_user,
+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);
@@ -408,26 +288,30 @@ 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);
 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_desc(u8 *buf, enum usb_device_speed speed,
-               u8 type, unsigned int index);
+static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+               u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
-       int kmalloc_flags);
+       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,
-       int kmalloc_flags);
+       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, int kmalloc_flags);
+static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);
 static void gs_free_ports(struct gs_dev *dev);
 
 /* circular buffer */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags);
+static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags);
 static void gs_buf_free(struct gs_buf *gb);
 static void gs_buf_clear(struct gs_buf *gb);
 static unsigned int gs_buf_data_avail(struct gs_buf *gb);
@@ -437,11 +321,18 @@ 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 semaphore        gs_open_close_sem[GS_NUM_PORTS];
 
 static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
@@ -449,8 +340,8 @@ static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
 
 static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
 
-static unsigned char gs_tmp_buf[GS_TMP_BUF_SIZE];
-static struct semaphore        gs_tmp_buf_sem;
+static unsigned int use_acm = GS_DEFAULT_USE_ACM;
+
 
 /* tty driver struct */
 static struct tty_operations gs_tty_ops = {
@@ -471,21 +362,18 @@ static struct tty_driver *gs_tty_driver;
 
 /* gadget driver struct */
 static struct usb_gadget_driver gs_gadget_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
        .speed =                USB_SPEED_HIGH,
 #else
        .speed =                USB_SPEED_FULL,
-#endif
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
        .function =             GS_LONG_NAME,
        .bind =                 gs_bind,
-       .unbind =               gs_unbind,
+       .unbind =               __exit_p(gs_unbind),
        .setup =                gs_setup,
        .disconnect =           gs_disconnect,
        .driver = {
                .name =         GS_SHORT_NAME,
-               /* .shutdown = ... */
-               /* .suspend = ...  */
-               /* .resume = ...   */
        },
 };
 
@@ -495,14 +383,21 @@ static struct usb_gadget_driver gs_gadget_driver = {
 #define GS_MANUFACTURER_STR_ID 1
 #define GS_PRODUCT_STR_ID      2
 #define GS_SERIAL_STR_ID       3
-#define GS_CONFIG_STR_ID       4
+#define GS_BULK_CONFIG_STR_ID  4
+#define GS_ACM_CONFIG_STR_ID   5
+#define GS_CONTROL_STR_ID      6
+#define GS_DATA_STR_ID         7
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
+static char manufacturer[50];
 static struct usb_string gs_strings[] = {
-       { GS_MANUFACTURER_STR_ID, UTS_SYSNAME " " UTS_RELEASE " with " CHIP },
+       { GS_MANUFACTURER_STR_ID, manufacturer },
        { GS_PRODUCT_STR_ID, GS_LONG_NAME },
        { GS_SERIAL_STR_ID, "0" },
-       { GS_CONFIG_STR_ID, "Bulk" },
+       { GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
+       { GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
+       { GS_CONTROL_STR_ID, "Gadget Serial Control" },
+       { GS_DATA_STR_ID, "Gadget Serial Data" },
        {  } /* end of list */
 };
 
@@ -511,83 +406,211 @@ static struct usb_gadget_strings gs_string_table = {
        .strings =              gs_strings,
 };
 
-static const struct usb_device_descriptor gs_device_desc = {
+static struct usb_device_descriptor gs_device_desc = {
        .bLength =              USB_DT_DEVICE_SIZE,
        .bDescriptorType =      USB_DT_DEVICE,
        .bcdUSB =               __constant_cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
-       .bMaxPacketSize0 =      EP0_MAXPACKET,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
        .idVendor =             __constant_cpu_to_le16(GS_VENDOR_ID),
        .idProduct =            __constant_cpu_to_le16(GS_PRODUCT_ID),
-       .bcdDevice =            __constant_cpu_to_le16(GS_VERSION_NUM),
        .iManufacturer =        GS_MANUFACTURER_STR_ID,
        .iProduct =             GS_PRODUCT_STR_ID,
        .iSerialNumber =        GS_SERIAL_STR_ID,
        .bNumConfigurations =   GS_NUM_CONFIGS,
 };
 
-static const struct usb_config_descriptor gs_config_desc = {
+static struct usb_otg_descriptor gs_otg_descriptor = {
+       .bLength =              sizeof(gs_otg_descriptor),
+       .bDescriptorType =      USB_DT_OTG,
+       .bmAttributes =         USB_OTG_SRP,
+};
+
+static struct usb_config_descriptor gs_bulk_config_desc = {
        .bLength =              USB_DT_CONFIG_SIZE,
        .bDescriptorType =      USB_DT_CONFIG,
-       /* .wTotalLength set by gs_build_config_desc */
-       .bNumInterfaces =       GS_NUM_INTERFACES,
+       /* .wTotalLength computed dynamically */
+       .bNumInterfaces =       1,
        .bConfigurationValue =  GS_BULK_CONFIG_ID,
-       .iConfiguration =       GS_CONFIG_STR_ID,
-       .bmAttributes =         USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
-       .bMaxPower =            (MAX_USB_POWER + 1) / 2,
+       .iConfiguration =       GS_BULK_CONFIG_STR_ID,
+       .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+       .bMaxPower =            1,
+};
+
+static struct usb_config_descriptor gs_acm_config_desc = {
+       .bLength =              USB_DT_CONFIG_SIZE,
+       .bDescriptorType =      USB_DT_CONFIG,
+       /* .wTotalLength computed dynamically */
+       .bNumInterfaces =       2,
+       .bConfigurationValue =  GS_ACM_CONFIG_ID,
+       .iConfiguration =       GS_ACM_CONFIG_STR_ID,
+       .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+       .bMaxPower =            1,
+};
+
+static const struct usb_interface_descriptor gs_bulk_interface_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bInterfaceNumber =     GS_BULK_INTERFACE_ID,
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_CDC_DATA,
+       .bInterfaceSubClass =   0,
+       .bInterfaceProtocol =   0,
+       .iInterface =           GS_DATA_STR_ID,
+};
+
+static const struct usb_interface_descriptor gs_control_interface_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bInterfaceNumber =     GS_CONTROL_INTERFACE_ID,
+       .bNumEndpoints =        1,
+       .bInterfaceClass =      USB_CLASS_COMM,
+       .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+       .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
+       .iInterface =           GS_CONTROL_STR_ID,
 };
 
-static const struct usb_interface_descriptor gs_interface_desc = {
+static const struct usb_interface_descriptor gs_data_interface_desc = {
        .bLength =              USB_DT_INTERFACE_SIZE,
        .bDescriptorType =      USB_DT_INTERFACE,
-       .bNumEndpoints =        GS_NUM_ENDPOINTS,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       .iInterface =           GS_CONFIG_STR_ID,
+       .bInterfaceNumber =     GS_DATA_INTERFACE_ID,
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_CDC_DATA,
+       .bInterfaceSubClass =   0,
+       .bInterfaceProtocol =   0,
+       .iInterface =           GS_DATA_STR_ID,
+};
+
+static const struct usb_cdc_header_desc gs_header_desc = {
+       .bLength =              sizeof(gs_header_desc),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
+       .bcdCDC =               __constant_cpu_to_le16(0x0110),
+};
+
+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 */
+};
+
+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,
 };
 
-static const struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
+static const struct usb_cdc_union_desc gs_union_desc = {
+       .bLength =              sizeof(gs_union_desc),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_UNION_TYPE,
+       .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,
-       .bEndpointAddress =     EP_IN_NUM | USB_DIR_IN,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+       .bInterval =            1 << GS_LOG2_NOTIFY_INTERVAL,
+};
+
+static struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       __constant_cpu_to_le16(64),
 };
 
-static const struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
+static struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     EP_OUT_NUM | USB_DIR_OUT,
+       .bEndpointAddress =     USB_DIR_OUT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       __constant_cpu_to_le16(64),
 };
 
-static const struct usb_endpoint_descriptor gs_highspeed_in_desc = {
+static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = {
+       (struct usb_descriptor_header *) &gs_otg_descriptor,
+       (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+       (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+       (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+       NULL,
+};
+
+static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
+       (struct usb_descriptor_header *) &gs_otg_descriptor,
+       (struct usb_descriptor_header *) &gs_control_interface_desc,
+       (struct usb_descriptor_header *) &gs_header_desc,
+       (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &gs_acm_descriptor,
+       (struct usb_descriptor_header *) &gs_union_desc,
+       (struct usb_descriptor_header *) &gs_fullspeed_notify_desc,
+       (struct usb_descriptor_header *) &gs_data_interface_desc,
+       (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+       (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+       NULL,
+};
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+       .bInterval =            GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_endpoint_descriptor gs_highspeed_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     EP_IN_NUM | USB_DIR_IN,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       __constant_cpu_to_le16(512),
 };
 
-static const struct usb_endpoint_descriptor gs_highspeed_out_desc = {
+static struct usb_endpoint_descriptor gs_highspeed_out_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     EP_OUT_NUM | USB_DIR_OUT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       __constant_cpu_to_le16(512),
 };
 
-#ifdef HIGHSPEED
-static const struct usb_qualifier_descriptor gs_qualifier_desc = {
+static struct usb_qualifier_descriptor gs_qualifier_desc = {
        .bLength =              sizeof(struct usb_qualifier_descriptor),
        .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
        .bcdUSB =               __constant_cpu_to_le16 (0x0200),
-       .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
        /* assumes ep0 uses the same value for both speeds ... */
-       .bMaxPacketSize0 =      EP0_MAXPACKET,
        .bNumConfigurations =   GS_NUM_CONFIGS,
 };
-#endif
+
+static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = {
+       (struct usb_descriptor_header *) &gs_otg_descriptor,
+       (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+       (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+       (struct usb_descriptor_header *) &gs_highspeed_out_desc,
+       NULL,
+};
+
+static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
+       (struct usb_descriptor_header *) &gs_otg_descriptor,
+       (struct usb_descriptor_header *) &gs_control_interface_desc,
+       (struct usb_descriptor_header *) &gs_header_desc,
+       (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &gs_acm_descriptor,
+       (struct usb_descriptor_header *) &gs_union_desc,
+       (struct usb_descriptor_header *) &gs_highspeed_notify_desc,
+       (struct usb_descriptor_header *) &gs_data_interface_desc,
+       (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+       (struct usb_descriptor_header *) &gs_highspeed_out_desc,
+       NULL,
+};
+
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
 
 
 /* Module */
@@ -595,18 +618,23 @@ MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
+#ifdef GS_DEBUG
+module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
+#endif
 
-MODULE_PARM(read_q_size, "i");
+module_param(read_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
 
-MODULE_PARM(write_q_size, "i");
+module_param(write_q_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
 
-MODULE_PARM(write_buf_size, "i");
+module_param(write_buf_size, uint, S_IRUGO);
 MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
 
+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);
 
@@ -645,8 +673,6 @@ static int __init gs_module_init(void)
        for (i=0; i < GS_NUM_PORTS; i++)
                sema_init(&gs_open_close_sem[i], 1);
 
-       sema_init(&gs_tmp_buf_sem, 1);
-
        retval = tty_register_driver(gs_tty_driver);
        if (retval) {
                usb_gadget_unregister_driver(&gs_gadget_driver);
@@ -686,13 +712,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        struct gs_dev *dev;
        struct gs_buf *buf;
        struct semaphore *sem;
+       int ret;
 
        port_num = tty->index;
 
        gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
 
-       tty->driver_data = NULL;
-
        if (port_num < 0 || port_num >= GS_NUM_PORTS) {
                printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
                        port_num, tty, file);
@@ -721,9 +746,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                printk(KERN_ERR
                        "gs_open: (%d,%p,%p) device is not connected\n",
                        port_num, tty, file);
-               spin_unlock_irqrestore(&dev->dev_lock, flags);
-               up(sem);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto exit_unlock_dev;
        }
 
        port = dev->dev_port[port_num];
@@ -731,9 +755,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        if (port == NULL) {
                printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
                        port_num, tty, file);
-               spin_unlock_irqrestore(&dev->dev_lock, flags);
-               up(sem);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto exit_unlock_dev;
        }
 
        spin_lock(&port->port_lock);
@@ -742,20 +765,20 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        if (port->port_dev == NULL) {
                printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
                        port_num, tty, file);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return -EIO;
+               ret = -EIO;
+               goto exit_unlock_port;
        }
 
        if (port->port_open_count > 0) {
                ++port->port_open_count;
-               spin_unlock_irqrestore(&port->port_lock, flags);
                gs_debug("gs_open: (%d,%p,%p) already open\n",
                        port_num, tty, file);
-               up(sem);
-               return 0;
+               ret = 0;
+               goto exit_unlock_port;
        }
 
+       tty->driver_data = NULL;
+
        /* mark port as in use, we can drop port lock and sleep if necessary */
        port->port_in_use = 1;
 
@@ -771,18 +794,16 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                                "gs_open: (%d,%p,%p) port disconnected (2)\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
-                       spin_unlock_irqrestore(&port->port_lock, flags);
-                       up(sem);
-                       return -EIO;
+                       ret = -EIO;
+                       goto exit_unlock_port;
                }
 
                if ((port->port_write_buf=buf) == NULL) {
                        printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
-                       spin_unlock_irqrestore(&port->port_lock, flags);
-                       up(sem);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto exit_unlock_port;
                }
 
        }
@@ -794,9 +815,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
                        port_num, tty, file);
                port->port_in_use = 0;
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return -EIO;
+               ret = -EIO;
+               goto exit_unlock_port;
        }
 
        tty->driver_data = port;
@@ -804,12 +824,20 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        port->port_open_count = 1;
        port->port_in_use = 0;
 
+       gs_debug("gs_open: (%d,%p,%p) completed\n", port_num, tty, file);
+
+       ret = 0;
+
+exit_unlock_port:
        spin_unlock_irqrestore(&port->port_lock, flags);
        up(sem);
+       return ret;
 
-       gs_debug("gs_open: (%d,%p,%p) completed\n", port_num, tty, file);
+exit_unlock_dev:
+       spin_unlock_irqrestore(&dev->dev_lock, flags);
+       up(sem);
+       return ret;
 
-       return 0;
 }
 
 /*
@@ -837,24 +865,18 @@ static void gs_close(struct tty_struct *tty, struct file *file)
                printk(KERN_ERR
                        "gs_close: (%d,%p,%p) port is already closed\n",
                        port->port_num, tty, file);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return;
+               goto exit;
        }
 
-       if (port->port_open_count > 0) {
+       if (port->port_open_count > 1) {
                --port->port_open_count;
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return;
+               goto exit;
        }
 
        /* free disconnected port on final close */
        if (port->port_dev == NULL) {
                kfree(port);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return;
+               goto exit;
        }
 
        /* mark port as closed but in use, we can drop port lock */
@@ -865,19 +887,19 @@ 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);
        }
 
        /* free disconnected port on final close */
        /* (might have happened during the above sleep) */
        if (port->port_dev == NULL) {
                kfree(port);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               up(sem);
-               return;
+               goto exit;
        }
 
        gs_buf_clear(port->port_write_buf);
@@ -886,20 +908,22 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        port->port_tty = NULL;
        port->port_in_use = 0;
 
-       spin_unlock_irqrestore(&port->port_lock, flags);
-       up(sem);
-
        gs_debug("gs_close: (%d,%p,%p) completed\n",
                port->port_num, tty, file);
+
+exit:
+       spin_unlock_irqrestore(&port->port_lock, flags);
+       up(sem);
 }
 
 /*
  * gs_write
  */
-static int gs_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        unsigned long flags;
        struct gs_port *port = tty->driver_data;
+       int ret;
 
        if (port == NULL) {
                printk(KERN_ERR "gs_write: NULL port pointer\n");
@@ -912,54 +936,36 @@ static int gs_write(struct tty_struct *tty, int from_user, const unsigned char *
        if (count == 0)
                return 0;
 
-       /* copy from user into tmp buffer, get tmp_buf semaphore */
-       if (from_user) {
-               if (count > GS_TMP_BUF_SIZE)
-                       count = GS_TMP_BUF_SIZE;
-               down(&gs_tmp_buf_sem);
-               if (copy_from_user(gs_tmp_buf, buf, count) != 0) {
-                       up(&gs_tmp_buf_sem);
-                       printk(KERN_ERR
-                       "gs_write: (%d,%p) cannot copy from user space\n",
-                               port->port_num, tty);
-                       return -EFAULT;
-               }
-               buf = gs_tmp_buf;
-       }
-
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
                printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               if (from_user)
-                       up(&gs_tmp_buf_sem);
-               return -EIO;
+               ret = -EIO;
+               goto exit;
        }
 
        if (port->port_open_count == 0) {
                printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               if (from_user)
-                       up(&gs_tmp_buf_sem);
-               return -EBADF;
+               ret = -EBADF;
+               goto exit;
        }
 
        count = gs_buf_put(port->port_write_buf, buf, count);
 
        spin_unlock_irqrestore(&port->port_lock, flags);
 
-       if (from_user)
-               up(&gs_tmp_buf_sem);
-
        gs_send(gs_device);
 
        gs_debug("gs_write: (%d,%p) wrote %d bytes\n", port->port_num, tty,
                count);
 
        return count;
+
+exit:
+       spin_unlock_irqrestore(&port->port_lock, flags);
+       return ret;
 }
 
 /*
@@ -982,19 +988,18 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
        if (port->port_dev == NULL) {
                printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               return;
+               goto exit;
        }
 
        if (port->port_open_count == 0) {
                printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               return;
+               goto exit;
        }
 
        gs_buf_put(port->port_write_buf, &ch, 1);
 
+exit:
        spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
@@ -1019,20 +1024,23 @@ static void gs_flush_chars(struct tty_struct *tty)
                printk(KERN_ERR
                        "gs_flush_chars: (%d,%p) port is not connected\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               return;
+               goto exit;
        }
 
        if (port->port_open_count == 0) {
                printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
                        port->port_num, tty);
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               return;
+               goto exit;
        }
 
        spin_unlock_irqrestore(&port->port_lock, flags);
 
        gs_send(gs_device);
+
+       return;
+
+exit:
+       spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
 /*
@@ -1229,17 +1237,16 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size)
        if (len < size)
                size = len;
 
-       if (size == 0) {
-               spin_unlock(&port->port_lock);
-               return 0;
-       }
+       if (size == 0)
+               goto exit;
 
        size = gs_buf_get(port->port_write_buf, packet, size);
 
-       wake_up_interruptible(&port->port_tty->write_wait);
+       if (port->port_tty)
+               wake_up_interruptible(&port->port_tty->write_wait);
 
+exit:
        spin_unlock(&port->port_lock);
-
        return size;
 }
 
@@ -1260,6 +1267,8 @@ 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];
@@ -1272,35 +1281,40 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
 
        spin_lock(&port->port_lock);
 
-       if (port->port_tty == NULL) {
+       if (port->port_open_count == 0) {
+               printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
+                       port->port_num);
+               ret = -EIO;
+               goto exit;
+       }
+
+
+       tty = port->port_tty;
+
+       if (tty == NULL) {
                printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
                        port->port_num);
-               spin_unlock(&port->port_lock);
-               return -EIO;
+               ret = -EIO;
+               goto exit;
        }
 
        if (port->port_tty->magic != TTY_MAGIC) {
                printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
                        port->port_num);
-               spin_unlock(&port->port_lock);
-               return -EIO;
+               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 0;
+       return ret;
 }
 
 /*
@@ -1399,21 +1413,97 @@ requeue:
  * 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;
        struct gs_dev *dev;
+       int gcnum;
+
+       /* Some controllers can't support CDC ACM:
+        * - sh doesn't support multiple interfaces or configs;
+        * - sa1100 doesn't have a third interrupt endpoint
+        */
+       if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
+               use_acm = 0;
+
+       gcnum = usb_gadget_controller_number(gadget);
+       if (gcnum >= 0)
+               gs_device_desc.bcdDevice =
+                               cpu_to_le16(GS_VERSION_NUM | gcnum);
+       else {
+               printk(KERN_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);
+       }
+
+       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 */
+
+       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 */
+
+       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);
+                       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 */
+       }
+
+       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 */
+
+       usb_gadget_set_selfpowered(gadget);
+
+       if (gadget->is_otg) {
+               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;
 
-       set_gadget_data(gadget, dev);
+       snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+               system_utsname.sysname, system_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");
@@ -1436,6 +1526,10 @@ static int gs_bind(struct usb_gadget *gadget)
                GS_LONG_NAME, GS_VERSION_STR);
 
        return 0;
+
+autoconf_fail:
+       printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name);
+       return -ENODEV;
 }
 
 /*
@@ -1444,7 +1538,7 @@ static int gs_bind(struct usb_gadget *gadget)
  * Called on module unload.  Frees the control request and device
  * structure.
  */
-static void gs_unbind(struct usb_gadget *gadget)
+static void __exit gs_unbind(struct usb_gadget *gadget)
 {
        struct gs_dev *dev = get_gadget_data(gadget);
 
@@ -1452,8 +1546,10 @@ static void gs_unbind(struct usb_gadget *gadget)
 
        /* read/write requests already freed, only control request remains */
        if (dev != NULL) {
-               if (dev->dev_ctrl_req != 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);
@@ -1472,47 +1568,100 @@ static void gs_unbind(struct usb_gadget *gadget)
  * 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)
+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)
 {
        int ret = -EOPNOTSUPP;
-       unsigned int sv_config;
        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->bRequest) {
        case USB_REQ_GET_DESCRIPTOR:
                if (ctrl->bRequestType != USB_DIR_IN)
                        break;
 
-               switch (ctrl->wValue >> 8) {
+               switch (wValue >> 8) {
                case USB_DT_DEVICE:
-                       ret = min(ctrl->wLength,
+                       ret = min(wLength,
                                (u16)sizeof(struct usb_device_descriptor));
                        memcpy(req->buf, &gs_device_desc, ret);
                        break;
 
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       ret = min(ctrl->wLength,
+                       if (!gadget->is_dualspeed)
+                               break;
+                       ret = min(wLength,
                                (u16)sizeof(struct usb_qualifier_descriptor));
                        memcpy(req->buf, &gs_qualifier_desc, ret);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-#endif /* HIGHSPEED */
+                       if (!gadget->is_dualspeed)
+                               break;
+                       /* fall through */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       ret = gs_build_config_desc(req->buf, gadget->speed,
-                               ctrl->wValue >> 8, ctrl->wValue & 0xff);
+                       ret = gs_build_config_buf(req->buf, gadget->speed,
+                               wValue >> 8, wValue & 0xff,
+                               gadget->is_otg);
                        if (ret >= 0)
-                               ret = min(ctrl->wLength, (u16)ret);
+                               ret = min(wLength, (u16)ret);
                        break;
 
                case USB_DT_STRING:
                        /* wIndex == language code. */
                        ret = usb_gadget_get_string(&gs_string_table,
-                               ctrl->wValue & 0xff, req->buf);
+                               wValue & 0xff, req->buf);
                        if (ret >= 0)
-                               ret = min(ctrl->wLength, (u16)ret);
+                               ret = min(wLength, (u16)ret);
                        break;
                }
                break;
@@ -1521,7 +1670,7 @@ static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctr
                if (ctrl->bRequestType != 0)
                        break;
                spin_lock(&dev->dev_lock);
-               ret = gs_set_config(dev, ctrl->wValue);
+               ret = gs_set_config(dev, wValue);
                spin_unlock(&dev->dev_lock);
                break;
 
@@ -1529,61 +1678,114 @@ static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctr
                if (ctrl->bRequestType != USB_DIR_IN)
                        break;
                *(u8 *)req->buf = dev->dev_config;
-               ret = min(ctrl->wLength, (u16)1);
+               ret = min(wLength, (u16)1);
                break;
 
        case USB_REQ_SET_INTERFACE:
-               if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+               if (ctrl->bRequestType != USB_RECIP_INTERFACE
+                               || !dev->dev_config
+                               || wIndex >= GS_MAX_NUM_INTERFACES)
                        break;
-               spin_lock(&dev->dev_lock);
                if (dev->dev_config == GS_BULK_CONFIG_ID
-               && ctrl->wIndex == GS_INTERFACE_ID
-               && ctrl->wValue == GS_ALT_INTERFACE_ID) {
-                       sv_config = dev->dev_config;
-                       /* since there is only one interface, setting the */
-                       /* interface is equivalent to setting the config */
-                       gs_reset_config(dev);
-                       gs_set_config(dev, sv_config);
-                       ret = 0;
+                               && wIndex != GS_BULK_INTERFACE_ID)
+                       break;
+               /* no alternate interface settings */
+               if (wValue != 0)
+                       break;
+               spin_lock(&dev->dev_lock);
+               /* PXA hardware partially handles SET_INTERFACE;
+                * we need to kluge around that interference.  */
+               if (gadget_is_pxa(gadget)) {
+                       ret = gs_set_config(dev, use_acm ?
+                               GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID);
+                       goto set_interface_done;
                }
+               if (dev->dev_config != GS_BULK_CONFIG_ID
+                               && wIndex == GS_CONTROL_INTERFACE_ID) {
+                       if (dev->dev_notify_ep) {
+                               usb_ep_disable(dev->dev_notify_ep);
+                               usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc);
+                       }
+               } else {
+                       usb_ep_disable(dev->dev_in_ep);
+                       usb_ep_disable(dev->dev_out_ep);
+                       usb_ep_enable(dev->dev_in_ep, dev->dev_in_ep_desc);
+                       usb_ep_enable(dev->dev_out_ep, dev->dev_out_ep_desc);
+               }
+               ret = 0;
+set_interface_done:
                spin_unlock(&dev->dev_lock);
                break;
 
        case USB_REQ_GET_INTERFACE:
-               if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
-                       break;
-               if (dev->dev_config == GS_NO_CONFIG_ID)
+               if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+               || dev->dev_config == GS_NO_CONFIG_ID)
                        break;
-               if (ctrl->wIndex != GS_INTERFACE_ID) {
+               if (wIndex >= GS_MAX_NUM_INTERFACES
+                               || (dev->dev_config == GS_BULK_CONFIG_ID
+                               && wIndex != GS_BULK_INTERFACE_ID)) {
                        ret = -EDOM;
                        break;
                }
-               *(u8 *)req->buf = GS_ALT_INTERFACE_ID;
-               ret = min(ctrl->wLength, (u16)1);
+               /* no alternate interface settings */
+               *(u8 *)req->buf = 0;
+               ret = min(wLength, (u16)1);
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
-                       ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
-                       ctrl->wIndex, ctrl->wLength);
+               printk(KERN_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;
-
        }
 
-       /* respond with data transfer before status phase? */
-       if (ret >= 0) {
-               req->length = ret;
-               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);
+       return ret;
+}
+
+static int gs_setup_class(struct usb_gadget *gadget,
+       const struct usb_ctrlrequest *ctrl)
+{
+       int ret = -EOPNOTSUPP;
+       struct gs_dev *dev = get_gadget_data(gadget);
+       struct gs_port *port = dev->dev_port[0];        /* ACM only has one port */
+       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->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);
                }
+               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));
+               if (port) {
+                       spin_lock(&port->port_lock);
+                       memcpy(req->buf, &port->port_line_coding, ret);
+                       spin_unlock(&port->port_lock);
+               }
+               break;
+
+       case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+               ret = 0;
+               break;
+
+       default:
+               printk(KERN_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;
        }
 
-       /* device either stalls (ret < 0) or reports success */
        return ret;
 }
 
@@ -1642,6 +1844,7 @@ 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_request *req;
        struct gs_req_entry *req_entry;
 
@@ -1655,53 +1858,90 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
        gs_reset_config(dev);
 
-       if (config == GS_NO_CONFIG_ID)
+       switch (config) {
+       case GS_NO_CONFIG_ID:
                return 0;
-
-       if (config != GS_BULK_CONFIG_ID)
+       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;
+       }
 
-       hw_optimize(gadget);
+       dev->dev_config = config;
 
        gadget_for_each_ep(ep, gadget) {
 
-               if (strcmp(ep->name, EP_IN_NAME) == 0) {
-                       ret = usb_ep_enable(ep,
-                               gadget->speed == USB_SPEED_HIGH ?
-                               &gs_highspeed_in_desc : &gs_fullspeed_in_desc);
+               if (EP_NOTIFY_NAME
+               && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
+                       ep_desc = GS_SPEED_SELECT(
+                               gadget->speed == USB_SPEED_HIGH,
+                               &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);
-                               gs_reset_config(dev);
-                               return ret;
+                               goto exit_reset_config;
                        }
                }
 
                else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-                       ret = usb_ep_enable(ep,
-                               gadget->speed == USB_SPEED_HIGH ?
-                               &gs_highspeed_out_desc :
+                       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);
-                               gs_reset_config(dev);
-                               return ret;
+                               goto exit_reset_config;
                        }
                }
 
        }
 
-       if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL) {
-               gs_reset_config(dev);
+       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");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto exit_reset_config;
        }
 
        /* allocate and queue read requests */
@@ -1714,10 +1954,9 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                                        ret);
                        }
                } else {
-                       gs_reset_config(dev);
-                       printk(KERN_ERR
-                       "gs_set_config: cannot allocate read requests\n");
-                       return -ENOMEM;
+                       printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
+                       ret = -ENOMEM;
+                       goto exit_reset_config;
                }
        }
 
@@ -1728,20 +1967,22 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                        req_entry->re_req->complete = gs_write_complete;
                        list_add(&req_entry->re_entry, &dev->dev_req_list);
                } else {
-                       gs_reset_config(dev);
-                       printk(KERN_ERR
-                       "gs_set_config: cannot allocate write requests\n");
-                       return -ENOMEM;
+                       printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
+                       ret = -ENOMEM;
+                       goto exit_reset_config;
                }
        }
 
-       dev->dev_config = config;
-
-       printk(KERN_INFO "gs_set_config: %s configured for %s speed\n",
+       printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
                GS_LONG_NAME,
-               gadget->speed == USB_SPEED_HIGH ? "high" : "full");
+               gadget->speed == USB_SPEED_HIGH ? "high" : "full",
+               config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
 
        return 0;
+
+exit_reset_config:
+       gs_reset_config(dev);
+       return ret;
 }
 
 /*
@@ -1778,6 +2019,10 @@ static void gs_reset_config(struct gs_dev *dev)
 
        /* disable endpoints, forcing completion of pending i/o; */
        /* completion handlers free their requests in this case */
+       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;
@@ -1789,41 +2034,48 @@ static void gs_reset_config(struct gs_dev *dev)
 }
 
 /*
- * gs_build_config_desc
+ * gs_build_config_buf
  *
- * Builds a config descriptor in the given buffer and returns the
+ * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_desc(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index)
+static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+       u8 type, unsigned int index, int is_otg)
 {
+       int len;
        int high_speed;
-       int len = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE
-                               + GS_NUM_ENDPOINTS * USB_DT_ENDPOINT_SIZE;
+       const struct usb_config_descriptor *config_desc;
+       const struct usb_descriptor_header **function;
 
-       /* only one config */
-       if (index != 0)
+       if (index >= gs_device_desc.bNumConfigurations)
                return -EINVAL;
 
-       memcpy(buf, &gs_config_desc, USB_DT_CONFIG_SIZE);
-       ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
-       ((struct usb_config_descriptor *)buf)->wTotalLength = __constant_cpu_to_le16(len);
-       buf += USB_DT_CONFIG_SIZE;
-
-       memcpy(buf, &gs_interface_desc, USB_DT_INTERFACE_SIZE);
-       buf += USB_DT_INTERFACE_SIZE;
-
        /* other speed switches high and full speed */
        high_speed = (speed == USB_SPEED_HIGH);
        if (type == USB_DT_OTHER_SPEED_CONFIG)
                high_speed = !high_speed;
 
-       memcpy(buf,
-               high_speed ? &gs_highspeed_in_desc : &gs_fullspeed_in_desc,
-               USB_DT_ENDPOINT_SIZE);
-       buf += USB_DT_ENDPOINT_SIZE;
-       memcpy(buf,
-               high_speed ? &gs_highspeed_out_desc : &gs_fullspeed_out_desc,
-               USB_DT_ENDPOINT_SIZE);
+       if (use_acm) {
+               config_desc = &gs_acm_config_desc;
+               function = GS_SPEED_SELECT(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);
+       }
+
+       /* for now, don't advertise srp-only devices */
+       if (!is_otg)
+               function++;
+
+       len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
+       if (len < 0)
+               return len;
+
+       ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
 
        return len;
 }
@@ -1834,7 +2086,8 @@ static int gs_build_config_desc(u8 *buf, enum usb_device_speed speed, u8 type, u
  * Allocate a usb_request and its buffer.  Returns a pointer to the
  * usb_request or NULL if there is an error.
  */
-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags)
+static struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags)
 {
        struct usb_request *req;
 
@@ -1845,8 +2098,7 @@ static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int
 
        if (req != NULL) {
                req->length = len;
-               req->buf = usb_ep_alloc_buffer(ep, len, &req->dma,
-                       kmalloc_flags);
+               req->buf = kmalloc(len, kmalloc_flags);
                if (req->buf == NULL) {
                        usb_ep_free_request(ep, req);
                        return NULL;
@@ -1864,9 +2116,7 @@ static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int
 static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
 {
        if (ep != NULL && req != NULL) {
-               if (req->buf != NULL)
-                       usb_ep_free_buffer(ep, req->buf, req->dma,
-                               req->length);
+               kfree(req->buf);
                usb_ep_free_request(ep, req);
        }
 }
@@ -1877,7 +2127,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
  * 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, int 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;
 
@@ -1918,7 +2169,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
  *
  * The device lock is normally held when calling this function.
  */
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
+static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
 {
        int i;
        struct gs_port *port;
@@ -1927,12 +2178,15 @@ static int gs_alloc_ports(struct gs_dev *dev, int 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);
+               port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
+               port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
+               port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
                spin_lock_init(&port->port_lock);
                init_waitqueue_head(&port->port_write_wait);
 
@@ -1975,13 +2229,16 @@ static void gs_free_ports(struct gs_dev *dev)
                        if (port->port_open_count > 0 || port->port_in_use) {
                                port->port_dev = NULL;
                                wake_up_interruptible(&port->port_write_wait);
-                               wake_up_interruptible(&port->port_tty->read_wait);
-                               wake_up_interruptible(&port->port_tty->write_wait);
+                               if (port->port_tty) {
+                                       wake_up_interruptible(&port->port_tty->read_wait);
+                                       wake_up_interruptible(&port->port_tty->write_wait);
+                               }
+                               spin_unlock_irqrestore(&port->port_lock, flags);
                        } else {
+                               spin_unlock_irqrestore(&port->port_lock, flags);
                                kfree(port);
                        }
 
-                       spin_unlock_irqrestore(&port->port_lock, flags);
                }
        }
 }
@@ -1993,7 +2250,7 @@ static void gs_free_ports(struct gs_dev *dev)
  *
  * Allocate a circular buffer and all associated memory.
  */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
+static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
 {
        struct gs_buf *gb;
 
@@ -2023,9 +2280,8 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
  */
 void gs_buf_free(struct gs_buf *gb)
 {
-       if (gb != NULL) {
-               if (gb->buf_buf != NULL)
-                       kfree(gb->buf_buf);
+       if (gb) {
+               kfree(gb->buf_buf);
                kfree(gb);
        }
 }