📄 serial.c
字号:
.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 computed dynamically */ .bNumInterfaces = 1, .bConfigurationValue = GS_BULK_CONFIG_ID, .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_CTRL_PROTO_AT, .iInterface = GS_CONTROL_STR_ID,};static const struct usb_interface_descriptor gs_data_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .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_SUBTYPE_HEADER, .bcdCDC = __constant_cpu_to_le16(0x0110),};static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = { .bLength = sizeof(gs_call_mgmt_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_SUBTYPE_CALL_MGMT, .bmCapabilities = 0, .bDataInterface = 1, /* index of data interface */};static struct usb_cdc_acm_desc gs_acm_descriptor = { .bLength = sizeof(gs_acm_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_SUBTYPE_ACM, .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_SUBTYPE_UNION, .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_DUALSPEEDstatic 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_DEBUGmodule_param(debug, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");#endifmodule_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -