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 <andrze...@samsung.com>
---
 drivers/usb/gadget/Kconfig              |   3 +
 drivers/usb/gadget/function/Makefile    |   2 +
 drivers/usb/gadget/function/f_printer.c | 185 +++++++++++++++++++++++++++++++-
 drivers/usb/gadget/function/u_printer.h |  30 ++++++
 drivers/usb/gadget/legacy/printer.c     |   1 +
 5 files changed, 220 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/gadget/function/u_printer.h

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b454d05..9d507cf 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -196,6 +196,9 @@ config USB_F_MIDI
 config USB_F_HID
        tristate
 
+config USB_F_PRINTER
+       tristate
+
 choice
        tristate "USB Gadget Drivers"
        default USB_ETH
diff --git a/drivers/usb/gadget/function/Makefile 
b/drivers/usb/gadget/function/Makefile
index f71b1aa..bd7def5 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -42,3 +42,5 @@ usb_f_midi-y                  := f_midi.o
 obj-$(CONFIG_USB_F_MIDI)       += usb_f_midi.o
 usb_f_hid-y                    := f_hid.o
 obj-$(CONFIG_USB_F_HID)                += usb_f_hid.o
+usb_f_printer-y                        := f_printer.o
+obj-$(CONFIG_USB_F_PRINTER)    += usb_f_printer.o
diff --git a/drivers/usb/gadget/function/f_printer.c 
b/drivers/usb/gadget/function/f_printer.c
index 0847972..93f4d4e 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)
 {
diff --git a/drivers/usb/gadget/function/u_printer.h 
b/drivers/usb/gadget/function/u_printer.h
new file mode 100644
index 0000000..b2338ca
--- /dev/null
+++ b/drivers/usb/gadget/function/u_printer.h
@@ -0,0 +1,30 @@
+/*
+ * u_printer.h
+ *
+ * Utility definitions for the printer function
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrze...@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef U_PRINTER_H
+#define U_PRINTER_H
+
+#include <linux/usb/composite.h>
+
+#define PNP_STRING_LEN                 1024
+
+struct f_printer_opts {
+       struct usb_function_instance    func_inst;
+       int                             minor;
+       char                            pnp_string[PNP_STRING_LEN];
+       unsigned                        q_len;
+};
+
+#endif /* U_PRINTER_H */
diff --git a/drivers/usb/gadget/legacy/printer.c 
b/drivers/usb/gadget/legacy/printer.c
index 4d926d0..770b504 100644
--- a/drivers/usb/gadget/legacy/printer.c
+++ b/drivers/usb/gadget/legacy/printer.c
@@ -33,6 +33,7 @@ static const char driver_desc [] = DRIVER_DESC;
  * This will be changed when f_printer is converted
  * to the new function interface.
  */
+#define USBF_PRINTER_INCLUDED
 #include "f_printer.c"
 
 /*-------------------------------------------------------------------------*/
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to