📄 serial.c
字号:
.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_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 = 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,
};
static struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
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,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(512),
};
static struct usb_endpoint_descriptor gs_highspeed_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(512),
};
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),
/* assumes ep0 uses the same value for both speeds ... */
.bNumConfigurations = GS_NUM_CONFIGS,
};
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 */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
#ifdef GS_DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
module_param(read_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
module_param(write_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
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);
/*
* gs_module_init
*
* Register as a USB gadget driver and a tty driver.
*/
static int __init gs_module_init(void)
{
int i;
int retval;
retval = usb_gadget_register_driver(&gs_gadget_driver);
if (retval) {
printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval);
return retval;
}
gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
if (!gs_tty_driver)
return -ENOMEM;
gs_tty_driver->owner = THIS_MODULE;
gs_tty_driver->driver_name = GS_SHORT_NAME;
gs_tty_driver->name = "ttygs";
gs_tty_driver->devfs_name = "usb/ttygs/";
gs_tty_driver->major = GS_MAJOR;
gs_tty_driver->minor_start = GS_MINOR_START;
gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
gs_tty_driver->init_termios = tty_std_termios;
gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i=0; i < GS_NUM_PORTS; i++)
sema_init(&gs_open_close_sem[i], 1);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
usb_gadget_unregister_driver(&gs_gadget_driver);
put_tty_driver(gs_tty_driver);
printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval);
return retval;
}
printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR);
return 0;
}
/*
* gs_module_exit
*
* Unregister as a tty driver and a USB gadget driver.
*/
static void __exit gs_module_exit(void)
{
tty_unregister_driver(gs_tty_driver);
put_tty_driver(gs_tty_driver);
usb_gadget_unregister_driver(&gs_gadget_driver);
printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR);
}
/* TTY Driver */
/*
* gs_open
*/
static int gs_open(struct tty_struct *tty, struct file *file)
{
int port_num;
unsigned long flags;
struct gs_port *port;
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);
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);
return -ENODEV;
}
dev = gs_device;
if (dev == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n",
port_num, tty, file);
return -ENODEV;
}
sem = &gs_open_close_sem[port_num];
if (down_interruptible(sem)) {
printk(KERN_ERR
"gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
port_num, tty, file);
return -ERESTARTSYS;
}
spin_lock_irqsave(&dev->dev_lock, flags);
if (dev->dev_config == GS_NO_CONFIG_ID) {
printk(KERN_ERR
"gs_open: (%d,%p,%p) device is not connected\n",
port_num, tty, file);
ret = -ENODEV;
goto exit_unlock_dev;
}
port = dev->dev_port[port_num];
if (port == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
port_num, tty, file);
ret = -ENODEV;
goto exit_unlock_dev;
}
spin_lock(&port->port_lock);
spin_unlock(&dev->dev_lock);
if (port->port_dev == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
port_num, tty, file);
ret = -EIO;
goto exit_unlock_port;
}
if (port->port_open_count > 0) {
++port->port_open_count;
gs_debug("gs_open: (%d,%p,%p) already open\n",
port_num, tty, file);
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;
/* allocate write buffer on first open */
if (port->port_write_buf == NULL) {
spin_unlock_irqrestore(&port->port_lock, flags);
buf = gs_buf_alloc(write_buf_size, GFP_KERNEL);
spin_lock_irqsave(&port->port_lock, flags);
/* might have been disconnected while asleep, check */
if (port->port_dev == NULL) {
printk(KERN_ERR
"gs_open: (%d,%p,%p) port disconnected (2)\n",
port_num, tty, file);
port->port_in_use = 0;
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;
ret = -ENOMEM;
goto exit_unlock_port;
}
}
/* wait for carrier detect (not implemented) */
/* might have been disconnected while asleep, check */
if (port->port_dev == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
port_num, tty, file);
port->port_in_use = 0;
ret = -EIO;
goto exit_unlock_port;
}
tty->driver_data = port;
port->port_tty = tty;
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;
exit_unlock_dev:
spin_unlock_irqrestore(&dev->dev_lock, flags);
up(sem);
return ret;
}
/*
* gs_close
*/
static void gs_close(struct tty_struct *tty, struct file *file)
{
unsigned long flags;
struct gs_port *port = tty->driver_data;
struct semaphore *sem;
if (port == NULL) {
printk(KERN_ERR "gs_close: NULL port pointer\n");
return;
}
gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
sem = &gs_open_close_sem[port->port_num];
down(sem);
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_open_count == 0) {
printk(KERN_ERR
"gs_close: (%d,%p,%p) port is already closed\n",
port->port_num, tty, file);
goto exit;
}
if (port->port_open_count > 1) {
--port->port_open_count;
goto exit;
}
/* free disconnected port on final close */
if (port->port_dev == NULL) {
kfree(port);
goto exit;
}
/* mark port as closed but in use, we can drop port lock */
/* and sleep if necessary */
port->port_in_use = 1;
port->port_open_count = 0;
/* wait for write buffer to drain, or */
/* at most GS_CLOSE_TIMEOUT seconds */
if (gs_buf_data_avail(port->port_write_buf) > 0) {
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);
}
/* free disconnected port on final close */
/* (might have happened during the above sleep) */
if (port->port_dev == NULL) {
kfree(port);
goto exit;
}
gs_buf_clear(port->port_write_buf);
tty->driver_data = NULL;
port->port_tty = NULL;
port->port_in_use = 0;
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, 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");
return -EIO;
}
gs_debug("gs_write: (%d,%p) writing %d bytes\n", port->port_num, tty,
count);
if (count == 0)
return 0;
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);
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);
ret = -EBADF;
goto exit;
}
count = gs_buf_put(port->port_write_buf, buf, count);
spin_unlock_irqrestore(&port->port_lock, flags);
gs_send(gs_device);
gs_debug("gs_write: (%d,%p) wrote %d bytes\n", port->port_num, tty,
count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -