📄 serial.c
字号:
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;
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:
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,
wValue, wIndex, wLength);
break;
}
/* respond with data transfer before status phase? */
if (ret >= 0) {
req->length = ret;
req->zero = ret < 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;
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 (wValue >> 8) {
case USB_DT_DEVICE:
ret = min(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(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,
wValue >> 8, wValue & 0xff,
gadget->is_otg);
if (ret >= 0)
ret = min(wLength, (u16)ret);
break;
case USB_DT_STRING:
/* wIndex == language code. */
ret = usb_gadget_get_string(&gs_string_table,
wValue & 0xff, req->buf);
if (ret >= 0)
ret = min(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, 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(wLength, (u16)1);
break;
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE
|| !dev->dev_config
|| wIndex >= GS_MAX_NUM_INTERFACES)
break;
if (dev->dev_config == GS_BULK_CONFIG_ID
&& wIndex != GS_BULK_INTERFACE_ID)
break;
/* no alternate interface settings */
if (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
&& 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 (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(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,
wValue, wIndex, 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;
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(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(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,
wValue, wIndex, 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,
&gs_highspeed_in_desc,
&gs_fullspeed_in_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
ep->driver_data = dev;
dev->dev_in_ep = ep;
dev->dev_in_ep_desc = ep_desc;
} else {
printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
ep_desc = GS_SPEED_SELECT(
gadget->speed == USB_SPEED_HIGH,
&gs_highspeed_out_desc,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -