18443f2d2SAndrzej Pietrasiewicz /* 28443f2d2SAndrzej Pietrasiewicz * printer.c -- Printer gadget driver 38443f2d2SAndrzej Pietrasiewicz * 48443f2d2SAndrzej Pietrasiewicz * Copyright (C) 2003-2005 David Brownell 58443f2d2SAndrzej Pietrasiewicz * Copyright (C) 2006 Craig W. Nadler 68443f2d2SAndrzej Pietrasiewicz * 78443f2d2SAndrzej Pietrasiewicz * This program is free software; you can redistribute it and/or modify 88443f2d2SAndrzej Pietrasiewicz * it under the terms of the GNU General Public License as published by 98443f2d2SAndrzej Pietrasiewicz * the Free Software Foundation; either version 2 of the License, or 108443f2d2SAndrzej Pietrasiewicz * (at your option) any later version. 118443f2d2SAndrzej Pietrasiewicz */ 128443f2d2SAndrzej Pietrasiewicz 138443f2d2SAndrzej Pietrasiewicz #include <linux/module.h> 148443f2d2SAndrzej Pietrasiewicz #include <linux/kernel.h> 158443f2d2SAndrzej Pietrasiewicz #include <asm/byteorder.h> 168443f2d2SAndrzej Pietrasiewicz 178443f2d2SAndrzej Pietrasiewicz #include <linux/usb/ch9.h> 188443f2d2SAndrzej Pietrasiewicz #include <linux/usb/composite.h> 198443f2d2SAndrzej Pietrasiewicz #include <linux/usb/gadget.h> 208443f2d2SAndrzej Pietrasiewicz #include <linux/usb/g_printer.h> 218443f2d2SAndrzej Pietrasiewicz 228443f2d2SAndrzej Pietrasiewicz #include "gadget_chips.h" 238443f2d2SAndrzej Pietrasiewicz 248443f2d2SAndrzej Pietrasiewicz USB_GADGET_COMPOSITE_OPTIONS(); 258443f2d2SAndrzej Pietrasiewicz 268443f2d2SAndrzej Pietrasiewicz #define DRIVER_DESC "Printer Gadget" 27b185f01aSAndrzej Pietrasiewicz #define DRIVER_VERSION "2015 FEB 17" 286dd8c2e6SAndrzej Pietrasiewicz 298443f2d2SAndrzej Pietrasiewicz static const char shortname [] = "printer"; 308443f2d2SAndrzej Pietrasiewicz static const char driver_desc [] = DRIVER_DESC; 318443f2d2SAndrzej Pietrasiewicz 3269504f80SAndrzej Pietrasiewicz #include "u_printer.h" 33143d53e1SAndrzej Pietrasiewicz 348443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/ 358443f2d2SAndrzej Pietrasiewicz 368443f2d2SAndrzej Pietrasiewicz /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! 378443f2d2SAndrzej Pietrasiewicz * Instead: allocate your own, using normal USB-IF procedures. 388443f2d2SAndrzej Pietrasiewicz */ 398443f2d2SAndrzej Pietrasiewicz 408443f2d2SAndrzej Pietrasiewicz /* Thanks to NetChip Technologies for donating this product ID. 418443f2d2SAndrzej Pietrasiewicz */ 428443f2d2SAndrzej Pietrasiewicz #define PRINTER_VENDOR_NUM 0x0525 /* NetChip */ 438443f2d2SAndrzej Pietrasiewicz #define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ 448443f2d2SAndrzej Pietrasiewicz 458443f2d2SAndrzej Pietrasiewicz /* Some systems will want different product identifiers published in the 468443f2d2SAndrzej Pietrasiewicz * device descriptor, either numbers or strings or both. These string 478443f2d2SAndrzej Pietrasiewicz * parameters are in UTF-8 (superset of ASCII's 7 bit characters). 488443f2d2SAndrzej Pietrasiewicz */ 498443f2d2SAndrzej Pietrasiewicz 508443f2d2SAndrzej Pietrasiewicz module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO); 518443f2d2SAndrzej Pietrasiewicz MODULE_PARM_DESC(iSerialNum, "1"); 528443f2d2SAndrzej Pietrasiewicz 538443f2d2SAndrzej Pietrasiewicz static char *iPNPstring; 548443f2d2SAndrzej Pietrasiewicz module_param(iPNPstring, charp, S_IRUGO); 558443f2d2SAndrzej Pietrasiewicz MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); 568443f2d2SAndrzej Pietrasiewicz 578443f2d2SAndrzej Pietrasiewicz /* Number of requests to allocate per endpoint, not used for ep0. */ 588443f2d2SAndrzej Pietrasiewicz static unsigned qlen = 10; 598443f2d2SAndrzej Pietrasiewicz module_param(qlen, uint, S_IRUGO|S_IWUSR); 608443f2d2SAndrzej Pietrasiewicz 618443f2d2SAndrzej Pietrasiewicz #define QLEN qlen 628443f2d2SAndrzej Pietrasiewicz 6369504f80SAndrzej Pietrasiewicz static struct usb_function_instance *fi_printer; 6469504f80SAndrzej Pietrasiewicz static struct usb_function *f_printer; 6569504f80SAndrzej Pietrasiewicz 668443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/ 678443f2d2SAndrzej Pietrasiewicz 688443f2d2SAndrzej Pietrasiewicz /* 698443f2d2SAndrzej Pietrasiewicz * DESCRIPTORS ... most are static, but strings and (full) configuration 708443f2d2SAndrzej Pietrasiewicz * descriptors are built on demand. 718443f2d2SAndrzej Pietrasiewicz */ 728443f2d2SAndrzej Pietrasiewicz 738443f2d2SAndrzej Pietrasiewicz static struct usb_device_descriptor device_desc = { 748443f2d2SAndrzej Pietrasiewicz .bLength = sizeof device_desc, 758443f2d2SAndrzej Pietrasiewicz .bDescriptorType = USB_DT_DEVICE, 768443f2d2SAndrzej Pietrasiewicz .bcdUSB = cpu_to_le16(0x0200), 778443f2d2SAndrzej Pietrasiewicz .bDeviceClass = USB_CLASS_PER_INTERFACE, 788443f2d2SAndrzej Pietrasiewicz .bDeviceSubClass = 0, 798443f2d2SAndrzej Pietrasiewicz .bDeviceProtocol = 0, 808443f2d2SAndrzej Pietrasiewicz .idVendor = cpu_to_le16(PRINTER_VENDOR_NUM), 818443f2d2SAndrzej Pietrasiewicz .idProduct = cpu_to_le16(PRINTER_PRODUCT_NUM), 828443f2d2SAndrzej Pietrasiewicz .bNumConfigurations = 1 838443f2d2SAndrzej Pietrasiewicz }; 848443f2d2SAndrzej Pietrasiewicz 858443f2d2SAndrzej Pietrasiewicz static struct usb_otg_descriptor otg_descriptor = { 868443f2d2SAndrzej Pietrasiewicz .bLength = sizeof otg_descriptor, 878443f2d2SAndrzej Pietrasiewicz .bDescriptorType = USB_DT_OTG, 888443f2d2SAndrzej Pietrasiewicz .bmAttributes = USB_OTG_SRP, 898443f2d2SAndrzej Pietrasiewicz }; 908443f2d2SAndrzej Pietrasiewicz 918443f2d2SAndrzej Pietrasiewicz static const struct usb_descriptor_header *otg_desc[] = { 928443f2d2SAndrzej Pietrasiewicz (struct usb_descriptor_header *) &otg_descriptor, 938443f2d2SAndrzej Pietrasiewicz NULL, 948443f2d2SAndrzej Pietrasiewicz }; 958443f2d2SAndrzej Pietrasiewicz 968443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/ 978443f2d2SAndrzej Pietrasiewicz 988443f2d2SAndrzej Pietrasiewicz /* descriptors that are built on-demand */ 998443f2d2SAndrzej Pietrasiewicz 1008443f2d2SAndrzej Pietrasiewicz static char product_desc [40] = DRIVER_DESC; 1018443f2d2SAndrzej Pietrasiewicz static char serial_num [40] = "1"; 102085617a1SAndrzej Pietrasiewicz static char pnp_string[PNP_STRING_LEN] = 1038443f2d2SAndrzej Pietrasiewicz "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; 1048443f2d2SAndrzej Pietrasiewicz 1058443f2d2SAndrzej Pietrasiewicz /* static strings, in UTF-8 */ 1068443f2d2SAndrzej Pietrasiewicz static struct usb_string strings [] = { 1078443f2d2SAndrzej Pietrasiewicz [USB_GADGET_MANUFACTURER_IDX].s = "", 1088443f2d2SAndrzej Pietrasiewicz [USB_GADGET_PRODUCT_IDX].s = product_desc, 1098443f2d2SAndrzej Pietrasiewicz [USB_GADGET_SERIAL_IDX].s = serial_num, 1108443f2d2SAndrzej Pietrasiewicz { } /* end of list */ 1118443f2d2SAndrzej Pietrasiewicz }; 1128443f2d2SAndrzej Pietrasiewicz 1138443f2d2SAndrzej Pietrasiewicz static struct usb_gadget_strings stringtab_dev = { 1148443f2d2SAndrzej Pietrasiewicz .language = 0x0409, /* en-us */ 1158443f2d2SAndrzej Pietrasiewicz .strings = strings, 1168443f2d2SAndrzej Pietrasiewicz }; 1178443f2d2SAndrzej Pietrasiewicz 1188443f2d2SAndrzej Pietrasiewicz static struct usb_gadget_strings *dev_strings[] = { 1198443f2d2SAndrzej Pietrasiewicz &stringtab_dev, 1208443f2d2SAndrzej Pietrasiewicz NULL, 1218443f2d2SAndrzej Pietrasiewicz }; 1228443f2d2SAndrzej Pietrasiewicz 1238443f2d2SAndrzej Pietrasiewicz static struct usb_configuration printer_cfg_driver = { 1248443f2d2SAndrzej Pietrasiewicz .label = "printer", 1258443f2d2SAndrzej Pietrasiewicz .bConfigurationValue = 1, 1268443f2d2SAndrzej Pietrasiewicz .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 1278443f2d2SAndrzej Pietrasiewicz }; 1288443f2d2SAndrzej Pietrasiewicz 129ae2dd0deSAndrzej Pietrasiewicz static int __init printer_do_config(struct usb_configuration *c) 130ae2dd0deSAndrzej Pietrasiewicz { 131ae2dd0deSAndrzej Pietrasiewicz struct usb_gadget *gadget = c->cdev->gadget; 13269504f80SAndrzej Pietrasiewicz int status = 0; 133ae2dd0deSAndrzej Pietrasiewicz 134ae2dd0deSAndrzej Pietrasiewicz usb_ep_autoconfig_reset(gadget); 135ae2dd0deSAndrzej Pietrasiewicz 136ae2dd0deSAndrzej Pietrasiewicz usb_gadget_set_selfpowered(gadget); 137ae2dd0deSAndrzej Pietrasiewicz 138ae2dd0deSAndrzej Pietrasiewicz if (gadget_is_otg(gadget)) { 139ae2dd0deSAndrzej Pietrasiewicz otg_descriptor.bmAttributes |= USB_OTG_HNP; 140ae2dd0deSAndrzej Pietrasiewicz printer_cfg_driver.descriptors = otg_desc; 141ae2dd0deSAndrzej Pietrasiewicz printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 142ae2dd0deSAndrzej Pietrasiewicz } 143ae2dd0deSAndrzej Pietrasiewicz 14469504f80SAndrzej Pietrasiewicz f_printer = usb_get_function(fi_printer); 14569504f80SAndrzej Pietrasiewicz if (IS_ERR(f_printer)) 14669504f80SAndrzej Pietrasiewicz return PTR_ERR(f_printer); 14769504f80SAndrzej Pietrasiewicz 14869504f80SAndrzej Pietrasiewicz status = usb_add_function(c, f_printer); 14969504f80SAndrzej Pietrasiewicz if (status < 0) 15069504f80SAndrzej Pietrasiewicz usb_put_function(f_printer); 15169504f80SAndrzej Pietrasiewicz 15269504f80SAndrzej Pietrasiewicz return status; 153ae2dd0deSAndrzej Pietrasiewicz } 154ae2dd0deSAndrzej Pietrasiewicz 1558443f2d2SAndrzej Pietrasiewicz static int __init printer_bind(struct usb_composite_dev *cdev) 1568443f2d2SAndrzej Pietrasiewicz { 15769504f80SAndrzej Pietrasiewicz struct f_printer_opts *opts; 15869504f80SAndrzej Pietrasiewicz int ret, len; 1598443f2d2SAndrzej Pietrasiewicz 16069504f80SAndrzej Pietrasiewicz fi_printer = usb_get_function_instance("printer"); 16169504f80SAndrzej Pietrasiewicz if (IS_ERR(fi_printer)) 16269504f80SAndrzej Pietrasiewicz return PTR_ERR(fi_printer); 16369504f80SAndrzej Pietrasiewicz 16469504f80SAndrzej Pietrasiewicz if (iPNPstring) 16569504f80SAndrzej Pietrasiewicz strlcpy(&pnp_string[2], iPNPstring, PNP_STRING_LEN - 2); 16669504f80SAndrzej Pietrasiewicz 16769504f80SAndrzej Pietrasiewicz len = strlen(pnp_string); 16869504f80SAndrzej Pietrasiewicz pnp_string[0] = (len >> 8) & 0xFF; 16969504f80SAndrzej Pietrasiewicz pnp_string[1] = len & 0xFF; 17069504f80SAndrzej Pietrasiewicz 17169504f80SAndrzej Pietrasiewicz opts = container_of(fi_printer, struct f_printer_opts, func_inst); 17269504f80SAndrzej Pietrasiewicz opts->minor = 0; 17369504f80SAndrzej Pietrasiewicz memcpy(opts->pnp_string, pnp_string, PNP_STRING_LEN); 17469504f80SAndrzej Pietrasiewicz opts->q_len = QLEN; 175a844715dSAndrzej Pietrasiewicz 176a844715dSAndrzej Pietrasiewicz ret = usb_string_ids_tab(cdev, strings); 177a844715dSAndrzej Pietrasiewicz if (ret < 0) { 17869504f80SAndrzej Pietrasiewicz usb_put_function_instance(fi_printer); 179a844715dSAndrzej Pietrasiewicz return ret; 180a844715dSAndrzej Pietrasiewicz } 1818443f2d2SAndrzej Pietrasiewicz device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; 1828443f2d2SAndrzej Pietrasiewicz device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; 1838443f2d2SAndrzej Pietrasiewicz device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; 1848443f2d2SAndrzej Pietrasiewicz 185406be2ccSAndrzej Pietrasiewicz ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); 186a844715dSAndrzej Pietrasiewicz if (ret) { 18769504f80SAndrzej Pietrasiewicz usb_put_function_instance(fi_printer); 1888443f2d2SAndrzej Pietrasiewicz return ret; 189a844715dSAndrzej Pietrasiewicz } 1908443f2d2SAndrzej Pietrasiewicz usb_composite_overwrite_options(cdev, &coverwrite); 1918443f2d2SAndrzej Pietrasiewicz return ret; 1928443f2d2SAndrzej Pietrasiewicz } 1938443f2d2SAndrzej Pietrasiewicz 194a844715dSAndrzej Pietrasiewicz static int __exit printer_unbind(struct usb_composite_dev *cdev) 195a844715dSAndrzej Pietrasiewicz { 19669504f80SAndrzej Pietrasiewicz usb_put_function(f_printer); 19769504f80SAndrzej Pietrasiewicz usb_put_function_instance(fi_printer); 19869504f80SAndrzej Pietrasiewicz 199a844715dSAndrzej Pietrasiewicz return 0; 200a844715dSAndrzej Pietrasiewicz } 201a844715dSAndrzej Pietrasiewicz 2028443f2d2SAndrzej Pietrasiewicz static __refdata struct usb_composite_driver printer_driver = { 2038443f2d2SAndrzej Pietrasiewicz .name = shortname, 2048443f2d2SAndrzej Pietrasiewicz .dev = &device_desc, 2058443f2d2SAndrzej Pietrasiewicz .strings = dev_strings, 20674df41b4SJorge Ramirez-Ortiz .max_speed = USB_SPEED_SUPER, 2078443f2d2SAndrzej Pietrasiewicz .bind = printer_bind, 208a844715dSAndrzej Pietrasiewicz .unbind = printer_unbind, 2098443f2d2SAndrzej Pietrasiewicz }; 2108443f2d2SAndrzej Pietrasiewicz 211*a2a8e48aSAndrzej Pietrasiewicz module_usb_composite_driver(printer_driver); 2128443f2d2SAndrzej Pietrasiewicz 2138443f2d2SAndrzej Pietrasiewicz MODULE_DESCRIPTION(DRIVER_DESC); 2148443f2d2SAndrzej Pietrasiewicz MODULE_AUTHOR("Craig Nadler"); 2158443f2d2SAndrzej Pietrasiewicz MODULE_LICENSE("GPL"); 216