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>
This commit is contained in:
Родитель
d3bfd25821
Коммит
2e87edf492
|
@ -51,6 +51,7 @@
|
||||||
* the runtime footprint, and giving us at least some parts of what
|
* the runtime footprint, and giving us at least some parts of what
|
||||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||||
*/
|
*/
|
||||||
|
#include "composite.c"
|
||||||
#include "usbstring.c"
|
#include "usbstring.c"
|
||||||
#include "config.c"
|
#include "config.c"
|
||||||
#include "epautoconf.c"
|
#include "epautoconf.c"
|
||||||
|
@ -75,8 +76,6 @@ struct printer_dev {
|
||||||
/* lock buffer lists during read/write calls */
|
/* lock buffer lists during read/write calls */
|
||||||
struct mutex lock_printer_io;
|
struct mutex lock_printer_io;
|
||||||
struct usb_gadget *gadget;
|
struct usb_gadget *gadget;
|
||||||
struct usb_request *req; /* for control responses */
|
|
||||||
u8 config;
|
|
||||||
s8 interface;
|
s8 interface;
|
||||||
struct usb_ep *in_ep, *out_ep;
|
struct usb_ep *in_ep, *out_ep;
|
||||||
|
|
||||||
|
@ -100,6 +99,7 @@ struct printer_dev {
|
||||||
struct device *pdev;
|
struct device *pdev;
|
||||||
u8 printer_cdev_open;
|
u8 printer_cdev_open;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
|
struct usb_function function;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct printer_dev usb_printer_gadget;
|
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).
|
* 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;
|
static char *iSerialNum;
|
||||||
module_param(iSerialNum, charp, S_IRUGO);
|
module_param(iSerialNum, charp, S_IRUGO);
|
||||||
MODULE_PARM_DESC(iSerialNum, "1");
|
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 ... most are static, but strings and (full) configuration
|
||||||
* descriptors are built on demand.
|
* descriptors are built on demand.
|
||||||
|
@ -221,24 +168,6 @@ static struct usb_device_descriptor device_desc = {
|
||||||
.bNumConfigurations = 1
|
.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 = {
|
static struct usb_interface_descriptor intf_desc = {
|
||||||
.bLength = sizeof intf_desc,
|
.bLength = sizeof intf_desc,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
@ -264,8 +193,7 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = {
|
||||||
.bmAttributes = USB_ENDPOINT_XFER_BULK
|
.bmAttributes = USB_ENDPOINT_XFER_BULK
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_descriptor_header *fs_printer_function [11] = {
|
static struct usb_descriptor_header *fs_printer_function[] = {
|
||||||
(struct usb_descriptor_header *) &otg_desc,
|
|
||||||
(struct usb_descriptor_header *) &intf_desc,
|
(struct usb_descriptor_header *) &intf_desc,
|
||||||
(struct usb_descriptor_header *) &fs_ep_in_desc,
|
(struct usb_descriptor_header *) &fs_ep_in_desc,
|
||||||
(struct usb_descriptor_header *) &fs_ep_out_desc,
|
(struct usb_descriptor_header *) &fs_ep_out_desc,
|
||||||
|
@ -299,14 +227,24 @@ static struct usb_qualifier_descriptor dev_qualifier = {
|
||||||
.bNumConfigurations = 1
|
.bNumConfigurations = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_descriptor_header *hs_printer_function [11] = {
|
static struct usb_descriptor_header *hs_printer_function[] = {
|
||||||
(struct usb_descriptor_header *) &otg_desc,
|
|
||||||
(struct usb_descriptor_header *) &intf_desc,
|
(struct usb_descriptor_header *) &intf_desc,
|
||||||
(struct usb_descriptor_header *) &hs_ep_in_desc,
|
(struct usb_descriptor_header *) &hs_ep_in_desc,
|
||||||
(struct usb_descriptor_header *) &hs_ep_out_desc,
|
(struct usb_descriptor_header *) &hs_ep_out_desc,
|
||||||
NULL
|
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. */
|
/* maxpacket and other transfer characteristics vary by speed. */
|
||||||
#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
|
#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 */
|
{ } /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_gadget_strings stringtab = {
|
static struct usb_gadget_strings stringtab_dev = {
|
||||||
.language = 0x0409, /* en-us */
|
.language = 0x0409, /* en-us */
|
||||||
.strings = strings,
|
.strings = strings,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct usb_gadget_strings *dev_strings[] = {
|
||||||
|
&stringtab_dev,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static struct usb_request *
|
static struct usb_request *
|
||||||
|
@ -922,78 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev)
|
||||||
dev->interface = -1;
|
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. */
|
/* Change our operational Interface. */
|
||||||
static int
|
static int set_interface(struct printer_dev *dev, unsigned number)
|
||||||
set_interface(struct printer_dev *dev, unsigned number)
|
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
|
@ -1024,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number)
|
||||||
return result;
|
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)
|
static void printer_soft_reset(struct printer_dev *dev)
|
||||||
{
|
{
|
||||||
struct usb_request *req;
|
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
|
* The setup() callback implements all the ep0 functionality that's not
|
||||||
* handled lower down.
|
* handled lower down.
|
||||||
*/
|
*/
|
||||||
static int
|
static int printer_func_setup(struct usb_function *f,
|
||||||
printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
const struct usb_ctrlrequest *ctrl)
|
||||||
{
|
{
|
||||||
struct printer_dev *dev = get_gadget_data(gadget);
|
struct printer_dev *dev = container_of(f, struct printer_dev, function);
|
||||||
struct usb_request *req = dev->req;
|
struct usb_composite_dev *cdev = f->config->cdev;
|
||||||
|
struct usb_request *req = cdev->req;
|
||||||
int value = -EOPNOTSUPP;
|
int value = -EOPNOTSUPP;
|
||||||
u16 wIndex = le16_to_cpu(ctrl->wIndex);
|
u16 wIndex = le16_to_cpu(ctrl->wIndex);
|
||||||
u16 wValue = le16_to_cpu(ctrl->wValue);
|
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",
|
DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
|
||||||
ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
|
ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
|
||||||
|
|
||||||
req->complete = printer_setup_complete;
|
|
||||||
|
|
||||||
switch (ctrl->bRequestType&USB_TYPE_MASK) {
|
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:
|
case USB_TYPE_CLASS:
|
||||||
switch (ctrl->bRequest) {
|
switch (ctrl->bRequest) {
|
||||||
case 0: /* Get the IEEE-1284 PNP String */
|
case 0: /* Get the IEEE-1284 PNP String */
|
||||||
|
@ -1240,44 +1013,50 @@ unknown:
|
||||||
wValue, wIndex, wLength);
|
wValue, wIndex, wLength);
|
||||||
break;
|
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 */
|
/* host either stalls (value < 0) or reports success */
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int __init printer_func_bind(struct usb_configuration *c,
|
||||||
printer_disconnect(struct usb_gadget *gadget)
|
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;
|
unsigned long flags;
|
||||||
|
|
||||||
DBG(dev, "%s\n", __func__);
|
DBG(dev, "%s\n", __func__);
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
|
||||||
printer_reset_interface(dev);
|
printer_reset_interface(dev);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
spin_unlock_irqrestore(&dev->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void printer_cfg_unbind(struct usb_configuration *c)
|
||||||
printer_unbind(struct usb_gadget *gadget)
|
|
||||||
{
|
{
|
||||||
struct printer_dev *dev = get_gadget_data(gadget);
|
struct printer_dev *dev;
|
||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
|
|
||||||
|
dev = &usb_printer_gadget;
|
||||||
|
|
||||||
DBG(dev, "%s\n", __func__);
|
DBG(dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
@ -1315,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget)
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
printer_req_free(dev->out_ep, req);
|
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
|
static struct usb_configuration printer_cfg_driver = {
|
||||||
printer_bind(struct usb_gadget *gadget)
|
.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 printer_dev *dev;
|
||||||
struct usb_ep *in_ep, *out_ep;
|
struct usb_ep *in_ep, *out_ep;
|
||||||
int status = -ENOMEM;
|
int status = -ENOMEM;
|
||||||
|
@ -1337,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget)
|
||||||
|
|
||||||
dev = &usb_printer_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. */
|
/* Setup the sysfs files for the printer gadget. */
|
||||||
dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
|
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,
|
init_utsname()->sysname, init_utsname()->release,
|
||||||
gadget->name);
|
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)
|
if (iSerialNum)
|
||||||
strlcpy(serial_num, iSerialNum, sizeof serial_num);
|
strlcpy(serial_num, iSerialNum, sizeof serial_num);
|
||||||
|
|
||||||
|
@ -1428,8 +1192,9 @@ autoconf_fail:
|
||||||
usb_gadget_set_selfpowered(gadget);
|
usb_gadget_set_selfpowered(gadget);
|
||||||
|
|
||||||
if (gadget->is_otg) {
|
if (gadget->is_otg) {
|
||||||
otg_desc.bmAttributes |= USB_OTG_HNP,
|
otg_descriptor.bmAttributes |= USB_OTG_HNP;
|
||||||
config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
printer_cfg_driver.descriptors = otg_desc;
|
||||||
|
printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&dev->lock);
|
spin_lock_init(&dev->lock);
|
||||||
|
@ -1443,7 +1208,6 @@ autoconf_fail:
|
||||||
init_waitqueue_head(&dev->tx_wait);
|
init_waitqueue_head(&dev->tx_wait);
|
||||||
init_waitqueue_head(&dev->tx_flush_wait);
|
init_waitqueue_head(&dev->tx_flush_wait);
|
||||||
|
|
||||||
dev->config = 0;
|
|
||||||
dev->interface = -1;
|
dev->interface = -1;
|
||||||
dev->printer_cdev_open = 0;
|
dev->printer_cdev_open = 0;
|
||||||
dev->printer_status = PRINTER_NOT_ERROR;
|
dev->printer_status = PRINTER_NOT_ERROR;
|
||||||
|
@ -1454,14 +1218,6 @@ autoconf_fail:
|
||||||
dev->in_ep = in_ep;
|
dev->in_ep = in_ep;
|
||||||
dev->out_ep = out_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++) {
|
for (i = 0; i < QLEN; i++) {
|
||||||
req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
|
req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
|
||||||
if (!req) {
|
if (!req) {
|
||||||
|
@ -1490,45 +1246,37 @@ autoconf_fail:
|
||||||
list_add(&req->list, &dev->rx_reqs);
|
list_add(&req->list, &dev->rx_reqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->req->complete = printer_setup_complete;
|
|
||||||
|
|
||||||
/* finish hookup to lower layer ... */
|
/* finish hookup to lower layer ... */
|
||||||
dev->gadget = gadget;
|
dev->gadget = gadget;
|
||||||
set_gadget_data(gadget, dev);
|
|
||||||
gadget->ep0->driver_data = dev;
|
|
||||||
|
|
||||||
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
|
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
|
||||||
INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
|
INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
|
||||||
in_ep->name);
|
in_ep->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
printer_unbind(gadget);
|
printer_cfg_unbind(c);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
static int printer_unbind(struct usb_composite_dev *cdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct usb_gadget_driver printer_driver = {
|
static int __init printer_bind(struct usb_composite_dev *cdev)
|
||||||
.max_speed = USB_SPEED_HIGH,
|
{
|
||||||
|
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,
|
.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
|
static int __init
|
||||||
init(void)
|
init(void)
|
||||||
{
|
{
|
||||||
|
@ -1537,23 +1285,23 @@ init(void)
|
||||||
usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
|
usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
|
||||||
if (IS_ERR(usb_gadget_class)) {
|
if (IS_ERR(usb_gadget_class)) {
|
||||||
status = PTR_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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = alloc_chrdev_region(&g_printer_devno, 0, 1,
|
status = alloc_chrdev_region(&g_printer_devno, 0, 1,
|
||||||
"USB printer gadget");
|
"USB printer gadget");
|
||||||
if (status) {
|
if (status) {
|
||||||
ERROR(dev, "alloc_chrdev_region %d\n", status);
|
pr_err("alloc_chrdev_region %d\n", status);
|
||||||
class_destroy(usb_gadget_class);
|
class_destroy(usb_gadget_class);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = usb_gadget_probe_driver(&printer_driver, printer_bind);
|
status = usb_composite_probe(&printer_driver, printer_bind);
|
||||||
if (status) {
|
if (status) {
|
||||||
class_destroy(usb_gadget_class);
|
class_destroy(usb_gadget_class);
|
||||||
unregister_chrdev_region(g_printer_devno, 1);
|
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;
|
return status;
|
||||||
|
@ -1563,15 +1311,14 @@ module_init(init);
|
||||||
static void __exit
|
static void __exit
|
||||||
cleanup(void)
|
cleanup(void)
|
||||||
{
|
{
|
||||||
int status;
|
|
||||||
|
|
||||||
mutex_lock(&usb_printer_gadget.lock_printer_io);
|
mutex_lock(&usb_printer_gadget.lock_printer_io);
|
||||||
status = usb_gadget_unregister_driver(&printer_driver);
|
usb_composite_unregister(&printer_driver);
|
||||||
if (status)
|
|
||||||
ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
|
|
||||||
|
|
||||||
unregister_chrdev_region(g_printer_devno, 1);
|
unregister_chrdev_region(g_printer_devno, 1);
|
||||||
class_destroy(usb_gadget_class);
|
class_destroy(usb_gadget_class);
|
||||||
mutex_unlock(&usb_printer_gadget.lock_printer_io);
|
mutex_unlock(&usb_printer_gadget.lock_printer_io);
|
||||||
}
|
}
|
||||||
module_exit(cleanup);
|
module_exit(cleanup);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||||
|
MODULE_AUTHOR("Craig Nadler");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче