diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/function/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_printer.c | 185 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_printer.h | 30 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/printer.c | 1 |
5 files changed, 220 insertions, 1 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b454d05be583..9d507cf98f94 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -196,6 +196,9 @@ config USB_F_MIDI | |||
196 | config USB_F_HID | 196 | config USB_F_HID |
197 | tristate | 197 | tristate |
198 | 198 | ||
199 | config USB_F_PRINTER | ||
200 | tristate | ||
201 | |||
199 | choice | 202 | choice |
200 | tristate "USB Gadget Drivers" | 203 | tristate "USB Gadget Drivers" |
201 | default USB_ETH | 204 | default USB_ETH |
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index f71b1aaa0edf..bd7def576955 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile | |||
@@ -42,3 +42,5 @@ usb_f_midi-y := f_midi.o | |||
42 | obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o | 42 | obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o |
43 | usb_f_hid-y := f_hid.o | 43 | usb_f_hid-y := f_hid.o |
44 | obj-$(CONFIG_USB_F_HID) += usb_f_hid.o | 44 | obj-$(CONFIG_USB_F_HID) += usb_f_hid.o |
45 | usb_f_printer-y := f_printer.o | ||
46 | 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 0847972b9686..93f4d4e61fef 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/idr.h> | ||
27 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
28 | #include <linux/list.h> | 29 | #include <linux/list.h> |
29 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
@@ -46,6 +47,8 @@ | |||
46 | #include <linux/usb/gadget.h> | 47 | #include <linux/usb/gadget.h> |
47 | #include <linux/usb/g_printer.h> | 48 | #include <linux/usb/g_printer.h> |
48 | 49 | ||
50 | #include "u_printer.h" | ||
51 | |||
49 | #define PNP_STRING_LEN 1024 | 52 | #define PNP_STRING_LEN 1024 |
50 | #define PRINTER_MINORS 4 | 53 | #define PRINTER_MINORS 4 |
51 | #define GET_DEVICE_ID 0 | 54 | #define GET_DEVICE_ID 0 |
@@ -54,6 +57,10 @@ | |||
54 | 57 | ||
55 | static int major, minors; | 58 | static int major, minors; |
56 | static struct class *usb_gadget_class; | 59 | static struct class *usb_gadget_class; |
60 | #ifndef USBF_PRINTER_INCLUDED | ||
61 | static DEFINE_IDA(printer_ida); | ||
62 | static DEFINE_MUTEX(printer_ida_lock); /* protects access do printer_ida */ | ||
63 | #endif | ||
57 | 64 | ||
58 | /*-------------------------------------------------------------------------*/ | 65 | /*-------------------------------------------------------------------------*/ |
59 | 66 | ||
@@ -999,7 +1006,7 @@ unknown: | |||
999 | return value; | 1006 | return value; |
1000 | } | 1007 | } |
1001 | 1008 | ||
1002 | static int __init printer_func_bind(struct usb_configuration *c, | 1009 | static int printer_func_bind(struct usb_configuration *c, |
1003 | struct usb_function *f) | 1010 | struct usb_function *f) |
1004 | { | 1011 | { |
1005 | struct usb_gadget *gadget = c->cdev->gadget; | 1012 | struct usb_gadget *gadget = c->cdev->gadget; |
@@ -1111,6 +1118,7 @@ fail_tx_reqs: | |||
1111 | 1118 | ||
1112 | } | 1119 | } |
1113 | 1120 | ||
1121 | #ifdef USBF_PRINTER_INCLUDED | ||
1114 | static void printer_func_unbind(struct usb_configuration *c, | 1122 | static void printer_func_unbind(struct usb_configuration *c, |
1115 | struct usb_function *f) | 1123 | struct usb_function *f) |
1116 | { | 1124 | { |
@@ -1155,6 +1163,7 @@ static void printer_func_unbind(struct usb_configuration *c, | |||
1155 | usb_free_all_descriptors(f); | 1163 | usb_free_all_descriptors(f); |
1156 | kfree(dev); | 1164 | kfree(dev); |
1157 | } | 1165 | } |
1166 | #endif | ||
1158 | 1167 | ||
1159 | static int printer_func_set_alt(struct usb_function *f, | 1168 | static int printer_func_set_alt(struct usb_function *f, |
1160 | unsigned intf, unsigned alt) | 1169 | unsigned intf, unsigned alt) |
@@ -1180,6 +1189,7 @@ static void printer_func_disable(struct usb_function *f) | |||
1180 | spin_unlock_irqrestore(&dev->lock, flags); | 1189 | spin_unlock_irqrestore(&dev->lock, flags); |
1181 | } | 1190 | } |
1182 | 1191 | ||
1192 | #ifdef USBF_PRINTER_INCLUDED | ||
1183 | static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str, | 1193 | static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str, |
1184 | char *pnp_string, unsigned q_len, int minor) | 1194 | char *pnp_string, unsigned q_len, int minor) |
1185 | { | 1195 | { |
@@ -1240,6 +1250,179 @@ static int f_printer_bind_config(struct usb_configuration *c, char *pnp_str, | |||
1240 | INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); | 1250 | INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); |
1241 | return 0; | 1251 | return 0; |
1242 | } | 1252 | } |
1253 | #else | ||
1254 | static inline int gprinter_get_minor(void) | ||
1255 | { | ||
1256 | return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); | ||
1257 | } | ||
1258 | |||
1259 | static inline void gprinter_put_minor(int minor) | ||
1260 | { | ||
1261 | ida_simple_remove(&printer_ida, minor); | ||
1262 | } | ||
1263 | |||
1264 | static int gprinter_setup(int); | ||
1265 | static void gprinter_cleanup(void); | ||
1266 | |||
1267 | static void gprinter_free_inst(struct usb_function_instance *f) | ||
1268 | { | ||
1269 | struct f_printer_opts *opts; | ||
1270 | |||
1271 | opts = container_of(f, struct f_printer_opts, func_inst); | ||
1272 | |||
1273 | mutex_lock(&printer_ida_lock); | ||
1274 | |||
1275 | gprinter_put_minor(opts->minor); | ||
1276 | if (idr_is_empty(&printer_ida.idr)) | ||
1277 | gprinter_cleanup(); | ||
1278 | |||
1279 | mutex_unlock(&printer_ida_lock); | ||
1280 | |||
1281 | kfree(opts); | ||
1282 | } | ||
1283 | |||
1284 | static struct usb_function_instance *gprinter_alloc_inst(void) | ||
1285 | { | ||
1286 | struct f_printer_opts *opts; | ||
1287 | struct usb_function_instance *ret; | ||
1288 | int status = 0; | ||
1289 | |||
1290 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
1291 | if (!opts) | ||
1292 | return ERR_PTR(-ENOMEM); | ||
1293 | |||
1294 | opts->func_inst.free_func_inst = gprinter_free_inst; | ||
1295 | ret = &opts->func_inst; | ||
1296 | |||
1297 | mutex_lock(&printer_ida_lock); | ||
1298 | |||
1299 | if (idr_is_empty(&printer_ida.idr)) { | ||
1300 | status = gprinter_setup(PRINTER_MINORS); | ||
1301 | if (status) { | ||
1302 | ret = ERR_PTR(status); | ||
1303 | kfree(opts); | ||
1304 | goto unlock; | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | opts->minor = gprinter_get_minor(); | ||
1309 | if (opts->minor < 0) { | ||
1310 | ret = ERR_PTR(opts->minor); | ||
1311 | kfree(opts); | ||
1312 | if (idr_is_empty(&printer_ida.idr)) | ||
1313 | gprinter_cleanup(); | ||
1314 | } | ||
1315 | |||
1316 | unlock: | ||
1317 | mutex_unlock(&printer_ida_lock); | ||
1318 | return ret; | ||
1319 | } | ||
1320 | |||
1321 | static void gprinter_free(struct usb_function *f) | ||
1322 | { | ||
1323 | struct printer_dev *dev = func_to_printer(f); | ||
1324 | |||
1325 | kfree(dev); | ||
1326 | } | ||
1327 | |||
1328 | static void printer_func_unbind(struct usb_configuration *c, | ||
1329 | struct usb_function *f) | ||
1330 | { | ||
1331 | struct printer_dev *dev; | ||
1332 | struct usb_request *req; | ||
1333 | |||
1334 | dev = func_to_printer(f); | ||
1335 | |||
1336 | device_destroy(usb_gadget_class, MKDEV(major, dev->minor)); | ||
1337 | |||
1338 | /* Remove Character Device */ | ||
1339 | cdev_del(&dev->printer_cdev); | ||
1340 | |||
1341 | /* we must already have been disconnected ... no i/o may be active */ | ||
1342 | WARN_ON(!list_empty(&dev->tx_reqs_active)); | ||
1343 | WARN_ON(!list_empty(&dev->rx_reqs_active)); | ||
1344 | |||
1345 | /* Free all memory for this driver. */ | ||
1346 | while (!list_empty(&dev->tx_reqs)) { | ||
1347 | req = container_of(dev->tx_reqs.next, struct usb_request, | ||
1348 | list); | ||
1349 | list_del(&req->list); | ||
1350 | printer_req_free(dev->in_ep, req); | ||
1351 | } | ||
1352 | |||
1353 | if (dev->current_rx_req != NULL) | ||
1354 | printer_req_free(dev->out_ep, dev->current_rx_req); | ||
1355 | |||
1356 | while (!list_empty(&dev->rx_reqs)) { | ||
1357 | req = container_of(dev->rx_reqs.next, | ||
1358 | struct usb_request, list); | ||
1359 | list_del(&req->list); | ||
1360 | printer_req_free(dev->out_ep, req); | ||
1361 | } | ||
1362 | |||
1363 | while (!list_empty(&dev->rx_buffers)) { | ||
1364 | req = container_of(dev->rx_buffers.next, | ||
1365 | struct usb_request, list); | ||
1366 | list_del(&req->list); | ||
1367 | printer_req_free(dev->out_ep, req); | ||
1368 | } | ||
1369 | usb_free_all_descriptors(f); | ||
1370 | } | ||
1371 | |||
1372 | static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) | ||
1373 | { | ||
1374 | struct printer_dev *dev; | ||
1375 | struct f_printer_opts *opts; | ||
1376 | |||
1377 | opts = container_of(fi, struct f_printer_opts, func_inst); | ||
1378 | |||
1379 | if (opts->minor >= minors) | ||
1380 | return ERR_PTR(-ENOENT); | ||
1381 | |||
1382 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
1383 | if (!dev) | ||
1384 | return ERR_PTR(-ENOMEM); | ||
1385 | |||
1386 | dev->minor = opts->minor; | ||
1387 | dev->pnp_string = opts->pnp_string; | ||
1388 | dev->q_len = opts->q_len; | ||
1389 | |||
1390 | dev->function.name = "printer"; | ||
1391 | dev->function.bind = printer_func_bind; | ||
1392 | dev->function.setup = printer_func_setup; | ||
1393 | dev->function.unbind = printer_func_unbind; | ||
1394 | dev->function.set_alt = printer_func_set_alt; | ||
1395 | dev->function.disable = printer_func_disable; | ||
1396 | dev->function.req_match = gprinter_req_match; | ||
1397 | dev->function.free_func = gprinter_free; | ||
1398 | |||
1399 | INIT_LIST_HEAD(&dev->tx_reqs); | ||
1400 | INIT_LIST_HEAD(&dev->rx_reqs); | ||
1401 | INIT_LIST_HEAD(&dev->rx_buffers); | ||
1402 | INIT_LIST_HEAD(&dev->tx_reqs_active); | ||
1403 | INIT_LIST_HEAD(&dev->rx_reqs_active); | ||
1404 | |||
1405 | spin_lock_init(&dev->lock); | ||
1406 | mutex_init(&dev->lock_printer_io); | ||
1407 | init_waitqueue_head(&dev->rx_wait); | ||
1408 | init_waitqueue_head(&dev->tx_wait); | ||
1409 | init_waitqueue_head(&dev->tx_flush_wait); | ||
1410 | |||
1411 | dev->interface = -1; | ||
1412 | dev->printer_cdev_open = 0; | ||
1413 | dev->printer_status = PRINTER_NOT_ERROR; | ||
1414 | dev->current_rx_req = NULL; | ||
1415 | dev->current_rx_bytes = 0; | ||
1416 | dev->current_rx_buf = NULL; | ||
1417 | |||
1418 | return &dev->function; | ||
1419 | } | ||
1420 | |||
1421 | DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc); | ||
1422 | MODULE_LICENSE("GPL"); | ||
1423 | MODULE_AUTHOR("Craig Nadler"); | ||
1424 | |||
1425 | #endif | ||
1243 | 1426 | ||
1244 | static int gprinter_setup(int count) | 1427 | static int gprinter_setup(int count) |
1245 | { | 1428 | { |
diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h new file mode 100644 index 000000000000..b2338cacdfe4 --- /dev/null +++ b/drivers/usb/gadget/function/u_printer.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * u_printer.h | ||
3 | * | ||
4 | * Utility definitions for the printer function | ||
5 | * | ||
6 | * Copyright (c) 2015 Samsung Electronics Co., Ltd. | ||
7 | * http://www.samsung.com | ||
8 | * | ||
9 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef U_PRINTER_H | ||
17 | #define U_PRINTER_H | ||
18 | |||
19 | #include <linux/usb/composite.h> | ||
20 | |||
21 | #define PNP_STRING_LEN 1024 | ||
22 | |||
23 | struct f_printer_opts { | ||
24 | struct usb_function_instance func_inst; | ||
25 | int minor; | ||
26 | char pnp_string[PNP_STRING_LEN]; | ||
27 | unsigned q_len; | ||
28 | }; | ||
29 | |||
30 | #endif /* U_PRINTER_H */ | ||
diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 4d926d08df02..770b5041323e 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; | |||
33 | * This will be changed when f_printer is converted | 33 | * This will be changed when f_printer is converted |
34 | * to the new function interface. | 34 | * to the new function interface. |
35 | */ | 35 | */ |
36 | #define USBF_PRINTER_INCLUDED | ||
36 | #include "f_printer.c" | 37 | #include "f_printer.c" |
37 | 38 | ||
38 | /*-------------------------------------------------------------------------*/ | 39 | /*-------------------------------------------------------------------------*/ |