* 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/kernel.h>
 #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
 
 #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_NOTIFY_MAXPACKET            8
 
 
-/* Structures */
-
-struct gs_dev;
-
 /* circular buffer */
 struct gs_buf {
        unsigned int            buf_size;
 
 /* 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 int 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 ktermios *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);
 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_setup_complete_set_line_coding(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, struct usb_gadget *g,
 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 mutex gs_open_close_lock[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 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,
-};
-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,
-       },
-};
 
+/*-------------------------------------------------------------------------*/
 
 /* USB descriptors */
 
 };
 
 
+/*-------------------------------------------------------------------------*/
+
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 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) {
-               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;
-       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++)
-               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;
-}
-
-/*
-* 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);
-}
+/*-------------------------------------------------------------------------*/
 
 /* TTY Driver */
 
  * gs_close
  */
 
-#define GS_WRITE_FINISHED_EVENT_SAFELY(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);                       \
-       cond;                                                   \
-})
+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)
 {
        if (gs_buf_data_avail(port->port_write_buf) > 0) {
                spin_unlock_irq(&port->port_lock);
                wait_event_interruptible_timeout(port->port_write_wait,
-                                       GS_WRITE_FINISHED_EVENT_SAFELY(port),
+                                       gs_write_finished_event_safely(port),
                                        GS_CLOSE_TIMEOUT * HZ);
                spin_lock_irq(&port->port_lock);
        }
 {
 }
 
+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
 *
        }
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* 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_free_ports(dev);
+               if (dev->dev_notify_ep)
+                       usb_ep_disable(dev->dev_notify_ep);
+               if (dev->dev_in_ep)
+                       usb_ep_disable(dev->dev_in_ep);
+               if (dev->dev_out_ep)
+                       usb_ep_disable(dev->dev_out_ep);
+               kfree(dev);
+               set_gadget_data(gadget, NULL);
+       }
+
+       pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+               GS_VERSION_STR);
+}
+
 /*
  * gs_bind
  *
                gs_unbind(gadget);
                return -ENOMEM;
        }
-       dev->dev_ctrl_req->complete = gs_setup_complete;
-
        gadget->ep0->driver_data = dev;
 
        pr_info("gs_bind: %s %s bound\n",
        return -ENODEV;
 }
 
-/*
- * 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_free_ports(dev);
-               if (dev->dev_notify_ep)
-                       usb_ep_disable(dev->dev_notify_ep);
-               if (dev->dev_in_ep)
-                       usb_ep_disable(dev->dev_in_ep);
-               if (dev->dev_out_ep)
-                       usb_ep_disable(dev->dev_out_ep);
-               kfree(dev);
-               set_gadget_data(gadget, NULL);
-       }
-
-       pr_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);
-
-       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;
-}
-
 static int gs_setup_standard(struct usb_gadget *gadget,
        const struct usb_ctrlrequest *ctrl)
 {
        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)
 {
        return ret;
 }
 
-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
-               struct usb_request *req)
+/*
+ * gs_setup_complete
+ */
+static void gs_setup_complete(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 */
+       if (req->status || req->actual != req->length) {
+               pr_err("gs_setup_complete: status error, status=%d, "
+                       "actual=%d, length=%d\n",
+                       req->status, req->actual, req->length);
+       }
+}
 
-       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;
+/*
+ * 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);
 
-                       /* 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);
-               }
+       req->complete = gs_setup_complete;
+
+       switch (ctrl->bRequestType & USB_TYPE_MASK) {
+       case USB_TYPE_STANDARD:
+               ret = gs_setup_standard(gadget, ctrl);
                break;
 
-       case -ESHUTDOWN:
-               /* disconnect */
-               gs_free_req(ep, req);
+       case USB_TYPE_CLASS:
+               ret = gs_setup_class(gadget, ctrl);
                break;
 
        default:
-               /* unexpected */
+               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;
        }
-       return;
-}
 
-/*
- * gs_setup_complete
- */
-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       if (req->status || req->actual != req->length) {
-               pr_err("gs_setup_complete: status error, status=%d, "
-                       "actual=%d, length=%d\n",
-                       req->status, req->actual, req->length);
+       /* 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;
 }
 
 /*
        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
  *
        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;
        }
 }
 
+/*-------------------------------------------------------------------------*/
+
 /* Circular Buffer */
 
 /*
 
        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);