📄 usbtty.c
字号:
/* * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments * * (C) Copyright 2006 * Bryan O'Donoghue, bodonoghue@codehermit.ie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <common.h>#ifdef CONFIG_USB_TTY#include <circbuf.h>#include <devices.h>#include "usbtty.h"#include "usb_cdc_acm.h"#include "usbdescriptors.h"#include <config.h> /* If defined, override Linux identifiers with * vendor specific ones */#if 0#define TTYDBG(fmt,args...)\ serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)#else#define TTYDBG(fmt,args...) do{}while(0)#endif#if 1#define TTYERR(fmt,args...)\ serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\ __LINE__,##args)#else#define TTYERR(fmt,args...) do{}while(0)#endif/* * Defines */#define NUM_CONFIGS 1#define MAX_INTERFACES 2#define NUM_ENDPOINTS 3#define ACM_TX_ENDPOINT 3#define ACM_RX_ENDPOINT 2#define GSERIAL_TX_ENDPOINT 2#define GSERIAL_RX_ENDPOINT 1#define NUM_ACM_INTERFACES 2#define NUM_GSERIAL_INTERFACES 1#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface"/* * Buffers to hold input and output data */#define USBTTY_BUFFER_SIZE 256static circbuf_t usbtty_input;static circbuf_t usbtty_output;/* * Instance variables */static device_t usbttydev;static struct usb_device_instance device_instance[1];static struct usb_bus_instance bus_instance[1];static struct usb_configuration_instance config_instance[NUM_CONFIGS];static struct usb_interface_instance interface_instance[MAX_INTERFACES];static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];/* one extra for control endpoint */static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];/* * Global flag */int usbtty_configured_flag = 0;/* * Serial number */static char serial_number[16];/* * Descriptors, Strings, Local variables. *//* defined and used by usbdcore_ep0.c */extern struct usb_string_descriptor **usb_strings;/* Indicies, References */static unsigned short rx_endpoint = 0;static unsigned short tx_endpoint = 0;static unsigned short interface_count = 0;static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];/* USB Descriptor Strings */static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];/* Standard USB Data Structures */static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];static struct usb_configuration_descriptor *configuration_descriptor = 0;static struct usb_device_descriptor device_descriptor = { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = USB_DT_DEVICE, .bcdUSB = cpu_to_le16(USB_BCD_VERSION), .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE, .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID), .bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE), .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT, .iSerialNumber = STR_SERIAL, .bNumConfigurations = NUM_CONFIGS};/* * Static CDC ACM specific descriptors */struct acm_config_desc { struct usb_configuration_descriptor configuration_desc; /* Master Interface */ struct usb_interface_descriptor interface_desc; struct usb_class_header_function_descriptor usb_class_header; struct usb_class_call_management_descriptor usb_class_call_mgt; struct usb_class_abstract_control_descriptor usb_class_acm; struct usb_class_union_function_descriptor usb_class_union; struct usb_endpoint_descriptor notification_endpoint; /* Slave Interface */ struct usb_interface_descriptor data_class_interface; struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));} __attribute__((packed));static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { { .configuration_desc ={ .bLength = sizeof(struct usb_configuration_descriptor), .bDescriptorType = USB_DT_CONFIG, .wTotalLength = cpu_to_le16(sizeof(struct acm_config_desc)), .bNumInterfaces = NUM_ACM_INTERFACES, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG, .bmAttributes = BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, .bMaxPower = USBTTY_MAXPOWER }, /* Interface 1 */ .interface_desc = { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 0x01, .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_CONTROL, .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS, .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL, .iInterface = STR_CTRL_INTERFACE, }, .usb_class_header = { .bFunctionLength = sizeof(struct usb_class_header_function_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_HEADER, .bcdCDC = cpu_to_le16(110), }, .usb_class_call_mgt = { .bFunctionLength = sizeof(struct usb_class_call_management_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_CMF, .bmCapabilities = 0x00, .bDataInterface = 0x01, }, .usb_class_acm = { .bFunctionLength = sizeof(struct usb_class_abstract_control_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_ACMF, .bmCapabilities = 0x00, }, .usb_class_union = { .bFunctionLength = sizeof(struct usb_class_union_function_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_UF, .bMasterInterface = 0x00, .bSlaveInterface0 = 0x01, }, .notification_endpoint = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), .bInterval = 0xFF, }, /* Interface 2 */ .data_class_interface = { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0x01, .bAlternateSetting = 0x00, .bNumEndpoints = 0x02, .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_DATA, .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE, .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE, .iInterface = STR_DATA_INTERFACE, }, .data_endpoints = { { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x02 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), .bInterval = 0xFF, }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x03 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), .bInterval = 0xFF, }, }, },};static struct rs232_emu rs232_desc={ .dter = 115200, .stop_bits = 0x00, .parity = 0x00, .data_bits = 0x08};/* * Static Generic Serial specific data */struct gserial_config_desc { struct usb_configuration_descriptor configuration_desc; struct usb_interface_descriptor interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed)); struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS] __attribute__((packed));} __attribute__((packed));static struct gserial_config_descgserial_configuration_descriptors[NUM_CONFIGS] ={ { .configuration_desc ={ .bLength = sizeof(struct usb_configuration_descriptor), .bDescriptorType = USB_DT_CONFIG, .wTotalLength = cpu_to_le16(sizeof(struct gserial_config_desc)), .bNumInterfaces = NUM_GSERIAL_INTERFACES, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG, .bmAttributes = BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, .bMaxPower = USBTTY_MAXPOWER }, .interface_desc = { { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = NUM_ENDPOINTS, .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_VENDOR, .bInterfaceSubClass = COMMUNICATIONS_NO_SUBCLASS, .bInterfaceProtocol = COMMUNICATIONS_NO_PROTOCOL, .iInterface = STR_DATA_INTERFACE }, }, .data_endpoints = { { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE), .bInterval= 0xFF, }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x02 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE), .bInterval = 0xFF, }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x03 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), .bInterval = 0xFF, }, }, },};/* * Static Function Prototypes */static void usbtty_init_strings (void);static void usbtty_init_instances (void);static void usbtty_init_endpoints (void);static void usbtty_init_terminal_type(short type);static void usbtty_event_handler (struct usb_device_instance *device, usb_device_event_t event, int data);static int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb);static int usbtty_configured (void);static int write_buffer (circbuf_t * buf);static int fill_buffer (circbuf_t * buf);void usbtty_poll (void);/* utility function for converting char* to wide string used by USB */static void str2wide (char *str, u16 * wide){ int i; for (i = 0; i < strlen (str) && str[i]; i++){ #if defined(__LITTLE_ENDIAN) wide[i] = (u16) str[i]; #elif defined(__BIG_ENDIAN) wide[i] = ((u16)(str[i])<<8); #else #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" #endif }}/* * Test whether a character is in the RX buffer */int usbtty_tstc (void){ struct usb_endpoint_instance *endpoint = &endpoint_instance[rx_endpoint]; /* If no input data exists, allow more RX to be accepted */ if(usbtty_input.size <= 0){ udc_unset_nak(endpoint->endpoint_address&0x03); } usbtty_poll (); return (usbtty_input.size > 0);}/* * Read a single byte from the usb client port. Returns 1 on success, 0 * otherwise. When the function is succesfull, the character read is * written into its argument c. */int usbtty_getc (void){ char c; struct usb_endpoint_instance *endpoint = &endpoint_instance[rx_endpoint]; while (usbtty_input.size <= 0) { udc_unset_nak(endpoint->endpoint_address&0x03); usbtty_poll (); } buf_pop (&usbtty_input, &c, 1); udc_set_nak(endpoint->endpoint_address&0x03); return c;}/* * Output a single byte to the usb client port. */void usbtty_putc (const char c){ buf_push (&usbtty_output, &c, 1); /* If \n, also do \r */ if (c == '\n') buf_push (&usbtty_output, "\r", 1); /* Poll at end to handle new data... */ if ((usbtty_output.size + 2) >= usbtty_output.totalsize) { usbtty_poll (); }}/* usbtty_puts() helper function for finding the next '\n' in a string */static int next_nl_pos (const char *s){ int i; for (i = 0; s[i] != '\0'; i++) { if (s[i] == '\n') return i; } return i;}/* * Output a string to the usb client port - implementing flow control */static void __usbtty_puts (const char *str, int len){ int maxlen = usbtty_output.totalsize; int space, n; /* break str into chunks < buffer size, if needed */ while (len > 0) { usbtty_poll (); space = maxlen - usbtty_output.size; /* Empty buffer here, if needed, to ensure space... */ if (space) { write_buffer (&usbtty_output); n = MIN (space, MIN (len, maxlen)); buf_push (&usbtty_output, str, n); str += n; len -= n; } }}void usbtty_puts (const char *str){ int n; int len = strlen (str); /* add '\r' for each '\n' */ while (len > 0) { n = next_nl_pos (str); if (str[n] == '\n') { __usbtty_puts (str, n + 1); __usbtty_puts ("\r", 1); str += (n + 1); len -= (n + 1); } else { /* No \n found. All done. */ __usbtty_puts (str, n); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -