serial.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,079 行 · 第 1/4 页
C
2,079 行
/* * g_serial.c -- USB gadget serial driver * * Copyright 2003 (C) Al Borchers (alborchers@steinerpoint.com) * * This code is based in part on the Gadget Zero driver, which * is Copyright (C) 2003 by David Brownell, all rights reserved. * * This code also borrows from usbserial.c, which is * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com) * * 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/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/uts.h>#include <linux/version.h>#include <linux/wait.h>#include <linux/proc_fs.h>#include <linux/device.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include <asm/uaccess.h>#include <linux/usb_ch9.h>#include <linux/usb_gadget.h>#include "gadget_chips.h"/* Wait Cond */#define __wait_cond_interruptible(wq, condition, lock, flags, ret) \do { \ wait_queue_t __wait; \ init_waitqueue_entry(&__wait, current); \ \ add_wait_queue(&wq, &__wait); \ for (;;) { \ set_current_state(TASK_INTERRUPTIBLE); \ if (condition) \ break; \ if (!signal_pending(current)) { \ spin_unlock_irqrestore(lock, flags); \ schedule(); \ spin_lock_irqsave(lock, flags); \ continue; \ } \ ret = -ERESTARTSYS; \ break; \ } \ current->state = TASK_RUNNING; \ remove_wait_queue(&wq, &__wait); \} while (0) #define wait_cond_interruptible(wq, condition, lock, flags) \({ \ int __ret = 0; \ if (!(condition)) \ __wait_cond_interruptible(wq, condition, lock, flags, \ __ret); \ __ret; \})#define __wait_cond_interruptible_timeout(wq, condition, lock, flags, \ timeout, ret) \do { \ signed long __timeout = timeout; \ wait_queue_t __wait; \ init_waitqueue_entry(&__wait, current); \ \ add_wait_queue(&wq, &__wait); \ for (;;) { \ set_current_state(TASK_INTERRUPTIBLE); \ if (__timeout == 0) \ break; \ if (condition) \ break; \ if (!signal_pending(current)) { \ spin_unlock_irqrestore(lock, flags); \ __timeout = schedule_timeout(__timeout); \ spin_lock_irqsave(lock, flags); \ continue; \ } \ ret = -ERESTARTSYS; \ break; \ } \ current->state = TASK_RUNNING; \ remove_wait_queue(&wq, &__wait); \} while (0) #define wait_cond_interruptible_timeout(wq, condition, lock, flags, \ timeout) \({ \ int __ret = 0; \ if (!(condition)) \ __wait_cond_interruptible_timeout(wq, condition, lock, \ flags, timeout, __ret); \ __ret; \})/* Defines */#define GS_VERSION_STR "v1.0"#define GS_VERSION_NUM 0x0100#define GS_LONG_NAME "Gadget Serial"#define GS_SHORT_NAME "g_serial"#define GS_MAJOR 127#define GS_MINOR_START 0#define GS_NUM_PORTS 16#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_NUM_ENDPOINTS 2#define GS_MAX_DESC_LEN 256#define GS_DEFAULT_READ_Q_SIZE 32#define GS_DEFAULT_WRITE_Q_SIZE 32#define GS_DEFAULT_WRITE_BUF_SIZE 8192#define GS_TMP_BUF_SIZE 8192#define GS_CLOSE_TIMEOUT 15/* debug settings */#if G_SERIAL_DEBUGstatic int debug = G_SERIAL_DEBUG;#define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)#define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)#else#define gs_debug(format, arg...) \ do { } while(0)#define gs_debug_level(level, format, arg...) \ do { } while(0)#endif /* G_SERIAL_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 *//* Structures */struct gs_dev;/* circular buffer */struct gs_buf { unsigned int buf_size; char *buf_buf; char *buf_get; char *buf_put;};/* list of requests */struct gs_req_entry { struct list_head re_entry; struct usb_request *re_req;};/* the port structure holds info for each port, one for each minor number */struct gs_port { struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ struct gs_buf *port_write_buf;};/* the device structure holds info for the USB device */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_in_ep; /* address of in endpoint */ struct usb_ep *dev_out_ep; /* address of out endpoint */ 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 */ struct gs_port *dev_port[GS_NUM_PORTS]; /* the ports */};/* 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, int from_user, 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);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 termios *old);static int gs_send(struct gs_dev *dev);static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size);static int gs_recv_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 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 struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int 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);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 void gs_free_ports(struct gs_dev *dev);/* circular buffer */static struct gs_buf *gs_buf_alloc(unsigned int size, int 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);static unsigned int gs_buf_space_avail(struct gs_buf *gb);static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count);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 struct semaphore gs_open_close_sem[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 char gs_tmp_buf[GS_TMP_BUF_SIZE];static struct semaphore gs_tmp_buf_sem;/* tty driver struct */static 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 .function = GS_LONG_NAME, .bind = gs_bind, .unbind = gs_unbind, .setup = gs_setup, .disconnect = gs_disconnect, .driver = { .name = GS_SHORT_NAME, /* .shutdown = ... */ /* .suspend = ... */ /* .resume = ... */ },};/* USB descriptors */#define GS_MANUFACTURER_STR_ID 1#define GS_PRODUCT_STR_ID 2#define GS_SERIAL_STR_ID 3#define GS_CONFIG_STR_ID 4/* static strings, in iso 8859/1 */static char manufacturer[40];static struct usb_string gs_strings[] = { { GS_MANUFACTURER_STR_ID, manufacturer }, { GS_PRODUCT_STR_ID, GS_LONG_NAME }, { GS_SERIAL_STR_ID, "0" }, { GS_CONFIG_STR_ID, "Bulk" }, { } /* end of list */};static struct usb_gadget_strings gs_string_table = { .language = 0x0409, /* en-us */ .strings = gs_strings,};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, .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID), .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID), .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 = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, /* .wTotalLength set by gs_build_config_desc */ .bNumInterfaces = GS_NUM_INTERFACES, .bConfigurationValue = GS_BULK_CONFIG_ID, .iConfiguration = GS_CONFIG_STR_ID, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 1,};static const struct usb_interface_descriptor gs_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,};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 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),};#ifdef CONFIG_USB_GADGET_DUALSPEEDstatic 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 ... */ .bNumConfigurations = GS_NUM_CONFIGS,};#endif/* Module */MODULE_DESCRIPTION(GS_LONG_NAME);MODULE_AUTHOR("Al Borchers");MODULE_LICENSE("GPL");#if G_SERIAL_DEBUGmodule_param(debug, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on, larger values for more messages");#endifmodule_param(read_q_size, int, 0);MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");module_param(write_q_size, int, 0);MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");module_param(write_buf_size, int, 0);MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");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); sema_init(&gs_tmp_buf_sem, 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;}/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?