📄 serial.c
字号:
/* 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 */ 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)) { gs_device_desc.bcdDevice = __constant_cpu_to_le16(GS_VERSION_NUM|0x0011); } else { printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", gadget->name); /* unrecognized, but safe unless bulk is REALLY quirky */ gs_device_desc.bcdDevice = __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); } usb_ep_autoconfig_reset(gadget); ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); if (!ep) goto autoconf_fail; EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim the endpoint */ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); if (!ep) goto autoconf_fail; EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim the endpoint */ if (use_acm) { ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); if (!ep) { printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); goto autoconf_fail; } gs_device_desc.idProduct = __constant_cpu_to_le16( GS_CDC_PRODUCT_ID), EP_NOTIFY_NAME = ep->name; ep->driver_data = ep; /* claim the endpoint */ } gs_device_desc.bDeviceClass = use_acm ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;#ifdef CONFIG_USB_GADGET_DUALSPEED gs_qualifier_desc.bDeviceClass = use_acm ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; /* assume ep0 uses the same packet size for both speeds */ gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; /* assume endpoints are dual-speed */ gs_highspeed_notify_desc.bEndpointAddress = gs_fullspeed_notify_desc.bEndpointAddress; gs_highspeed_in_desc.bEndpointAddress = gs_fullspeed_in_desc.bEndpointAddress; gs_highspeed_out_desc.bEndpointAddress = gs_fullspeed_out_desc.bEndpointAddress;#endif /* CONFIG_USB_GADGET_DUALSPEED */ usb_gadget_set_selfpowered(gadget); if (gadget->is_otg) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", system_utsname.sysname, system_utsname.release, gadget->name); memset(dev, 0, sizeof(struct gs_dev)); dev->dev_gadget = gadget; spin_lock_init(&dev->dev_lock); INIT_LIST_HEAD(&dev->dev_req_list); set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { printk(KERN_ERR "gs_bind: cannot allocate ports\n"); gs_unbind(gadget); return ret; } /* preallocate control response and buffer */ dev->dev_ctrl_req = gs_alloc_req(gadget->ep0, GS_MAX_DESC_LEN, GFP_KERNEL); if (dev->dev_ctrl_req == NULL) { gs_unbind(gadget); return -ENOMEM; } dev->dev_ctrl_req->complete = gs_setup_complete; gadget->ep0->driver_data = dev; printk(KERN_INFO "gs_bind: %s %s bound\n", GS_LONG_NAME, GS_VERSION_STR); return 0;autoconf_fail: printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); return -ENODEV;}/* * gs_unbind * * Called on module unload. Frees the control request and device * structure. */static void gs_unbind(struct usb_gadget *gadget){ struct gs_dev *dev = get_gadget_data(gadget); gs_device = NULL; /* read/write requests already freed, only control request remains */ if (dev != NULL) { if (dev->dev_ctrl_req != NULL) { gs_free_req(gadget->ep0, dev->dev_ctrl_req); dev->dev_ctrl_req = NULL; } gs_free_ports(dev); kfree(dev); set_gadget_data(gadget, NULL); } printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME, GS_VERSION_STR);}/* * gs_setup * * Implements all the control endpoint functionality that's not * handled in hardware or the hardware driver. * * Returns the size of the data sent to the host, or a negative * error number. */static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){ int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: ret = gs_setup_standard(gadget,ctrl); break; case USB_TYPE_CLASS: ret = gs_setup_class(gadget,ctrl); break; 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); break; } /* respond with data transfer before status phase? */ if (ret >= 0) { req->length = ret; req->zero = ret < ctrl->wLength && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n", ret); req->status = 0; gs_setup_complete(gadget->ep0, req); } } /* device either stalls (ret < 0) or reports success */ return ret;}static int gs_setup_standard(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){ int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; switch (ctrl->wValue >> 8) { case USB_DT_DEVICE: ret = min(ctrl->wLength, (u16)sizeof(struct usb_device_descriptor)); memcpy(req->buf, &gs_device_desc, ret); break;#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; ret = min(ctrl->wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget->is_dualspeed) break; /* fall through */#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_buf(req->buf, gadget->speed, ctrl->wValue >> 8, ctrl->wValue & 0xff, gadget->is_otg); if (ret >= 0) ret = min(ctrl->wLength, (u16)ret); break; case USB_DT_STRING: /* wIndex == language code. */ ret = usb_gadget_get_string(&gs_string_table, ctrl->wValue & 0xff, req->buf); if (ret >= 0) ret = min(ctrl->wLength, (u16)ret); break; } break; case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; spin_lock(&dev->dev_lock); ret = gs_set_config(dev, ctrl->wValue); spin_unlock(&dev->dev_lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *)req->buf = dev->dev_config; ret = min(ctrl->wLength, (u16)1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES) break; if (dev->dev_config == GS_BULK_CONFIG_ID && ctrl->wIndex != GS_BULK_INTERFACE_ID) break; /* no alternate interface settings */ if (ctrl->wValue != 0) break; spin_lock(&dev->dev_lock); /* PXA hardware partially handles SET_INTERFACE; * we need to kluge around that interference. */ if (gadget_is_pxa(gadget)) { ret = gs_set_config(dev, use_acm ? GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID); goto set_interface_done; } if (dev->dev_config != GS_BULK_CONFIG_ID && ctrl->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); } } else { usb_ep_disable(dev->dev_in_ep); usb_ep_disable(dev->dev_out_ep); usb_ep_enable(dev->dev_in_ep, dev->dev_in_ep_desc); usb_ep_enable(dev->dev_out_ep, dev->dev_out_ep_desc); } ret = 0;set_interface_done: spin_unlock(&dev->dev_lock); break; case USB_REQ_GET_INTERFACE: 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)) { ret = -EDOM; break; } /* no alternate interface settings */ *(u8 *)req->buf = 0; ret = min(ctrl->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); break; } return ret;}static int gs_setup_class(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){ int ret = -EOPNOTSUPP; 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; switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: ret = min(ctrl->wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); memcpy(&port->port_line_coding, req->buf, ret); spin_unlock(&port->port_lock); } break; case USB_CDC_REQ_GET_LINE_CODING: port = dev->dev_port[0]; /* ACM only has one port */ ret = min(ctrl->wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); memcpy(req->buf, &port->port_line_coding, ret); spin_unlock(&port->port_lock); } break; case USB_CDC_REQ_SET_CONTROL_LINE_STATE: ret = 0; break; 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); break; } return ret;}/* * gs_setup_complete */static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req){ if (req->status || req->actual != req->length) { printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n", req->status, req->actual, req->length); }}/* * gs_disconnect * * Called when the device is disconnected. Frees the closed * ports and disconnects open ports. Open ports will be freed * on close. Then reallocates the ports for the next connection. */static void gs_disconnect(struct usb_gadget *gadget){ unsigned long flags; struct gs_dev *dev = get_gadget_data(gadget); spin_lock_irqsave(&dev->dev_lock, flags); gs_reset_config(dev); /* free closed ports and disconnect open ports */ /* (open ports will be freed when closed) */ gs_free_ports(dev); /* re-allocate ports for the next connection */ if (gs_alloc_ports(dev, GFP_ATOMIC) != 0) printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n"); spin_unlock_irqrestore(&dev->dev_lock, flags); printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME);}/* * gs_set_config * * Configures the device by enabling device specific * optimizations, setting up the endpoints, allocating * read and write requests and queuing read requests. * * The device lock must be held when calling this function. */static int gs_set_config(struct gs_dev *dev, unsigned config){ int i; int ret = 0; struct usb_gadget *gadget = dev->dev_gadget; struct usb_ep *ep; struct usb_endpoint_descriptor *ep_desc; struct usb_request *req; struct gs_req_entry *req_entry; if (dev == NULL) { printk(KERN_ERR "gs_set_config: NULL device pointer\n"); return 0; } if (config == dev->dev_config) return 0; gs_reset_config(dev); switch (config) { case GS_NO_CONFIG_ID: return 0; case GS_BULK_CONFIG_ID: if (use_acm) return -EINVAL; /* device specific optimizations */ if (gadget_is_net2280(gadget)) net2280_set_fifo_mode(gadget, 1); break; case GS_ACM_CONFIG_ID: if (!use_acm) return -EINVAL; /* device specific optimizations */ if (gadget_is_net2280(gadget)) net2280_set_fifo_mode(gadget, 1); break; default: return -EINVAL; } dev->dev_config = config; gadget_for_each_ep(ep, gadget) { if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { ep_desc = GS_SPEED_SELECT( gadget->speed == USB_SPEED_HIGH, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { ep->driver_data = dev; dev->dev_notify_ep = ep; dev->dev_notify_ep_desc = ep_desc; } else { printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n", ep->name, ret); goto exit_reset_config; } } else if (strcmp(ep->name, EP_IN_NAME) == 0) { ep_desc = GS_SPEED_SELECT( gadget->speed == USB_SPEED_HIGH,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -