X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Fserial.c;h=b992546c394d5c1e5aac6dd823d6875d506b9846;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=9432b85b8fe27eab46d6e4b000f3116ef9f325d9;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 9432b85b8..b992546c3 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -45,6 +45,7 @@ #include #include +#include #include #include "gadget_chips.h" @@ -122,80 +123,6 @@ do { \ }) -/* CDC-ACM Defines and Structures */ - -#define USB_CDC_SUBCLASS_ACM 2 - -#define USB_CDC_CTRL_PROTO_NONE 0 -#define USB_CDC_CTRL_PROTO_AT 1 -#define USB_CDC_CTRL_PROTO_VENDOR 0xff - -#define USB_CDC_SUBTYPE_HEADER 0 -#define USB_CDC_SUBTYPE_CALL_MGMT 1 -#define USB_CDC_SUBTYPE_ACM 2 -#define USB_CDC_SUBTYPE_UNION 6 - -#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01 -#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02 - -#define USB_CDC_REQ_SET_LINE_CODING 0x20 -#define USB_CDC_REQ_GET_LINE_CODING 0x21 -#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 - -#define USB_CDC_1_STOP_BITS 0 -#define USB_CDC_1_5_STOP_BITS 1 -#define USB_CDC_2_STOP_BITS 2 - -#define USB_CDC_NO_PARITY 0 -#define USB_CDC_ODD_PARITY 1 -#define USB_CDC_EVEN_PARITY 2 -#define USB_CDC_MARK_PARITY 3 -#define USB_CDC_SPACE_PARITY 4 - -/* Header Functional Descriptor from CDC spec 5.2.3.1 */ -struct usb_cdc_header_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u16 bcdCDC; -} __attribute__ ((packed)); - -/* Call Management Descriptor from CDC spec 5.2.3.3 */ -struct usb_cdc_call_mgmt_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bmCapabilities; - u8 bDataInterface; -} __attribute__ ((packed)); - -/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */ -struct usb_cdc_acm_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bmCapabilities; -} __attribute__ ((packed)); - -/* Union Functional Descriptor from CDC spec 5.2.3.8 */ -struct usb_cdc_union_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bMasterInterface0; - u8 bSlaveInterface0; - /* ... and there could be other slave interfaces */ -} __attribute__ ((packed)); - -/* Line Coding Structure from CDC spec 6.2.13 */ -struct usb_cdc_line_coding { - u32 dwDTERate; - u8 bCharFormat; - u8 bParityType; - u8 bDataBits; -} __attribute__ ((packed)); - - /* Defines */ #define GS_VERSION_STR "v2.0" @@ -313,7 +240,7 @@ struct gs_dev { struct usb_ep *dev_notify_ep; /* address of notify endpoint */ struct usb_ep *dev_in_ep; /* address of in endpoint */ struct usb_ep *dev_out_ep; /* address of out endpoint */ - struct usb_endpoint_descriptor /* desciptor of notify ep */ + struct usb_endpoint_descriptor /* descriptor of notify ep */ *dev_notify_ep_desc; struct usb_endpoint_descriptor /* descriptor of in endpoint */ *dev_in_ep_desc; @@ -373,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - int kmalloc_flags); + gfp_t 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); + gfp_t 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 int gs_alloc_ports(struct gs_dev *dev, gfp_t 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 struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t 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); @@ -442,14 +369,11 @@ static struct usb_gadget_driver gs_gadget_driver = { #endif /* CONFIG_USB_GADGET_DUALSPEED */ .function = GS_LONG_NAME, .bind = gs_bind, - .unbind = gs_unbind, + .unbind = __exit_p(gs_unbind), .setup = gs_setup, .disconnect = gs_disconnect, .driver = { .name = GS_SHORT_NAME, - /* .shutdown = ... */ - /* .suspend = ... */ - /* .resume = ... */ }, }; @@ -542,7 +466,7 @@ static const struct usb_interface_descriptor gs_control_interface_desc = { .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_CTRL_PROTO_AT, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, .iInterface = GS_CONTROL_STR_ID, }; @@ -560,29 +484,29 @@ static const struct usb_interface_descriptor gs_data_interface_desc = { 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, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = __constant_cpu_to_le16(0x0110), }; -static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = { +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_SUBTYPE_CALL_MGMT, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, .bmCapabilities = 0, .bDataInterface = 1, /* index of data interface */ }; -static struct usb_cdc_acm_desc gs_acm_descriptor = { +static struct usb_cdc_acm_descriptor gs_acm_descriptor = { .bLength = sizeof(gs_acm_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_SUBTYPE_ACM, + .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_SUBTYPE_UNION, + .bDescriptorSubType = USB_CDC_UNION_TYPE, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; @@ -963,10 +887,12 @@ static void gs_close(struct tty_struct *tty, struct file *file) /* wait for write buffer to drain, or */ /* at most GS_CLOSE_TIMEOUT seconds */ if (gs_buf_data_avail(port->port_write_buf) > 0) { + spin_unlock_irqrestore(&port->port_lock, flags); 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); + spin_lock_irqsave(&port->port_lock, flags); } /* free disconnected port on final close */ @@ -1342,6 +1268,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) unsigned int len; struct gs_port *port; int ret; + struct tty_struct *tty; /* TEMPORARY -- only port 0 is supported right now */ port = dev->dev_port[0]; @@ -1361,7 +1288,10 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) goto exit; } - if (port->port_tty == NULL) { + + tty = port->port_tty; + + if (tty == NULL) { printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n", port->port_num); ret = -EIO; @@ -1375,20 +1305,13 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size) goto exit; } - len = (unsigned int)(TTY_FLIPBUF_SIZE - port->port_tty->flip.count); - if (len < size) - size = len; - - if (size > 0) { - memcpy(port->port_tty->flip.char_buf_ptr, packet, size); - port->port_tty->flip.char_buf_ptr += size; - port->port_tty->flip.count += size; + len = tty_buffer_request_room(tty, size); + if (len > 0) { + tty_insert_flip_string(tty, packet, len); tty_flip_buffer_push(port->port_tty); wake_up_interruptible(&port->port_tty->read_wait); } - ret = 0; - exit: spin_unlock(&port->port_lock); return ret; @@ -1490,48 +1413,25 @@ requeue: * Called on module load. Allocates and initializes the device * structure and a control request. */ -static int gs_bind(struct usb_gadget *gadget) +static int __init gs_bind(struct usb_gadget *gadget) { int ret; struct usb_ep *ep; struct gs_dev *dev; + int gcnum; - /* device specific */ - if (gadget_is_net2280(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0001); - } else if (gadget_is_pxa(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0002); - } else if (gadget_is_sh(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0003); - /* sh doesn't support multiple interfaces or configs */ - use_acm = 0; - } else if (gadget_is_sa1100(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0004); - /* sa1100 doesn't support necessary endpoints */ + /* Some controllers can't support CDC ACM: + * - sh doesn't support multiple interfaces or configs; + * - sa1100 doesn't have a third interrupt endpoint + */ + if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget)) use_acm = 0; - } else if (gadget_is_goku(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0005); - } else if (gadget_is_mq11xx(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0006); - } else if (gadget_is_omap(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0007); - } else if (gadget_is_lh7a40x(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0008); - } else if (gadget_is_n9604(gadget)) { - gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0009); - } else if (gadget_is_pxa27x(gadget)) { + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) gs_device_desc.bcdDevice = - __constant_cpu_to_le16(GS_VERSION_NUM|0x0011); - } else { + cpu_to_le16(GS_VERSION_NUM | gcnum); + else { printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", gadget->name); /* unrecognized, but safe unless bulk is REALLY quirky */ @@ -1638,7 +1538,7 @@ autoconf_fail: * Called on module unload. Frees the control request and device * structure. */ -static void gs_unbind(struct usb_gadget *gadget) +static void __exit gs_unbind(struct usb_gadget *gadget) { struct gs_dev *dev = get_gadget_data(gadget); @@ -1674,6 +1574,9 @@ static int gs_setup(struct usb_gadget *gadget, 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); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: @@ -1686,15 +1589,15 @@ static int gs_setup(struct usb_gadget *gadget, default: printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } /* respond with data transfer before status phase? */ if (ret >= 0) { req->length = ret; - req->zero = ret < ctrl->wLength + req->zero = ret < wLength && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { @@ -1715,15 +1618,18 @@ static int gs_setup_standard(struct usb_gadget *gadget, 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); switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; - switch (ctrl->wValue >> 8) { + switch (wValue >> 8) { case USB_DT_DEVICE: - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_device_descriptor)); memcpy(req->buf, &gs_device_desc, ret); break; @@ -1732,7 +1638,7 @@ static int gs_setup_standard(struct usb_gadget *gadget, case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; @@ -1744,18 +1650,18 @@ static int gs_setup_standard(struct usb_gadget *gadget, #endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_buf(req->buf, gadget->speed, - ctrl->wValue >> 8, ctrl->wValue & 0xff, + wValue >> 8, wValue & 0xff, gadget->is_otg); if (ret >= 0) - ret = min(ctrl->wLength, (u16)ret); + ret = min(wLength, (u16)ret); break; case USB_DT_STRING: /* wIndex == language code. */ ret = usb_gadget_get_string(&gs_string_table, - ctrl->wValue & 0xff, req->buf); + wValue & 0xff, req->buf); if (ret >= 0) - ret = min(ctrl->wLength, (u16)ret); + ret = min(wLength, (u16)ret); break; } break; @@ -1764,7 +1670,7 @@ static int gs_setup_standard(struct usb_gadget *gadget, if (ctrl->bRequestType != 0) break; spin_lock(&dev->dev_lock); - ret = gs_set_config(dev, ctrl->wValue); + ret = gs_set_config(dev, wValue); spin_unlock(&dev->dev_lock); break; @@ -1772,18 +1678,19 @@ static int gs_setup_standard(struct usb_gadget *gadget, if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *)req->buf = dev->dev_config; - ret = min(ctrl->wLength, (u16)1); + ret = min(wLength, (u16)1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE - || !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES) + || !dev->dev_config + || wIndex >= GS_MAX_NUM_INTERFACES) break; if (dev->dev_config == GS_BULK_CONFIG_ID - && ctrl->wIndex != GS_BULK_INTERFACE_ID) + && wIndex != GS_BULK_INTERFACE_ID) break; /* no alternate interface settings */ - if (ctrl->wValue != 0) + if (wValue != 0) break; spin_lock(&dev->dev_lock); /* PXA hardware partially handles SET_INTERFACE; @@ -1794,7 +1701,7 @@ static int gs_setup_standard(struct usb_gadget *gadget, goto set_interface_done; } if (dev->dev_config != GS_BULK_CONFIG_ID - && ctrl->wIndex == GS_CONTROL_INTERFACE_ID) { + && wIndex == GS_CONTROL_INTERFACE_ID) { if (dev->dev_notify_ep) { usb_ep_disable(dev->dev_notify_ep); usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc); @@ -1814,21 +1721,21 @@ set_interface_done: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) || dev->dev_config == GS_NO_CONFIG_ID) break; - if (ctrl->wIndex >= GS_MAX_NUM_INTERFACES - || (dev->dev_config == GS_BULK_CONFIG_ID - && ctrl->wIndex != GS_BULK_INTERFACE_ID)) { + if (wIndex >= GS_MAX_NUM_INTERFACES + || (dev->dev_config == GS_BULK_CONFIG_ID + && wIndex != GS_BULK_INTERFACE_ID)) { ret = -EDOM; break; } /* no alternate interface settings */ *(u8 *)req->buf = 0; - ret = min(ctrl->wLength, (u16)1); + ret = min(wLength, (u16)1); break; default: printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } @@ -1842,10 +1749,13 @@ static int gs_setup_class(struct usb_gadget *gadget, struct gs_dev *dev = get_gadget_data(gadget); struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ 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); switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); @@ -1856,7 +1766,7 @@ static int gs_setup_class(struct usb_gadget *gadget, case USB_CDC_REQ_GET_LINE_CODING: port = dev->dev_port[0]; /* ACM only has one port */ - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); @@ -1871,8 +1781,8 @@ static int gs_setup_class(struct usb_gadget *gadget, default: printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } @@ -2176,7 +2086,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * Allocate a usb_request and its buffer. Returns a pointer to the * usb_request or NULL if there is an error. */ -static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags) +static struct usb_request * +gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags) { struct usb_request *req; @@ -2216,7 +2127,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * Allocates a request and its buffer, using the given * endpoint, buffer len, and kmalloc flags. */ -static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags) +static struct gs_req_entry * +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) { struct gs_req_entry *req; @@ -2257,7 +2169,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags) { int i; struct gs_port *port; @@ -2266,13 +2178,12 @@ static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags) return -EIO; for (i=0; iport_dev = dev; port->port_num = i; - port->port_line_coding.dwDTERate = GS_DEFAULT_DTE_RATE; + port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE); port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT; port->port_line_coding.bParityType = GS_DEFAULT_PARITY; port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS; @@ -2324,6 +2235,7 @@ static void gs_free_ports(struct gs_dev *dev) } spin_unlock_irqrestore(&port->port_lock, flags); } else { + spin_unlock_irqrestore(&port->port_lock, flags); kfree(port); } @@ -2338,7 +2250,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) { struct gs_buf *gb; @@ -2368,9 +2280,8 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags) */ void gs_buf_free(struct gs_buf *gb) { - if (gb != NULL) { - if (gb->buf_buf != NULL) - kfree(gb->buf_buf); + if (gb) { + kfree(gb->buf_buf); kfree(gb); } }