Commit 9079e91b authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB: serial gadget: cleanup/reorg

Some cleanup/reorg of g_serial ... simplifying it, and disentangling
its structure so morphing it into a "function" driver (combinable with
other interfaces) should be less painful.

 - Remove most forward declarations
     * put tty and gadget driver structs after their contents
     * snug module init/exit decls next to their functions
     * reordered some functions

 - Other cleanup:
     * convert a funky macro to an inline function
     * snug up module params next to their declarations
     * add missing driver.owner
     * add separator lines between major driver sections

 - Add comments re potential parameter/#define changes:
     * only supports one port (shrank GS_NUM_PORTS)
     * changing from 9600-8-N-1 affects multiple sites

 - Remove net2280-specific optimization ... it was being done
   way too late, can be done by net2280 module options, and in
   any case doesn't matter at any sane serial data rates.

There are no behavioral changes, but the macro thing saves I-space.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Al Borchers <alborchers@steinerpoint.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent fe312e77
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
* This software is distributed under the terms of the GNU General * This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation, * Public License ("GPL") as published by the Free Software Foundation,
* either version 2 of that License or (at your option) any later version. * either version 2 of that License or (at your option) any later version.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -41,7 +40,11 @@ ...@@ -41,7 +40,11 @@
#define GS_MAJOR 127 #define GS_MAJOR 127
#define GS_MINOR_START 0 #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_NUM_CONFIGS 1
#define GS_NO_CONFIG_ID 0 #define GS_NO_CONFIG_ID 0
...@@ -65,6 +68,9 @@ ...@@ -65,6 +68,9 @@
#define GS_DEFAULT_USE_ACM 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_DTE_RATE 9600
#define GS_DEFAULT_DATA_BITS 8 #define GS_DEFAULT_DATA_BITS 8
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
...@@ -107,10 +113,6 @@ static int debug = 1; ...@@ -107,10 +113,6 @@ static int debug = 1;
#define GS_NOTIFY_MAXPACKET 8 #define GS_NOTIFY_MAXPACKET 8
/* Structures */
struct gs_dev;
/* circular buffer */ /* circular buffer */
struct gs_buf { struct gs_buf {
unsigned int buf_size; unsigned int buf_size;
...@@ -164,26 +166,7 @@ struct gs_dev { ...@@ -164,26 +166,7 @@ struct gs_dev {
/* Functions */ /* Functions */
/* module */ /* tty driver internals */
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);
static int gs_send(struct gs_dev *dev); static int gs_send(struct gs_dev *dev);
static int gs_send_packet(struct gs_dev *dev, char *packet, static int gs_send_packet(struct gs_dev *dev, char *packet,
unsigned int size); unsigned int size);
...@@ -192,19 +175,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, ...@@ -192,19 +175,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet,
static void gs_read_complete(struct usb_ep *ep, struct usb_request *req); static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_write_complete(struct usb_ep *ep, struct usb_request *req); static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);
/* gadget driver */ /* gadget driver internals */
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);
static int gs_set_config(struct gs_dev *dev, unsigned config); static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev); static void gs_reset_config(struct gs_dev *dev);
static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
...@@ -232,9 +203,6 @@ static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, ...@@ -232,9 +203,6 @@ 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, static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
unsigned int count); unsigned int count);
/* external functions */
extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);
/* Globals */ /* Globals */
...@@ -246,48 +214,8 @@ static const char *EP_NOTIFY_NAME; ...@@ -246,48 +214,8 @@ static const char *EP_NOTIFY_NAME;
static struct mutex gs_open_close_lock[GS_NUM_PORTS]; 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 */ /* USB descriptors */
...@@ -521,6 +449,8 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { ...@@ -521,6 +449,8 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
}; };
/*-------------------------------------------------------------------------*/
/* Module */ /* Module */
MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers"); MODULE_AUTHOR("Al Borchers");
...@@ -531,84 +461,23 @@ module_param(debug, int, S_IRUGO|S_IWUSR); ...@@ -531,84 +461,23 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif #endif
static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
module_param(read_q_size, uint, S_IRUGO); module_param(read_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); 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_param(write_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32"); 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_param(write_buf_size, uint, S_IRUGO);
MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192"); 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_param(use_acm, uint, S_IRUGO);
MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no"); 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 */ /* TTY Driver */
...@@ -753,15 +622,15 @@ static int gs_open(struct tty_struct *tty, struct file *file) ...@@ -753,15 +622,15 @@ static int gs_open(struct tty_struct *tty, struct file *file)
* gs_close * gs_close
*/ */
#define GS_WRITE_FINISHED_EVENT_SAFELY(p) \ static int gs_write_finished_event_safely(struct gs_port *p)
({ \ {
int cond; \ int cond;
\
spin_lock_irq(&(p)->port_lock); \ spin_lock_irq(&(p)->port_lock);
cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \ cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf);
spin_unlock_irq(&(p)->port_lock); \ spin_unlock_irq(&(p)->port_lock);
cond; \ return cond;
}) }
static void gs_close(struct tty_struct *tty, struct file *file) static void gs_close(struct tty_struct *tty, struct file *file)
{ {
...@@ -807,7 +676,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) ...@@ -807,7 +676,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
if (gs_buf_data_avail(port->port_write_buf) > 0) { if (gs_buf_data_avail(port->port_write_buf) > 0) {
spin_unlock_irq(&port->port_lock); spin_unlock_irq(&port->port_lock);
wait_event_interruptible_timeout(port->port_write_wait, wait_event_interruptible_timeout(port->port_write_wait,
GS_WRITE_FINISHED_EVENT_SAFELY(port), gs_write_finished_event_safely(port),
GS_CLOSE_TIMEOUT * HZ); GS_CLOSE_TIMEOUT * HZ);
spin_lock_irq(&port->port_lock); spin_lock_irq(&port->port_lock);
} }
...@@ -1065,6 +934,23 @@ static void gs_set_termios(struct tty_struct *tty, struct ktermios *old) ...@@ -1065,6 +934,23 @@ static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
{ {
} }
static const struct tty_operations gs_tty_ops = {
.open = gs_open,
.close = gs_close,
.write = gs_write,
.put_char = gs_put_char,
.flush_chars = gs_flush_chars,
.write_room = gs_write_room,
.ioctl = gs_ioctl,
.set_termios = gs_set_termios,
.throttle = gs_throttle,
.unthrottle = gs_unthrottle,
.break_ctl = gs_break,
.chars_in_buffer = gs_chars_in_buffer,
};
/*-------------------------------------------------------------------------*/
/* /*
* gs_send * gs_send
* *
...@@ -1328,8 +1214,43 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -1328,8 +1214,43 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
} }
} }
/*-------------------------------------------------------------------------*/
/* Gadget Driver */ /* 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_bind
* *
...@@ -1441,8 +1362,6 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1441,8 +1362,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_unbind(gadget); gs_unbind(gadget);
return -ENOMEM; return -ENOMEM;
} }
dev->dev_ctrl_req->complete = gs_setup_complete;
gadget->ep0->driver_data = dev; gadget->ep0->driver_data = dev;
pr_info("gs_bind: %s %s bound\n", pr_info("gs_bind: %s %s bound\n",
...@@ -1455,95 +1374,6 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1455,95 +1374,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
return -ENODEV; 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, static int gs_setup_standard(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl) const struct usb_ctrlrequest *ctrl)
{ {
...@@ -1673,6 +1503,42 @@ static int gs_setup_standard(struct usb_gadget *gadget, ...@@ -1673,6 +1503,42 @@ static int gs_setup_standard(struct usb_gadget *gadget,
return ret; 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, static int gs_setup_class(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl) const struct usb_ctrlrequest *ctrl)
{ {
...@@ -1734,52 +1600,72 @@ static int gs_setup_class(struct usb_gadget *gadget, ...@@ -1734,52 +1600,72 @@ static int gs_setup_class(struct usb_gadget *gadget,
return ret; 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; if (req->status || req->actual != req->length) {
struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ 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: * gs_setup
/* normal completion */ *
if (req->actual != sizeof(port->port_line_coding)) * Implements all the control endpoint functionality that's not
usb_ep_set_halt(ep); * handled in hardware or the hardware driver.
else if (port) { *
struct usb_cdc_line_coding *value = req->buf; * 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. req->complete = gs_setup_complete;
* If we change that, (a) validate it first, then
* (b) update whatever hardware needs updating. switch (ctrl->bRequestType & USB_TYPE_MASK) {
*/ case USB_TYPE_STANDARD:
spin_lock(&port->port_lock); ret = gs_setup_standard(gadget, ctrl);
port->port_line_coding = *value;
spin_unlock(&port->port_lock);
}
break; break;
case -ESHUTDOWN: case USB_TYPE_CLASS:
/* disconnect */ ret = gs_setup_class(gadget, ctrl);
gs_free_req(ep, req);
break; break;
default: 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; break;
} }
return;
}
/* /* respond with data transfer before status phase? */
* gs_setup_complete if (ret >= 0) {
*/ req->length = ret;
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req) req->zero = ret < wLength
{ && (ret % gadget->ep0->maxpacket) == 0;
if (req->status || req->actual != req->length) { ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
pr_err("gs_setup_complete: status error, status=%d, " if (ret < 0) {
"actual=%d, length=%d\n", pr_err("gs_setup: cannot queue response, ret=%d\n",
req->status, req->actual, req->length); ret);
req->status = 0;
gs_setup_complete(gadget->ep0, req);
}
} }
/* device either stalls (ret < 0) or reports success */
return ret;
} }
/* /*
...@@ -1811,6 +1697,23 @@ static void gs_disconnect(struct usb_gadget *gadget) ...@@ -1811,6 +1697,23 @@ static void gs_disconnect(struct usb_gadget *gadget)
pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME); pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
} }
static struct usb_gadget_driver gs_gadget_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
#endif /* CONFIG_USB_GADGET_DUALSPEED */
.function = GS_LONG_NAME,
.bind = gs_bind,
.unbind = gs_unbind,
.setup = gs_setup,
.disconnect = gs_disconnect,
.driver = {
.name = GS_SHORT_NAME,
.owner = THIS_MODULE,
},
};
/* /*
* gs_set_config * gs_set_config
* *
...@@ -1846,16 +1749,10 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) ...@@ -1846,16 +1749,10 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
case GS_BULK_CONFIG_ID: case GS_BULK_CONFIG_ID:
if (use_acm) if (use_acm)
return -EINVAL; return -EINVAL;
/* device specific optimizations */
if (gadget_is_net2280(gadget))
net2280_set_fifo_mode(gadget, 1);
break; break;
case GS_ACM_CONFIG_ID: case GS_ACM_CONFIG_ID:
if (!use_acm) if (!use_acm)
return -EINVAL; return -EINVAL;
/* device specific optimizations */
if (gadget_is_net2280(gadget))
net2280_set_fifo_mode(gadget, 1);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -2233,6 +2130,8 @@ static void gs_free_ports(struct gs_dev *dev) ...@@ -2233,6 +2130,8 @@ static void gs_free_ports(struct gs_dev *dev)
} }
} }
/*-------------------------------------------------------------------------*/
/* Circular Buffer */ /* Circular Buffer */
/* /*
...@@ -2393,3 +2292,77 @@ gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count) ...@@ -2393,3 +2292,77 @@ gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
return count; return count;
} }
/*-------------------------------------------------------------------------*/
static struct tty_driver *gs_tty_driver;
/*
* gs_module_init
*
* Register as a USB gadget driver and a tty driver.
*/
static int __init gs_module_init(void)
{
int i;
int retval;
retval = usb_gadget_register_driver(&gs_gadget_driver);
if (retval) {
pr_err("gs_module_init: cannot register gadget driver, "
"ret=%d\n", retval);
return retval;
}
gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
if (!gs_tty_driver)
return -ENOMEM;
gs_tty_driver->owner = THIS_MODULE;
gs_tty_driver->driver_name = GS_SHORT_NAME;
gs_tty_driver->name = "ttygs";
gs_tty_driver->major = GS_MAJOR;
gs_tty_driver->minor_start = GS_MINOR_START;
gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
gs_tty_driver->init_termios = tty_std_termios;
/* must match GS_DEFAULT_DTE_RATE and friends */
gs_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
gs_tty_driver->init_termios.c_ispeed = GS_DEFAULT_DTE_RATE;
gs_tty_driver->init_termios.c_ospeed = GS_DEFAULT_DTE_RATE;
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i = 0; i < GS_NUM_PORTS; i++)
mutex_init(&gs_open_close_lock[i]);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
usb_gadget_unregister_driver(&gs_gadget_driver);
put_tty_driver(gs_tty_driver);
pr_err("gs_module_init: cannot register tty driver, "
"ret=%d\n", retval);
return retval;
}
pr_info("gs_module_init: %s %s loaded\n",
GS_LONG_NAME, GS_VERSION_STR);
return 0;
}
module_init(gs_module_init);
/*
* gs_module_exit
*
* Unregister as a tty driver and a USB gadget driver.
*/
static void __exit gs_module_exit(void)
{
tty_unregister_driver(gs_tty_driver);
put_tty_driver(gs_tty_driver);
usb_gadget_unregister_driver(&gs_gadget_driver);
pr_info("gs_module_exit: %s %s unloaded\n",
GS_LONG_NAME, GS_VERSION_STR);
}
module_exit(gs_module_exit);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment