summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function/f_printer.c
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2015-03-03 10:52:28 +0100
committerFelipe Balbi <balbi@ti.com>2015-03-10 15:33:40 -0500
commitb26394bd567e5ebe57ec4dee7fe6cd14023c96e9 (patch)
treefe1dcc7107817aee8ca63240946316ae8e42a762 /drivers/usb/gadget/function/f_printer.c
parentb185f01a9ab7af586133be2555298e960237359b (diff)
downloadlinux-stable-b26394bd567e5ebe57ec4dee7fe6cd14023c96e9.tar.gz
linux-stable-b26394bd567e5ebe57ec4dee7fe6cd14023c96e9.tar.bz2
linux-stable-b26394bd567e5ebe57ec4dee7fe6cd14023c96e9.zip
usb: gadget: f_printer: convert to new function interface with backward compatibility
In order to add configfs support, a usb function must be converted to use the new interface. This patch converts the function to the new interface and provides backward compatiblity layer, which can be removed after all its users are converted to use the new interface. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/function/f_printer.c')
-rw-r--r--drivers/usb/gadget/function/f_printer.c185
1 files changed, 184 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 0847972b9686..93f4d4e61fef 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/idr.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
@@ -46,6 +47,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/g_printer.h>
+#include "u_printer.h"
+
#define PNP_STRING_LEN 1024
#define PRINTER_MINORS 4
#define GET_DEVICE_ID 0
@@ -54,6 +57,10 @@
static int major, minors;
static struct class *usb_gadget_class;
+#ifndef USBF_PRINTER_INCLUDED
+static DEFINE_IDA(printer_ida);
+static DEFINE_MUTEX(printer_ida_lock); /* protects access do printer_ida */
+#endif
/*-------------------------------------------------------------------------*/
@@ -999,7 +1006,7 @@ unknown:
return value;
}
-static int __init printer_func_bind(struct usb_configuration *c,
+static int printer_func_bind(struct usb_configuration *c,
struct usb_function *f)
{
struct usb_gadget *gadget = c->cdev->gadget;
@@ -1111,6 +1118,7 @@ fail_tx_reqs:
}
+#ifdef USBF_PRINTER_INCLUDED
static void printer_func_unbind(struct usb_configuration *c,
struct usb_function *f)
{
@@ -1155,6 +1163,7 @@ static void printer_func_unbind(struct usb_configuration *c,
usb_free_all_descriptors(f);
kfree(dev);
}
+#endif
static int printer_func_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
@@ -1180,6 +1189,7 @@ static void printer_func_disable(struct usb_function *f)
spin_unlock_irqrestore(&dev->lock, flags);
}
+#ifdef USBF_PRINTER_INCLUDED
static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str,
char *pnp_string, unsigned q_len, int minor)
{
@@ -1240,6 +1250,179 @@ static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str,
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
return 0;
}
+#else
+static inline int gprinter_get_minor(void)
+{
+ return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+}
+
+static inline void gprinter_put_minor(int minor)
+{
+ ida_simple_remove(&printer_ida, minor);
+}
+
+static int gprinter_setup(int);
+static void gprinter_cleanup(void);
+
+static void gprinter_free_inst(struct usb_function_instance *f)
+{
+ struct f_printer_opts *opts;
+
+ opts = container_of(f, struct f_printer_opts, func_inst);
+
+ mutex_lock(&printer_ida_lock);
+
+ gprinter_put_minor(opts->minor);
+ if (idr_is_empty(&printer_ida.idr))
+ gprinter_cleanup();
+
+ mutex_unlock(&printer_ida_lock);
+
+ kfree(opts);
+}
+
+static struct usb_function_instance *gprinter_alloc_inst(void)
+{
+ struct f_printer_opts *opts;
+ struct usb_function_instance *ret;
+ int status = 0;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.free_func_inst = gprinter_free_inst;
+ ret = &opts->func_inst;
+
+ mutex_lock(&printer_ida_lock);
+
+ if (idr_is_empty(&printer_ida.idr)) {
+ status = gprinter_setup(PRINTER_MINORS);
+ if (status) {
+ ret = ERR_PTR(status);
+ kfree(opts);
+ goto unlock;
+ }
+ }
+
+ opts->minor = gprinter_get_minor();
+ if (opts->minor < 0) {
+ ret = ERR_PTR(opts->minor);
+ kfree(opts);
+ if (idr_is_empty(&printer_ida.idr))
+ gprinter_cleanup();
+ }
+
+unlock:
+ mutex_unlock(&printer_ida_lock);
+ return ret;
+}
+
+static void gprinter_free(struct usb_function *f)
+{
+ struct printer_dev *dev = func_to_printer(f);
+
+ kfree(dev);
+}
+
+static void printer_func_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct printer_dev *dev;
+ struct usb_request *req;
+
+ dev = func_to_printer(f);
+
+ device_destroy(usb_gadget_class, MKDEV(major, dev->minor));
+
+ /* Remove Character Device */
+ cdev_del(&dev->printer_cdev);
+
+ /* we must already have been disconnected ... no i/o may be active */
+ WARN_ON(!list_empty(&dev->tx_reqs_active));
+ WARN_ON(!list_empty(&dev->rx_reqs_active));
+
+ /* Free all memory for this driver. */
+ while (!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 != NULL)
+ printer_req_free(dev->out_ep, dev->current_rx_req);
+
+ while (!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 (!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);
+ }
+ usb_free_all_descriptors(f);
+}
+
+static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
+{
+ struct printer_dev *dev;
+ struct f_printer_opts *opts;
+
+ opts = container_of(fi, struct f_printer_opts, func_inst);
+
+ if (opts->minor >= minors)
+ return ERR_PTR(-ENOENT);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->minor = opts->minor;
+ dev->pnp_string = opts->pnp_string;
+ dev->q_len = opts->q_len;
+
+ dev->function.name = "printer";
+ 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;
+ dev->function.req_match = gprinter_req_match;
+ dev->function.free_func = gprinter_free;
+
+ INIT_LIST_HEAD(&dev->tx_reqs);
+ INIT_LIST_HEAD(&dev->rx_reqs);
+ INIT_LIST_HEAD(&dev->rx_buffers);
+ INIT_LIST_HEAD(&dev->tx_reqs_active);
+ INIT_LIST_HEAD(&dev->rx_reqs_active);
+
+ spin_lock_init(&dev->lock);
+ mutex_init(&dev->lock_printer_io);
+ init_waitqueue_head(&dev->rx_wait);
+ init_waitqueue_head(&dev->tx_wait);
+ init_waitqueue_head(&dev->tx_flush_wait);
+
+ dev->interface = -1;
+ dev->printer_cdev_open = 0;
+ dev->printer_status = PRINTER_NOT_ERROR;
+ dev->current_rx_req = NULL;
+ dev->current_rx_bytes = 0;
+ dev->current_rx_buf = NULL;
+
+ return &dev->function;
+}
+
+DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Craig Nadler");
+
+#endif
static int gprinter_setup(int count)
{