📄 scanner.c
字号:
DBG(dev, "Failed to dequeue in req %p\n",req); list_del_init (&req->list); list_add (&req->list, &dev->rx_reqs); } while (likely (!(list_empty (&dev->tx_reqs_active)))) { req = container_of (dev->tx_reqs_active.next, struct usb_request, list); if (usb_ep_dequeue (dev->out_ep, req)) DBG(dev, "Failed to dequeue in req %p\n",req); list_del_init (&req->list); list_add (&req->list, &dev->tx_reqs); } if (usb_ep_enable (dev->in_ep, dev->in)) DBG(dev, "Failed to enable USB in_ep\n"); if (usb_ep_enable (dev->out_ep, dev->out)) DBG(dev, "Failed to enable USB out_ep\n"); wake_up_interruptible(&dev->tx_wait); wake_up_interruptible(&dev->tx_flush_wait);}/*-------------------------------------------------------------------------*//* * The setup() callback implements all the ep0 functionality that's not * handled lower down. */static intprinter_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){ struct printer_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); u16 wLength = le16_to_cpu(ctrl->wLength); DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); req->complete = printer_setup_complete; switch (ctrl->bRequestType&USB_TYPE_MASK) { case USB_TYPE_STANDARD: switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; switch (wValue >> 8) { case USB_DT_DEVICE: value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break;#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget->is_dualspeed) break; // FALLTHROUGH#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, wValue >> 8, wValue & 0xff, gadget->is_otg); if (value >= 0) value = min (wLength, (u16) value); break; case USB_DT_STRING: value = usb_gadget_get_string (&stringtab, wValue & 0xff, req->buf); if (value >= 0) value = min (wLength, (u16) value); break; } break; case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; if (gadget->a_hnp_support) DBG(dev,"HNP available\n"); else if (gadget->a_alt_hnp_support) DBG(dev,"HNP needs a different root port\n"); value = printer_set_config (dev, wValue); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *)req->buf = dev->config; value = min (wLength, (u16) 1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->config) break; value = set_interface (dev, PRINTER_INTERFACE); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) || !dev->config) break; *(u8 *)req->buf = dev->interface; value = min (wLength, (u16) 1); break; default: VDBG(dev, "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); } break; case USB_TYPE_CLASS: switch (ctrl->bRequest) { case 0: /* Get the IEEE-1284 PNP String */ /* Only one printer interface is supported. */ if ((wIndex>>8) != PRINTER_INTERFACE) break; //req->buf = pnp_string; value = (pnp_string[0]<<8)|pnp_string[1]; memcpy(req->buf,pnp_string,value); DBG(dev, "1284 PNP String: %x %s\n", value, &pnp_string[2]); break; case 1: /* Get Port Status */ /* Only one printer interface is supported. */ if (wIndex != PRINTER_INTERFACE) break; req->buf = &dev->printer_status; value = min (wLength, (u16) 1); break; case 2: /* Soft Reset */ /* Only one printer interface is supported. */ if (wIndex != PRINTER_INTERFACE) break; printer_soft_reset(dev); value = 0; break; default: VDBG(dev, "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); } break; default: VDBG(dev, "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = value < wLength && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG(dev, "ep_queue --> %d\n", value); req->status = 0; printer_setup_complete (gadget->ep0, req); } } /* host either stalls (value < 0) or reports success */ return value;}static voidprinter_disconnect (struct usb_gadget *gadget){ struct printer_dev *dev = get_gadget_data (gadget); unsigned long flags; DBG(dev, "%s\n", __FUNCTION__); spin_lock_irqsave (&dev->lock, flags); printer_reset_interface (dev); spin_unlock_irqrestore (&dev->lock, flags);}static voidprinter_unbind (struct usb_gadget *gadget){ struct printer_dev *dev = get_gadget_data (gadget); struct usb_request *req; DBG(dev, "%s\n", __FUNCTION__); /* Remove sysfs files */ device_destroy(usb_gadget_class, g_printer_devno); /* Remove Character Device */ cdev_del(&dev->printer_cdev); /* we've already been disconnected ... no i/o is active */ /* Free all memory for this driver. */ while (likely (!list_empty (&dev->tx_reqs_active))) { req = container_of (dev->tx_reqs_active.next, struct usb_request, list); list_del (&req->list); if (usb_ep_dequeue (dev->in_ep, req)) { DBG(dev, "Failed to dequeue in req %p\n", req); } printer_req_free (dev->in_ep, req); } while (likely (!list_empty (&dev->tx_reqs))) { req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); printer_req_free (dev->in_ep, req); } if (dev->current_rx_req) { printer_req_free (dev->out_ep, dev->current_rx_req); } while (likely (!list_empty (&dev->rx_reqs_active))) { req = container_of (dev->rx_reqs_active.next, struct usb_request, list); list_del (&req->list); if (usb_ep_dequeue (dev->out_ep, req)) { DBG(dev, "Failed to dequeue in req %p\n", req); } printer_req_free (dev->out_ep, req); } while (likely (!list_empty (&dev->rx_reqs))) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del (&req->list); printer_req_free (dev->out_ep, req); } while (likely (!list_empty (&dev->rx_buffers))) { req = container_of (dev->rx_buffers.next, struct usb_request, list); list_del (&req->list); printer_req_free (dev->out_ep, req); } if (dev->req) { INFO (dev,"printer_req_free ep0=%p buf=%p\n", dev->req, dev->req_copy.buf); kfree(dev->req_copy.buf); //usb_ep_free_buffer (gadget->ep0, dev->req_copy.buf, // dev->req_copy.dma, dev->req_copy.length); usb_ep_free_request (gadget->ep0, dev->req); dev->req = NULL; } set_gadget_data (gadget, NULL);}static int __initprinter_bind (struct usb_gadget *gadget){ struct printer_dev *dev; u8 zlp = 1; struct usb_ep *in_ep, *out_ep; int status = -ENOMEM; int gcnum; size_t len; u32 i; struct usb_request *req; dev = &usb_printer_gadget; /* Setup the sysfs files for the printer gadget. */ dev->pdev = device_create( usb_gadget_class, NULL, g_printer_devno, "g_printer"); if (IS_ERR(dev->pdev)) { ERROR (dev, "Failed to create device: g_printer\n"); goto fail; } /* * Register a character device as an interface to a user mode * program that handles the printer specific functionality. */ cdev_init(&dev->printer_cdev, &printer_io_operations); dev->printer_cdev.owner = THIS_MODULE; status = cdev_add (&dev->printer_cdev, g_printer_devno, 1); if (status) { ERROR (dev, "Failed to open char device\n"); goto fail; } if (gadget_is_sa1100 (gadget)) { /* hardware can't write zlps */ zlp = 0; } gcnum = usb_gadget_controller_number (gadget); if (gcnum >= 0) { device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum); } else { dev_warn (&gadget->dev, "controller '%s' not recognized\n", gadget->name); /* unrecognized, but safe unless bulk is REALLY quirky */ device_desc.bcdDevice = __constant_cpu_to_le16(0xFFFF); } snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", init_utsname()->sysname, init_utsname()->release, gadget->name); device_desc.idVendor = __constant_cpu_to_le16(PRINTER_VENDOR_NUM); device_desc.idProduct = __constant_cpu_to_le16(PRINTER_PRODUCT_NUM); /* support optional vendor/distro customization */ if (idVendor) { if (!idProduct) { dev_err (&gadget->dev, "idVendor needs idProduct!\n"); return -ENODEV; } device_desc.idVendor = cpu_to_le16(idVendor); device_desc.idProduct = cpu_to_le16(idProduct); if (bcdDevice) device_desc.bcdDevice = cpu_to_le16(bcdDevice); } if (iManufacturer) strlcpy (manufacturer, iManufacturer, sizeof manufacturer); if (iProduct) strlcpy (product_desc, iProduct, sizeof product_desc); if (iSerialNum) strlcpy (serial_num, iSerialNum, sizeof serial_num); if (iPNPstring) { strlcpy (&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); } len = strlen (pnp_string); pnp_string[0] = (len >> 8) & 0xFF; pnp_string[1] = len & 0xFF; /* all we really need is bulk IN/OUT */ usb_ep_autoconfig_reset (gadget); in_ep = usb_ep_autoconfig (gadget, &fs_ep_in_desc); if (!in_ep) {autoconf_fail: dev_err (&gadget->dev, "can't autoconfigure on %s\n", gadget->name); return -ENODEV; } in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig (gadget, &fs_ep_out_desc); if (!out_ep) goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; /* and that all endpoints are dual-speed */ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;#endif /* DUALSPEED */ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered (gadget); if (gadget->is_otg) { otg_desc.bmAttributes |= USB_OTG_HNP, config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; config_desc.bMaxPower = 4; } spin_lock_init (&dev->lock); spin_lock_init (&dev->lock_printer_io); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->tx_reqs_active); INIT_LIST_HEAD (&dev->rx_reqs); INIT_LIST_HEAD (&dev->rx_reqs_active); INIT_LIST_HEAD (&dev->rx_buffers); init_waitqueue_head(&dev->rx_wait); init_waitqueue_head(&dev->tx_wait); init_waitqueue_head(&dev->tx_flush_wait); dev->config = 0; dev->interface = -1; dev->printer_cdev_open = 0; dev->zlp = zlp; dev->printer_status = PRINTER_NOT_ERROR; dev->current_rx_req = NULL; dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; dev->in_ep = in_ep; dev->out_ep = out_ep; /* preallocate control message data and buffer */ dev->req = printer_req_alloc (gadget->ep0, USB_DESC_BUFSIZE, GFP_KERNEL); memcpy (&dev->req_copy, dev->req, sizeof dev->req_copy); INFO (dev,"printer_req_free ep0=%p buf=%p\n", dev->req, dev->req->buf); if (!dev->req) { status = -ENOMEM; goto fail; } for (i=0; i < QLEN; i++) { req = printer_req_alloc (dev->in_ep, USB_BUFSIZE, GFP_KERNEL); if (!req) { while (likely (!list_empty (&dev->tx_reqs))) { req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); printer_req_free (dev->in_ep, req); } return -ENOMEM; } list_add (&req->list, &dev->tx_reqs); } for (i=0; i < QLEN; i++) { req = printer_req_alloc (dev->out_ep, USB_BUFSIZE, GFP_KERNEL); if (!req) { while (likely (!list_empty (&dev->rx_reqs))) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del (&req->list); printer_req_free (dev->out_ep, req); } return -ENOMEM; } list_add (&req->list, &dev->rx_reqs); } dev->req->complete = printer_setup_complete; /* finish hookup to lower layer ... */ dev->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, in_ep->name); return 0;fail: printer_unbind (gadget); return status;}static voidprinter_suspend (struct usb_gadget *gadget){ struct printer_dev *dev = get_gadget_data (gadget); DBG(dev, "suspend\n"); dev->suspended = 1;}static voidprinter_resume (struct usb_gadget *gadget){ struct printer_dev *dev = get_gadget_data (gadget); DBG(dev, "resume\n"); dev->suspended = 0;}/*-------------------------------------------------------------------------*/static struct usb_gadget_driver printer_driver = { .speed = DEVSPEED, .function = (char *) driver_desc, .bind = printer_bind, .unbind = printer_unbind, .setup = printer_setup, .disconnect = printer_disconnect, .suspend = printer_suspend, .resume = printer_resume, .driver = { .name = (char *) shortname, .owner = THIS_MODULE, },};MODULE_DESCRIPTION (DRIVER_DESC);MODULE_AUTHOR ("Craig Nadler, David Brownell");MODULE_LICENSE ("GPL");static int __init init (void){ int status; usb_gadget_class = class_create(THIS_MODULE, "usb_gadget"); if (IS_ERR(usb_gadget_class)) { status = PTR_ERR(usb_gadget_class); ERROR (dev, "unable to create usb_gadget class %d\n", status); return status; } status = alloc_chrdev_region (&g_printer_devno, 0, 2, "USB printer gadget"); if (status) { ERROR (dev, "alloc_chrdev_region %d\n", status); class_destroy(usb_gadget_class); return status; } status = usb_gadget_register_driver (&printer_driver); if (status) { class_destroy(usb_gadget_class); unregister_chrdev_region (g_printer_devno, 2); DBG(dev, "usb_gadget_register_driver %x\n", status); } return status;}module_init (init);static void __exit cleanup (void){ int status; spin_lock (&usb_printer_gadget.lock_printer_io); class_destroy(usb_gadget_class); unregister_chrdev_region (g_printer_devno, 2); status = usb_gadget_unregister_driver (&printer_driver); if (status) { ERROR (dev, "usb_gadget_unregister_driver %x\n", status); } spin_unlock (&usb_printer_gadget.lock_printer_io);}module_exit (cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -