15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2b185f01aSAndrzej Pietrasiewicz /*
3b185f01aSAndrzej Pietrasiewicz * f_printer.c - USB printer function driver
4b185f01aSAndrzej Pietrasiewicz *
5b185f01aSAndrzej Pietrasiewicz * Copied from drivers/usb/gadget/legacy/printer.c,
6b185f01aSAndrzej Pietrasiewicz * which was:
7b185f01aSAndrzej Pietrasiewicz *
8b185f01aSAndrzej Pietrasiewicz * printer.c -- Printer gadget driver
9b185f01aSAndrzej Pietrasiewicz *
10b185f01aSAndrzej Pietrasiewicz * Copyright (C) 2003-2005 David Brownell
11b185f01aSAndrzej Pietrasiewicz * Copyright (C) 2006 Craig W. Nadler
12b185f01aSAndrzej Pietrasiewicz */
13b185f01aSAndrzej Pietrasiewicz
14b185f01aSAndrzej Pietrasiewicz #include <linux/module.h>
15b185f01aSAndrzej Pietrasiewicz #include <linux/kernel.h>
16b185f01aSAndrzej Pietrasiewicz #include <linux/delay.h>
17b185f01aSAndrzej Pietrasiewicz #include <linux/ioport.h>
18b185f01aSAndrzej Pietrasiewicz #include <linux/sched.h>
19b185f01aSAndrzej Pietrasiewicz #include <linux/slab.h>
20b185f01aSAndrzej Pietrasiewicz #include <linux/mutex.h>
21b185f01aSAndrzej Pietrasiewicz #include <linux/errno.h>
22b185f01aSAndrzej Pietrasiewicz #include <linux/init.h>
23b26394bdSAndrzej Pietrasiewicz #include <linux/idr.h>
24b185f01aSAndrzej Pietrasiewicz #include <linux/timer.h>
25b185f01aSAndrzej Pietrasiewicz #include <linux/list.h>
26b185f01aSAndrzej Pietrasiewicz #include <linux/interrupt.h>
27b185f01aSAndrzej Pietrasiewicz #include <linux/device.h>
28b185f01aSAndrzej Pietrasiewicz #include <linux/moduleparam.h>
29b185f01aSAndrzej Pietrasiewicz #include <linux/fs.h>
30b185f01aSAndrzej Pietrasiewicz #include <linux/poll.h>
31b185f01aSAndrzej Pietrasiewicz #include <linux/types.h>
32b185f01aSAndrzej Pietrasiewicz #include <linux/ctype.h>
33b185f01aSAndrzej Pietrasiewicz #include <linux/cdev.h>
34e8d5f92bSZqiang #include <linux/kref.h>
35b185f01aSAndrzej Pietrasiewicz
36b185f01aSAndrzej Pietrasiewicz #include <asm/byteorder.h>
37b185f01aSAndrzej Pietrasiewicz #include <linux/io.h>
38b185f01aSAndrzej Pietrasiewicz #include <linux/irq.h>
39b185f01aSAndrzej Pietrasiewicz #include <linux/uaccess.h>
40*5f60d5f6SAl Viro #include <linux/unaligned.h>
41b185f01aSAndrzej Pietrasiewicz
42b185f01aSAndrzej Pietrasiewicz #include <linux/usb/ch9.h>
43b185f01aSAndrzej Pietrasiewicz #include <linux/usb/composite.h>
44b185f01aSAndrzej Pietrasiewicz #include <linux/usb/gadget.h>
45b185f01aSAndrzej Pietrasiewicz #include <linux/usb/g_printer.h>
46b185f01aSAndrzej Pietrasiewicz
47b26394bdSAndrzej Pietrasiewicz #include "u_printer.h"
48b26394bdSAndrzej Pietrasiewicz
49b185f01aSAndrzej Pietrasiewicz #define PRINTER_MINORS 4
50b185f01aSAndrzej Pietrasiewicz #define GET_DEVICE_ID 0
51b185f01aSAndrzej Pietrasiewicz #define GET_PORT_STATUS 1
52b185f01aSAndrzej Pietrasiewicz #define SOFT_RESET 2
53b185f01aSAndrzej Pietrasiewicz
54ed054e4eSMichael R Sweet #define DEFAULT_Q_LEN 10 /* same as legacy g_printer gadget */
55ed054e4eSMichael R Sweet
56b185f01aSAndrzej Pietrasiewicz static int major, minors;
572c10e7a0SIvan Orlov static const struct class usb_gadget_class = {
582c10e7a0SIvan Orlov .name = "usb_printer_gadget",
592c10e7a0SIvan Orlov };
602c10e7a0SIvan Orlov
61b26394bdSAndrzej Pietrasiewicz static DEFINE_IDA(printer_ida);
62b26394bdSAndrzej Pietrasiewicz static DEFINE_MUTEX(printer_ida_lock); /* protects access do printer_ida */
63b185f01aSAndrzej Pietrasiewicz
64b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
65b185f01aSAndrzej Pietrasiewicz
66b185f01aSAndrzej Pietrasiewicz struct printer_dev {
67b185f01aSAndrzej Pietrasiewicz spinlock_t lock; /* lock this structure */
68b185f01aSAndrzej Pietrasiewicz /* lock buffer lists during read/write calls */
69b185f01aSAndrzej Pietrasiewicz struct mutex lock_printer_io;
70b185f01aSAndrzej Pietrasiewicz struct usb_gadget *gadget;
71b185f01aSAndrzej Pietrasiewicz s8 interface;
72b185f01aSAndrzej Pietrasiewicz struct usb_ep *in_ep, *out_ep;
73e8d5f92bSZqiang struct kref kref;
74b185f01aSAndrzej Pietrasiewicz struct list_head rx_reqs; /* List of free RX structs */
75b185f01aSAndrzej Pietrasiewicz struct list_head rx_reqs_active; /* List of Active RX xfers */
76b185f01aSAndrzej Pietrasiewicz struct list_head rx_buffers; /* List of completed xfers */
77b185f01aSAndrzej Pietrasiewicz /* wait until there is data to be read. */
78b185f01aSAndrzej Pietrasiewicz wait_queue_head_t rx_wait;
79b185f01aSAndrzej Pietrasiewicz struct list_head tx_reqs; /* List of free TX structs */
80b185f01aSAndrzej Pietrasiewicz struct list_head tx_reqs_active; /* List of Active TX xfers */
81b185f01aSAndrzej Pietrasiewicz /* Wait until there are write buffers available to use. */
82b185f01aSAndrzej Pietrasiewicz wait_queue_head_t tx_wait;
83b185f01aSAndrzej Pietrasiewicz /* Wait until all write buffers have been sent. */
84b185f01aSAndrzej Pietrasiewicz wait_queue_head_t tx_flush_wait;
85b185f01aSAndrzej Pietrasiewicz struct usb_request *current_rx_req;
86b185f01aSAndrzej Pietrasiewicz size_t current_rx_bytes;
87b185f01aSAndrzej Pietrasiewicz u8 *current_rx_buf;
88b185f01aSAndrzej Pietrasiewicz u8 printer_status;
89b185f01aSAndrzej Pietrasiewicz u8 reset_printer;
90b185f01aSAndrzej Pietrasiewicz int minor;
91b185f01aSAndrzej Pietrasiewicz struct cdev printer_cdev;
92b185f01aSAndrzej Pietrasiewicz u8 printer_cdev_open;
93b185f01aSAndrzej Pietrasiewicz wait_queue_head_t wait;
94b185f01aSAndrzej Pietrasiewicz unsigned q_len;
9524b7ba2fSAlbert Briscoe char **pnp_string; /* We don't own memory! */
96b185f01aSAndrzej Pietrasiewicz struct usb_function function;
97b185f01aSAndrzej Pietrasiewicz };
98b185f01aSAndrzej Pietrasiewicz
func_to_printer(struct usb_function * f)99b185f01aSAndrzej Pietrasiewicz static inline struct printer_dev *func_to_printer(struct usb_function *f)
100b185f01aSAndrzej Pietrasiewicz {
101b185f01aSAndrzej Pietrasiewicz return container_of(f, struct printer_dev, function);
102b185f01aSAndrzej Pietrasiewicz }
103b185f01aSAndrzej Pietrasiewicz
104b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
105b185f01aSAndrzej Pietrasiewicz
106b185f01aSAndrzej Pietrasiewicz /*
107b185f01aSAndrzej Pietrasiewicz * DESCRIPTORS ... most are static, but strings and (full) configuration
108b185f01aSAndrzej Pietrasiewicz * descriptors are built on demand.
109b185f01aSAndrzej Pietrasiewicz */
110b185f01aSAndrzej Pietrasiewicz
111b185f01aSAndrzej Pietrasiewicz /* holds our biggest descriptor */
112b185f01aSAndrzej Pietrasiewicz #define USB_DESC_BUFSIZE 256
113b185f01aSAndrzej Pietrasiewicz #define USB_BUFSIZE 8192
114b185f01aSAndrzej Pietrasiewicz
115b185f01aSAndrzej Pietrasiewicz static struct usb_interface_descriptor intf_desc = {
116b185f01aSAndrzej Pietrasiewicz .bLength = sizeof(intf_desc),
117b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_INTERFACE,
118b185f01aSAndrzej Pietrasiewicz .bNumEndpoints = 2,
119b185f01aSAndrzej Pietrasiewicz .bInterfaceClass = USB_CLASS_PRINTER,
120b185f01aSAndrzej Pietrasiewicz .bInterfaceSubClass = 1, /* Printer Sub-Class */
121b185f01aSAndrzej Pietrasiewicz .bInterfaceProtocol = 2, /* Bi-Directional */
122b185f01aSAndrzej Pietrasiewicz .iInterface = 0
123b185f01aSAndrzej Pietrasiewicz };
124b185f01aSAndrzej Pietrasiewicz
125b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor fs_ep_in_desc = {
126b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
127b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
128b185f01aSAndrzej Pietrasiewicz .bEndpointAddress = USB_DIR_IN,
129b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK
130b185f01aSAndrzej Pietrasiewicz };
131b185f01aSAndrzej Pietrasiewicz
132b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor fs_ep_out_desc = {
133b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
134b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
135b185f01aSAndrzej Pietrasiewicz .bEndpointAddress = USB_DIR_OUT,
136b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK
137b185f01aSAndrzej Pietrasiewicz };
138b185f01aSAndrzej Pietrasiewicz
139b185f01aSAndrzej Pietrasiewicz static struct usb_descriptor_header *fs_printer_function[] = {
140b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &intf_desc,
141b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fs_ep_in_desc,
142b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fs_ep_out_desc,
143b185f01aSAndrzej Pietrasiewicz NULL
144b185f01aSAndrzej Pietrasiewicz };
145b185f01aSAndrzej Pietrasiewicz
146b185f01aSAndrzej Pietrasiewicz /*
147b185f01aSAndrzej Pietrasiewicz * usb 2.0 devices need to expose both high speed and full speed
148b185f01aSAndrzej Pietrasiewicz * descriptors, unless they only run at full speed.
149b185f01aSAndrzej Pietrasiewicz */
150b185f01aSAndrzej Pietrasiewicz
151b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor hs_ep_in_desc = {
152b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
153b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
154b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
155b185f01aSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(512)
156b185f01aSAndrzej Pietrasiewicz };
157b185f01aSAndrzej Pietrasiewicz
158b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor hs_ep_out_desc = {
159b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
160b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
161b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
162b185f01aSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(512)
163b185f01aSAndrzej Pietrasiewicz };
164b185f01aSAndrzej Pietrasiewicz
165b185f01aSAndrzej Pietrasiewicz static struct usb_descriptor_header *hs_printer_function[] = {
166b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &intf_desc,
167b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &hs_ep_in_desc,
168b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &hs_ep_out_desc,
169b185f01aSAndrzej Pietrasiewicz NULL
170b185f01aSAndrzej Pietrasiewicz };
171b185f01aSAndrzej Pietrasiewicz
172b185f01aSAndrzej Pietrasiewicz /*
173b185f01aSAndrzej Pietrasiewicz * Added endpoint descriptors for 3.0 devices
174b185f01aSAndrzej Pietrasiewicz */
175b185f01aSAndrzej Pietrasiewicz
176b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor ss_ep_in_desc = {
177b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
178b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
179b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
180b185f01aSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(1024),
181b185f01aSAndrzej Pietrasiewicz };
182b185f01aSAndrzej Pietrasiewicz
183b185f01aSAndrzej Pietrasiewicz static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = {
184b185f01aSAndrzej Pietrasiewicz .bLength = sizeof(ss_ep_in_comp_desc),
185b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
186b185f01aSAndrzej Pietrasiewicz };
187b185f01aSAndrzej Pietrasiewicz
188b185f01aSAndrzej Pietrasiewicz static struct usb_endpoint_descriptor ss_ep_out_desc = {
189b185f01aSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
190b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
191b185f01aSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
192b185f01aSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(1024),
193b185f01aSAndrzej Pietrasiewicz };
194b185f01aSAndrzej Pietrasiewicz
195b185f01aSAndrzej Pietrasiewicz static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {
196b185f01aSAndrzej Pietrasiewicz .bLength = sizeof(ss_ep_out_comp_desc),
197b185f01aSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
198b185f01aSAndrzej Pietrasiewicz };
199b185f01aSAndrzej Pietrasiewicz
200b185f01aSAndrzej Pietrasiewicz static struct usb_descriptor_header *ss_printer_function[] = {
201b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &intf_desc,
202b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &ss_ep_in_desc,
203b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &ss_ep_in_comp_desc,
204b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &ss_ep_out_desc,
205b185f01aSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &ss_ep_out_comp_desc,
206b185f01aSAndrzej Pietrasiewicz NULL
207b185f01aSAndrzej Pietrasiewicz };
208b185f01aSAndrzej Pietrasiewicz
209b185f01aSAndrzej Pietrasiewicz /* maxpacket and other transfer characteristics vary by speed. */
ep_desc(struct usb_gadget * gadget,struct usb_endpoint_descriptor * fs,struct usb_endpoint_descriptor * hs,struct usb_endpoint_descriptor * ss)210b185f01aSAndrzej Pietrasiewicz static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
211b185f01aSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *fs,
212b185f01aSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *hs,
213b185f01aSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ss)
214b185f01aSAndrzej Pietrasiewicz {
215b185f01aSAndrzej Pietrasiewicz switch (gadget->speed) {
216fd80731eSOliver Neukum case USB_SPEED_SUPER_PLUS:
217b185f01aSAndrzej Pietrasiewicz case USB_SPEED_SUPER:
218b185f01aSAndrzej Pietrasiewicz return ss;
219b185f01aSAndrzej Pietrasiewicz case USB_SPEED_HIGH:
220b185f01aSAndrzej Pietrasiewicz return hs;
221b185f01aSAndrzej Pietrasiewicz default:
222b185f01aSAndrzej Pietrasiewicz return fs;
223b185f01aSAndrzej Pietrasiewicz }
224b185f01aSAndrzej Pietrasiewicz }
225b185f01aSAndrzej Pietrasiewicz
226b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
227b185f01aSAndrzej Pietrasiewicz
printer_dev_free(struct kref * kref)228e8d5f92bSZqiang static void printer_dev_free(struct kref *kref)
229e8d5f92bSZqiang {
230e8d5f92bSZqiang struct printer_dev *dev = container_of(kref, struct printer_dev, kref);
231e8d5f92bSZqiang
232e8d5f92bSZqiang kfree(dev);
233e8d5f92bSZqiang }
234e8d5f92bSZqiang
235b185f01aSAndrzej Pietrasiewicz static struct usb_request *
printer_req_alloc(struct usb_ep * ep,unsigned len,gfp_t gfp_flags)236b185f01aSAndrzej Pietrasiewicz printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
237b185f01aSAndrzej Pietrasiewicz {
238b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
239b185f01aSAndrzej Pietrasiewicz
240b185f01aSAndrzej Pietrasiewicz req = usb_ep_alloc_request(ep, gfp_flags);
241b185f01aSAndrzej Pietrasiewicz
242b185f01aSAndrzej Pietrasiewicz if (req != NULL) {
243b185f01aSAndrzej Pietrasiewicz req->length = len;
244b185f01aSAndrzej Pietrasiewicz req->buf = kmalloc(len, gfp_flags);
245b185f01aSAndrzej Pietrasiewicz if (req->buf == NULL) {
246b185f01aSAndrzej Pietrasiewicz usb_ep_free_request(ep, req);
247b185f01aSAndrzej Pietrasiewicz return NULL;
248b185f01aSAndrzej Pietrasiewicz }
249b185f01aSAndrzej Pietrasiewicz }
250b185f01aSAndrzej Pietrasiewicz
251b185f01aSAndrzej Pietrasiewicz return req;
252b185f01aSAndrzej Pietrasiewicz }
253b185f01aSAndrzej Pietrasiewicz
254b185f01aSAndrzej Pietrasiewicz static void
printer_req_free(struct usb_ep * ep,struct usb_request * req)255b185f01aSAndrzej Pietrasiewicz printer_req_free(struct usb_ep *ep, struct usb_request *req)
256b185f01aSAndrzej Pietrasiewicz {
257b185f01aSAndrzej Pietrasiewicz if (ep != NULL && req != NULL) {
258b185f01aSAndrzej Pietrasiewicz kfree(req->buf);
259b185f01aSAndrzej Pietrasiewicz usb_ep_free_request(ep, req);
260b185f01aSAndrzej Pietrasiewicz }
261b185f01aSAndrzej Pietrasiewicz }
262b185f01aSAndrzej Pietrasiewicz
263b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
264b185f01aSAndrzej Pietrasiewicz
rx_complete(struct usb_ep * ep,struct usb_request * req)265b185f01aSAndrzej Pietrasiewicz static void rx_complete(struct usb_ep *ep, struct usb_request *req)
266b185f01aSAndrzej Pietrasiewicz {
267b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = ep->driver_data;
268b185f01aSAndrzej Pietrasiewicz int status = req->status;
269b185f01aSAndrzej Pietrasiewicz unsigned long flags;
270b185f01aSAndrzej Pietrasiewicz
271b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
272b185f01aSAndrzej Pietrasiewicz
273b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list); /* Remode from Active List */
274b185f01aSAndrzej Pietrasiewicz
275b185f01aSAndrzej Pietrasiewicz switch (status) {
276b185f01aSAndrzej Pietrasiewicz
277b185f01aSAndrzej Pietrasiewicz /* normal completion */
278b185f01aSAndrzej Pietrasiewicz case 0:
279b185f01aSAndrzej Pietrasiewicz if (req->actual > 0) {
280b185f01aSAndrzej Pietrasiewicz list_add_tail(&req->list, &dev->rx_buffers);
281b185f01aSAndrzej Pietrasiewicz DBG(dev, "G_Printer : rx length %d\n", req->actual);
282b185f01aSAndrzej Pietrasiewicz } else {
283b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
284b185f01aSAndrzej Pietrasiewicz }
285b185f01aSAndrzej Pietrasiewicz break;
286b185f01aSAndrzej Pietrasiewicz
287b185f01aSAndrzej Pietrasiewicz /* software-driven interface shutdown */
288b185f01aSAndrzej Pietrasiewicz case -ECONNRESET: /* unlink */
289b185f01aSAndrzej Pietrasiewicz case -ESHUTDOWN: /* disconnect etc */
290b185f01aSAndrzej Pietrasiewicz VDBG(dev, "rx shutdown, code %d\n", status);
291b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
292b185f01aSAndrzej Pietrasiewicz break;
293b185f01aSAndrzej Pietrasiewicz
294b185f01aSAndrzej Pietrasiewicz /* for hardware automagic (such as pxa) */
295b185f01aSAndrzej Pietrasiewicz case -ECONNABORTED: /* endpoint reset */
296b185f01aSAndrzej Pietrasiewicz DBG(dev, "rx %s reset\n", ep->name);
297b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
298b185f01aSAndrzej Pietrasiewicz break;
299b185f01aSAndrzej Pietrasiewicz
300b185f01aSAndrzej Pietrasiewicz /* data overrun */
301b185f01aSAndrzej Pietrasiewicz case -EOVERFLOW:
302a74005abSGustavo A. R. Silva fallthrough;
303b185f01aSAndrzej Pietrasiewicz
304b185f01aSAndrzej Pietrasiewicz default:
305b185f01aSAndrzej Pietrasiewicz DBG(dev, "rx status %d\n", status);
306b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
307b185f01aSAndrzej Pietrasiewicz break;
308b185f01aSAndrzej Pietrasiewicz }
309b185f01aSAndrzej Pietrasiewicz
310b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->rx_wait);
311b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
312b185f01aSAndrzej Pietrasiewicz }
313b185f01aSAndrzej Pietrasiewicz
tx_complete(struct usb_ep * ep,struct usb_request * req)314b185f01aSAndrzej Pietrasiewicz static void tx_complete(struct usb_ep *ep, struct usb_request *req)
315b185f01aSAndrzej Pietrasiewicz {
316b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = ep->driver_data;
317b185f01aSAndrzej Pietrasiewicz
318b185f01aSAndrzej Pietrasiewicz switch (req->status) {
319b185f01aSAndrzej Pietrasiewicz default:
320b185f01aSAndrzej Pietrasiewicz VDBG(dev, "tx err %d\n", req->status);
321a74005abSGustavo A. R. Silva fallthrough;
322b185f01aSAndrzej Pietrasiewicz case -ECONNRESET: /* unlink */
323b185f01aSAndrzej Pietrasiewicz case -ESHUTDOWN: /* disconnect etc */
324b185f01aSAndrzej Pietrasiewicz break;
325b185f01aSAndrzej Pietrasiewicz case 0:
326b185f01aSAndrzej Pietrasiewicz break;
327b185f01aSAndrzej Pietrasiewicz }
328b185f01aSAndrzej Pietrasiewicz
329b185f01aSAndrzej Pietrasiewicz spin_lock(&dev->lock);
330b185f01aSAndrzej Pietrasiewicz /* Take the request struct off the active list and put it on the
331b185f01aSAndrzej Pietrasiewicz * free list.
332b185f01aSAndrzej Pietrasiewicz */
333b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
334b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->tx_reqs);
335b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->tx_wait);
336b185f01aSAndrzej Pietrasiewicz if (likely(list_empty(&dev->tx_reqs_active)))
337b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->tx_flush_wait);
338b185f01aSAndrzej Pietrasiewicz
339b185f01aSAndrzej Pietrasiewicz spin_unlock(&dev->lock);
340b185f01aSAndrzej Pietrasiewicz }
341b185f01aSAndrzej Pietrasiewicz
342b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
343b185f01aSAndrzej Pietrasiewicz
344b185f01aSAndrzej Pietrasiewicz static int
printer_open(struct inode * inode,struct file * fd)345b185f01aSAndrzej Pietrasiewicz printer_open(struct inode *inode, struct file *fd)
346b185f01aSAndrzej Pietrasiewicz {
347b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev;
348b185f01aSAndrzej Pietrasiewicz unsigned long flags;
349b185f01aSAndrzej Pietrasiewicz int ret = -EBUSY;
350b185f01aSAndrzej Pietrasiewicz
351b185f01aSAndrzej Pietrasiewicz dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
352b185f01aSAndrzej Pietrasiewicz
353b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
354b185f01aSAndrzej Pietrasiewicz
3557f2ca14dSZqiang if (dev->interface < 0) {
3567f2ca14dSZqiang spin_unlock_irqrestore(&dev->lock, flags);
3577f2ca14dSZqiang return -ENODEV;
3587f2ca14dSZqiang }
3597f2ca14dSZqiang
360b185f01aSAndrzej Pietrasiewicz if (!dev->printer_cdev_open) {
361b185f01aSAndrzej Pietrasiewicz dev->printer_cdev_open = 1;
362b185f01aSAndrzej Pietrasiewicz fd->private_data = dev;
363b185f01aSAndrzej Pietrasiewicz ret = 0;
364b185f01aSAndrzej Pietrasiewicz /* Change the printer status to show that it's on-line. */
365b185f01aSAndrzej Pietrasiewicz dev->printer_status |= PRINTER_SELECTED;
366b185f01aSAndrzej Pietrasiewicz }
367b185f01aSAndrzej Pietrasiewicz
368b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
369b185f01aSAndrzej Pietrasiewicz
370e8d5f92bSZqiang kref_get(&dev->kref);
37157b7b733SAndrzej Pietrasiewicz
372b185f01aSAndrzej Pietrasiewicz return ret;
373b185f01aSAndrzej Pietrasiewicz }
374b185f01aSAndrzej Pietrasiewicz
375b185f01aSAndrzej Pietrasiewicz static int
printer_close(struct inode * inode,struct file * fd)376b185f01aSAndrzej Pietrasiewicz printer_close(struct inode *inode, struct file *fd)
377b185f01aSAndrzej Pietrasiewicz {
378b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
379b185f01aSAndrzej Pietrasiewicz unsigned long flags;
380b185f01aSAndrzej Pietrasiewicz
381b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
382b185f01aSAndrzej Pietrasiewicz dev->printer_cdev_open = 0;
383b185f01aSAndrzej Pietrasiewicz fd->private_data = NULL;
384b185f01aSAndrzej Pietrasiewicz /* Change printer status to show that the printer is off-line. */
385b185f01aSAndrzej Pietrasiewicz dev->printer_status &= ~PRINTER_SELECTED;
386b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
387b185f01aSAndrzej Pietrasiewicz
388e8d5f92bSZqiang kref_put(&dev->kref, printer_dev_free);
389b185f01aSAndrzej Pietrasiewicz
390b185f01aSAndrzej Pietrasiewicz return 0;
391b185f01aSAndrzej Pietrasiewicz }
392b185f01aSAndrzej Pietrasiewicz
393b185f01aSAndrzej Pietrasiewicz /* This function must be called with interrupts turned off. */
394b185f01aSAndrzej Pietrasiewicz static void
setup_rx_reqs(struct printer_dev * dev)395b185f01aSAndrzej Pietrasiewicz setup_rx_reqs(struct printer_dev *dev)
396b185f01aSAndrzej Pietrasiewicz {
397b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
398b185f01aSAndrzej Pietrasiewicz
399b185f01aSAndrzej Pietrasiewicz while (likely(!list_empty(&dev->rx_reqs))) {
400b185f01aSAndrzej Pietrasiewicz int error;
401b185f01aSAndrzej Pietrasiewicz
402b185f01aSAndrzej Pietrasiewicz req = container_of(dev->rx_reqs.next,
403b185f01aSAndrzej Pietrasiewicz struct usb_request, list);
404b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
405b185f01aSAndrzej Pietrasiewicz
406b185f01aSAndrzej Pietrasiewicz /* The USB Host sends us whatever amount of data it wants to
407b185f01aSAndrzej Pietrasiewicz * so we always set the length field to the full USB_BUFSIZE.
408b185f01aSAndrzej Pietrasiewicz * If the amount of data is more than the read() caller asked
409b185f01aSAndrzej Pietrasiewicz * for it will be stored in the request buffer until it is
410b185f01aSAndrzej Pietrasiewicz * asked for by read().
411b185f01aSAndrzej Pietrasiewicz */
412b185f01aSAndrzej Pietrasiewicz req->length = USB_BUFSIZE;
413b185f01aSAndrzej Pietrasiewicz req->complete = rx_complete;
414b185f01aSAndrzej Pietrasiewicz
415b185f01aSAndrzej Pietrasiewicz /* here, we unlock, and only unlock, to avoid deadlock. */
416b185f01aSAndrzej Pietrasiewicz spin_unlock(&dev->lock);
417b185f01aSAndrzej Pietrasiewicz error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
418b185f01aSAndrzej Pietrasiewicz spin_lock(&dev->lock);
419b185f01aSAndrzej Pietrasiewicz if (error) {
420b185f01aSAndrzej Pietrasiewicz DBG(dev, "rx submit --> %d\n", error);
421b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
422b185f01aSAndrzej Pietrasiewicz break;
423b185f01aSAndrzej Pietrasiewicz }
424b185f01aSAndrzej Pietrasiewicz /* if the req is empty, then add it into dev->rx_reqs_active. */
425b185f01aSAndrzej Pietrasiewicz else if (list_empty(&req->list))
426b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs_active);
427b185f01aSAndrzej Pietrasiewicz }
428b185f01aSAndrzej Pietrasiewicz }
429b185f01aSAndrzej Pietrasiewicz
430b185f01aSAndrzej Pietrasiewicz static ssize_t
printer_read(struct file * fd,char __user * buf,size_t len,loff_t * ptr)431b185f01aSAndrzej Pietrasiewicz printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
432b185f01aSAndrzej Pietrasiewicz {
433b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
434b185f01aSAndrzej Pietrasiewicz unsigned long flags;
435b185f01aSAndrzej Pietrasiewicz size_t size;
436b185f01aSAndrzej Pietrasiewicz size_t bytes_copied;
437b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
438b185f01aSAndrzej Pietrasiewicz /* This is a pointer to the current USB rx request. */
439b185f01aSAndrzej Pietrasiewicz struct usb_request *current_rx_req;
440b185f01aSAndrzej Pietrasiewicz /* This is the number of bytes in the current rx buffer. */
441b185f01aSAndrzej Pietrasiewicz size_t current_rx_bytes;
442b185f01aSAndrzej Pietrasiewicz /* This is a pointer to the current rx buffer. */
443b185f01aSAndrzej Pietrasiewicz u8 *current_rx_buf;
444b185f01aSAndrzej Pietrasiewicz
445b185f01aSAndrzej Pietrasiewicz if (len == 0)
446b185f01aSAndrzej Pietrasiewicz return -EINVAL;
447b185f01aSAndrzej Pietrasiewicz
448b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
449b185f01aSAndrzej Pietrasiewicz
450b185f01aSAndrzej Pietrasiewicz mutex_lock(&dev->lock_printer_io);
451b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
452b185f01aSAndrzej Pietrasiewicz
453e587a763SOliver Neukum if (dev->interface < 0)
454e587a763SOliver Neukum goto out_disabled;
4557f2ca14dSZqiang
456b185f01aSAndrzej Pietrasiewicz /* We will use this flag later to check if a printer reset happened
457b185f01aSAndrzej Pietrasiewicz * after we turn interrupts back on.
458b185f01aSAndrzej Pietrasiewicz */
459b185f01aSAndrzej Pietrasiewicz dev->reset_printer = 0;
460b185f01aSAndrzej Pietrasiewicz
461b185f01aSAndrzej Pietrasiewicz setup_rx_reqs(dev);
462e587a763SOliver Neukum /* this dropped the lock - need to retest */
463e587a763SOliver Neukum if (dev->interface < 0)
464e587a763SOliver Neukum goto out_disabled;
465b185f01aSAndrzej Pietrasiewicz
466b185f01aSAndrzej Pietrasiewicz bytes_copied = 0;
467b185f01aSAndrzej Pietrasiewicz current_rx_req = dev->current_rx_req;
468b185f01aSAndrzej Pietrasiewicz current_rx_bytes = dev->current_rx_bytes;
469b185f01aSAndrzej Pietrasiewicz current_rx_buf = dev->current_rx_buf;
470b185f01aSAndrzej Pietrasiewicz dev->current_rx_req = NULL;
471b185f01aSAndrzej Pietrasiewicz dev->current_rx_bytes = 0;
472b185f01aSAndrzej Pietrasiewicz dev->current_rx_buf = NULL;
473b185f01aSAndrzej Pietrasiewicz
474b185f01aSAndrzej Pietrasiewicz /* Check if there is any data in the read buffers. Please note that
475b185f01aSAndrzej Pietrasiewicz * current_rx_bytes is the number of bytes in the current rx buffer.
476b185f01aSAndrzej Pietrasiewicz * If it is zero then check if there are any other rx_buffers that
477b185f01aSAndrzej Pietrasiewicz * are on the completed list. We are only out of data if all rx
478b185f01aSAndrzej Pietrasiewicz * buffers are empty.
479b185f01aSAndrzej Pietrasiewicz */
480b185f01aSAndrzej Pietrasiewicz if ((current_rx_bytes == 0) &&
481b185f01aSAndrzej Pietrasiewicz (likely(list_empty(&dev->rx_buffers)))) {
482b185f01aSAndrzej Pietrasiewicz /* Turn interrupts back on before sleeping. */
483b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
484b185f01aSAndrzej Pietrasiewicz
485b185f01aSAndrzej Pietrasiewicz /*
486b185f01aSAndrzej Pietrasiewicz * If no data is available check if this is a NON-Blocking
487b185f01aSAndrzej Pietrasiewicz * call or not.
488b185f01aSAndrzej Pietrasiewicz */
489b185f01aSAndrzej Pietrasiewicz if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
490b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
491b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
492b185f01aSAndrzej Pietrasiewicz }
493b185f01aSAndrzej Pietrasiewicz
494b185f01aSAndrzej Pietrasiewicz /* Sleep until data is available */
495b185f01aSAndrzej Pietrasiewicz wait_event_interruptible(dev->rx_wait,
496b185f01aSAndrzej Pietrasiewicz (likely(!list_empty(&dev->rx_buffers))));
497b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
498e587a763SOliver Neukum if (dev->interface < 0)
499e587a763SOliver Neukum goto out_disabled;
500b185f01aSAndrzej Pietrasiewicz }
501b185f01aSAndrzej Pietrasiewicz
502b185f01aSAndrzej Pietrasiewicz /* We have data to return then copy it to the caller's buffer.*/
503b185f01aSAndrzej Pietrasiewicz while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
504b185f01aSAndrzej Pietrasiewicz && len) {
505b185f01aSAndrzej Pietrasiewicz if (current_rx_bytes == 0) {
506b185f01aSAndrzej Pietrasiewicz req = container_of(dev->rx_buffers.next,
507b185f01aSAndrzej Pietrasiewicz struct usb_request, list);
508b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
509b185f01aSAndrzej Pietrasiewicz
510b185f01aSAndrzej Pietrasiewicz if (req->actual && req->buf) {
511b185f01aSAndrzej Pietrasiewicz current_rx_req = req;
512b185f01aSAndrzej Pietrasiewicz current_rx_bytes = req->actual;
513b185f01aSAndrzej Pietrasiewicz current_rx_buf = req->buf;
514b185f01aSAndrzej Pietrasiewicz } else {
515b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
516b185f01aSAndrzej Pietrasiewicz continue;
517b185f01aSAndrzej Pietrasiewicz }
518b185f01aSAndrzej Pietrasiewicz }
519b185f01aSAndrzej Pietrasiewicz
520b185f01aSAndrzej Pietrasiewicz /* Don't leave irqs off while doing memory copies */
521b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
522b185f01aSAndrzej Pietrasiewicz
523b185f01aSAndrzej Pietrasiewicz if (len > current_rx_bytes)
524b185f01aSAndrzej Pietrasiewicz size = current_rx_bytes;
525b185f01aSAndrzej Pietrasiewicz else
526b185f01aSAndrzej Pietrasiewicz size = len;
527b185f01aSAndrzej Pietrasiewicz
528b185f01aSAndrzej Pietrasiewicz size -= copy_to_user(buf, current_rx_buf, size);
529b185f01aSAndrzej Pietrasiewicz bytes_copied += size;
530b185f01aSAndrzej Pietrasiewicz len -= size;
531b185f01aSAndrzej Pietrasiewicz buf += size;
532b185f01aSAndrzej Pietrasiewicz
533b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
534b185f01aSAndrzej Pietrasiewicz
535b185f01aSAndrzej Pietrasiewicz /* We've disconnected or reset so return. */
536b185f01aSAndrzej Pietrasiewicz if (dev->reset_printer) {
537b185f01aSAndrzej Pietrasiewicz list_add(¤t_rx_req->list, &dev->rx_reqs);
538b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
539b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
540b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
541b185f01aSAndrzej Pietrasiewicz }
542b185f01aSAndrzej Pietrasiewicz
543e587a763SOliver Neukum if (dev->interface < 0)
544e587a763SOliver Neukum goto out_disabled;
545e587a763SOliver Neukum
546b185f01aSAndrzej Pietrasiewicz /* If we not returning all the data left in this RX request
547b185f01aSAndrzej Pietrasiewicz * buffer then adjust the amount of data left in the buffer.
548b185f01aSAndrzej Pietrasiewicz * Othewise if we are done with this RX request buffer then
549b185f01aSAndrzej Pietrasiewicz * requeue it to get any incoming data from the USB host.
550b185f01aSAndrzej Pietrasiewicz */
551b185f01aSAndrzej Pietrasiewicz if (size < current_rx_bytes) {
552b185f01aSAndrzej Pietrasiewicz current_rx_bytes -= size;
553b185f01aSAndrzej Pietrasiewicz current_rx_buf += size;
554b185f01aSAndrzej Pietrasiewicz } else {
555b185f01aSAndrzej Pietrasiewicz list_add(¤t_rx_req->list, &dev->rx_reqs);
556b185f01aSAndrzej Pietrasiewicz current_rx_bytes = 0;
557b185f01aSAndrzej Pietrasiewicz current_rx_buf = NULL;
558b185f01aSAndrzej Pietrasiewicz current_rx_req = NULL;
559b185f01aSAndrzej Pietrasiewicz }
560b185f01aSAndrzej Pietrasiewicz }
561b185f01aSAndrzej Pietrasiewicz
562b185f01aSAndrzej Pietrasiewicz dev->current_rx_req = current_rx_req;
563b185f01aSAndrzej Pietrasiewicz dev->current_rx_bytes = current_rx_bytes;
564b185f01aSAndrzej Pietrasiewicz dev->current_rx_buf = current_rx_buf;
565b185f01aSAndrzej Pietrasiewicz
566b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
567b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
568b185f01aSAndrzej Pietrasiewicz
569b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
570b185f01aSAndrzej Pietrasiewicz
571b185f01aSAndrzej Pietrasiewicz if (bytes_copied)
572b185f01aSAndrzej Pietrasiewicz return bytes_copied;
573b185f01aSAndrzej Pietrasiewicz else
574b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
575e587a763SOliver Neukum
576e587a763SOliver Neukum out_disabled:
577e587a763SOliver Neukum spin_unlock_irqrestore(&dev->lock, flags);
578e587a763SOliver Neukum mutex_unlock(&dev->lock_printer_io);
579e587a763SOliver Neukum return -ENODEV;
580b185f01aSAndrzej Pietrasiewicz }
581b185f01aSAndrzej Pietrasiewicz
582b185f01aSAndrzej Pietrasiewicz static ssize_t
printer_write(struct file * fd,const char __user * buf,size_t len,loff_t * ptr)583b185f01aSAndrzej Pietrasiewicz printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
584b185f01aSAndrzej Pietrasiewicz {
585b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
586b185f01aSAndrzej Pietrasiewicz unsigned long flags;
587b185f01aSAndrzej Pietrasiewicz size_t size; /* Amount of data in a TX request. */
588b185f01aSAndrzej Pietrasiewicz size_t bytes_copied = 0;
589b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
5909ada8c58SYoshihiro Shimoda int value;
591b185f01aSAndrzej Pietrasiewicz
592b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
593b185f01aSAndrzej Pietrasiewicz
594b185f01aSAndrzej Pietrasiewicz if (len == 0)
595b185f01aSAndrzej Pietrasiewicz return -EINVAL;
596b185f01aSAndrzej Pietrasiewicz
597b185f01aSAndrzej Pietrasiewicz mutex_lock(&dev->lock_printer_io);
598b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
599b185f01aSAndrzej Pietrasiewicz
600e587a763SOliver Neukum if (dev->interface < 0)
601e587a763SOliver Neukum goto out_disabled;
6027f2ca14dSZqiang
603b185f01aSAndrzej Pietrasiewicz /* Check if a printer reset happens while we have interrupts on */
604b185f01aSAndrzej Pietrasiewicz dev->reset_printer = 0;
605b185f01aSAndrzej Pietrasiewicz
606b185f01aSAndrzej Pietrasiewicz /* Check if there is any available write buffers */
607b185f01aSAndrzej Pietrasiewicz if (likely(list_empty(&dev->tx_reqs))) {
608b185f01aSAndrzej Pietrasiewicz /* Turn interrupts back on before sleeping. */
609b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
610b185f01aSAndrzej Pietrasiewicz
611b185f01aSAndrzej Pietrasiewicz /*
612b185f01aSAndrzej Pietrasiewicz * If write buffers are available check if this is
613b185f01aSAndrzej Pietrasiewicz * a NON-Blocking call or not.
614b185f01aSAndrzej Pietrasiewicz */
615b185f01aSAndrzej Pietrasiewicz if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
616b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
617b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
618b185f01aSAndrzej Pietrasiewicz }
619b185f01aSAndrzej Pietrasiewicz
620b185f01aSAndrzej Pietrasiewicz /* Sleep until a write buffer is available */
621b185f01aSAndrzej Pietrasiewicz wait_event_interruptible(dev->tx_wait,
622b185f01aSAndrzej Pietrasiewicz (likely(!list_empty(&dev->tx_reqs))));
623b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
624e587a763SOliver Neukum if (dev->interface < 0)
625e587a763SOliver Neukum goto out_disabled;
626b185f01aSAndrzej Pietrasiewicz }
627b185f01aSAndrzej Pietrasiewicz
628b185f01aSAndrzej Pietrasiewicz while (likely(!list_empty(&dev->tx_reqs)) && len) {
629b185f01aSAndrzej Pietrasiewicz
630b185f01aSAndrzej Pietrasiewicz if (len > USB_BUFSIZE)
631b185f01aSAndrzej Pietrasiewicz size = USB_BUFSIZE;
632b185f01aSAndrzej Pietrasiewicz else
633b185f01aSAndrzej Pietrasiewicz size = len;
634b185f01aSAndrzej Pietrasiewicz
635b185f01aSAndrzej Pietrasiewicz req = container_of(dev->tx_reqs.next, struct usb_request,
636b185f01aSAndrzej Pietrasiewicz list);
637b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
638b185f01aSAndrzej Pietrasiewicz
639b185f01aSAndrzej Pietrasiewicz req->complete = tx_complete;
640b185f01aSAndrzej Pietrasiewicz req->length = size;
641b185f01aSAndrzej Pietrasiewicz
642b185f01aSAndrzej Pietrasiewicz /* Check if we need to send a zero length packet. */
643b185f01aSAndrzej Pietrasiewicz if (len > size)
644b185f01aSAndrzej Pietrasiewicz /* They will be more TX requests so no yet. */
645b185f01aSAndrzej Pietrasiewicz req->zero = 0;
646b185f01aSAndrzej Pietrasiewicz else
647b185f01aSAndrzej Pietrasiewicz /* If the data amount is not a multiple of the
648b185f01aSAndrzej Pietrasiewicz * maxpacket size then send a zero length packet.
649b185f01aSAndrzej Pietrasiewicz */
650b185f01aSAndrzej Pietrasiewicz req->zero = ((len % dev->in_ep->maxpacket) == 0);
651b185f01aSAndrzej Pietrasiewicz
652b185f01aSAndrzej Pietrasiewicz /* Don't leave irqs off while doing memory copies */
653b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
654b185f01aSAndrzej Pietrasiewicz
655b185f01aSAndrzej Pietrasiewicz if (copy_from_user(req->buf, buf, size)) {
656b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->tx_reqs);
657b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
658b185f01aSAndrzej Pietrasiewicz return bytes_copied;
659b185f01aSAndrzej Pietrasiewicz }
660b185f01aSAndrzej Pietrasiewicz
661b185f01aSAndrzej Pietrasiewicz bytes_copied += size;
662b185f01aSAndrzej Pietrasiewicz len -= size;
663b185f01aSAndrzej Pietrasiewicz buf += size;
664b185f01aSAndrzej Pietrasiewicz
665b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
666b185f01aSAndrzej Pietrasiewicz
667b185f01aSAndrzej Pietrasiewicz /* We've disconnected or reset so free the req and buffer */
668b185f01aSAndrzej Pietrasiewicz if (dev->reset_printer) {
669b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->tx_reqs);
670b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
671b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
672b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
673b185f01aSAndrzej Pietrasiewicz }
674b185f01aSAndrzej Pietrasiewicz
675e587a763SOliver Neukum if (dev->interface < 0)
676e587a763SOliver Neukum goto out_disabled;
677e587a763SOliver Neukum
6784a014a73SYoshihiro Shimoda list_add(&req->list, &dev->tx_reqs_active);
6794a014a73SYoshihiro Shimoda
6809ada8c58SYoshihiro Shimoda /* here, we unlock, and only unlock, to avoid deadlock. */
6819ada8c58SYoshihiro Shimoda spin_unlock(&dev->lock);
6829ada8c58SYoshihiro Shimoda value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
6839ada8c58SYoshihiro Shimoda spin_lock(&dev->lock);
6849ada8c58SYoshihiro Shimoda if (value) {
685307462a6SBaokun Li list_move(&req->list, &dev->tx_reqs);
686b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
687b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
688b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
689b185f01aSAndrzej Pietrasiewicz }
690e587a763SOliver Neukum if (dev->interface < 0)
691e587a763SOliver Neukum goto out_disabled;
692b185f01aSAndrzej Pietrasiewicz }
693b185f01aSAndrzej Pietrasiewicz
694b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
695b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
696b185f01aSAndrzej Pietrasiewicz
697b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
698b185f01aSAndrzej Pietrasiewicz
699b185f01aSAndrzej Pietrasiewicz if (bytes_copied)
700b185f01aSAndrzej Pietrasiewicz return bytes_copied;
701b185f01aSAndrzej Pietrasiewicz else
702b185f01aSAndrzej Pietrasiewicz return -EAGAIN;
703e587a763SOliver Neukum
704e587a763SOliver Neukum out_disabled:
705e587a763SOliver Neukum spin_unlock_irqrestore(&dev->lock, flags);
706e587a763SOliver Neukum mutex_unlock(&dev->lock_printer_io);
707e587a763SOliver Neukum return -ENODEV;
708b185f01aSAndrzej Pietrasiewicz }
709b185f01aSAndrzej Pietrasiewicz
710b185f01aSAndrzej Pietrasiewicz static int
printer_fsync(struct file * fd,loff_t start,loff_t end,int datasync)711b185f01aSAndrzej Pietrasiewicz printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
712b185f01aSAndrzej Pietrasiewicz {
713b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
714b185f01aSAndrzej Pietrasiewicz struct inode *inode = file_inode(fd);
715b185f01aSAndrzej Pietrasiewicz unsigned long flags;
716b185f01aSAndrzej Pietrasiewicz int tx_list_empty;
717b185f01aSAndrzej Pietrasiewicz
7185955102cSAl Viro inode_lock(inode);
719b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
7207f2ca14dSZqiang
7217f2ca14dSZqiang if (dev->interface < 0) {
7227f2ca14dSZqiang spin_unlock_irqrestore(&dev->lock, flags);
7237f2ca14dSZqiang inode_unlock(inode);
7247f2ca14dSZqiang return -ENODEV;
7257f2ca14dSZqiang }
7267f2ca14dSZqiang
727b185f01aSAndrzej Pietrasiewicz tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
728b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
729b185f01aSAndrzej Pietrasiewicz
730b185f01aSAndrzej Pietrasiewicz if (!tx_list_empty) {
731b185f01aSAndrzej Pietrasiewicz /* Sleep until all data has been sent */
732b185f01aSAndrzej Pietrasiewicz wait_event_interruptible(dev->tx_flush_wait,
733b185f01aSAndrzej Pietrasiewicz (likely(list_empty(&dev->tx_reqs_active))));
734b185f01aSAndrzej Pietrasiewicz }
7355955102cSAl Viro inode_unlock(inode);
736b185f01aSAndrzej Pietrasiewicz
737b185f01aSAndrzej Pietrasiewicz return 0;
738b185f01aSAndrzej Pietrasiewicz }
739b185f01aSAndrzej Pietrasiewicz
740afc9a42bSAl Viro static __poll_t
printer_poll(struct file * fd,poll_table * wait)741b185f01aSAndrzej Pietrasiewicz printer_poll(struct file *fd, poll_table *wait)
742b185f01aSAndrzej Pietrasiewicz {
743b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
744b185f01aSAndrzej Pietrasiewicz unsigned long flags;
745afc9a42bSAl Viro __poll_t status = 0;
746b185f01aSAndrzej Pietrasiewicz
747b185f01aSAndrzej Pietrasiewicz mutex_lock(&dev->lock_printer_io);
748b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
7497f2ca14dSZqiang
7507f2ca14dSZqiang if (dev->interface < 0) {
7517f2ca14dSZqiang spin_unlock_irqrestore(&dev->lock, flags);
7527f2ca14dSZqiang mutex_unlock(&dev->lock_printer_io);
7537f2ca14dSZqiang return EPOLLERR | EPOLLHUP;
7547f2ca14dSZqiang }
7557f2ca14dSZqiang
756b185f01aSAndrzej Pietrasiewicz setup_rx_reqs(dev);
757b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
758b185f01aSAndrzej Pietrasiewicz mutex_unlock(&dev->lock_printer_io);
759b185f01aSAndrzej Pietrasiewicz
760b185f01aSAndrzej Pietrasiewicz poll_wait(fd, &dev->rx_wait, wait);
761b185f01aSAndrzej Pietrasiewicz poll_wait(fd, &dev->tx_wait, wait);
762b185f01aSAndrzej Pietrasiewicz
763b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
764b185f01aSAndrzej Pietrasiewicz if (likely(!list_empty(&dev->tx_reqs)))
765a9a08845SLinus Torvalds status |= EPOLLOUT | EPOLLWRNORM;
766b185f01aSAndrzej Pietrasiewicz
767b185f01aSAndrzej Pietrasiewicz if (likely(dev->current_rx_bytes) ||
768b185f01aSAndrzej Pietrasiewicz likely(!list_empty(&dev->rx_buffers)))
769a9a08845SLinus Torvalds status |= EPOLLIN | EPOLLRDNORM;
770b185f01aSAndrzej Pietrasiewicz
771b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
772b185f01aSAndrzej Pietrasiewicz
773b185f01aSAndrzej Pietrasiewicz return status;
774b185f01aSAndrzej Pietrasiewicz }
775b185f01aSAndrzej Pietrasiewicz
776b185f01aSAndrzej Pietrasiewicz static long
printer_ioctl(struct file * fd,unsigned int code,unsigned long arg)777b185f01aSAndrzej Pietrasiewicz printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
778b185f01aSAndrzej Pietrasiewicz {
779b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = fd->private_data;
780b185f01aSAndrzej Pietrasiewicz unsigned long flags;
781b185f01aSAndrzej Pietrasiewicz int status = 0;
782b185f01aSAndrzej Pietrasiewicz
783b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
784b185f01aSAndrzej Pietrasiewicz
785b185f01aSAndrzej Pietrasiewicz /* handle ioctls */
786b185f01aSAndrzej Pietrasiewicz
787b185f01aSAndrzej Pietrasiewicz spin_lock_irqsave(&dev->lock, flags);
788b185f01aSAndrzej Pietrasiewicz
7897f2ca14dSZqiang if (dev->interface < 0) {
7907f2ca14dSZqiang spin_unlock_irqrestore(&dev->lock, flags);
7917f2ca14dSZqiang return -ENODEV;
7927f2ca14dSZqiang }
7937f2ca14dSZqiang
794b185f01aSAndrzej Pietrasiewicz switch (code) {
795b185f01aSAndrzej Pietrasiewicz case GADGET_GET_PRINTER_STATUS:
796b185f01aSAndrzej Pietrasiewicz status = (int)dev->printer_status;
797b185f01aSAndrzej Pietrasiewicz break;
798b185f01aSAndrzej Pietrasiewicz case GADGET_SET_PRINTER_STATUS:
799b185f01aSAndrzej Pietrasiewicz dev->printer_status = (u8)arg;
800b185f01aSAndrzej Pietrasiewicz break;
801b185f01aSAndrzej Pietrasiewicz default:
802b185f01aSAndrzej Pietrasiewicz /* could not handle ioctl */
803b185f01aSAndrzej Pietrasiewicz DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
804b185f01aSAndrzej Pietrasiewicz code);
805b185f01aSAndrzej Pietrasiewicz status = -ENOTTY;
806b185f01aSAndrzej Pietrasiewicz }
807b185f01aSAndrzej Pietrasiewicz
808b185f01aSAndrzej Pietrasiewicz spin_unlock_irqrestore(&dev->lock, flags);
809b185f01aSAndrzej Pietrasiewicz
810b185f01aSAndrzej Pietrasiewicz return status;
811b185f01aSAndrzej Pietrasiewicz }
812b185f01aSAndrzej Pietrasiewicz
813b185f01aSAndrzej Pietrasiewicz /* used after endpoint configuration */
814b185f01aSAndrzej Pietrasiewicz static const struct file_operations printer_io_operations = {
815b185f01aSAndrzej Pietrasiewicz .owner = THIS_MODULE,
816b185f01aSAndrzej Pietrasiewicz .open = printer_open,
817b185f01aSAndrzej Pietrasiewicz .read = printer_read,
818b185f01aSAndrzej Pietrasiewicz .write = printer_write,
819b185f01aSAndrzej Pietrasiewicz .fsync = printer_fsync,
820b185f01aSAndrzej Pietrasiewicz .poll = printer_poll,
821b185f01aSAndrzej Pietrasiewicz .unlocked_ioctl = printer_ioctl,
822b185f01aSAndrzej Pietrasiewicz .release = printer_close,
823b185f01aSAndrzej Pietrasiewicz .llseek = noop_llseek,
824b185f01aSAndrzej Pietrasiewicz };
825b185f01aSAndrzej Pietrasiewicz
826b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
827b185f01aSAndrzej Pietrasiewicz
828b185f01aSAndrzej Pietrasiewicz static int
set_printer_interface(struct printer_dev * dev)829b185f01aSAndrzej Pietrasiewicz set_printer_interface(struct printer_dev *dev)
830b185f01aSAndrzej Pietrasiewicz {
831b185f01aSAndrzej Pietrasiewicz int result = 0;
832b185f01aSAndrzej Pietrasiewicz
833b185f01aSAndrzej Pietrasiewicz dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc,
834b185f01aSAndrzej Pietrasiewicz &ss_ep_in_desc);
835b185f01aSAndrzej Pietrasiewicz dev->in_ep->driver_data = dev;
836b185f01aSAndrzej Pietrasiewicz
837b185f01aSAndrzej Pietrasiewicz dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc,
838b185f01aSAndrzej Pietrasiewicz &hs_ep_out_desc, &ss_ep_out_desc);
839b185f01aSAndrzej Pietrasiewicz dev->out_ep->driver_data = dev;
840b185f01aSAndrzej Pietrasiewicz
841b185f01aSAndrzej Pietrasiewicz result = usb_ep_enable(dev->in_ep);
842b185f01aSAndrzej Pietrasiewicz if (result != 0) {
843b185f01aSAndrzej Pietrasiewicz DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
844b185f01aSAndrzej Pietrasiewicz goto done;
845b185f01aSAndrzej Pietrasiewicz }
846b185f01aSAndrzej Pietrasiewicz
847b185f01aSAndrzej Pietrasiewicz result = usb_ep_enable(dev->out_ep);
848b185f01aSAndrzej Pietrasiewicz if (result != 0) {
849e21a2e0aSWei Ming Chen DBG(dev, "enable %s --> %d\n", dev->out_ep->name, result);
850b185f01aSAndrzej Pietrasiewicz goto done;
851b185f01aSAndrzej Pietrasiewicz }
852b185f01aSAndrzej Pietrasiewicz
853b185f01aSAndrzej Pietrasiewicz done:
854b185f01aSAndrzej Pietrasiewicz /* on error, disable any endpoints */
855b185f01aSAndrzej Pietrasiewicz if (result != 0) {
856b185f01aSAndrzej Pietrasiewicz (void) usb_ep_disable(dev->in_ep);
857b185f01aSAndrzej Pietrasiewicz (void) usb_ep_disable(dev->out_ep);
858b185f01aSAndrzej Pietrasiewicz dev->in_ep->desc = NULL;
859b185f01aSAndrzej Pietrasiewicz dev->out_ep->desc = NULL;
860b185f01aSAndrzej Pietrasiewicz }
861b185f01aSAndrzej Pietrasiewicz
862b185f01aSAndrzej Pietrasiewicz /* caller is responsible for cleanup on error */
863b185f01aSAndrzej Pietrasiewicz return result;
864b185f01aSAndrzej Pietrasiewicz }
865b185f01aSAndrzej Pietrasiewicz
printer_reset_interface(struct printer_dev * dev)866b185f01aSAndrzej Pietrasiewicz static void printer_reset_interface(struct printer_dev *dev)
867b185f01aSAndrzej Pietrasiewicz {
868a24b071bSFupan Li unsigned long flags;
869a24b071bSFupan Li
870b185f01aSAndrzej Pietrasiewicz if (dev->interface < 0)
871b185f01aSAndrzej Pietrasiewicz return;
872b185f01aSAndrzej Pietrasiewicz
873b185f01aSAndrzej Pietrasiewicz if (dev->in_ep->desc)
874b185f01aSAndrzej Pietrasiewicz usb_ep_disable(dev->in_ep);
875b185f01aSAndrzej Pietrasiewicz
876b185f01aSAndrzej Pietrasiewicz if (dev->out_ep->desc)
877b185f01aSAndrzej Pietrasiewicz usb_ep_disable(dev->out_ep);
878b185f01aSAndrzej Pietrasiewicz
879a24b071bSFupan Li spin_lock_irqsave(&dev->lock, flags);
880b185f01aSAndrzej Pietrasiewicz dev->in_ep->desc = NULL;
881b185f01aSAndrzej Pietrasiewicz dev->out_ep->desc = NULL;
882b185f01aSAndrzej Pietrasiewicz dev->interface = -1;
883a24b071bSFupan Li spin_unlock_irqrestore(&dev->lock, flags);
884b185f01aSAndrzej Pietrasiewicz }
885b185f01aSAndrzej Pietrasiewicz
886b185f01aSAndrzej Pietrasiewicz /* Change our operational Interface. */
set_interface(struct printer_dev * dev,unsigned number)887b185f01aSAndrzej Pietrasiewicz static int set_interface(struct printer_dev *dev, unsigned number)
888b185f01aSAndrzej Pietrasiewicz {
889b185f01aSAndrzej Pietrasiewicz int result = 0;
890b185f01aSAndrzej Pietrasiewicz
891b185f01aSAndrzej Pietrasiewicz /* Free the current interface */
892b185f01aSAndrzej Pietrasiewicz printer_reset_interface(dev);
893b185f01aSAndrzej Pietrasiewicz
894b185f01aSAndrzej Pietrasiewicz result = set_printer_interface(dev);
895b185f01aSAndrzej Pietrasiewicz if (result)
896b185f01aSAndrzej Pietrasiewicz printer_reset_interface(dev);
897b185f01aSAndrzej Pietrasiewicz else
898b185f01aSAndrzej Pietrasiewicz dev->interface = number;
899b185f01aSAndrzej Pietrasiewicz
900b185f01aSAndrzej Pietrasiewicz if (!result)
901b185f01aSAndrzej Pietrasiewicz INFO(dev, "Using interface %x\n", number);
902b185f01aSAndrzej Pietrasiewicz
903b185f01aSAndrzej Pietrasiewicz return result;
904b185f01aSAndrzej Pietrasiewicz }
905b185f01aSAndrzej Pietrasiewicz
printer_soft_reset(struct printer_dev * dev)906b185f01aSAndrzej Pietrasiewicz static void printer_soft_reset(struct printer_dev *dev)
907b185f01aSAndrzej Pietrasiewicz {
908b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
909b185f01aSAndrzej Pietrasiewicz
910b185f01aSAndrzej Pietrasiewicz if (usb_ep_disable(dev->in_ep))
911b185f01aSAndrzej Pietrasiewicz DBG(dev, "Failed to disable USB in_ep\n");
912b185f01aSAndrzej Pietrasiewicz if (usb_ep_disable(dev->out_ep))
913b185f01aSAndrzej Pietrasiewicz DBG(dev, "Failed to disable USB out_ep\n");
914b185f01aSAndrzej Pietrasiewicz
915b185f01aSAndrzej Pietrasiewicz if (dev->current_rx_req != NULL) {
916b185f01aSAndrzej Pietrasiewicz list_add(&dev->current_rx_req->list, &dev->rx_reqs);
917b185f01aSAndrzej Pietrasiewicz dev->current_rx_req = NULL;
918b185f01aSAndrzej Pietrasiewicz }
919b185f01aSAndrzej Pietrasiewicz dev->current_rx_bytes = 0;
920b185f01aSAndrzej Pietrasiewicz dev->current_rx_buf = NULL;
921b185f01aSAndrzej Pietrasiewicz dev->reset_printer = 1;
922b185f01aSAndrzej Pietrasiewicz
923b185f01aSAndrzej Pietrasiewicz while (likely(!(list_empty(&dev->rx_buffers)))) {
924b185f01aSAndrzej Pietrasiewicz req = container_of(dev->rx_buffers.next, struct usb_request,
925b185f01aSAndrzej Pietrasiewicz list);
926b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
927b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
928b185f01aSAndrzej Pietrasiewicz }
929b185f01aSAndrzej Pietrasiewicz
930b185f01aSAndrzej Pietrasiewicz while (likely(!(list_empty(&dev->rx_reqs_active)))) {
931b185f01aSAndrzej Pietrasiewicz req = container_of(dev->rx_buffers.next, struct usb_request,
932b185f01aSAndrzej Pietrasiewicz list);
933b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
934b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
935b185f01aSAndrzej Pietrasiewicz }
936b185f01aSAndrzej Pietrasiewicz
937b185f01aSAndrzej Pietrasiewicz while (likely(!(list_empty(&dev->tx_reqs_active)))) {
938b185f01aSAndrzej Pietrasiewicz req = container_of(dev->tx_reqs_active.next,
939b185f01aSAndrzej Pietrasiewicz struct usb_request, list);
940b185f01aSAndrzej Pietrasiewicz list_del_init(&req->list);
941b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->tx_reqs);
942b185f01aSAndrzej Pietrasiewicz }
943b185f01aSAndrzej Pietrasiewicz
944b185f01aSAndrzej Pietrasiewicz if (usb_ep_enable(dev->in_ep))
945b185f01aSAndrzej Pietrasiewicz DBG(dev, "Failed to enable USB in_ep\n");
946b185f01aSAndrzej Pietrasiewicz if (usb_ep_enable(dev->out_ep))
947b185f01aSAndrzej Pietrasiewicz DBG(dev, "Failed to enable USB out_ep\n");
948b185f01aSAndrzej Pietrasiewicz
949b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->rx_wait);
950b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->tx_wait);
951b185f01aSAndrzej Pietrasiewicz wake_up_interruptible(&dev->tx_flush_wait);
952b185f01aSAndrzej Pietrasiewicz }
953b185f01aSAndrzej Pietrasiewicz
954b185f01aSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
955b185f01aSAndrzej Pietrasiewicz
gprinter_req_match(struct usb_function * f,const struct usb_ctrlrequest * ctrl,bool config0)956b185f01aSAndrzej Pietrasiewicz static bool gprinter_req_match(struct usb_function *f,
9571a00b457SFelix Hädicke const struct usb_ctrlrequest *ctrl,
9581a00b457SFelix Hädicke bool config0)
959b185f01aSAndrzej Pietrasiewicz {
960b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
961b185f01aSAndrzej Pietrasiewicz u16 w_index = le16_to_cpu(ctrl->wIndex);
962b185f01aSAndrzej Pietrasiewicz u16 w_value = le16_to_cpu(ctrl->wValue);
963b185f01aSAndrzej Pietrasiewicz u16 w_length = le16_to_cpu(ctrl->wLength);
964b185f01aSAndrzej Pietrasiewicz
9651a00b457SFelix Hädicke if (config0)
9661a00b457SFelix Hädicke return false;
9671a00b457SFelix Hädicke
968b185f01aSAndrzej Pietrasiewicz if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE ||
969b185f01aSAndrzej Pietrasiewicz (ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
970b185f01aSAndrzej Pietrasiewicz return false;
971b185f01aSAndrzej Pietrasiewicz
972b185f01aSAndrzej Pietrasiewicz switch (ctrl->bRequest) {
973b185f01aSAndrzej Pietrasiewicz case GET_DEVICE_ID:
974b185f01aSAndrzej Pietrasiewicz w_index >>= 8;
975fdc01cc2SKrzysztof Opasiak if (USB_DIR_IN & ctrl->bRequestType)
976b185f01aSAndrzej Pietrasiewicz break;
977b185f01aSAndrzej Pietrasiewicz return false;
978b185f01aSAndrzej Pietrasiewicz case GET_PORT_STATUS:
979b185f01aSAndrzej Pietrasiewicz if (!w_value && w_length == 1 &&
980b185f01aSAndrzej Pietrasiewicz (USB_DIR_IN & ctrl->bRequestType))
981b185f01aSAndrzej Pietrasiewicz break;
982b185f01aSAndrzej Pietrasiewicz return false;
983b185f01aSAndrzej Pietrasiewicz case SOFT_RESET:
984b185f01aSAndrzej Pietrasiewicz if (!w_value && !w_length &&
985fbdecad9SAndrzej Pietrasiewicz !(USB_DIR_IN & ctrl->bRequestType))
986b185f01aSAndrzej Pietrasiewicz break;
987a74005abSGustavo A. R. Silva fallthrough;
988b185f01aSAndrzej Pietrasiewicz default:
989b185f01aSAndrzej Pietrasiewicz return false;
990b185f01aSAndrzej Pietrasiewicz }
991b185f01aSAndrzej Pietrasiewicz return w_index == dev->interface;
992b185f01aSAndrzej Pietrasiewicz }
993b185f01aSAndrzej Pietrasiewicz
994b185f01aSAndrzej Pietrasiewicz /*
995b185f01aSAndrzej Pietrasiewicz * The setup() callback implements all the ep0 functionality that's not
996b185f01aSAndrzej Pietrasiewicz * handled lower down.
997b185f01aSAndrzej Pietrasiewicz */
printer_func_setup(struct usb_function * f,const struct usb_ctrlrequest * ctrl)998b185f01aSAndrzej Pietrasiewicz static int printer_func_setup(struct usb_function *f,
999b185f01aSAndrzej Pietrasiewicz const struct usb_ctrlrequest *ctrl)
1000b185f01aSAndrzej Pietrasiewicz {
1001b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
1002b185f01aSAndrzej Pietrasiewicz struct usb_composite_dev *cdev = f->config->cdev;
1003b185f01aSAndrzej Pietrasiewicz struct usb_request *req = cdev->req;
1004fdc01cc2SKrzysztof Opasiak u8 *buf = req->buf;
1005b185f01aSAndrzej Pietrasiewicz int value = -EOPNOTSUPP;
1006b185f01aSAndrzej Pietrasiewicz u16 wIndex = le16_to_cpu(ctrl->wIndex);
1007b185f01aSAndrzej Pietrasiewicz u16 wValue = le16_to_cpu(ctrl->wValue);
1008b185f01aSAndrzej Pietrasiewicz u16 wLength = le16_to_cpu(ctrl->wLength);
1009b185f01aSAndrzej Pietrasiewicz
1010b185f01aSAndrzej Pietrasiewicz DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
1011b185f01aSAndrzej Pietrasiewicz ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
1012b185f01aSAndrzej Pietrasiewicz
1013b185f01aSAndrzej Pietrasiewicz switch (ctrl->bRequestType&USB_TYPE_MASK) {
1014b185f01aSAndrzej Pietrasiewicz case USB_TYPE_CLASS:
1015b185f01aSAndrzej Pietrasiewicz switch (ctrl->bRequest) {
1016b185f01aSAndrzej Pietrasiewicz case GET_DEVICE_ID: /* Get the IEEE-1284 PNP String */
1017b185f01aSAndrzej Pietrasiewicz /* Only one printer interface is supported. */
1018b185f01aSAndrzej Pietrasiewicz if ((wIndex>>8) != dev->interface)
1019b185f01aSAndrzej Pietrasiewicz break;
1020b185f01aSAndrzej Pietrasiewicz
102124b7ba2fSAlbert Briscoe if (!*dev->pnp_string) {
1022fdc01cc2SKrzysztof Opasiak value = 0;
1023fdc01cc2SKrzysztof Opasiak break;
1024fdc01cc2SKrzysztof Opasiak }
102524b7ba2fSAlbert Briscoe value = strlen(*dev->pnp_string);
1026fdc01cc2SKrzysztof Opasiak buf[0] = (value >> 8) & 0xFF;
1027fdc01cc2SKrzysztof Opasiak buf[1] = value & 0xFF;
102824b7ba2fSAlbert Briscoe memcpy(buf + 2, *dev->pnp_string, value);
1029b185f01aSAndrzej Pietrasiewicz DBG(dev, "1284 PNP String: %x %s\n", value,
103024b7ba2fSAlbert Briscoe *dev->pnp_string);
1031b185f01aSAndrzej Pietrasiewicz break;
1032b185f01aSAndrzej Pietrasiewicz
1033b185f01aSAndrzej Pietrasiewicz case GET_PORT_STATUS: /* Get Port Status */
1034b185f01aSAndrzej Pietrasiewicz /* Only one printer interface is supported. */
1035b185f01aSAndrzej Pietrasiewicz if (wIndex != dev->interface)
1036b185f01aSAndrzej Pietrasiewicz break;
1037b185f01aSAndrzej Pietrasiewicz
1038fdc01cc2SKrzysztof Opasiak buf[0] = dev->printer_status;
1039b185f01aSAndrzej Pietrasiewicz value = min_t(u16, wLength, 1);
1040b185f01aSAndrzej Pietrasiewicz break;
1041b185f01aSAndrzej Pietrasiewicz
1042b185f01aSAndrzej Pietrasiewicz case SOFT_RESET: /* Soft Reset */
1043b185f01aSAndrzej Pietrasiewicz /* Only one printer interface is supported. */
1044b185f01aSAndrzej Pietrasiewicz if (wIndex != dev->interface)
1045b185f01aSAndrzej Pietrasiewicz break;
1046b185f01aSAndrzej Pietrasiewicz
1047b185f01aSAndrzej Pietrasiewicz printer_soft_reset(dev);
1048b185f01aSAndrzej Pietrasiewicz
1049b185f01aSAndrzej Pietrasiewicz value = 0;
1050b185f01aSAndrzej Pietrasiewicz break;
1051b185f01aSAndrzej Pietrasiewicz
1052b185f01aSAndrzej Pietrasiewicz default:
1053b185f01aSAndrzej Pietrasiewicz goto unknown;
1054b185f01aSAndrzej Pietrasiewicz }
1055b185f01aSAndrzej Pietrasiewicz break;
1056b185f01aSAndrzej Pietrasiewicz
1057b185f01aSAndrzej Pietrasiewicz default:
1058b185f01aSAndrzej Pietrasiewicz unknown:
1059b185f01aSAndrzej Pietrasiewicz VDBG(dev,
1060b185f01aSAndrzej Pietrasiewicz "unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
1061b185f01aSAndrzej Pietrasiewicz ctrl->bRequestType, ctrl->bRequest,
1062b185f01aSAndrzej Pietrasiewicz wValue, wIndex, wLength);
1063b185f01aSAndrzej Pietrasiewicz break;
1064b185f01aSAndrzej Pietrasiewicz }
1065b185f01aSAndrzej Pietrasiewicz /* host either stalls (value < 0) or reports success */
1066b185f01aSAndrzej Pietrasiewicz if (value >= 0) {
1067b185f01aSAndrzej Pietrasiewicz req->length = value;
1068b185f01aSAndrzej Pietrasiewicz req->zero = value < wLength;
1069b185f01aSAndrzej Pietrasiewicz value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1070b185f01aSAndrzej Pietrasiewicz if (value < 0) {
1071b185f01aSAndrzej Pietrasiewicz ERROR(dev, "%s:%d Error!\n", __func__, __LINE__);
1072b185f01aSAndrzej Pietrasiewicz req->status = 0;
1073b185f01aSAndrzej Pietrasiewicz }
1074b185f01aSAndrzej Pietrasiewicz }
1075b185f01aSAndrzej Pietrasiewicz return value;
1076b185f01aSAndrzej Pietrasiewicz }
1077b185f01aSAndrzej Pietrasiewicz
printer_func_bind(struct usb_configuration * c,struct usb_function * f)1078b26394bdSAndrzej Pietrasiewicz static int printer_func_bind(struct usb_configuration *c,
1079b185f01aSAndrzej Pietrasiewicz struct usb_function *f)
1080b185f01aSAndrzej Pietrasiewicz {
1081b185f01aSAndrzej Pietrasiewicz struct usb_gadget *gadget = c->cdev->gadget;
1082b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
1083b185f01aSAndrzej Pietrasiewicz struct device *pdev;
1084b185f01aSAndrzej Pietrasiewicz struct usb_composite_dev *cdev = c->cdev;
1085b185f01aSAndrzej Pietrasiewicz struct usb_ep *in_ep;
1086b185f01aSAndrzej Pietrasiewicz struct usb_ep *out_ep = NULL;
1087b185f01aSAndrzej Pietrasiewicz struct usb_request *req;
1088b185f01aSAndrzej Pietrasiewicz dev_t devt;
1089b185f01aSAndrzej Pietrasiewicz int id;
1090b185f01aSAndrzej Pietrasiewicz int ret;
1091b185f01aSAndrzej Pietrasiewicz u32 i;
1092b185f01aSAndrzej Pietrasiewicz
1093b185f01aSAndrzej Pietrasiewicz id = usb_interface_id(c, f);
1094b185f01aSAndrzej Pietrasiewicz if (id < 0)
1095b185f01aSAndrzej Pietrasiewicz return id;
1096b185f01aSAndrzej Pietrasiewicz intf_desc.bInterfaceNumber = id;
1097b185f01aSAndrzej Pietrasiewicz
1098b185f01aSAndrzej Pietrasiewicz /* finish hookup to lower layer ... */
1099b185f01aSAndrzej Pietrasiewicz dev->gadget = gadget;
1100b185f01aSAndrzej Pietrasiewicz
1101b185f01aSAndrzej Pietrasiewicz /* all we really need is bulk IN/OUT */
1102b185f01aSAndrzej Pietrasiewicz in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
1103b185f01aSAndrzej Pietrasiewicz if (!in_ep) {
1104b185f01aSAndrzej Pietrasiewicz autoconf_fail:
1105b185f01aSAndrzej Pietrasiewicz dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
1106b185f01aSAndrzej Pietrasiewicz cdev->gadget->name);
1107b185f01aSAndrzej Pietrasiewicz return -ENODEV;
1108b185f01aSAndrzej Pietrasiewicz }
1109b185f01aSAndrzej Pietrasiewicz
1110b185f01aSAndrzej Pietrasiewicz out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
1111b185f01aSAndrzej Pietrasiewicz if (!out_ep)
1112b185f01aSAndrzej Pietrasiewicz goto autoconf_fail;
1113b185f01aSAndrzej Pietrasiewicz
1114b185f01aSAndrzej Pietrasiewicz /* assumes that all endpoints are dual-speed */
1115b185f01aSAndrzej Pietrasiewicz hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
1116b185f01aSAndrzej Pietrasiewicz hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
1117b185f01aSAndrzej Pietrasiewicz ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
1118b185f01aSAndrzej Pietrasiewicz ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
1119b185f01aSAndrzej Pietrasiewicz
1120b185f01aSAndrzej Pietrasiewicz ret = usb_assign_descriptors(f, fs_printer_function,
112190c4d057SMaciej Żenczykowski hs_printer_function, ss_printer_function,
112290c4d057SMaciej Żenczykowski ss_printer_function);
1123b185f01aSAndrzej Pietrasiewicz if (ret)
1124b185f01aSAndrzej Pietrasiewicz return ret;
1125b185f01aSAndrzej Pietrasiewicz
1126b185f01aSAndrzej Pietrasiewicz dev->in_ep = in_ep;
1127b185f01aSAndrzej Pietrasiewicz dev->out_ep = out_ep;
1128b185f01aSAndrzej Pietrasiewicz
1129b185f01aSAndrzej Pietrasiewicz ret = -ENOMEM;
1130b185f01aSAndrzej Pietrasiewicz for (i = 0; i < dev->q_len; i++) {
1131b185f01aSAndrzej Pietrasiewicz req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
1132b185f01aSAndrzej Pietrasiewicz if (!req)
1133b185f01aSAndrzej Pietrasiewicz goto fail_tx_reqs;
1134b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->tx_reqs);
1135b185f01aSAndrzej Pietrasiewicz }
1136b185f01aSAndrzej Pietrasiewicz
1137b185f01aSAndrzej Pietrasiewicz for (i = 0; i < dev->q_len; i++) {
1138b185f01aSAndrzej Pietrasiewicz req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
1139b185f01aSAndrzej Pietrasiewicz if (!req)
1140b185f01aSAndrzej Pietrasiewicz goto fail_rx_reqs;
1141b185f01aSAndrzej Pietrasiewicz list_add(&req->list, &dev->rx_reqs);
1142b185f01aSAndrzej Pietrasiewicz }
1143b185f01aSAndrzej Pietrasiewicz
1144b185f01aSAndrzej Pietrasiewicz /* Setup the sysfs files for the printer gadget. */
1145b185f01aSAndrzej Pietrasiewicz devt = MKDEV(major, dev->minor);
11462c10e7a0SIvan Orlov pdev = device_create(&usb_gadget_class, NULL, devt,
1147b185f01aSAndrzej Pietrasiewicz NULL, "g_printer%d", dev->minor);
1148b185f01aSAndrzej Pietrasiewicz if (IS_ERR(pdev)) {
1149b185f01aSAndrzej Pietrasiewicz ERROR(dev, "Failed to create device: g_printer\n");
1150b185f01aSAndrzej Pietrasiewicz ret = PTR_ERR(pdev);
1151b185f01aSAndrzej Pietrasiewicz goto fail_rx_reqs;
1152b185f01aSAndrzej Pietrasiewicz }
1153b185f01aSAndrzej Pietrasiewicz
1154b185f01aSAndrzej Pietrasiewicz /*
1155b185f01aSAndrzej Pietrasiewicz * Register a character device as an interface to a user mode
1156b185f01aSAndrzej Pietrasiewicz * program that handles the printer specific functionality.
1157b185f01aSAndrzej Pietrasiewicz */
1158b185f01aSAndrzej Pietrasiewicz cdev_init(&dev->printer_cdev, &printer_io_operations);
1159b185f01aSAndrzej Pietrasiewicz dev->printer_cdev.owner = THIS_MODULE;
1160b185f01aSAndrzej Pietrasiewicz ret = cdev_add(&dev->printer_cdev, devt, 1);
1161b185f01aSAndrzej Pietrasiewicz if (ret) {
1162b185f01aSAndrzej Pietrasiewicz ERROR(dev, "Failed to open char device\n");
1163b185f01aSAndrzej Pietrasiewicz goto fail_cdev_add;
1164b185f01aSAndrzej Pietrasiewicz }
1165b185f01aSAndrzej Pietrasiewicz
1166b185f01aSAndrzej Pietrasiewicz return 0;
1167b185f01aSAndrzej Pietrasiewicz
1168b185f01aSAndrzej Pietrasiewicz fail_cdev_add:
11692c10e7a0SIvan Orlov device_destroy(&usb_gadget_class, devt);
1170b185f01aSAndrzej Pietrasiewicz
1171b185f01aSAndrzej Pietrasiewicz fail_rx_reqs:
1172b185f01aSAndrzej Pietrasiewicz while (!list_empty(&dev->rx_reqs)) {
1173b185f01aSAndrzej Pietrasiewicz req = container_of(dev->rx_reqs.next, struct usb_request, list);
1174b185f01aSAndrzej Pietrasiewicz list_del(&req->list);
1175b185f01aSAndrzej Pietrasiewicz printer_req_free(dev->out_ep, req);
1176b185f01aSAndrzej Pietrasiewicz }
1177b185f01aSAndrzej Pietrasiewicz
1178b185f01aSAndrzej Pietrasiewicz fail_tx_reqs:
1179b185f01aSAndrzej Pietrasiewicz while (!list_empty(&dev->tx_reqs)) {
1180b185f01aSAndrzej Pietrasiewicz req = container_of(dev->tx_reqs.next, struct usb_request, list);
1181b185f01aSAndrzej Pietrasiewicz list_del(&req->list);
1182b185f01aSAndrzej Pietrasiewicz printer_req_free(dev->in_ep, req);
1183b185f01aSAndrzej Pietrasiewicz }
1184b185f01aSAndrzej Pietrasiewicz
11852cc332e4SZqiang usb_free_all_descriptors(f);
1186b185f01aSAndrzej Pietrasiewicz return ret;
1187b185f01aSAndrzej Pietrasiewicz
1188b185f01aSAndrzej Pietrasiewicz }
1189b185f01aSAndrzej Pietrasiewicz
printer_func_set_alt(struct usb_function * f,unsigned intf,unsigned alt)1190b185f01aSAndrzej Pietrasiewicz static int printer_func_set_alt(struct usb_function *f,
1191b185f01aSAndrzej Pietrasiewicz unsigned intf, unsigned alt)
1192b185f01aSAndrzej Pietrasiewicz {
1193b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
1194b185f01aSAndrzej Pietrasiewicz int ret = -ENOTSUPP;
1195b185f01aSAndrzej Pietrasiewicz
1196b185f01aSAndrzej Pietrasiewicz if (!alt)
1197b185f01aSAndrzej Pietrasiewicz ret = set_interface(dev, intf);
1198b185f01aSAndrzej Pietrasiewicz
1199b185f01aSAndrzej Pietrasiewicz return ret;
1200b185f01aSAndrzej Pietrasiewicz }
1201b185f01aSAndrzej Pietrasiewicz
printer_func_disable(struct usb_function * f)1202b185f01aSAndrzej Pietrasiewicz static void printer_func_disable(struct usb_function *f)
1203b185f01aSAndrzej Pietrasiewicz {
1204b185f01aSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
1205b185f01aSAndrzej Pietrasiewicz
1206b185f01aSAndrzej Pietrasiewicz printer_reset_interface(dev);
1207b185f01aSAndrzej Pietrasiewicz }
1208b185f01aSAndrzej Pietrasiewicz
1209ee1cd515SAndrzej Pietrasiewicz static inline struct f_printer_opts
to_f_printer_opts(struct config_item * item)1210ee1cd515SAndrzej Pietrasiewicz *to_f_printer_opts(struct config_item *item)
1211ee1cd515SAndrzej Pietrasiewicz {
1212ee1cd515SAndrzej Pietrasiewicz return container_of(to_config_group(item), struct f_printer_opts,
1213ee1cd515SAndrzej Pietrasiewicz func_inst.group);
1214ee1cd515SAndrzej Pietrasiewicz }
1215ee1cd515SAndrzej Pietrasiewicz
printer_attr_release(struct config_item * item)1216ee1cd515SAndrzej Pietrasiewicz static void printer_attr_release(struct config_item *item)
1217ee1cd515SAndrzej Pietrasiewicz {
1218ee1cd515SAndrzej Pietrasiewicz struct f_printer_opts *opts = to_f_printer_opts(item);
1219ee1cd515SAndrzej Pietrasiewicz
1220ee1cd515SAndrzej Pietrasiewicz usb_put_function_instance(&opts->func_inst);
1221ee1cd515SAndrzej Pietrasiewicz }
1222ee1cd515SAndrzej Pietrasiewicz
1223ee1cd515SAndrzej Pietrasiewicz static struct configfs_item_operations printer_item_ops = {
1224ee1cd515SAndrzej Pietrasiewicz .release = printer_attr_release,
1225ee1cd515SAndrzej Pietrasiewicz };
1226ee1cd515SAndrzej Pietrasiewicz
f_printer_opts_pnp_string_show(struct config_item * item,char * page)1227aa48a415SChristoph Hellwig static ssize_t f_printer_opts_pnp_string_show(struct config_item *item,
1228ee1cd515SAndrzej Pietrasiewicz char *page)
1229ee1cd515SAndrzej Pietrasiewicz {
1230aa48a415SChristoph Hellwig struct f_printer_opts *opts = to_f_printer_opts(item);
1231fdc01cc2SKrzysztof Opasiak int result = 0;
1232ee1cd515SAndrzej Pietrasiewicz
1233ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1234fdc01cc2SKrzysztof Opasiak if (!opts->pnp_string)
1235fdc01cc2SKrzysztof Opasiak goto unlock;
1236fdc01cc2SKrzysztof Opasiak
1237ee400a1bSAzeem Shaikh result = strscpy(page, opts->pnp_string, PAGE_SIZE);
1238ee400a1bSAzeem Shaikh if (result < 1) {
1239fdc01cc2SKrzysztof Opasiak result = PAGE_SIZE;
1240fdc01cc2SKrzysztof Opasiak } else if (page[result - 1] != '\n' && result + 1 < PAGE_SIZE) {
1241fdc01cc2SKrzysztof Opasiak page[result++] = '\n';
1242fdc01cc2SKrzysztof Opasiak page[result] = '\0';
1243fdc01cc2SKrzysztof Opasiak }
1244fdc01cc2SKrzysztof Opasiak
1245fdc01cc2SKrzysztof Opasiak unlock:
1246ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1247ee1cd515SAndrzej Pietrasiewicz
1248ee1cd515SAndrzej Pietrasiewicz return result;
1249ee1cd515SAndrzej Pietrasiewicz }
1250ee1cd515SAndrzej Pietrasiewicz
f_printer_opts_pnp_string_store(struct config_item * item,const char * page,size_t len)1251aa48a415SChristoph Hellwig static ssize_t f_printer_opts_pnp_string_store(struct config_item *item,
1252ee1cd515SAndrzej Pietrasiewicz const char *page, size_t len)
1253ee1cd515SAndrzej Pietrasiewicz {
1254aa48a415SChristoph Hellwig struct f_printer_opts *opts = to_f_printer_opts(item);
1255fdc01cc2SKrzysztof Opasiak char *new_pnp;
1256fdc01cc2SKrzysztof Opasiak int result;
1257ee1cd515SAndrzej Pietrasiewicz
1258ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1259fdc01cc2SKrzysztof Opasiak
1260fdc01cc2SKrzysztof Opasiak new_pnp = kstrndup(page, len, GFP_KERNEL);
1261fdc01cc2SKrzysztof Opasiak if (!new_pnp) {
1262fdc01cc2SKrzysztof Opasiak result = -ENOMEM;
1263fdc01cc2SKrzysztof Opasiak goto unlock;
1264fdc01cc2SKrzysztof Opasiak }
1265fdc01cc2SKrzysztof Opasiak
1266fdc01cc2SKrzysztof Opasiak if (opts->pnp_string_allocated)
1267fdc01cc2SKrzysztof Opasiak kfree(opts->pnp_string);
1268fdc01cc2SKrzysztof Opasiak
1269fdc01cc2SKrzysztof Opasiak opts->pnp_string_allocated = true;
1270fdc01cc2SKrzysztof Opasiak opts->pnp_string = new_pnp;
1271fdc01cc2SKrzysztof Opasiak result = len;
1272fdc01cc2SKrzysztof Opasiak unlock:
1273ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1274ee1cd515SAndrzej Pietrasiewicz
1275ee1cd515SAndrzej Pietrasiewicz return result;
1276ee1cd515SAndrzej Pietrasiewicz }
1277ee1cd515SAndrzej Pietrasiewicz
1278aa48a415SChristoph Hellwig CONFIGFS_ATTR(f_printer_opts_, pnp_string);
1279ee1cd515SAndrzej Pietrasiewicz
f_printer_opts_q_len_show(struct config_item * item,char * page)1280aa48a415SChristoph Hellwig static ssize_t f_printer_opts_q_len_show(struct config_item *item,
1281ee1cd515SAndrzej Pietrasiewicz char *page)
1282ee1cd515SAndrzej Pietrasiewicz {
1283aa48a415SChristoph Hellwig struct f_printer_opts *opts = to_f_printer_opts(item);
1284ee1cd515SAndrzej Pietrasiewicz int result;
1285ee1cd515SAndrzej Pietrasiewicz
1286ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1287ee1cd515SAndrzej Pietrasiewicz result = sprintf(page, "%d\n", opts->q_len);
1288ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1289ee1cd515SAndrzej Pietrasiewicz
1290ee1cd515SAndrzej Pietrasiewicz return result;
1291ee1cd515SAndrzej Pietrasiewicz }
1292ee1cd515SAndrzej Pietrasiewicz
f_printer_opts_q_len_store(struct config_item * item,const char * page,size_t len)1293aa48a415SChristoph Hellwig static ssize_t f_printer_opts_q_len_store(struct config_item *item,
1294ee1cd515SAndrzej Pietrasiewicz const char *page, size_t len)
1295ee1cd515SAndrzej Pietrasiewicz {
1296aa48a415SChristoph Hellwig struct f_printer_opts *opts = to_f_printer_opts(item);
1297ee1cd515SAndrzej Pietrasiewicz int ret;
1298ee1cd515SAndrzej Pietrasiewicz u16 num;
1299ee1cd515SAndrzej Pietrasiewicz
1300ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1301ee1cd515SAndrzej Pietrasiewicz if (opts->refcnt) {
1302ee1cd515SAndrzej Pietrasiewicz ret = -EBUSY;
1303ee1cd515SAndrzej Pietrasiewicz goto end;
1304ee1cd515SAndrzej Pietrasiewicz }
1305ee1cd515SAndrzej Pietrasiewicz
1306ee1cd515SAndrzej Pietrasiewicz ret = kstrtou16(page, 0, &num);
1307ee1cd515SAndrzej Pietrasiewicz if (ret)
1308ee1cd515SAndrzej Pietrasiewicz goto end;
1309ee1cd515SAndrzej Pietrasiewicz
1310ee1cd515SAndrzej Pietrasiewicz opts->q_len = (unsigned)num;
1311ee1cd515SAndrzej Pietrasiewicz ret = len;
1312ee1cd515SAndrzej Pietrasiewicz end:
1313ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1314ee1cd515SAndrzej Pietrasiewicz return ret;
1315ee1cd515SAndrzej Pietrasiewicz }
1316ee1cd515SAndrzej Pietrasiewicz
1317aa48a415SChristoph Hellwig CONFIGFS_ATTR(f_printer_opts_, q_len);
1318ee1cd515SAndrzej Pietrasiewicz
1319ee1cd515SAndrzej Pietrasiewicz static struct configfs_attribute *printer_attrs[] = {
1320aa48a415SChristoph Hellwig &f_printer_opts_attr_pnp_string,
1321aa48a415SChristoph Hellwig &f_printer_opts_attr_q_len,
1322ee1cd515SAndrzej Pietrasiewicz NULL,
1323ee1cd515SAndrzej Pietrasiewicz };
1324ee1cd515SAndrzej Pietrasiewicz
132597363902SBhumika Goyal static const struct config_item_type printer_func_type = {
1326ee1cd515SAndrzej Pietrasiewicz .ct_item_ops = &printer_item_ops,
1327ee1cd515SAndrzej Pietrasiewicz .ct_attrs = printer_attrs,
1328ee1cd515SAndrzej Pietrasiewicz .ct_owner = THIS_MODULE,
1329ee1cd515SAndrzej Pietrasiewicz };
1330ee1cd515SAndrzej Pietrasiewicz
gprinter_get_minor(void)1331b26394bdSAndrzej Pietrasiewicz static inline int gprinter_get_minor(void)
1332b26394bdSAndrzej Pietrasiewicz {
13334248bd7dSAndrzej Pietrasiewicz int ret;
13344248bd7dSAndrzej Pietrasiewicz
1335920e7522SChristophe JAILLET ret = ida_alloc(&printer_ida, GFP_KERNEL);
13364248bd7dSAndrzej Pietrasiewicz if (ret >= PRINTER_MINORS) {
1337920e7522SChristophe JAILLET ida_free(&printer_ida, ret);
13384248bd7dSAndrzej Pietrasiewicz ret = -ENODEV;
13394248bd7dSAndrzej Pietrasiewicz }
13404248bd7dSAndrzej Pietrasiewicz
13414248bd7dSAndrzej Pietrasiewicz return ret;
1342b26394bdSAndrzej Pietrasiewicz }
1343b26394bdSAndrzej Pietrasiewicz
gprinter_put_minor(int minor)1344b26394bdSAndrzej Pietrasiewicz static inline void gprinter_put_minor(int minor)
1345b26394bdSAndrzej Pietrasiewicz {
1346920e7522SChristophe JAILLET ida_free(&printer_ida, minor);
1347b26394bdSAndrzej Pietrasiewicz }
1348b26394bdSAndrzej Pietrasiewicz
1349b26394bdSAndrzej Pietrasiewicz static int gprinter_setup(int);
1350b26394bdSAndrzej Pietrasiewicz static void gprinter_cleanup(void);
1351b26394bdSAndrzej Pietrasiewicz
gprinter_free_inst(struct usb_function_instance * f)1352b26394bdSAndrzej Pietrasiewicz static void gprinter_free_inst(struct usb_function_instance *f)
1353b26394bdSAndrzej Pietrasiewicz {
1354b26394bdSAndrzej Pietrasiewicz struct f_printer_opts *opts;
1355b26394bdSAndrzej Pietrasiewicz
1356b26394bdSAndrzej Pietrasiewicz opts = container_of(f, struct f_printer_opts, func_inst);
1357b26394bdSAndrzej Pietrasiewicz
1358b26394bdSAndrzej Pietrasiewicz mutex_lock(&printer_ida_lock);
1359b26394bdSAndrzej Pietrasiewicz
1360b26394bdSAndrzej Pietrasiewicz gprinter_put_minor(opts->minor);
136199c49407SMatthew Wilcox if (ida_is_empty(&printer_ida))
1362b26394bdSAndrzej Pietrasiewicz gprinter_cleanup();
1363b26394bdSAndrzej Pietrasiewicz
1364b26394bdSAndrzej Pietrasiewicz mutex_unlock(&printer_ida_lock);
1365b26394bdSAndrzej Pietrasiewicz
1366fdc01cc2SKrzysztof Opasiak if (opts->pnp_string_allocated)
1367fdc01cc2SKrzysztof Opasiak kfree(opts->pnp_string);
1368b26394bdSAndrzej Pietrasiewicz kfree(opts);
1369b26394bdSAndrzej Pietrasiewicz }
1370b26394bdSAndrzej Pietrasiewicz
gprinter_alloc_inst(void)1371b26394bdSAndrzej Pietrasiewicz static struct usb_function_instance *gprinter_alloc_inst(void)
1372b26394bdSAndrzej Pietrasiewicz {
1373b26394bdSAndrzej Pietrasiewicz struct f_printer_opts *opts;
1374b26394bdSAndrzej Pietrasiewicz struct usb_function_instance *ret;
1375b26394bdSAndrzej Pietrasiewicz int status = 0;
1376b26394bdSAndrzej Pietrasiewicz
1377b26394bdSAndrzej Pietrasiewicz opts = kzalloc(sizeof(*opts), GFP_KERNEL);
1378b26394bdSAndrzej Pietrasiewicz if (!opts)
1379b26394bdSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM);
1380b26394bdSAndrzej Pietrasiewicz
1381ee1cd515SAndrzej Pietrasiewicz mutex_init(&opts->lock);
1382b26394bdSAndrzej Pietrasiewicz opts->func_inst.free_func_inst = gprinter_free_inst;
1383b26394bdSAndrzej Pietrasiewicz ret = &opts->func_inst;
1384b26394bdSAndrzej Pietrasiewicz
1385ed054e4eSMichael R Sweet /* Make sure q_len is initialized, otherwise the bound device can't support read/write! */
1386ed054e4eSMichael R Sweet opts->q_len = DEFAULT_Q_LEN;
1387ed054e4eSMichael R Sweet
1388b26394bdSAndrzej Pietrasiewicz mutex_lock(&printer_ida_lock);
1389b26394bdSAndrzej Pietrasiewicz
139099c49407SMatthew Wilcox if (ida_is_empty(&printer_ida)) {
1391b26394bdSAndrzej Pietrasiewicz status = gprinter_setup(PRINTER_MINORS);
1392b26394bdSAndrzej Pietrasiewicz if (status) {
1393b26394bdSAndrzej Pietrasiewicz ret = ERR_PTR(status);
1394b26394bdSAndrzej Pietrasiewicz kfree(opts);
1395b26394bdSAndrzej Pietrasiewicz goto unlock;
1396b26394bdSAndrzej Pietrasiewicz }
1397b26394bdSAndrzej Pietrasiewicz }
1398b26394bdSAndrzej Pietrasiewicz
1399b26394bdSAndrzej Pietrasiewicz opts->minor = gprinter_get_minor();
1400b26394bdSAndrzej Pietrasiewicz if (opts->minor < 0) {
1401b26394bdSAndrzej Pietrasiewicz ret = ERR_PTR(opts->minor);
1402b26394bdSAndrzej Pietrasiewicz kfree(opts);
140399c49407SMatthew Wilcox if (ida_is_empty(&printer_ida))
1404b26394bdSAndrzej Pietrasiewicz gprinter_cleanup();
14052bb2077eSDan Carpenter goto unlock;
1406b26394bdSAndrzej Pietrasiewicz }
1407ee1cd515SAndrzej Pietrasiewicz config_group_init_type_name(&opts->func_inst.group, "",
1408ee1cd515SAndrzej Pietrasiewicz &printer_func_type);
1409b26394bdSAndrzej Pietrasiewicz
1410b26394bdSAndrzej Pietrasiewicz unlock:
1411b26394bdSAndrzej Pietrasiewicz mutex_unlock(&printer_ida_lock);
1412b26394bdSAndrzej Pietrasiewicz return ret;
1413b26394bdSAndrzej Pietrasiewicz }
1414b26394bdSAndrzej Pietrasiewicz
gprinter_free(struct usb_function * f)1415b26394bdSAndrzej Pietrasiewicz static void gprinter_free(struct usb_function *f)
1416b26394bdSAndrzej Pietrasiewicz {
1417b26394bdSAndrzej Pietrasiewicz struct printer_dev *dev = func_to_printer(f);
1418ee1cd515SAndrzej Pietrasiewicz struct f_printer_opts *opts;
1419b26394bdSAndrzej Pietrasiewicz
1420ee1cd515SAndrzej Pietrasiewicz opts = container_of(f->fi, struct f_printer_opts, func_inst);
1421e8d5f92bSZqiang
1422e8d5f92bSZqiang kref_put(&dev->kref, printer_dev_free);
1423ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1424ee1cd515SAndrzej Pietrasiewicz --opts->refcnt;
1425ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1426b26394bdSAndrzej Pietrasiewicz }
1427b26394bdSAndrzej Pietrasiewicz
printer_func_unbind(struct usb_configuration * c,struct usb_function * f)1428b26394bdSAndrzej Pietrasiewicz static void printer_func_unbind(struct usb_configuration *c,
1429b26394bdSAndrzej Pietrasiewicz struct usb_function *f)
1430b26394bdSAndrzej Pietrasiewicz {
1431b26394bdSAndrzej Pietrasiewicz struct printer_dev *dev;
1432b26394bdSAndrzej Pietrasiewicz struct usb_request *req;
1433b26394bdSAndrzej Pietrasiewicz
1434b26394bdSAndrzej Pietrasiewicz dev = func_to_printer(f);
1435b26394bdSAndrzej Pietrasiewicz
14362c10e7a0SIvan Orlov device_destroy(&usb_gadget_class, MKDEV(major, dev->minor));
1437b26394bdSAndrzej Pietrasiewicz
1438b26394bdSAndrzej Pietrasiewicz /* Remove Character Device */
1439b26394bdSAndrzej Pietrasiewicz cdev_del(&dev->printer_cdev);
1440b26394bdSAndrzej Pietrasiewicz
1441b26394bdSAndrzej Pietrasiewicz /* we must already have been disconnected ... no i/o may be active */
1442b26394bdSAndrzej Pietrasiewicz WARN_ON(!list_empty(&dev->tx_reqs_active));
1443b26394bdSAndrzej Pietrasiewicz WARN_ON(!list_empty(&dev->rx_reqs_active));
1444b26394bdSAndrzej Pietrasiewicz
1445b26394bdSAndrzej Pietrasiewicz /* Free all memory for this driver. */
1446b26394bdSAndrzej Pietrasiewicz while (!list_empty(&dev->tx_reqs)) {
1447b26394bdSAndrzej Pietrasiewicz req = container_of(dev->tx_reqs.next, struct usb_request,
1448b26394bdSAndrzej Pietrasiewicz list);
1449b26394bdSAndrzej Pietrasiewicz list_del(&req->list);
1450b26394bdSAndrzej Pietrasiewicz printer_req_free(dev->in_ep, req);
1451b26394bdSAndrzej Pietrasiewicz }
1452b26394bdSAndrzej Pietrasiewicz
1453b26394bdSAndrzej Pietrasiewicz if (dev->current_rx_req != NULL)
1454b26394bdSAndrzej Pietrasiewicz printer_req_free(dev->out_ep, dev->current_rx_req);
1455b26394bdSAndrzej Pietrasiewicz
1456b26394bdSAndrzej Pietrasiewicz while (!list_empty(&dev->rx_reqs)) {
1457b26394bdSAndrzej Pietrasiewicz req = container_of(dev->rx_reqs.next,
1458b26394bdSAndrzej Pietrasiewicz struct usb_request, list);
1459b26394bdSAndrzej Pietrasiewicz list_del(&req->list);
1460b26394bdSAndrzej Pietrasiewicz printer_req_free(dev->out_ep, req);
1461b26394bdSAndrzej Pietrasiewicz }
1462b26394bdSAndrzej Pietrasiewicz
1463b26394bdSAndrzej Pietrasiewicz while (!list_empty(&dev->rx_buffers)) {
1464b26394bdSAndrzej Pietrasiewicz req = container_of(dev->rx_buffers.next,
1465b26394bdSAndrzej Pietrasiewicz struct usb_request, list);
1466b26394bdSAndrzej Pietrasiewicz list_del(&req->list);
1467b26394bdSAndrzej Pietrasiewicz printer_req_free(dev->out_ep, req);
1468b26394bdSAndrzej Pietrasiewicz }
1469b26394bdSAndrzej Pietrasiewicz usb_free_all_descriptors(f);
1470b26394bdSAndrzej Pietrasiewicz }
1471b26394bdSAndrzej Pietrasiewicz
gprinter_alloc(struct usb_function_instance * fi)1472b26394bdSAndrzej Pietrasiewicz static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
1473b26394bdSAndrzej Pietrasiewicz {
1474b26394bdSAndrzej Pietrasiewicz struct printer_dev *dev;
1475b26394bdSAndrzej Pietrasiewicz struct f_printer_opts *opts;
1476b26394bdSAndrzej Pietrasiewicz
1477b26394bdSAndrzej Pietrasiewicz opts = container_of(fi, struct f_printer_opts, func_inst);
1478b26394bdSAndrzej Pietrasiewicz
1479ee1cd515SAndrzej Pietrasiewicz mutex_lock(&opts->lock);
1480ee1cd515SAndrzej Pietrasiewicz if (opts->minor >= minors) {
1481ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1482b26394bdSAndrzej Pietrasiewicz return ERR_PTR(-ENOENT);
1483ee1cd515SAndrzej Pietrasiewicz }
1484b26394bdSAndrzej Pietrasiewicz
1485b26394bdSAndrzej Pietrasiewicz dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1486ee1cd515SAndrzej Pietrasiewicz if (!dev) {
1487ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1488b26394bdSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM);
1489ee1cd515SAndrzej Pietrasiewicz }
1490b26394bdSAndrzej Pietrasiewicz
1491e8d5f92bSZqiang kref_init(&dev->kref);
1492ee1cd515SAndrzej Pietrasiewicz ++opts->refcnt;
1493b26394bdSAndrzej Pietrasiewicz dev->minor = opts->minor;
149424b7ba2fSAlbert Briscoe dev->pnp_string = &opts->pnp_string;
1495b26394bdSAndrzej Pietrasiewicz dev->q_len = opts->q_len;
1496ee1cd515SAndrzej Pietrasiewicz mutex_unlock(&opts->lock);
1497b26394bdSAndrzej Pietrasiewicz
1498b26394bdSAndrzej Pietrasiewicz dev->function.name = "printer";
1499b26394bdSAndrzej Pietrasiewicz dev->function.bind = printer_func_bind;
1500b26394bdSAndrzej Pietrasiewicz dev->function.setup = printer_func_setup;
1501b26394bdSAndrzej Pietrasiewicz dev->function.unbind = printer_func_unbind;
1502b26394bdSAndrzej Pietrasiewicz dev->function.set_alt = printer_func_set_alt;
1503b26394bdSAndrzej Pietrasiewicz dev->function.disable = printer_func_disable;
1504b26394bdSAndrzej Pietrasiewicz dev->function.req_match = gprinter_req_match;
1505b26394bdSAndrzej Pietrasiewicz dev->function.free_func = gprinter_free;
1506b26394bdSAndrzej Pietrasiewicz
1507b26394bdSAndrzej Pietrasiewicz INIT_LIST_HEAD(&dev->tx_reqs);
1508b26394bdSAndrzej Pietrasiewicz INIT_LIST_HEAD(&dev->rx_reqs);
1509b26394bdSAndrzej Pietrasiewicz INIT_LIST_HEAD(&dev->rx_buffers);
1510b26394bdSAndrzej Pietrasiewicz INIT_LIST_HEAD(&dev->tx_reqs_active);
1511b26394bdSAndrzej Pietrasiewicz INIT_LIST_HEAD(&dev->rx_reqs_active);
1512b26394bdSAndrzej Pietrasiewicz
1513b26394bdSAndrzej Pietrasiewicz spin_lock_init(&dev->lock);
1514b26394bdSAndrzej Pietrasiewicz mutex_init(&dev->lock_printer_io);
1515b26394bdSAndrzej Pietrasiewicz init_waitqueue_head(&dev->rx_wait);
1516b26394bdSAndrzej Pietrasiewicz init_waitqueue_head(&dev->tx_wait);
1517b26394bdSAndrzej Pietrasiewicz init_waitqueue_head(&dev->tx_flush_wait);
1518b26394bdSAndrzej Pietrasiewicz
1519b26394bdSAndrzej Pietrasiewicz dev->interface = -1;
1520b26394bdSAndrzej Pietrasiewicz dev->printer_cdev_open = 0;
1521b26394bdSAndrzej Pietrasiewicz dev->printer_status = PRINTER_NOT_ERROR;
1522b26394bdSAndrzej Pietrasiewicz dev->current_rx_req = NULL;
1523b26394bdSAndrzej Pietrasiewicz dev->current_rx_bytes = 0;
1524b26394bdSAndrzej Pietrasiewicz dev->current_rx_buf = NULL;
1525b26394bdSAndrzej Pietrasiewicz
1526b26394bdSAndrzej Pietrasiewicz return &dev->function;
1527b26394bdSAndrzej Pietrasiewicz }
1528b26394bdSAndrzej Pietrasiewicz
1529b26394bdSAndrzej Pietrasiewicz DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc);
15301cb9ba5eSJeff Johnson MODULE_DESCRIPTION("USB printer function driver");
1531b26394bdSAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
1532b26394bdSAndrzej Pietrasiewicz MODULE_AUTHOR("Craig Nadler");
1533b26394bdSAndrzej Pietrasiewicz
gprinter_setup(int count)1534b185f01aSAndrzej Pietrasiewicz static int gprinter_setup(int count)
1535b185f01aSAndrzej Pietrasiewicz {
1536b185f01aSAndrzej Pietrasiewicz int status;
1537b185f01aSAndrzej Pietrasiewicz dev_t devt;
1538b185f01aSAndrzej Pietrasiewicz
15392c10e7a0SIvan Orlov status = class_register(&usb_gadget_class);
15402c10e7a0SIvan Orlov if (status)
1541b185f01aSAndrzej Pietrasiewicz return status;
1542b185f01aSAndrzej Pietrasiewicz
1543b185f01aSAndrzej Pietrasiewicz status = alloc_chrdev_region(&devt, 0, count, "USB printer gadget");
1544b185f01aSAndrzej Pietrasiewicz if (status) {
1545b185f01aSAndrzej Pietrasiewicz pr_err("alloc_chrdev_region %d\n", status);
15462c10e7a0SIvan Orlov class_unregister(&usb_gadget_class);
1547b185f01aSAndrzej Pietrasiewicz return status;
1548b185f01aSAndrzej Pietrasiewicz }
1549b185f01aSAndrzej Pietrasiewicz
1550b185f01aSAndrzej Pietrasiewicz major = MAJOR(devt);
1551b185f01aSAndrzej Pietrasiewicz minors = count;
1552b185f01aSAndrzej Pietrasiewicz
1553b185f01aSAndrzej Pietrasiewicz return status;
1554b185f01aSAndrzej Pietrasiewicz }
1555b185f01aSAndrzej Pietrasiewicz
gprinter_cleanup(void)1556b185f01aSAndrzej Pietrasiewicz static void gprinter_cleanup(void)
1557b185f01aSAndrzej Pietrasiewicz {
1558b185f01aSAndrzej Pietrasiewicz if (major) {
1559b185f01aSAndrzej Pietrasiewicz unregister_chrdev_region(MKDEV(major, 0), minors);
1560b185f01aSAndrzej Pietrasiewicz major = minors = 0;
1561b185f01aSAndrzej Pietrasiewicz }
15622c10e7a0SIvan Orlov class_unregister(&usb_gadget_class);
1563b185f01aSAndrzej Pietrasiewicz }
1564