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(&current_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(&current_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