1
0
Fork 0

usb: gadget: make g_printer use composite

This patch converts the g_printer to make use of the compoiste framework
for descriptor parsing instead of its own implementation of it.
This gadget contains now one function which is the printer gadget.
Compile tested only.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Signed-off-by: Felipe Balbi <balbi@ti.com>
hifive-unleashed-5.1
Sebastian Andrzej Siewior 2012-02-04 18:55:20 +01:00 committed by Felipe Balbi
parent d3bfd25821
commit 2e87edf492
1 changed files with 97 additions and 350 deletions

View File

@ -51,6 +51,7 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
@ -75,8 +76,6 @@ struct printer_dev {
/* lock buffer lists during read/write calls */
struct mutex lock_printer_io;
struct usb_gadget *gadget;
struct usb_request *req; /* for control responses */
u8 config;
s8 interface;
struct usb_ep *in_ep, *out_ep;
@ -100,6 +99,7 @@ struct printer_dev {
struct device *pdev;
u8 printer_cdev_open;
wait_queue_head_t wait;
struct usb_function function;
};
static struct printer_dev usb_printer_gadget;
@ -120,26 +120,6 @@ static struct printer_dev usb_printer_gadget;
* parameters are in UTF-8 (superset of ASCII's 7 bit characters).
*/
static ushort idVendor;
module_param(idVendor, ushort, S_IRUGO);
MODULE_PARM_DESC(idVendor, "USB Vendor ID");
static ushort idProduct;
module_param(idProduct, ushort, S_IRUGO);
MODULE_PARM_DESC(idProduct, "USB Product ID");
static ushort bcdDevice;
module_param(bcdDevice, ushort, S_IRUGO);
MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
static char *iManufacturer;
module_param(iManufacturer, charp, S_IRUGO);
MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
static char *iProduct;
module_param(iProduct, charp, S_IRUGO);
MODULE_PARM_DESC(iProduct, "USB Product string");
static char *iSerialNum;
module_param(iSerialNum, charp, S_IRUGO);
MODULE_PARM_DESC(iSerialNum, "1");
@ -156,39 +136,6 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
/*-------------------------------------------------------------------------*/
#define xprintk(d, level, fmt, args...) \
printk(level "%s: " fmt, DRIVER_DESC, ## args)
#ifdef DEBUG
#define DBG(dev, fmt, args...) \
xprintk(dev, KERN_DEBUG, fmt, ## args)
#else
#define DBG(dev, fmt, args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG(dev, fmt, args...) \
xprintk(dev, KERN_DEBUG, fmt, ## args)
#else
#define VDBG(dev, fmt, args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(dev, fmt, args...) \
xprintk(dev, KERN_ERR, fmt, ## args)
#define WARNING(dev, fmt, args...) \
xprintk(dev, KERN_WARNING, fmt, ## args)
#define INFO(dev, fmt, args...) \
xprintk(dev, KERN_INFO, fmt, ## args)
/*-------------------------------------------------------------------------*/
/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
* ep0 implementation: descriptors, config management, setup().
* also optional class-specific notification interrupt transfer.
*/
/*
* DESCRIPTORS ... most are static, but strings and (full) configuration
* descriptors are built on demand.
@ -221,24 +168,6 @@ static struct usb_device_descriptor device_desc = {
.bNumConfigurations = 1
};
static struct usb_otg_descriptor otg_desc = {
.bLength = sizeof otg_desc,
.bDescriptorType = USB_DT_OTG,
.bmAttributes = USB_OTG_SRP
};
static struct usb_config_descriptor config_desc = {
.bLength = sizeof config_desc,
.bDescriptorType = USB_DT_CONFIG,
/* compute wTotalLength on the fly */
.bNumInterfaces = 1,
.bConfigurationValue = DEV_CONFIG_VALUE,
.iConfiguration = 0,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
@ -264,8 +193,7 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK
};
static const struct usb_descriptor_header *fs_printer_function [11] = {
(struct usb_descriptor_header *) &otg_desc,
static struct usb_descriptor_header *fs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_ep_in_desc,
(struct usb_descriptor_header *) &fs_ep_out_desc,
@ -299,14 +227,24 @@ static struct usb_qualifier_descriptor dev_qualifier = {
.bNumConfigurations = 1
};
static const struct usb_descriptor_header *hs_printer_function [11] = {
(struct usb_descriptor_header *) &otg_desc,
static struct usb_descriptor_header *hs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_ep_in_desc,
(struct usb_descriptor_header *) &hs_ep_out_desc,
NULL
};
static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
.bmAttributes = USB_OTG_SRP,
};
static const struct usb_descriptor_header *otg_desc[] = {
(struct usb_descriptor_header *) &otg_descriptor,
NULL,
};
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
@ -328,11 +266,16 @@ static struct usb_string strings [] = {
{ } /* end of list */
};
static struct usb_gadget_strings stringtab = {
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
NULL,
};
/*-------------------------------------------------------------------------*/
static struct usb_request *
@ -922,78 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev)
dev->interface = -1;
}
/* change our operational config. must agree with the code
* that returns config descriptors, and altsetting code.
*/
static int
printer_set_config(struct printer_dev *dev, unsigned number)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
switch (number) {
case DEV_CONFIG_VALUE:
result = 0;
break;
default:
result = -EINVAL;
/* FALL THROUGH */
case 0:
break;
}
if (result) {
usb_gadget_vbus_draw(dev->gadget,
dev->gadget->is_otg ? 8 : 100);
} else {
unsigned power;
power = 2 * config_desc.bMaxPower;
usb_gadget_vbus_draw(dev->gadget, power);
dev->config = number;
INFO(dev, "%s config #%d: %d mA, %s\n",
usb_speed_string(gadget->speed),
number, power, driver_desc);
}
return result;
}
static int
config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
int is_otg)
{
int len;
const struct usb_descriptor_header **function;
int hs = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
if (hs) {
function = hs_printer_function;
} else {
function = fs_printer_function;
}
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
/* for now, don't advertise srp-only devices */
if (!is_otg)
function++;
len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
function);
if (len < 0)
return len;
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
}
/* Change our operational Interface. */
static int
set_interface(struct printer_dev *dev, unsigned number)
static int set_interface(struct printer_dev *dev, unsigned number)
{
int result = 0;
@ -1024,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number)
return result;
}
static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
DBG((struct printer_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
static void printer_soft_reset(struct printer_dev *dev)
{
struct usb_request *req;
@ -1088,11 +953,12 @@ static void printer_soft_reset(struct printer_dev *dev)
* The setup() callback implements all the ep0 functionality that's not
* handled lower down.
*/
static int
printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
static int printer_func_setup(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct printer_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->req;
struct printer_dev *dev = container_of(f, struct printer_dev, function);
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
@ -1101,100 +967,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
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:
device_desc.bMaxPacketSize0 =
gadget->ep0->maxpacket;
value = min(wLength, (u16) sizeof device_desc);
memcpy(req->buf, &device_desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget))
break;
/*
* assumes ep0 uses the same value for both
* speeds
*/
dev_qualifier.bMaxPacketSize0 =
gadget->ep0->maxpacket;
value = min(wLength,
(u16) sizeof dev_qualifier);
memcpy(req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget_is_dualspeed(gadget))
break;
/* FALLTHROUGH */
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);
if (!value)
value = set_interface(dev, PRINTER_INTERFACE);
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:
goto unknown;
}
break;
case USB_TYPE_CLASS:
switch (ctrl->bRequest) {
case 0: /* Get the IEEE-1284 PNP String */
@ -1240,44 +1013,50 @@ unknown:
wValue, wIndex, wLength);
break;
}
/* respond with data transfer before status phase? */
if (value >= 0) {
req->length = value;
req->zero = value < wLength;
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 void
printer_disconnect(struct usb_gadget *gadget)
static int __init printer_func_bind(struct usb_configuration *c,
struct usb_function *f)
{
struct printer_dev *dev = get_gadget_data(gadget);
return 0;
}
static void printer_func_unbind(struct usb_configuration *c,
struct usb_function *f)
{
}
static int printer_func_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
struct printer_dev *dev = container_of(f, struct printer_dev, function);
int ret = -ENOTSUPP;
if (!alt)
ret = set_interface(dev, PRINTER_INTERFACE);
return ret;
}
static void printer_func_disable(struct usb_function *f)
{
struct printer_dev *dev = container_of(f, struct printer_dev, function);
unsigned long flags;
DBG(dev, "%s\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
printer_reset_interface(dev);
spin_unlock_irqrestore(&dev->lock, flags);
}
static void
printer_unbind(struct usb_gadget *gadget)
static void printer_cfg_unbind(struct usb_configuration *c)
{
struct printer_dev *dev = get_gadget_data(gadget);
struct printer_dev *dev;
struct usb_request *req;
dev = &usb_printer_gadget;
DBG(dev, "%s\n", __func__);
@ -1315,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget)
list_del(&req->list);
printer_req_free(dev->out_ep, req);
}
if (dev->req) {
printer_req_free(gadget->ep0, dev->req);
dev->req = NULL;
}
set_gadget_data(gadget, NULL);
}
static int __init
printer_bind(struct usb_gadget *gadget)
static struct usb_configuration printer_cfg_driver = {
.label = "printer",
.unbind = printer_cfg_unbind,
.bConfigurationValue = 1,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
};
static int __init printer_bind_config(struct usb_configuration *c)
{
struct usb_gadget *gadget = c->cdev->gadget;
struct printer_dev *dev;
struct usb_ep *in_ep, *out_ep;
int status = -ENOMEM;
@ -1337,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget)
dev = &usb_printer_gadget;
dev->function.name = shortname;
dev->function.descriptors = fs_printer_function;
dev->function.hs_descriptors = hs_printer_function;
dev->function.bind = printer_func_bind;
dev->function.setup = printer_func_setup;
dev->function.unbind = printer_func_unbind;
dev->function.set_alt = printer_func_set_alt;
dev->function.disable = printer_func_disable;
/* Setup the sysfs files for the printer gadget. */
dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
@ -1372,29 +1159,6 @@ printer_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
device_desc.idVendor =
cpu_to_le16(PRINTER_VENDOR_NUM);
device_desc.idProduct =
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);
@ -1428,8 +1192,9 @@ autoconf_fail:
usb_gadget_set_selfpowered(gadget);
if (gadget->is_otg) {
otg_desc.bmAttributes |= USB_OTG_HNP,
config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
otg_descriptor.bmAttributes |= USB_OTG_HNP;
printer_cfg_driver.descriptors = otg_desc;
printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
spin_lock_init(&dev->lock);
@ -1443,7 +1208,6 @@ autoconf_fail:
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->printer_status = PRINTER_NOT_ERROR;
@ -1454,14 +1218,6 @@ autoconf_fail:
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);
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) {
@ -1490,45 +1246,37 @@ autoconf_fail:
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);
printer_cfg_unbind(c);
return status;
}
/*-------------------------------------------------------------------------*/
static int printer_unbind(struct usb_composite_dev *cdev)
{
return 0;
}
static struct usb_gadget_driver printer_driver = {
.max_speed = USB_SPEED_HIGH,
static int __init printer_bind(struct usb_composite_dev *cdev)
{
return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
}
.function = (char *) driver_desc,
static struct usb_composite_driver printer_driver = {
.name = shortname,
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_HIGH,
.unbind = printer_unbind,
.setup = printer_setup,
.disconnect = printer_disconnect,
.driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Craig Nadler");
MODULE_LICENSE("GPL");
static int __init
init(void)
{
@ -1537,23 +1285,23 @@ init(void)
usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
if (IS_ERR(usb_gadget_class)) {
status = PTR_ERR(usb_gadget_class);
ERROR(dev, "unable to create usb_gadget class %d\n", status);
pr_err("unable to create usb_gadget class %d\n", status);
return status;
}
status = alloc_chrdev_region(&g_printer_devno, 0, 1,
"USB printer gadget");
if (status) {
ERROR(dev, "alloc_chrdev_region %d\n", status);
pr_err("alloc_chrdev_region %d\n", status);
class_destroy(usb_gadget_class);
return status;
}
status = usb_gadget_probe_driver(&printer_driver, printer_bind);
status = usb_composite_probe(&printer_driver, printer_bind);
if (status) {
class_destroy(usb_gadget_class);
unregister_chrdev_region(g_printer_devno, 1);
DBG(dev, "usb_gadget_probe_driver %x\n", status);
pr_err("usb_gadget_probe_driver %x\n", status);
}
return status;
@ -1563,15 +1311,14 @@ module_init(init);
static void __exit
cleanup(void)
{
int status;
mutex_lock(&usb_printer_gadget.lock_printer_io);
status = usb_gadget_unregister_driver(&printer_driver);
if (status)
ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
usb_composite_unregister(&printer_driver);
unregister_chrdev_region(g_printer_devno, 1);
class_destroy(usb_gadget_class);
mutex_unlock(&usb_printer_gadget.lock_printer_io);
}
module_exit(cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Craig Nadler");
MODULE_LICENSE("GPL");