usb: gadget: printer: allocate printer_dev instances dynamically
With all the obstacles removed it is possible to allow more than one instance of the printer function. Since the function requires allocating character device region, a maximum number of allowed instances is defined. Such an approach is used in f_acm and in f_hid. With multiple instances it does not make sense to depend on a lock_printer_io member of a dynamically allocated (and destroyed) struct printer_dev to clean up after all instances of the printer function. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
636bc0ed27
commit
6dd8c2e695
|
@ -51,11 +51,12 @@ USB_GADGET_COMPOSITE_OPTIONS();
|
||||||
#define GET_PORT_STATUS 1
|
#define GET_PORT_STATUS 1
|
||||||
#define SOFT_RESET 2
|
#define SOFT_RESET 2
|
||||||
|
|
||||||
|
#define PRINTER_MINORS 4
|
||||||
|
|
||||||
static const char shortname [] = "printer";
|
static const char shortname [] = "printer";
|
||||||
static const char driver_desc [] = DRIVER_DESC;
|
static const char driver_desc [] = DRIVER_DESC;
|
||||||
|
|
||||||
static dev_t g_printer_devno;
|
static int major, minors;
|
||||||
|
|
||||||
static struct class *usb_gadget_class;
|
static struct class *usb_gadget_class;
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
@ -84,6 +85,7 @@ struct printer_dev {
|
||||||
u8 *current_rx_buf;
|
u8 *current_rx_buf;
|
||||||
u8 printer_status;
|
u8 printer_status;
|
||||||
u8 reset_printer;
|
u8 reset_printer;
|
||||||
|
int minor;
|
||||||
struct cdev printer_cdev;
|
struct cdev printer_cdev;
|
||||||
u8 printer_cdev_open;
|
u8 printer_cdev_open;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
|
@ -97,8 +99,6 @@ static inline struct printer_dev *func_to_printer(struct usb_function *f)
|
||||||
return container_of(f, struct printer_dev, function);
|
return container_of(f, struct printer_dev, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct printer_dev usb_printer_gadget;
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
|
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
|
||||||
|
@ -1096,6 +1096,7 @@ static int __init printer_func_bind(struct usb_configuration *c,
|
||||||
struct usb_ep *in_ep;
|
struct usb_ep *in_ep;
|
||||||
struct usb_ep *out_ep = NULL;
|
struct usb_ep *out_ep = NULL;
|
||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
|
dev_t devt;
|
||||||
int id;
|
int id;
|
||||||
int ret;
|
int ret;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
@ -1153,8 +1154,9 @@ static int __init printer_func_bind(struct usb_configuration *c,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the sysfs files for the printer gadget. */
|
/* Setup the sysfs files for the printer gadget. */
|
||||||
pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
|
devt = MKDEV(major, dev->minor);
|
||||||
NULL, "g_printer");
|
pdev = device_create(usb_gadget_class, NULL, devt,
|
||||||
|
NULL, "g_printer%d", dev->minor);
|
||||||
if (IS_ERR(pdev)) {
|
if (IS_ERR(pdev)) {
|
||||||
ERROR(dev, "Failed to create device: g_printer\n");
|
ERROR(dev, "Failed to create device: g_printer\n");
|
||||||
ret = PTR_ERR(pdev);
|
ret = PTR_ERR(pdev);
|
||||||
|
@ -1167,7 +1169,7 @@ static int __init printer_func_bind(struct usb_configuration *c,
|
||||||
*/
|
*/
|
||||||
cdev_init(&dev->printer_cdev, &printer_io_operations);
|
cdev_init(&dev->printer_cdev, &printer_io_operations);
|
||||||
dev->printer_cdev.owner = THIS_MODULE;
|
dev->printer_cdev.owner = THIS_MODULE;
|
||||||
ret = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
|
ret = cdev_add(&dev->printer_cdev, devt, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ERROR(dev, "Failed to open char device\n");
|
ERROR(dev, "Failed to open char device\n");
|
||||||
goto fail_cdev_add;
|
goto fail_cdev_add;
|
||||||
|
@ -1176,7 +1178,7 @@ static int __init printer_func_bind(struct usb_configuration *c,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_cdev_add:
|
fail_cdev_add:
|
||||||
device_destroy(usb_gadget_class, g_printer_devno);
|
device_destroy(usb_gadget_class, devt);
|
||||||
|
|
||||||
fail_rx_reqs:
|
fail_rx_reqs:
|
||||||
while (!list_empty(&dev->rx_reqs)) {
|
while (!list_empty(&dev->rx_reqs)) {
|
||||||
|
@ -1204,7 +1206,7 @@ static void printer_func_unbind(struct usb_configuration *c,
|
||||||
|
|
||||||
dev = func_to_printer(f);
|
dev = func_to_printer(f);
|
||||||
|
|
||||||
device_destroy(usb_gadget_class, g_printer_devno);
|
device_destroy(usb_gadget_class, MKDEV(major, dev->minor));
|
||||||
|
|
||||||
/* Remove Character Device */
|
/* Remove Character Device */
|
||||||
cdev_del(&dev->printer_cdev);
|
cdev_del(&dev->printer_cdev);
|
||||||
|
@ -1238,6 +1240,7 @@ static void printer_func_unbind(struct usb_configuration *c,
|
||||||
printer_req_free(dev->out_ep, req);
|
printer_req_free(dev->out_ep, req);
|
||||||
}
|
}
|
||||||
usb_free_all_descriptors(f);
|
usb_free_all_descriptors(f);
|
||||||
|
kfree(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printer_func_set_alt(struct usb_function *f,
|
static int printer_func_set_alt(struct usb_function *f,
|
||||||
|
@ -1271,14 +1274,21 @@ static struct usb_configuration printer_cfg_driver = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str,
|
static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str,
|
||||||
char *pnp_string, unsigned q_len)
|
char *pnp_string, unsigned q_len, int minor)
|
||||||
{
|
{
|
||||||
struct printer_dev *dev;
|
struct printer_dev *dev;
|
||||||
int status = -ENOMEM;
|
int status = -ENOMEM;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
dev = &usb_printer_gadget;
|
if (minor >= minors)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||||
|
if (!dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
dev->pnp_string = pnp_string;
|
dev->pnp_string = pnp_string;
|
||||||
|
dev->minor = minor;
|
||||||
|
|
||||||
dev->function.name = shortname;
|
dev->function.name = shortname;
|
||||||
dev->function.bind = printer_func_bind;
|
dev->function.bind = printer_func_bind;
|
||||||
|
@ -1315,8 +1325,10 @@ static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str,
|
||||||
dev->q_len = q_len;
|
dev->q_len = q_len;
|
||||||
|
|
||||||
status = usb_add_function(c, &dev->function);
|
status = usb_add_function(c, &dev->function);
|
||||||
if (status)
|
if (status) {
|
||||||
|
kfree(dev);
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
|
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1335,43 +1347,51 @@ static int __init printer_do_config(struct usb_configuration *c)
|
||||||
printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return f_printer_bind_config(c, iPNPstring, pnp_string, QLEN);
|
return f_printer_bind_config(c, iPNPstring, pnp_string, QLEN, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gprinter_setup(void)
|
static int gprinter_setup(int count)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
dev_t devt;
|
||||||
|
|
||||||
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);
|
||||||
|
usb_gadget_class = NULL;
|
||||||
pr_err("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(&devt, 0, count, "USB printer gadget");
|
||||||
"USB printer gadget");
|
|
||||||
if (status) {
|
if (status) {
|
||||||
pr_err("alloc_chrdev_region %d\n", status);
|
pr_err("alloc_chrdev_region %d\n", status);
|
||||||
class_destroy(usb_gadget_class);
|
class_destroy(usb_gadget_class);
|
||||||
|
usb_gadget_class = NULL;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
major = MAJOR(devt);
|
||||||
|
minors = count;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must be called with struct printer_dev's lock_printer_io held */
|
|
||||||
static void gprinter_cleanup(void)
|
static void gprinter_cleanup(void)
|
||||||
{
|
{
|
||||||
unregister_chrdev_region(g_printer_devno, 1);
|
if (major) {
|
||||||
|
unregister_chrdev_region(MKDEV(major, 0), minors);
|
||||||
|
major = minors = 0;
|
||||||
|
}
|
||||||
class_destroy(usb_gadget_class);
|
class_destroy(usb_gadget_class);
|
||||||
|
usb_gadget_class = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init printer_bind(struct usb_composite_dev *cdev)
|
static int __init printer_bind(struct usb_composite_dev *cdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = gprinter_setup();
|
ret = gprinter_setup(PRINTER_MINORS);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1418,9 +1438,7 @@ module_init(init);
|
||||||
static void __exit
|
static void __exit
|
||||||
cleanup(void)
|
cleanup(void)
|
||||||
{
|
{
|
||||||
mutex_lock(&usb_printer_gadget.lock_printer_io);
|
|
||||||
usb_composite_unregister(&printer_driver);
|
usb_composite_unregister(&printer_driver);
|
||||||
mutex_unlock(&usb_printer_gadget.lock_printer_io);
|
|
||||||
}
|
}
|
||||||
module_exit(cleanup);
|
module_exit(cleanup);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue