xref: /openbmc/linux/drivers/usb/gadget/legacy/printer.c (revision 8443f2d2b7782fef35fe579bf1eb612c24951486)
1*8443f2d2SAndrzej Pietrasiewicz /*
2*8443f2d2SAndrzej Pietrasiewicz  * printer.c -- Printer gadget driver
3*8443f2d2SAndrzej Pietrasiewicz  *
4*8443f2d2SAndrzej Pietrasiewicz  * Copyright (C) 2003-2005 David Brownell
5*8443f2d2SAndrzej Pietrasiewicz  * Copyright (C) 2006 Craig W. Nadler
6*8443f2d2SAndrzej Pietrasiewicz  *
7*8443f2d2SAndrzej Pietrasiewicz  * This program is free software; you can redistribute it and/or modify
8*8443f2d2SAndrzej Pietrasiewicz  * it under the terms of the GNU General Public License as published by
9*8443f2d2SAndrzej Pietrasiewicz  * the Free Software Foundation; either version 2 of the License, or
10*8443f2d2SAndrzej Pietrasiewicz  * (at your option) any later version.
11*8443f2d2SAndrzej Pietrasiewicz  */
12*8443f2d2SAndrzej Pietrasiewicz 
13*8443f2d2SAndrzej Pietrasiewicz #include <linux/module.h>
14*8443f2d2SAndrzej Pietrasiewicz #include <linux/kernel.h>
15*8443f2d2SAndrzej Pietrasiewicz #include <linux/delay.h>
16*8443f2d2SAndrzej Pietrasiewicz #include <linux/ioport.h>
17*8443f2d2SAndrzej Pietrasiewicz #include <linux/sched.h>
18*8443f2d2SAndrzej Pietrasiewicz #include <linux/slab.h>
19*8443f2d2SAndrzej Pietrasiewicz #include <linux/mutex.h>
20*8443f2d2SAndrzej Pietrasiewicz #include <linux/errno.h>
21*8443f2d2SAndrzej Pietrasiewicz #include <linux/init.h>
22*8443f2d2SAndrzej Pietrasiewicz #include <linux/timer.h>
23*8443f2d2SAndrzej Pietrasiewicz #include <linux/list.h>
24*8443f2d2SAndrzej Pietrasiewicz #include <linux/interrupt.h>
25*8443f2d2SAndrzej Pietrasiewicz #include <linux/device.h>
26*8443f2d2SAndrzej Pietrasiewicz #include <linux/moduleparam.h>
27*8443f2d2SAndrzej Pietrasiewicz #include <linux/fs.h>
28*8443f2d2SAndrzej Pietrasiewicz #include <linux/poll.h>
29*8443f2d2SAndrzej Pietrasiewicz #include <linux/types.h>
30*8443f2d2SAndrzej Pietrasiewicz #include <linux/ctype.h>
31*8443f2d2SAndrzej Pietrasiewicz #include <linux/cdev.h>
32*8443f2d2SAndrzej Pietrasiewicz 
33*8443f2d2SAndrzej Pietrasiewicz #include <asm/byteorder.h>
34*8443f2d2SAndrzej Pietrasiewicz #include <linux/io.h>
35*8443f2d2SAndrzej Pietrasiewicz #include <linux/irq.h>
36*8443f2d2SAndrzej Pietrasiewicz #include <linux/uaccess.h>
37*8443f2d2SAndrzej Pietrasiewicz #include <asm/unaligned.h>
38*8443f2d2SAndrzej Pietrasiewicz 
39*8443f2d2SAndrzej Pietrasiewicz #include <linux/usb/ch9.h>
40*8443f2d2SAndrzej Pietrasiewicz #include <linux/usb/composite.h>
41*8443f2d2SAndrzej Pietrasiewicz #include <linux/usb/gadget.h>
42*8443f2d2SAndrzej Pietrasiewicz #include <linux/usb/g_printer.h>
43*8443f2d2SAndrzej Pietrasiewicz 
44*8443f2d2SAndrzej Pietrasiewicz #include "gadget_chips.h"
45*8443f2d2SAndrzej Pietrasiewicz 
46*8443f2d2SAndrzej Pietrasiewicz USB_GADGET_COMPOSITE_OPTIONS();
47*8443f2d2SAndrzej Pietrasiewicz 
48*8443f2d2SAndrzej Pietrasiewicz #define DRIVER_DESC		"Printer Gadget"
49*8443f2d2SAndrzej Pietrasiewicz #define DRIVER_VERSION		"2007 OCT 06"
50*8443f2d2SAndrzej Pietrasiewicz 
51*8443f2d2SAndrzej Pietrasiewicz static DEFINE_MUTEX(printer_mutex);
52*8443f2d2SAndrzej Pietrasiewicz static const char shortname [] = "printer";
53*8443f2d2SAndrzej Pietrasiewicz static const char driver_desc [] = DRIVER_DESC;
54*8443f2d2SAndrzej Pietrasiewicz 
55*8443f2d2SAndrzej Pietrasiewicz static dev_t g_printer_devno;
56*8443f2d2SAndrzej Pietrasiewicz 
57*8443f2d2SAndrzej Pietrasiewicz static struct class *usb_gadget_class;
58*8443f2d2SAndrzej Pietrasiewicz 
59*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
60*8443f2d2SAndrzej Pietrasiewicz 
61*8443f2d2SAndrzej Pietrasiewicz struct printer_dev {
62*8443f2d2SAndrzej Pietrasiewicz 	spinlock_t		lock;		/* lock this structure */
63*8443f2d2SAndrzej Pietrasiewicz 	/* lock buffer lists during read/write calls */
64*8443f2d2SAndrzej Pietrasiewicz 	struct mutex		lock_printer_io;
65*8443f2d2SAndrzej Pietrasiewicz 	struct usb_gadget	*gadget;
66*8443f2d2SAndrzej Pietrasiewicz 	s8			interface;
67*8443f2d2SAndrzej Pietrasiewicz 	struct usb_ep		*in_ep, *out_ep;
68*8443f2d2SAndrzej Pietrasiewicz 
69*8443f2d2SAndrzej Pietrasiewicz 	struct list_head	rx_reqs;	/* List of free RX structs */
70*8443f2d2SAndrzej Pietrasiewicz 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
71*8443f2d2SAndrzej Pietrasiewicz 	struct list_head	rx_buffers;	/* List of completed xfers */
72*8443f2d2SAndrzej Pietrasiewicz 	/* wait until there is data to be read. */
73*8443f2d2SAndrzej Pietrasiewicz 	wait_queue_head_t	rx_wait;
74*8443f2d2SAndrzej Pietrasiewicz 	struct list_head	tx_reqs;	/* List of free TX structs */
75*8443f2d2SAndrzej Pietrasiewicz 	struct list_head	tx_reqs_active; /* List of Active TX xfers */
76*8443f2d2SAndrzej Pietrasiewicz 	/* Wait until there are write buffers available to use. */
77*8443f2d2SAndrzej Pietrasiewicz 	wait_queue_head_t	tx_wait;
78*8443f2d2SAndrzej Pietrasiewicz 	/* Wait until all write buffers have been sent. */
79*8443f2d2SAndrzej Pietrasiewicz 	wait_queue_head_t	tx_flush_wait;
80*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*current_rx_req;
81*8443f2d2SAndrzej Pietrasiewicz 	size_t			current_rx_bytes;
82*8443f2d2SAndrzej Pietrasiewicz 	u8			*current_rx_buf;
83*8443f2d2SAndrzej Pietrasiewicz 	u8			printer_status;
84*8443f2d2SAndrzej Pietrasiewicz 	u8			reset_printer;
85*8443f2d2SAndrzej Pietrasiewicz 	struct cdev		printer_cdev;
86*8443f2d2SAndrzej Pietrasiewicz 	struct device		*pdev;
87*8443f2d2SAndrzej Pietrasiewicz 	u8			printer_cdev_open;
88*8443f2d2SAndrzej Pietrasiewicz 	wait_queue_head_t	wait;
89*8443f2d2SAndrzej Pietrasiewicz 	struct usb_function	function;
90*8443f2d2SAndrzej Pietrasiewicz };
91*8443f2d2SAndrzej Pietrasiewicz 
92*8443f2d2SAndrzej Pietrasiewicz static struct printer_dev usb_printer_gadget;
93*8443f2d2SAndrzej Pietrasiewicz 
94*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
95*8443f2d2SAndrzej Pietrasiewicz 
96*8443f2d2SAndrzej Pietrasiewicz /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
97*8443f2d2SAndrzej Pietrasiewicz  * Instead:  allocate your own, using normal USB-IF procedures.
98*8443f2d2SAndrzej Pietrasiewicz  */
99*8443f2d2SAndrzej Pietrasiewicz 
100*8443f2d2SAndrzej Pietrasiewicz /* Thanks to NetChip Technologies for donating this product ID.
101*8443f2d2SAndrzej Pietrasiewicz  */
102*8443f2d2SAndrzej Pietrasiewicz #define PRINTER_VENDOR_NUM	0x0525		/* NetChip */
103*8443f2d2SAndrzej Pietrasiewicz #define PRINTER_PRODUCT_NUM	0xa4a8		/* Linux-USB Printer Gadget */
104*8443f2d2SAndrzej Pietrasiewicz 
105*8443f2d2SAndrzej Pietrasiewicz /* Some systems will want different product identifiers published in the
106*8443f2d2SAndrzej Pietrasiewicz  * device descriptor, either numbers or strings or both.  These string
107*8443f2d2SAndrzej Pietrasiewicz  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
108*8443f2d2SAndrzej Pietrasiewicz  */
109*8443f2d2SAndrzej Pietrasiewicz 
110*8443f2d2SAndrzej Pietrasiewicz module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO);
111*8443f2d2SAndrzej Pietrasiewicz MODULE_PARM_DESC(iSerialNum, "1");
112*8443f2d2SAndrzej Pietrasiewicz 
113*8443f2d2SAndrzej Pietrasiewicz static char *iPNPstring;
114*8443f2d2SAndrzej Pietrasiewicz module_param(iPNPstring, charp, S_IRUGO);
115*8443f2d2SAndrzej Pietrasiewicz MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
116*8443f2d2SAndrzej Pietrasiewicz 
117*8443f2d2SAndrzej Pietrasiewicz /* Number of requests to allocate per endpoint, not used for ep0. */
118*8443f2d2SAndrzej Pietrasiewicz static unsigned qlen = 10;
119*8443f2d2SAndrzej Pietrasiewicz module_param(qlen, uint, S_IRUGO|S_IWUSR);
120*8443f2d2SAndrzej Pietrasiewicz 
121*8443f2d2SAndrzej Pietrasiewicz #define QLEN	qlen
122*8443f2d2SAndrzej Pietrasiewicz 
123*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
124*8443f2d2SAndrzej Pietrasiewicz 
125*8443f2d2SAndrzej Pietrasiewicz /*
126*8443f2d2SAndrzej Pietrasiewicz  * DESCRIPTORS ... most are static, but strings and (full) configuration
127*8443f2d2SAndrzej Pietrasiewicz  * descriptors are built on demand.
128*8443f2d2SAndrzej Pietrasiewicz  */
129*8443f2d2SAndrzej Pietrasiewicz 
130*8443f2d2SAndrzej Pietrasiewicz /* holds our biggest descriptor */
131*8443f2d2SAndrzej Pietrasiewicz #define USB_DESC_BUFSIZE		256
132*8443f2d2SAndrzej Pietrasiewicz #define USB_BUFSIZE			8192
133*8443f2d2SAndrzej Pietrasiewicz 
134*8443f2d2SAndrzej Pietrasiewicz static struct usb_device_descriptor device_desc = {
135*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		sizeof device_desc,
136*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_DEVICE,
137*8443f2d2SAndrzej Pietrasiewicz 	.bcdUSB =		cpu_to_le16(0x0200),
138*8443f2d2SAndrzej Pietrasiewicz 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
139*8443f2d2SAndrzej Pietrasiewicz 	.bDeviceSubClass =	0,
140*8443f2d2SAndrzej Pietrasiewicz 	.bDeviceProtocol =	0,
141*8443f2d2SAndrzej Pietrasiewicz 	.idVendor =		cpu_to_le16(PRINTER_VENDOR_NUM),
142*8443f2d2SAndrzej Pietrasiewicz 	.idProduct =		cpu_to_le16(PRINTER_PRODUCT_NUM),
143*8443f2d2SAndrzej Pietrasiewicz 	.bNumConfigurations =	1
144*8443f2d2SAndrzej Pietrasiewicz };
145*8443f2d2SAndrzej Pietrasiewicz 
146*8443f2d2SAndrzej Pietrasiewicz static struct usb_interface_descriptor intf_desc = {
147*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		sizeof intf_desc,
148*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_INTERFACE,
149*8443f2d2SAndrzej Pietrasiewicz 	.bNumEndpoints =	2,
150*8443f2d2SAndrzej Pietrasiewicz 	.bInterfaceClass =	USB_CLASS_PRINTER,
151*8443f2d2SAndrzej Pietrasiewicz 	.bInterfaceSubClass =	1,	/* Printer Sub-Class */
152*8443f2d2SAndrzej Pietrasiewicz 	.bInterfaceProtocol =	2,	/* Bi-Directional */
153*8443f2d2SAndrzej Pietrasiewicz 	.iInterface =		0
154*8443f2d2SAndrzej Pietrasiewicz };
155*8443f2d2SAndrzej Pietrasiewicz 
156*8443f2d2SAndrzej Pietrasiewicz static struct usb_endpoint_descriptor fs_ep_in_desc = {
157*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		USB_DT_ENDPOINT_SIZE,
158*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_ENDPOINT,
159*8443f2d2SAndrzej Pietrasiewicz 	.bEndpointAddress =	USB_DIR_IN,
160*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes =		USB_ENDPOINT_XFER_BULK
161*8443f2d2SAndrzej Pietrasiewicz };
162*8443f2d2SAndrzej Pietrasiewicz 
163*8443f2d2SAndrzej Pietrasiewicz static struct usb_endpoint_descriptor fs_ep_out_desc = {
164*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		USB_DT_ENDPOINT_SIZE,
165*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_ENDPOINT,
166*8443f2d2SAndrzej Pietrasiewicz 	.bEndpointAddress =	USB_DIR_OUT,
167*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes =		USB_ENDPOINT_XFER_BULK
168*8443f2d2SAndrzej Pietrasiewicz };
169*8443f2d2SAndrzej Pietrasiewicz 
170*8443f2d2SAndrzej Pietrasiewicz static struct usb_descriptor_header *fs_printer_function[] = {
171*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &intf_desc,
172*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &fs_ep_in_desc,
173*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &fs_ep_out_desc,
174*8443f2d2SAndrzej Pietrasiewicz 	NULL
175*8443f2d2SAndrzej Pietrasiewicz };
176*8443f2d2SAndrzej Pietrasiewicz 
177*8443f2d2SAndrzej Pietrasiewicz /*
178*8443f2d2SAndrzej Pietrasiewicz  * usb 2.0 devices need to expose both high speed and full speed
179*8443f2d2SAndrzej Pietrasiewicz  * descriptors, unless they only run at full speed.
180*8443f2d2SAndrzej Pietrasiewicz  */
181*8443f2d2SAndrzej Pietrasiewicz 
182*8443f2d2SAndrzej Pietrasiewicz static struct usb_endpoint_descriptor hs_ep_in_desc = {
183*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		USB_DT_ENDPOINT_SIZE,
184*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_ENDPOINT,
185*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
186*8443f2d2SAndrzej Pietrasiewicz 	.wMaxPacketSize =	cpu_to_le16(512)
187*8443f2d2SAndrzej Pietrasiewicz };
188*8443f2d2SAndrzej Pietrasiewicz 
189*8443f2d2SAndrzej Pietrasiewicz static struct usb_endpoint_descriptor hs_ep_out_desc = {
190*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		USB_DT_ENDPOINT_SIZE,
191*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_ENDPOINT,
192*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
193*8443f2d2SAndrzej Pietrasiewicz 	.wMaxPacketSize =	cpu_to_le16(512)
194*8443f2d2SAndrzej Pietrasiewicz };
195*8443f2d2SAndrzej Pietrasiewicz 
196*8443f2d2SAndrzej Pietrasiewicz static struct usb_qualifier_descriptor dev_qualifier = {
197*8443f2d2SAndrzej Pietrasiewicz 	.bLength =		sizeof dev_qualifier,
198*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
199*8443f2d2SAndrzej Pietrasiewicz 	.bcdUSB =		cpu_to_le16(0x0200),
200*8443f2d2SAndrzej Pietrasiewicz 	.bDeviceClass =		USB_CLASS_PRINTER,
201*8443f2d2SAndrzej Pietrasiewicz 	.bNumConfigurations =	1
202*8443f2d2SAndrzej Pietrasiewicz };
203*8443f2d2SAndrzej Pietrasiewicz 
204*8443f2d2SAndrzej Pietrasiewicz static struct usb_descriptor_header *hs_printer_function[] = {
205*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &intf_desc,
206*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &hs_ep_in_desc,
207*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &hs_ep_out_desc,
208*8443f2d2SAndrzej Pietrasiewicz 	NULL
209*8443f2d2SAndrzej Pietrasiewicz };
210*8443f2d2SAndrzej Pietrasiewicz 
211*8443f2d2SAndrzej Pietrasiewicz static struct usb_otg_descriptor otg_descriptor = {
212*8443f2d2SAndrzej Pietrasiewicz 	.bLength =              sizeof otg_descriptor,
213*8443f2d2SAndrzej Pietrasiewicz 	.bDescriptorType =      USB_DT_OTG,
214*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes =         USB_OTG_SRP,
215*8443f2d2SAndrzej Pietrasiewicz };
216*8443f2d2SAndrzej Pietrasiewicz 
217*8443f2d2SAndrzej Pietrasiewicz static const struct usb_descriptor_header *otg_desc[] = {
218*8443f2d2SAndrzej Pietrasiewicz 	(struct usb_descriptor_header *) &otg_descriptor,
219*8443f2d2SAndrzej Pietrasiewicz 	NULL,
220*8443f2d2SAndrzej Pietrasiewicz };
221*8443f2d2SAndrzej Pietrasiewicz 
222*8443f2d2SAndrzej Pietrasiewicz /* maxpacket and other transfer characteristics vary by speed. */
223*8443f2d2SAndrzej Pietrasiewicz #define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
224*8443f2d2SAndrzej Pietrasiewicz 
225*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
226*8443f2d2SAndrzej Pietrasiewicz 
227*8443f2d2SAndrzej Pietrasiewicz /* descriptors that are built on-demand */
228*8443f2d2SAndrzej Pietrasiewicz 
229*8443f2d2SAndrzej Pietrasiewicz static char				product_desc [40] = DRIVER_DESC;
230*8443f2d2SAndrzej Pietrasiewicz static char				serial_num [40] = "1";
231*8443f2d2SAndrzej Pietrasiewicz static char				pnp_string [1024] =
232*8443f2d2SAndrzej Pietrasiewicz 	"XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
233*8443f2d2SAndrzej Pietrasiewicz 
234*8443f2d2SAndrzej Pietrasiewicz /* static strings, in UTF-8 */
235*8443f2d2SAndrzej Pietrasiewicz static struct usb_string		strings [] = {
236*8443f2d2SAndrzej Pietrasiewicz 	[USB_GADGET_MANUFACTURER_IDX].s = "",
237*8443f2d2SAndrzej Pietrasiewicz 	[USB_GADGET_PRODUCT_IDX].s = product_desc,
238*8443f2d2SAndrzej Pietrasiewicz 	[USB_GADGET_SERIAL_IDX].s =	serial_num,
239*8443f2d2SAndrzej Pietrasiewicz 	{  }		/* end of list */
240*8443f2d2SAndrzej Pietrasiewicz };
241*8443f2d2SAndrzej Pietrasiewicz 
242*8443f2d2SAndrzej Pietrasiewicz static struct usb_gadget_strings	stringtab_dev = {
243*8443f2d2SAndrzej Pietrasiewicz 	.language	= 0x0409,	/* en-us */
244*8443f2d2SAndrzej Pietrasiewicz 	.strings	= strings,
245*8443f2d2SAndrzej Pietrasiewicz };
246*8443f2d2SAndrzej Pietrasiewicz 
247*8443f2d2SAndrzej Pietrasiewicz static struct usb_gadget_strings *dev_strings[] = {
248*8443f2d2SAndrzej Pietrasiewicz 	&stringtab_dev,
249*8443f2d2SAndrzej Pietrasiewicz 	NULL,
250*8443f2d2SAndrzej Pietrasiewicz };
251*8443f2d2SAndrzej Pietrasiewicz 
252*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
253*8443f2d2SAndrzej Pietrasiewicz 
254*8443f2d2SAndrzej Pietrasiewicz static struct usb_request *
255*8443f2d2SAndrzej Pietrasiewicz printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
256*8443f2d2SAndrzej Pietrasiewicz {
257*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req;
258*8443f2d2SAndrzej Pietrasiewicz 
259*8443f2d2SAndrzej Pietrasiewicz 	req = usb_ep_alloc_request(ep, gfp_flags);
260*8443f2d2SAndrzej Pietrasiewicz 
261*8443f2d2SAndrzej Pietrasiewicz 	if (req != NULL) {
262*8443f2d2SAndrzej Pietrasiewicz 		req->length = len;
263*8443f2d2SAndrzej Pietrasiewicz 		req->buf = kmalloc(len, gfp_flags);
264*8443f2d2SAndrzej Pietrasiewicz 		if (req->buf == NULL) {
265*8443f2d2SAndrzej Pietrasiewicz 			usb_ep_free_request(ep, req);
266*8443f2d2SAndrzej Pietrasiewicz 			return NULL;
267*8443f2d2SAndrzej Pietrasiewicz 		}
268*8443f2d2SAndrzej Pietrasiewicz 	}
269*8443f2d2SAndrzej Pietrasiewicz 
270*8443f2d2SAndrzej Pietrasiewicz 	return req;
271*8443f2d2SAndrzej Pietrasiewicz }
272*8443f2d2SAndrzej Pietrasiewicz 
273*8443f2d2SAndrzej Pietrasiewicz static void
274*8443f2d2SAndrzej Pietrasiewicz printer_req_free(struct usb_ep *ep, struct usb_request *req)
275*8443f2d2SAndrzej Pietrasiewicz {
276*8443f2d2SAndrzej Pietrasiewicz 	if (ep != NULL && req != NULL) {
277*8443f2d2SAndrzej Pietrasiewicz 		kfree(req->buf);
278*8443f2d2SAndrzej Pietrasiewicz 		usb_ep_free_request(ep, req);
279*8443f2d2SAndrzej Pietrasiewicz 	}
280*8443f2d2SAndrzej Pietrasiewicz }
281*8443f2d2SAndrzej Pietrasiewicz 
282*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
283*8443f2d2SAndrzej Pietrasiewicz 
284*8443f2d2SAndrzej Pietrasiewicz static void rx_complete(struct usb_ep *ep, struct usb_request *req)
285*8443f2d2SAndrzej Pietrasiewicz {
286*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = ep->driver_data;
287*8443f2d2SAndrzej Pietrasiewicz 	int			status = req->status;
288*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
289*8443f2d2SAndrzej Pietrasiewicz 
290*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
291*8443f2d2SAndrzej Pietrasiewicz 
292*8443f2d2SAndrzej Pietrasiewicz 	list_del_init(&req->list);	/* Remode from Active List */
293*8443f2d2SAndrzej Pietrasiewicz 
294*8443f2d2SAndrzej Pietrasiewicz 	switch (status) {
295*8443f2d2SAndrzej Pietrasiewicz 
296*8443f2d2SAndrzej Pietrasiewicz 	/* normal completion */
297*8443f2d2SAndrzej Pietrasiewicz 	case 0:
298*8443f2d2SAndrzej Pietrasiewicz 		if (req->actual > 0) {
299*8443f2d2SAndrzej Pietrasiewicz 			list_add_tail(&req->list, &dev->rx_buffers);
300*8443f2d2SAndrzej Pietrasiewicz 			DBG(dev, "G_Printer : rx length %d\n", req->actual);
301*8443f2d2SAndrzej Pietrasiewicz 		} else {
302*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->rx_reqs);
303*8443f2d2SAndrzej Pietrasiewicz 		}
304*8443f2d2SAndrzej Pietrasiewicz 		break;
305*8443f2d2SAndrzej Pietrasiewicz 
306*8443f2d2SAndrzej Pietrasiewicz 	/* software-driven interface shutdown */
307*8443f2d2SAndrzej Pietrasiewicz 	case -ECONNRESET:		/* unlink */
308*8443f2d2SAndrzej Pietrasiewicz 	case -ESHUTDOWN:		/* disconnect etc */
309*8443f2d2SAndrzej Pietrasiewicz 		VDBG(dev, "rx shutdown, code %d\n", status);
310*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
311*8443f2d2SAndrzej Pietrasiewicz 		break;
312*8443f2d2SAndrzej Pietrasiewicz 
313*8443f2d2SAndrzej Pietrasiewicz 	/* for hardware automagic (such as pxa) */
314*8443f2d2SAndrzej Pietrasiewicz 	case -ECONNABORTED:		/* endpoint reset */
315*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "rx %s reset\n", ep->name);
316*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
317*8443f2d2SAndrzej Pietrasiewicz 		break;
318*8443f2d2SAndrzej Pietrasiewicz 
319*8443f2d2SAndrzej Pietrasiewicz 	/* data overrun */
320*8443f2d2SAndrzej Pietrasiewicz 	case -EOVERFLOW:
321*8443f2d2SAndrzej Pietrasiewicz 		/* FALLTHROUGH */
322*8443f2d2SAndrzej Pietrasiewicz 
323*8443f2d2SAndrzej Pietrasiewicz 	default:
324*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "rx status %d\n", status);
325*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
326*8443f2d2SAndrzej Pietrasiewicz 		break;
327*8443f2d2SAndrzej Pietrasiewicz 	}
328*8443f2d2SAndrzej Pietrasiewicz 
329*8443f2d2SAndrzej Pietrasiewicz 	wake_up_interruptible(&dev->rx_wait);
330*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
331*8443f2d2SAndrzej Pietrasiewicz }
332*8443f2d2SAndrzej Pietrasiewicz 
333*8443f2d2SAndrzej Pietrasiewicz static void tx_complete(struct usb_ep *ep, struct usb_request *req)
334*8443f2d2SAndrzej Pietrasiewicz {
335*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = ep->driver_data;
336*8443f2d2SAndrzej Pietrasiewicz 
337*8443f2d2SAndrzej Pietrasiewicz 	switch (req->status) {
338*8443f2d2SAndrzej Pietrasiewicz 	default:
339*8443f2d2SAndrzej Pietrasiewicz 		VDBG(dev, "tx err %d\n", req->status);
340*8443f2d2SAndrzej Pietrasiewicz 		/* FALLTHROUGH */
341*8443f2d2SAndrzej Pietrasiewicz 	case -ECONNRESET:		/* unlink */
342*8443f2d2SAndrzej Pietrasiewicz 	case -ESHUTDOWN:		/* disconnect etc */
343*8443f2d2SAndrzej Pietrasiewicz 		break;
344*8443f2d2SAndrzej Pietrasiewicz 	case 0:
345*8443f2d2SAndrzej Pietrasiewicz 		break;
346*8443f2d2SAndrzej Pietrasiewicz 	}
347*8443f2d2SAndrzej Pietrasiewicz 
348*8443f2d2SAndrzej Pietrasiewicz 	spin_lock(&dev->lock);
349*8443f2d2SAndrzej Pietrasiewicz 	/* Take the request struct off the active list and put it on the
350*8443f2d2SAndrzej Pietrasiewicz 	 * free list.
351*8443f2d2SAndrzej Pietrasiewicz 	 */
352*8443f2d2SAndrzej Pietrasiewicz 	list_del_init(&req->list);
353*8443f2d2SAndrzej Pietrasiewicz 	list_add(&req->list, &dev->tx_reqs);
354*8443f2d2SAndrzej Pietrasiewicz 	wake_up_interruptible(&dev->tx_wait);
355*8443f2d2SAndrzej Pietrasiewicz 	if (likely(list_empty(&dev->tx_reqs_active)))
356*8443f2d2SAndrzej Pietrasiewicz 		wake_up_interruptible(&dev->tx_flush_wait);
357*8443f2d2SAndrzej Pietrasiewicz 
358*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock(&dev->lock);
359*8443f2d2SAndrzej Pietrasiewicz }
360*8443f2d2SAndrzej Pietrasiewicz 
361*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
362*8443f2d2SAndrzej Pietrasiewicz 
363*8443f2d2SAndrzej Pietrasiewicz static int
364*8443f2d2SAndrzej Pietrasiewicz printer_open(struct inode *inode, struct file *fd)
365*8443f2d2SAndrzej Pietrasiewicz {
366*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev;
367*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
368*8443f2d2SAndrzej Pietrasiewicz 	int			ret = -EBUSY;
369*8443f2d2SAndrzej Pietrasiewicz 
370*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&printer_mutex);
371*8443f2d2SAndrzej Pietrasiewicz 	dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
372*8443f2d2SAndrzej Pietrasiewicz 
373*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
374*8443f2d2SAndrzej Pietrasiewicz 
375*8443f2d2SAndrzej Pietrasiewicz 	if (!dev->printer_cdev_open) {
376*8443f2d2SAndrzej Pietrasiewicz 		dev->printer_cdev_open = 1;
377*8443f2d2SAndrzej Pietrasiewicz 		fd->private_data = dev;
378*8443f2d2SAndrzej Pietrasiewicz 		ret = 0;
379*8443f2d2SAndrzej Pietrasiewicz 		/* Change the printer status to show that it's on-line. */
380*8443f2d2SAndrzej Pietrasiewicz 		dev->printer_status |= PRINTER_SELECTED;
381*8443f2d2SAndrzej Pietrasiewicz 	}
382*8443f2d2SAndrzej Pietrasiewicz 
383*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
384*8443f2d2SAndrzej Pietrasiewicz 
385*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_open returned %x\n", ret);
386*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&printer_mutex);
387*8443f2d2SAndrzej Pietrasiewicz 	return ret;
388*8443f2d2SAndrzej Pietrasiewicz }
389*8443f2d2SAndrzej Pietrasiewicz 
390*8443f2d2SAndrzej Pietrasiewicz static int
391*8443f2d2SAndrzej Pietrasiewicz printer_close(struct inode *inode, struct file *fd)
392*8443f2d2SAndrzej Pietrasiewicz {
393*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = fd->private_data;
394*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
395*8443f2d2SAndrzej Pietrasiewicz 
396*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
397*8443f2d2SAndrzej Pietrasiewicz 	dev->printer_cdev_open = 0;
398*8443f2d2SAndrzej Pietrasiewicz 	fd->private_data = NULL;
399*8443f2d2SAndrzej Pietrasiewicz 	/* Change printer status to show that the printer is off-line. */
400*8443f2d2SAndrzej Pietrasiewicz 	dev->printer_status &= ~PRINTER_SELECTED;
401*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
402*8443f2d2SAndrzej Pietrasiewicz 
403*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_close\n");
404*8443f2d2SAndrzej Pietrasiewicz 
405*8443f2d2SAndrzej Pietrasiewicz 	return 0;
406*8443f2d2SAndrzej Pietrasiewicz }
407*8443f2d2SAndrzej Pietrasiewicz 
408*8443f2d2SAndrzej Pietrasiewicz /* This function must be called with interrupts turned off. */
409*8443f2d2SAndrzej Pietrasiewicz static void
410*8443f2d2SAndrzej Pietrasiewicz setup_rx_reqs(struct printer_dev *dev)
411*8443f2d2SAndrzej Pietrasiewicz {
412*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request              *req;
413*8443f2d2SAndrzej Pietrasiewicz 
414*8443f2d2SAndrzej Pietrasiewicz 	while (likely(!list_empty(&dev->rx_reqs))) {
415*8443f2d2SAndrzej Pietrasiewicz 		int error;
416*8443f2d2SAndrzej Pietrasiewicz 
417*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->rx_reqs.next,
418*8443f2d2SAndrzej Pietrasiewicz 				struct usb_request, list);
419*8443f2d2SAndrzej Pietrasiewicz 		list_del_init(&req->list);
420*8443f2d2SAndrzej Pietrasiewicz 
421*8443f2d2SAndrzej Pietrasiewicz 		/* The USB Host sends us whatever amount of data it wants to
422*8443f2d2SAndrzej Pietrasiewicz 		 * so we always set the length field to the full USB_BUFSIZE.
423*8443f2d2SAndrzej Pietrasiewicz 		 * If the amount of data is more than the read() caller asked
424*8443f2d2SAndrzej Pietrasiewicz 		 * for it will be stored in the request buffer until it is
425*8443f2d2SAndrzej Pietrasiewicz 		 * asked for by read().
426*8443f2d2SAndrzej Pietrasiewicz 		 */
427*8443f2d2SAndrzej Pietrasiewicz 		req->length = USB_BUFSIZE;
428*8443f2d2SAndrzej Pietrasiewicz 		req->complete = rx_complete;
429*8443f2d2SAndrzej Pietrasiewicz 
430*8443f2d2SAndrzej Pietrasiewicz 		/* here, we unlock, and only unlock, to avoid deadlock. */
431*8443f2d2SAndrzej Pietrasiewicz 		spin_unlock(&dev->lock);
432*8443f2d2SAndrzej Pietrasiewicz 		error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
433*8443f2d2SAndrzej Pietrasiewicz 		spin_lock(&dev->lock);
434*8443f2d2SAndrzej Pietrasiewicz 		if (error) {
435*8443f2d2SAndrzej Pietrasiewicz 			DBG(dev, "rx submit --> %d\n", error);
436*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->rx_reqs);
437*8443f2d2SAndrzej Pietrasiewicz 			break;
438*8443f2d2SAndrzej Pietrasiewicz 		}
439*8443f2d2SAndrzej Pietrasiewicz 		/* if the req is empty, then add it into dev->rx_reqs_active. */
440*8443f2d2SAndrzej Pietrasiewicz 		else if (list_empty(&req->list)) {
441*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->rx_reqs_active);
442*8443f2d2SAndrzej Pietrasiewicz 		}
443*8443f2d2SAndrzej Pietrasiewicz 	}
444*8443f2d2SAndrzej Pietrasiewicz }
445*8443f2d2SAndrzej Pietrasiewicz 
446*8443f2d2SAndrzej Pietrasiewicz static ssize_t
447*8443f2d2SAndrzej Pietrasiewicz printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
448*8443f2d2SAndrzej Pietrasiewicz {
449*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev		*dev = fd->private_data;
450*8443f2d2SAndrzej Pietrasiewicz 	unsigned long			flags;
451*8443f2d2SAndrzej Pietrasiewicz 	size_t				size;
452*8443f2d2SAndrzej Pietrasiewicz 	size_t				bytes_copied;
453*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request		*req;
454*8443f2d2SAndrzej Pietrasiewicz 	/* This is a pointer to the current USB rx request. */
455*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request		*current_rx_req;
456*8443f2d2SAndrzej Pietrasiewicz 	/* This is the number of bytes in the current rx buffer. */
457*8443f2d2SAndrzej Pietrasiewicz 	size_t				current_rx_bytes;
458*8443f2d2SAndrzej Pietrasiewicz 	/* This is a pointer to the current rx buffer. */
459*8443f2d2SAndrzej Pietrasiewicz 	u8				*current_rx_buf;
460*8443f2d2SAndrzej Pietrasiewicz 
461*8443f2d2SAndrzej Pietrasiewicz 	if (len == 0)
462*8443f2d2SAndrzej Pietrasiewicz 		return -EINVAL;
463*8443f2d2SAndrzej Pietrasiewicz 
464*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
465*8443f2d2SAndrzej Pietrasiewicz 
466*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&dev->lock_printer_io);
467*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
468*8443f2d2SAndrzej Pietrasiewicz 
469*8443f2d2SAndrzej Pietrasiewicz 	/* We will use this flag later to check if a printer reset happened
470*8443f2d2SAndrzej Pietrasiewicz 	 * after we turn interrupts back on.
471*8443f2d2SAndrzej Pietrasiewicz 	 */
472*8443f2d2SAndrzej Pietrasiewicz 	dev->reset_printer = 0;
473*8443f2d2SAndrzej Pietrasiewicz 
474*8443f2d2SAndrzej Pietrasiewicz 	setup_rx_reqs(dev);
475*8443f2d2SAndrzej Pietrasiewicz 
476*8443f2d2SAndrzej Pietrasiewicz 	bytes_copied = 0;
477*8443f2d2SAndrzej Pietrasiewicz 	current_rx_req = dev->current_rx_req;
478*8443f2d2SAndrzej Pietrasiewicz 	current_rx_bytes = dev->current_rx_bytes;
479*8443f2d2SAndrzej Pietrasiewicz 	current_rx_buf = dev->current_rx_buf;
480*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_req = NULL;
481*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_bytes = 0;
482*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_buf = NULL;
483*8443f2d2SAndrzej Pietrasiewicz 
484*8443f2d2SAndrzej Pietrasiewicz 	/* Check if there is any data in the read buffers. Please note that
485*8443f2d2SAndrzej Pietrasiewicz 	 * current_rx_bytes is the number of bytes in the current rx buffer.
486*8443f2d2SAndrzej Pietrasiewicz 	 * If it is zero then check if there are any other rx_buffers that
487*8443f2d2SAndrzej Pietrasiewicz 	 * are on the completed list. We are only out of data if all rx
488*8443f2d2SAndrzej Pietrasiewicz 	 * buffers are empty.
489*8443f2d2SAndrzej Pietrasiewicz 	 */
490*8443f2d2SAndrzej Pietrasiewicz 	if ((current_rx_bytes == 0) &&
491*8443f2d2SAndrzej Pietrasiewicz 			(likely(list_empty(&dev->rx_buffers)))) {
492*8443f2d2SAndrzej Pietrasiewicz 		/* Turn interrupts back on before sleeping. */
493*8443f2d2SAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&dev->lock, flags);
494*8443f2d2SAndrzej Pietrasiewicz 
495*8443f2d2SAndrzej Pietrasiewicz 		/*
496*8443f2d2SAndrzej Pietrasiewicz 		 * If no data is available check if this is a NON-Blocking
497*8443f2d2SAndrzej Pietrasiewicz 		 * call or not.
498*8443f2d2SAndrzej Pietrasiewicz 		 */
499*8443f2d2SAndrzej Pietrasiewicz 		if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
500*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
501*8443f2d2SAndrzej Pietrasiewicz 			return -EAGAIN;
502*8443f2d2SAndrzej Pietrasiewicz 		}
503*8443f2d2SAndrzej Pietrasiewicz 
504*8443f2d2SAndrzej Pietrasiewicz 		/* Sleep until data is available */
505*8443f2d2SAndrzej Pietrasiewicz 		wait_event_interruptible(dev->rx_wait,
506*8443f2d2SAndrzej Pietrasiewicz 				(likely(!list_empty(&dev->rx_buffers))));
507*8443f2d2SAndrzej Pietrasiewicz 		spin_lock_irqsave(&dev->lock, flags);
508*8443f2d2SAndrzej Pietrasiewicz 	}
509*8443f2d2SAndrzej Pietrasiewicz 
510*8443f2d2SAndrzej Pietrasiewicz 	/* We have data to return then copy it to the caller's buffer.*/
511*8443f2d2SAndrzej Pietrasiewicz 	while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
512*8443f2d2SAndrzej Pietrasiewicz 			&& len) {
513*8443f2d2SAndrzej Pietrasiewicz 		if (current_rx_bytes == 0) {
514*8443f2d2SAndrzej Pietrasiewicz 			req = container_of(dev->rx_buffers.next,
515*8443f2d2SAndrzej Pietrasiewicz 					struct usb_request, list);
516*8443f2d2SAndrzej Pietrasiewicz 			list_del_init(&req->list);
517*8443f2d2SAndrzej Pietrasiewicz 
518*8443f2d2SAndrzej Pietrasiewicz 			if (req->actual && req->buf) {
519*8443f2d2SAndrzej Pietrasiewicz 				current_rx_req = req;
520*8443f2d2SAndrzej Pietrasiewicz 				current_rx_bytes = req->actual;
521*8443f2d2SAndrzej Pietrasiewicz 				current_rx_buf = req->buf;
522*8443f2d2SAndrzej Pietrasiewicz 			} else {
523*8443f2d2SAndrzej Pietrasiewicz 				list_add(&req->list, &dev->rx_reqs);
524*8443f2d2SAndrzej Pietrasiewicz 				continue;
525*8443f2d2SAndrzej Pietrasiewicz 			}
526*8443f2d2SAndrzej Pietrasiewicz 		}
527*8443f2d2SAndrzej Pietrasiewicz 
528*8443f2d2SAndrzej Pietrasiewicz 		/* Don't leave irqs off while doing memory copies */
529*8443f2d2SAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&dev->lock, flags);
530*8443f2d2SAndrzej Pietrasiewicz 
531*8443f2d2SAndrzej Pietrasiewicz 		if (len > current_rx_bytes)
532*8443f2d2SAndrzej Pietrasiewicz 			size = current_rx_bytes;
533*8443f2d2SAndrzej Pietrasiewicz 		else
534*8443f2d2SAndrzej Pietrasiewicz 			size = len;
535*8443f2d2SAndrzej Pietrasiewicz 
536*8443f2d2SAndrzej Pietrasiewicz 		size -= copy_to_user(buf, current_rx_buf, size);
537*8443f2d2SAndrzej Pietrasiewicz 		bytes_copied += size;
538*8443f2d2SAndrzej Pietrasiewicz 		len -= size;
539*8443f2d2SAndrzej Pietrasiewicz 		buf += size;
540*8443f2d2SAndrzej Pietrasiewicz 
541*8443f2d2SAndrzej Pietrasiewicz 		spin_lock_irqsave(&dev->lock, flags);
542*8443f2d2SAndrzej Pietrasiewicz 
543*8443f2d2SAndrzej Pietrasiewicz 		/* We've disconnected or reset so return. */
544*8443f2d2SAndrzej Pietrasiewicz 		if (dev->reset_printer) {
545*8443f2d2SAndrzej Pietrasiewicz 			list_add(&current_rx_req->list, &dev->rx_reqs);
546*8443f2d2SAndrzej Pietrasiewicz 			spin_unlock_irqrestore(&dev->lock, flags);
547*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
548*8443f2d2SAndrzej Pietrasiewicz 			return -EAGAIN;
549*8443f2d2SAndrzej Pietrasiewicz 		}
550*8443f2d2SAndrzej Pietrasiewicz 
551*8443f2d2SAndrzej Pietrasiewicz 		/* If we not returning all the data left in this RX request
552*8443f2d2SAndrzej Pietrasiewicz 		 * buffer then adjust the amount of data left in the buffer.
553*8443f2d2SAndrzej Pietrasiewicz 		 * Othewise if we are done with this RX request buffer then
554*8443f2d2SAndrzej Pietrasiewicz 		 * requeue it to get any incoming data from the USB host.
555*8443f2d2SAndrzej Pietrasiewicz 		 */
556*8443f2d2SAndrzej Pietrasiewicz 		if (size < current_rx_bytes) {
557*8443f2d2SAndrzej Pietrasiewicz 			current_rx_bytes -= size;
558*8443f2d2SAndrzej Pietrasiewicz 			current_rx_buf += size;
559*8443f2d2SAndrzej Pietrasiewicz 		} else {
560*8443f2d2SAndrzej Pietrasiewicz 			list_add(&current_rx_req->list, &dev->rx_reqs);
561*8443f2d2SAndrzej Pietrasiewicz 			current_rx_bytes = 0;
562*8443f2d2SAndrzej Pietrasiewicz 			current_rx_buf = NULL;
563*8443f2d2SAndrzej Pietrasiewicz 			current_rx_req = NULL;
564*8443f2d2SAndrzej Pietrasiewicz 		}
565*8443f2d2SAndrzej Pietrasiewicz 	}
566*8443f2d2SAndrzej Pietrasiewicz 
567*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_req = current_rx_req;
568*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_bytes = current_rx_bytes;
569*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_buf = current_rx_buf;
570*8443f2d2SAndrzej Pietrasiewicz 
571*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
572*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&dev->lock_printer_io);
573*8443f2d2SAndrzej Pietrasiewicz 
574*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
575*8443f2d2SAndrzej Pietrasiewicz 
576*8443f2d2SAndrzej Pietrasiewicz 	if (bytes_copied)
577*8443f2d2SAndrzej Pietrasiewicz 		return bytes_copied;
578*8443f2d2SAndrzej Pietrasiewicz 	else
579*8443f2d2SAndrzej Pietrasiewicz 		return -EAGAIN;
580*8443f2d2SAndrzej Pietrasiewicz }
581*8443f2d2SAndrzej Pietrasiewicz 
582*8443f2d2SAndrzej Pietrasiewicz static ssize_t
583*8443f2d2SAndrzej Pietrasiewicz printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
584*8443f2d2SAndrzej Pietrasiewicz {
585*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = fd->private_data;
586*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
587*8443f2d2SAndrzej Pietrasiewicz 	size_t			size;	/* Amount of data in a TX request. */
588*8443f2d2SAndrzej Pietrasiewicz 	size_t			bytes_copied = 0;
589*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req;
590*8443f2d2SAndrzej Pietrasiewicz 
591*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
592*8443f2d2SAndrzej Pietrasiewicz 
593*8443f2d2SAndrzej Pietrasiewicz 	if (len == 0)
594*8443f2d2SAndrzej Pietrasiewicz 		return -EINVAL;
595*8443f2d2SAndrzej Pietrasiewicz 
596*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&dev->lock_printer_io);
597*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
598*8443f2d2SAndrzej Pietrasiewicz 
599*8443f2d2SAndrzej Pietrasiewicz 	/* Check if a printer reset happens while we have interrupts on */
600*8443f2d2SAndrzej Pietrasiewicz 	dev->reset_printer = 0;
601*8443f2d2SAndrzej Pietrasiewicz 
602*8443f2d2SAndrzej Pietrasiewicz 	/* Check if there is any available write buffers */
603*8443f2d2SAndrzej Pietrasiewicz 	if (likely(list_empty(&dev->tx_reqs))) {
604*8443f2d2SAndrzej Pietrasiewicz 		/* Turn interrupts back on before sleeping. */
605*8443f2d2SAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&dev->lock, flags);
606*8443f2d2SAndrzej Pietrasiewicz 
607*8443f2d2SAndrzej Pietrasiewicz 		/*
608*8443f2d2SAndrzej Pietrasiewicz 		 * If write buffers are available check if this is
609*8443f2d2SAndrzej Pietrasiewicz 		 * a NON-Blocking call or not.
610*8443f2d2SAndrzej Pietrasiewicz 		 */
611*8443f2d2SAndrzej Pietrasiewicz 		if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
612*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
613*8443f2d2SAndrzej Pietrasiewicz 			return -EAGAIN;
614*8443f2d2SAndrzej Pietrasiewicz 		}
615*8443f2d2SAndrzej Pietrasiewicz 
616*8443f2d2SAndrzej Pietrasiewicz 		/* Sleep until a write buffer is available */
617*8443f2d2SAndrzej Pietrasiewicz 		wait_event_interruptible(dev->tx_wait,
618*8443f2d2SAndrzej Pietrasiewicz 				(likely(!list_empty(&dev->tx_reqs))));
619*8443f2d2SAndrzej Pietrasiewicz 		spin_lock_irqsave(&dev->lock, flags);
620*8443f2d2SAndrzej Pietrasiewicz 	}
621*8443f2d2SAndrzej Pietrasiewicz 
622*8443f2d2SAndrzej Pietrasiewicz 	while (likely(!list_empty(&dev->tx_reqs)) && len) {
623*8443f2d2SAndrzej Pietrasiewicz 
624*8443f2d2SAndrzej Pietrasiewicz 		if (len > USB_BUFSIZE)
625*8443f2d2SAndrzej Pietrasiewicz 			size = USB_BUFSIZE;
626*8443f2d2SAndrzej Pietrasiewicz 		else
627*8443f2d2SAndrzej Pietrasiewicz 			size = len;
628*8443f2d2SAndrzej Pietrasiewicz 
629*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->tx_reqs.next, struct usb_request,
630*8443f2d2SAndrzej Pietrasiewicz 				list);
631*8443f2d2SAndrzej Pietrasiewicz 		list_del_init(&req->list);
632*8443f2d2SAndrzej Pietrasiewicz 
633*8443f2d2SAndrzej Pietrasiewicz 		req->complete = tx_complete;
634*8443f2d2SAndrzej Pietrasiewicz 		req->length = size;
635*8443f2d2SAndrzej Pietrasiewicz 
636*8443f2d2SAndrzej Pietrasiewicz 		/* Check if we need to send a zero length packet. */
637*8443f2d2SAndrzej Pietrasiewicz 		if (len > size)
638*8443f2d2SAndrzej Pietrasiewicz 			/* They will be more TX requests so no yet. */
639*8443f2d2SAndrzej Pietrasiewicz 			req->zero = 0;
640*8443f2d2SAndrzej Pietrasiewicz 		else
641*8443f2d2SAndrzej Pietrasiewicz 			/* If the data amount is not a multple of the
642*8443f2d2SAndrzej Pietrasiewicz 			 * maxpacket size then send a zero length packet.
643*8443f2d2SAndrzej Pietrasiewicz 			 */
644*8443f2d2SAndrzej Pietrasiewicz 			req->zero = ((len % dev->in_ep->maxpacket) == 0);
645*8443f2d2SAndrzej Pietrasiewicz 
646*8443f2d2SAndrzej Pietrasiewicz 		/* Don't leave irqs off while doing memory copies */
647*8443f2d2SAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&dev->lock, flags);
648*8443f2d2SAndrzej Pietrasiewicz 
649*8443f2d2SAndrzej Pietrasiewicz 		if (copy_from_user(req->buf, buf, size)) {
650*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->tx_reqs);
651*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
652*8443f2d2SAndrzej Pietrasiewicz 			return bytes_copied;
653*8443f2d2SAndrzej Pietrasiewicz 		}
654*8443f2d2SAndrzej Pietrasiewicz 
655*8443f2d2SAndrzej Pietrasiewicz 		bytes_copied += size;
656*8443f2d2SAndrzej Pietrasiewicz 		len -= size;
657*8443f2d2SAndrzej Pietrasiewicz 		buf += size;
658*8443f2d2SAndrzej Pietrasiewicz 
659*8443f2d2SAndrzej Pietrasiewicz 		spin_lock_irqsave(&dev->lock, flags);
660*8443f2d2SAndrzej Pietrasiewicz 
661*8443f2d2SAndrzej Pietrasiewicz 		/* We've disconnected or reset so free the req and buffer */
662*8443f2d2SAndrzej Pietrasiewicz 		if (dev->reset_printer) {
663*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->tx_reqs);
664*8443f2d2SAndrzej Pietrasiewicz 			spin_unlock_irqrestore(&dev->lock, flags);
665*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
666*8443f2d2SAndrzej Pietrasiewicz 			return -EAGAIN;
667*8443f2d2SAndrzej Pietrasiewicz 		}
668*8443f2d2SAndrzej Pietrasiewicz 
669*8443f2d2SAndrzej Pietrasiewicz 		if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
670*8443f2d2SAndrzej Pietrasiewicz 			list_add(&req->list, &dev->tx_reqs);
671*8443f2d2SAndrzej Pietrasiewicz 			spin_unlock_irqrestore(&dev->lock, flags);
672*8443f2d2SAndrzej Pietrasiewicz 			mutex_unlock(&dev->lock_printer_io);
673*8443f2d2SAndrzej Pietrasiewicz 			return -EAGAIN;
674*8443f2d2SAndrzej Pietrasiewicz 		}
675*8443f2d2SAndrzej Pietrasiewicz 
676*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->tx_reqs_active);
677*8443f2d2SAndrzej Pietrasiewicz 
678*8443f2d2SAndrzej Pietrasiewicz 	}
679*8443f2d2SAndrzej Pietrasiewicz 
680*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
681*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&dev->lock_printer_io);
682*8443f2d2SAndrzej Pietrasiewicz 
683*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
684*8443f2d2SAndrzej Pietrasiewicz 
685*8443f2d2SAndrzej Pietrasiewicz 	if (bytes_copied) {
686*8443f2d2SAndrzej Pietrasiewicz 		return bytes_copied;
687*8443f2d2SAndrzej Pietrasiewicz 	} else {
688*8443f2d2SAndrzej Pietrasiewicz 		return -EAGAIN;
689*8443f2d2SAndrzej Pietrasiewicz 	}
690*8443f2d2SAndrzej Pietrasiewicz }
691*8443f2d2SAndrzej Pietrasiewicz 
692*8443f2d2SAndrzej Pietrasiewicz static int
693*8443f2d2SAndrzej Pietrasiewicz printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
694*8443f2d2SAndrzej Pietrasiewicz {
695*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = fd->private_data;
696*8443f2d2SAndrzej Pietrasiewicz 	struct inode *inode = file_inode(fd);
697*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
698*8443f2d2SAndrzej Pietrasiewicz 	int			tx_list_empty;
699*8443f2d2SAndrzej Pietrasiewicz 
700*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&inode->i_mutex);
701*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
702*8443f2d2SAndrzej Pietrasiewicz 	tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
703*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
704*8443f2d2SAndrzej Pietrasiewicz 
705*8443f2d2SAndrzej Pietrasiewicz 	if (!tx_list_empty) {
706*8443f2d2SAndrzej Pietrasiewicz 		/* Sleep until all data has been sent */
707*8443f2d2SAndrzej Pietrasiewicz 		wait_event_interruptible(dev->tx_flush_wait,
708*8443f2d2SAndrzej Pietrasiewicz 				(likely(list_empty(&dev->tx_reqs_active))));
709*8443f2d2SAndrzej Pietrasiewicz 	}
710*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&inode->i_mutex);
711*8443f2d2SAndrzej Pietrasiewicz 
712*8443f2d2SAndrzej Pietrasiewicz 	return 0;
713*8443f2d2SAndrzej Pietrasiewicz }
714*8443f2d2SAndrzej Pietrasiewicz 
715*8443f2d2SAndrzej Pietrasiewicz static unsigned int
716*8443f2d2SAndrzej Pietrasiewicz printer_poll(struct file *fd, poll_table *wait)
717*8443f2d2SAndrzej Pietrasiewicz {
718*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = fd->private_data;
719*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
720*8443f2d2SAndrzej Pietrasiewicz 	int			status = 0;
721*8443f2d2SAndrzej Pietrasiewicz 
722*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&dev->lock_printer_io);
723*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
724*8443f2d2SAndrzej Pietrasiewicz 	setup_rx_reqs(dev);
725*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
726*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&dev->lock_printer_io);
727*8443f2d2SAndrzej Pietrasiewicz 
728*8443f2d2SAndrzej Pietrasiewicz 	poll_wait(fd, &dev->rx_wait, wait);
729*8443f2d2SAndrzej Pietrasiewicz 	poll_wait(fd, &dev->tx_wait, wait);
730*8443f2d2SAndrzej Pietrasiewicz 
731*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
732*8443f2d2SAndrzej Pietrasiewicz 	if (likely(!list_empty(&dev->tx_reqs)))
733*8443f2d2SAndrzej Pietrasiewicz 		status |= POLLOUT | POLLWRNORM;
734*8443f2d2SAndrzej Pietrasiewicz 
735*8443f2d2SAndrzej Pietrasiewicz 	if (likely(dev->current_rx_bytes) ||
736*8443f2d2SAndrzej Pietrasiewicz 			likely(!list_empty(&dev->rx_buffers)))
737*8443f2d2SAndrzej Pietrasiewicz 		status |= POLLIN | POLLRDNORM;
738*8443f2d2SAndrzej Pietrasiewicz 
739*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
740*8443f2d2SAndrzej Pietrasiewicz 
741*8443f2d2SAndrzej Pietrasiewicz 	return status;
742*8443f2d2SAndrzej Pietrasiewicz }
743*8443f2d2SAndrzej Pietrasiewicz 
744*8443f2d2SAndrzej Pietrasiewicz static long
745*8443f2d2SAndrzej Pietrasiewicz printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
746*8443f2d2SAndrzej Pietrasiewicz {
747*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev = fd->private_data;
748*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
749*8443f2d2SAndrzej Pietrasiewicz 	int			status = 0;
750*8443f2d2SAndrzej Pietrasiewicz 
751*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
752*8443f2d2SAndrzej Pietrasiewicz 
753*8443f2d2SAndrzej Pietrasiewicz 	/* handle ioctls */
754*8443f2d2SAndrzej Pietrasiewicz 
755*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
756*8443f2d2SAndrzej Pietrasiewicz 
757*8443f2d2SAndrzej Pietrasiewicz 	switch (code) {
758*8443f2d2SAndrzej Pietrasiewicz 	case GADGET_GET_PRINTER_STATUS:
759*8443f2d2SAndrzej Pietrasiewicz 		status = (int)dev->printer_status;
760*8443f2d2SAndrzej Pietrasiewicz 		break;
761*8443f2d2SAndrzej Pietrasiewicz 	case GADGET_SET_PRINTER_STATUS:
762*8443f2d2SAndrzej Pietrasiewicz 		dev->printer_status = (u8)arg;
763*8443f2d2SAndrzej Pietrasiewicz 		break;
764*8443f2d2SAndrzej Pietrasiewicz 	default:
765*8443f2d2SAndrzej Pietrasiewicz 		/* could not handle ioctl */
766*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
767*8443f2d2SAndrzej Pietrasiewicz 				code);
768*8443f2d2SAndrzej Pietrasiewicz 		status = -ENOTTY;
769*8443f2d2SAndrzej Pietrasiewicz 	}
770*8443f2d2SAndrzej Pietrasiewicz 
771*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
772*8443f2d2SAndrzej Pietrasiewicz 
773*8443f2d2SAndrzej Pietrasiewicz 	return status;
774*8443f2d2SAndrzej Pietrasiewicz }
775*8443f2d2SAndrzej Pietrasiewicz 
776*8443f2d2SAndrzej Pietrasiewicz /* used after endpoint configuration */
777*8443f2d2SAndrzej Pietrasiewicz static const struct file_operations printer_io_operations = {
778*8443f2d2SAndrzej Pietrasiewicz 	.owner =	THIS_MODULE,
779*8443f2d2SAndrzej Pietrasiewicz 	.open =		printer_open,
780*8443f2d2SAndrzej Pietrasiewicz 	.read =		printer_read,
781*8443f2d2SAndrzej Pietrasiewicz 	.write =	printer_write,
782*8443f2d2SAndrzej Pietrasiewicz 	.fsync =	printer_fsync,
783*8443f2d2SAndrzej Pietrasiewicz 	.poll =		printer_poll,
784*8443f2d2SAndrzej Pietrasiewicz 	.unlocked_ioctl = printer_ioctl,
785*8443f2d2SAndrzej Pietrasiewicz 	.release =	printer_close,
786*8443f2d2SAndrzej Pietrasiewicz 	.llseek =	noop_llseek,
787*8443f2d2SAndrzej Pietrasiewicz };
788*8443f2d2SAndrzej Pietrasiewicz 
789*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
790*8443f2d2SAndrzej Pietrasiewicz 
791*8443f2d2SAndrzej Pietrasiewicz static int
792*8443f2d2SAndrzej Pietrasiewicz set_printer_interface(struct printer_dev *dev)
793*8443f2d2SAndrzej Pietrasiewicz {
794*8443f2d2SAndrzej Pietrasiewicz 	int			result = 0;
795*8443f2d2SAndrzej Pietrasiewicz 
796*8443f2d2SAndrzej Pietrasiewicz 	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
797*8443f2d2SAndrzej Pietrasiewicz 	dev->in_ep->driver_data = dev;
798*8443f2d2SAndrzej Pietrasiewicz 
799*8443f2d2SAndrzej Pietrasiewicz 	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
800*8443f2d2SAndrzej Pietrasiewicz 				    &fs_ep_out_desc);
801*8443f2d2SAndrzej Pietrasiewicz 	dev->out_ep->driver_data = dev;
802*8443f2d2SAndrzej Pietrasiewicz 
803*8443f2d2SAndrzej Pietrasiewicz 	result = usb_ep_enable(dev->in_ep);
804*8443f2d2SAndrzej Pietrasiewicz 	if (result != 0) {
805*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
806*8443f2d2SAndrzej Pietrasiewicz 		goto done;
807*8443f2d2SAndrzej Pietrasiewicz 	}
808*8443f2d2SAndrzej Pietrasiewicz 
809*8443f2d2SAndrzej Pietrasiewicz 	result = usb_ep_enable(dev->out_ep);
810*8443f2d2SAndrzej Pietrasiewicz 	if (result != 0) {
811*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
812*8443f2d2SAndrzej Pietrasiewicz 		goto done;
813*8443f2d2SAndrzej Pietrasiewicz 	}
814*8443f2d2SAndrzej Pietrasiewicz 
815*8443f2d2SAndrzej Pietrasiewicz done:
816*8443f2d2SAndrzej Pietrasiewicz 	/* on error, disable any endpoints  */
817*8443f2d2SAndrzej Pietrasiewicz 	if (result != 0) {
818*8443f2d2SAndrzej Pietrasiewicz 		(void) usb_ep_disable(dev->in_ep);
819*8443f2d2SAndrzej Pietrasiewicz 		(void) usb_ep_disable(dev->out_ep);
820*8443f2d2SAndrzej Pietrasiewicz 		dev->in_ep->desc = NULL;
821*8443f2d2SAndrzej Pietrasiewicz 		dev->out_ep->desc = NULL;
822*8443f2d2SAndrzej Pietrasiewicz 	}
823*8443f2d2SAndrzej Pietrasiewicz 
824*8443f2d2SAndrzej Pietrasiewicz 	/* caller is responsible for cleanup on error */
825*8443f2d2SAndrzej Pietrasiewicz 	return result;
826*8443f2d2SAndrzej Pietrasiewicz }
827*8443f2d2SAndrzej Pietrasiewicz 
828*8443f2d2SAndrzej Pietrasiewicz static void printer_reset_interface(struct printer_dev *dev)
829*8443f2d2SAndrzej Pietrasiewicz {
830*8443f2d2SAndrzej Pietrasiewicz 	if (dev->interface < 0)
831*8443f2d2SAndrzej Pietrasiewicz 		return;
832*8443f2d2SAndrzej Pietrasiewicz 
833*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "%s\n", __func__);
834*8443f2d2SAndrzej Pietrasiewicz 
835*8443f2d2SAndrzej Pietrasiewicz 	if (dev->in_ep->desc)
836*8443f2d2SAndrzej Pietrasiewicz 		usb_ep_disable(dev->in_ep);
837*8443f2d2SAndrzej Pietrasiewicz 
838*8443f2d2SAndrzej Pietrasiewicz 	if (dev->out_ep->desc)
839*8443f2d2SAndrzej Pietrasiewicz 		usb_ep_disable(dev->out_ep);
840*8443f2d2SAndrzej Pietrasiewicz 
841*8443f2d2SAndrzej Pietrasiewicz 	dev->in_ep->desc = NULL;
842*8443f2d2SAndrzej Pietrasiewicz 	dev->out_ep->desc = NULL;
843*8443f2d2SAndrzej Pietrasiewicz 	dev->interface = -1;
844*8443f2d2SAndrzej Pietrasiewicz }
845*8443f2d2SAndrzej Pietrasiewicz 
846*8443f2d2SAndrzej Pietrasiewicz /* Change our operational Interface. */
847*8443f2d2SAndrzej Pietrasiewicz static int set_interface(struct printer_dev *dev, unsigned number)
848*8443f2d2SAndrzej Pietrasiewicz {
849*8443f2d2SAndrzej Pietrasiewicz 	int			result = 0;
850*8443f2d2SAndrzej Pietrasiewicz 
851*8443f2d2SAndrzej Pietrasiewicz 	/* Free the current interface */
852*8443f2d2SAndrzej Pietrasiewicz 	printer_reset_interface(dev);
853*8443f2d2SAndrzej Pietrasiewicz 
854*8443f2d2SAndrzej Pietrasiewicz 	result = set_printer_interface(dev);
855*8443f2d2SAndrzej Pietrasiewicz 	if (result)
856*8443f2d2SAndrzej Pietrasiewicz 		printer_reset_interface(dev);
857*8443f2d2SAndrzej Pietrasiewicz 	else
858*8443f2d2SAndrzej Pietrasiewicz 		dev->interface = number;
859*8443f2d2SAndrzej Pietrasiewicz 
860*8443f2d2SAndrzej Pietrasiewicz 	if (!result)
861*8443f2d2SAndrzej Pietrasiewicz 		INFO(dev, "Using interface %x\n", number);
862*8443f2d2SAndrzej Pietrasiewicz 
863*8443f2d2SAndrzej Pietrasiewicz 	return result;
864*8443f2d2SAndrzej Pietrasiewicz }
865*8443f2d2SAndrzej Pietrasiewicz 
866*8443f2d2SAndrzej Pietrasiewicz static void printer_soft_reset(struct printer_dev *dev)
867*8443f2d2SAndrzej Pietrasiewicz {
868*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req;
869*8443f2d2SAndrzej Pietrasiewicz 
870*8443f2d2SAndrzej Pietrasiewicz 	INFO(dev, "Received Printer Reset Request\n");
871*8443f2d2SAndrzej Pietrasiewicz 
872*8443f2d2SAndrzej Pietrasiewicz 	if (usb_ep_disable(dev->in_ep))
873*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "Failed to disable USB in_ep\n");
874*8443f2d2SAndrzej Pietrasiewicz 	if (usb_ep_disable(dev->out_ep))
875*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "Failed to disable USB out_ep\n");
876*8443f2d2SAndrzej Pietrasiewicz 
877*8443f2d2SAndrzej Pietrasiewicz 	if (dev->current_rx_req != NULL) {
878*8443f2d2SAndrzej Pietrasiewicz 		list_add(&dev->current_rx_req->list, &dev->rx_reqs);
879*8443f2d2SAndrzej Pietrasiewicz 		dev->current_rx_req = NULL;
880*8443f2d2SAndrzej Pietrasiewicz 	}
881*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_bytes = 0;
882*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_buf = NULL;
883*8443f2d2SAndrzej Pietrasiewicz 	dev->reset_printer = 1;
884*8443f2d2SAndrzej Pietrasiewicz 
885*8443f2d2SAndrzej Pietrasiewicz 	while (likely(!(list_empty(&dev->rx_buffers)))) {
886*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->rx_buffers.next, struct usb_request,
887*8443f2d2SAndrzej Pietrasiewicz 				list);
888*8443f2d2SAndrzej Pietrasiewicz 		list_del_init(&req->list);
889*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
890*8443f2d2SAndrzej Pietrasiewicz 	}
891*8443f2d2SAndrzej Pietrasiewicz 
892*8443f2d2SAndrzej Pietrasiewicz 	while (likely(!(list_empty(&dev->rx_reqs_active)))) {
893*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->rx_buffers.next, struct usb_request,
894*8443f2d2SAndrzej Pietrasiewicz 				list);
895*8443f2d2SAndrzej Pietrasiewicz 		list_del_init(&req->list);
896*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
897*8443f2d2SAndrzej Pietrasiewicz 	}
898*8443f2d2SAndrzej Pietrasiewicz 
899*8443f2d2SAndrzej Pietrasiewicz 	while (likely(!(list_empty(&dev->tx_reqs_active)))) {
900*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->tx_reqs_active.next,
901*8443f2d2SAndrzej Pietrasiewicz 				struct usb_request, list);
902*8443f2d2SAndrzej Pietrasiewicz 		list_del_init(&req->list);
903*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->tx_reqs);
904*8443f2d2SAndrzej Pietrasiewicz 	}
905*8443f2d2SAndrzej Pietrasiewicz 
906*8443f2d2SAndrzej Pietrasiewicz 	if (usb_ep_enable(dev->in_ep))
907*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "Failed to enable USB in_ep\n");
908*8443f2d2SAndrzej Pietrasiewicz 	if (usb_ep_enable(dev->out_ep))
909*8443f2d2SAndrzej Pietrasiewicz 		DBG(dev, "Failed to enable USB out_ep\n");
910*8443f2d2SAndrzej Pietrasiewicz 
911*8443f2d2SAndrzej Pietrasiewicz 	wake_up_interruptible(&dev->rx_wait);
912*8443f2d2SAndrzej Pietrasiewicz 	wake_up_interruptible(&dev->tx_wait);
913*8443f2d2SAndrzej Pietrasiewicz 	wake_up_interruptible(&dev->tx_flush_wait);
914*8443f2d2SAndrzej Pietrasiewicz }
915*8443f2d2SAndrzej Pietrasiewicz 
916*8443f2d2SAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
917*8443f2d2SAndrzej Pietrasiewicz 
918*8443f2d2SAndrzej Pietrasiewicz /*
919*8443f2d2SAndrzej Pietrasiewicz  * The setup() callback implements all the ep0 functionality that's not
920*8443f2d2SAndrzej Pietrasiewicz  * handled lower down.
921*8443f2d2SAndrzej Pietrasiewicz  */
922*8443f2d2SAndrzej Pietrasiewicz static int printer_func_setup(struct usb_function *f,
923*8443f2d2SAndrzej Pietrasiewicz 		const struct usb_ctrlrequest *ctrl)
924*8443f2d2SAndrzej Pietrasiewicz {
925*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev *dev = container_of(f, struct printer_dev, function);
926*8443f2d2SAndrzej Pietrasiewicz 	struct usb_composite_dev *cdev = f->config->cdev;
927*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req = cdev->req;
928*8443f2d2SAndrzej Pietrasiewicz 	int			value = -EOPNOTSUPP;
929*8443f2d2SAndrzej Pietrasiewicz 	u16			wIndex = le16_to_cpu(ctrl->wIndex);
930*8443f2d2SAndrzej Pietrasiewicz 	u16			wValue = le16_to_cpu(ctrl->wValue);
931*8443f2d2SAndrzej Pietrasiewicz 	u16			wLength = le16_to_cpu(ctrl->wLength);
932*8443f2d2SAndrzej Pietrasiewicz 
933*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
934*8443f2d2SAndrzej Pietrasiewicz 		ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
935*8443f2d2SAndrzej Pietrasiewicz 
936*8443f2d2SAndrzej Pietrasiewicz 	switch (ctrl->bRequestType&USB_TYPE_MASK) {
937*8443f2d2SAndrzej Pietrasiewicz 	case USB_TYPE_CLASS:
938*8443f2d2SAndrzej Pietrasiewicz 		switch (ctrl->bRequest) {
939*8443f2d2SAndrzej Pietrasiewicz 		case 0: /* Get the IEEE-1284 PNP String */
940*8443f2d2SAndrzej Pietrasiewicz 			/* Only one printer interface is supported. */
941*8443f2d2SAndrzej Pietrasiewicz 			if ((wIndex>>8) != dev->interface)
942*8443f2d2SAndrzej Pietrasiewicz 				break;
943*8443f2d2SAndrzej Pietrasiewicz 
944*8443f2d2SAndrzej Pietrasiewicz 			value = (pnp_string[0]<<8)|pnp_string[1];
945*8443f2d2SAndrzej Pietrasiewicz 			memcpy(req->buf, pnp_string, value);
946*8443f2d2SAndrzej Pietrasiewicz 			DBG(dev, "1284 PNP String: %x %s\n", value,
947*8443f2d2SAndrzej Pietrasiewicz 					&pnp_string[2]);
948*8443f2d2SAndrzej Pietrasiewicz 			break;
949*8443f2d2SAndrzej Pietrasiewicz 
950*8443f2d2SAndrzej Pietrasiewicz 		case 1: /* Get Port Status */
951*8443f2d2SAndrzej Pietrasiewicz 			/* Only one printer interface is supported. */
952*8443f2d2SAndrzej Pietrasiewicz 			if (wIndex != dev->interface)
953*8443f2d2SAndrzej Pietrasiewicz 				break;
954*8443f2d2SAndrzej Pietrasiewicz 
955*8443f2d2SAndrzej Pietrasiewicz 			*(u8 *)req->buf = dev->printer_status;
956*8443f2d2SAndrzej Pietrasiewicz 			value = min(wLength, (u16) 1);
957*8443f2d2SAndrzej Pietrasiewicz 			break;
958*8443f2d2SAndrzej Pietrasiewicz 
959*8443f2d2SAndrzej Pietrasiewicz 		case 2: /* Soft Reset */
960*8443f2d2SAndrzej Pietrasiewicz 			/* Only one printer interface is supported. */
961*8443f2d2SAndrzej Pietrasiewicz 			if (wIndex != dev->interface)
962*8443f2d2SAndrzej Pietrasiewicz 				break;
963*8443f2d2SAndrzej Pietrasiewicz 
964*8443f2d2SAndrzej Pietrasiewicz 			printer_soft_reset(dev);
965*8443f2d2SAndrzej Pietrasiewicz 
966*8443f2d2SAndrzej Pietrasiewicz 			value = 0;
967*8443f2d2SAndrzej Pietrasiewicz 			break;
968*8443f2d2SAndrzej Pietrasiewicz 
969*8443f2d2SAndrzej Pietrasiewicz 		default:
970*8443f2d2SAndrzej Pietrasiewicz 			goto unknown;
971*8443f2d2SAndrzej Pietrasiewicz 		}
972*8443f2d2SAndrzej Pietrasiewicz 		break;
973*8443f2d2SAndrzej Pietrasiewicz 
974*8443f2d2SAndrzej Pietrasiewicz 	default:
975*8443f2d2SAndrzej Pietrasiewicz unknown:
976*8443f2d2SAndrzej Pietrasiewicz 		VDBG(dev,
977*8443f2d2SAndrzej Pietrasiewicz 			"unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
978*8443f2d2SAndrzej Pietrasiewicz 			ctrl->bRequestType, ctrl->bRequest,
979*8443f2d2SAndrzej Pietrasiewicz 			wValue, wIndex, wLength);
980*8443f2d2SAndrzej Pietrasiewicz 		break;
981*8443f2d2SAndrzej Pietrasiewicz 	}
982*8443f2d2SAndrzej Pietrasiewicz 	/* host either stalls (value < 0) or reports success */
983*8443f2d2SAndrzej Pietrasiewicz 	return value;
984*8443f2d2SAndrzej Pietrasiewicz }
985*8443f2d2SAndrzej Pietrasiewicz 
986*8443f2d2SAndrzej Pietrasiewicz static int __init printer_func_bind(struct usb_configuration *c,
987*8443f2d2SAndrzej Pietrasiewicz 		struct usb_function *f)
988*8443f2d2SAndrzej Pietrasiewicz {
989*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev *dev = container_of(f, struct printer_dev, function);
990*8443f2d2SAndrzej Pietrasiewicz 	struct usb_composite_dev *cdev = c->cdev;
991*8443f2d2SAndrzej Pietrasiewicz 	struct usb_ep *in_ep;
992*8443f2d2SAndrzej Pietrasiewicz 	struct usb_ep *out_ep = NULL;
993*8443f2d2SAndrzej Pietrasiewicz 	int id;
994*8443f2d2SAndrzej Pietrasiewicz 	int ret;
995*8443f2d2SAndrzej Pietrasiewicz 
996*8443f2d2SAndrzej Pietrasiewicz 	id = usb_interface_id(c, f);
997*8443f2d2SAndrzej Pietrasiewicz 	if (id < 0)
998*8443f2d2SAndrzej Pietrasiewicz 		return id;
999*8443f2d2SAndrzej Pietrasiewicz 	intf_desc.bInterfaceNumber = id;
1000*8443f2d2SAndrzej Pietrasiewicz 
1001*8443f2d2SAndrzej Pietrasiewicz 	/* all we really need is bulk IN/OUT */
1002*8443f2d2SAndrzej Pietrasiewicz 	in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
1003*8443f2d2SAndrzej Pietrasiewicz 	if (!in_ep) {
1004*8443f2d2SAndrzej Pietrasiewicz autoconf_fail:
1005*8443f2d2SAndrzej Pietrasiewicz 		dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
1006*8443f2d2SAndrzej Pietrasiewicz 			cdev->gadget->name);
1007*8443f2d2SAndrzej Pietrasiewicz 		return -ENODEV;
1008*8443f2d2SAndrzej Pietrasiewicz 	}
1009*8443f2d2SAndrzej Pietrasiewicz 	in_ep->driver_data = in_ep;	/* claim */
1010*8443f2d2SAndrzej Pietrasiewicz 
1011*8443f2d2SAndrzej Pietrasiewicz 	out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
1012*8443f2d2SAndrzej Pietrasiewicz 	if (!out_ep)
1013*8443f2d2SAndrzej Pietrasiewicz 		goto autoconf_fail;
1014*8443f2d2SAndrzej Pietrasiewicz 	out_ep->driver_data = out_ep;	/* claim */
1015*8443f2d2SAndrzej Pietrasiewicz 
1016*8443f2d2SAndrzej Pietrasiewicz 	/* assumes that all endpoints are dual-speed */
1017*8443f2d2SAndrzej Pietrasiewicz 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
1018*8443f2d2SAndrzej Pietrasiewicz 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
1019*8443f2d2SAndrzej Pietrasiewicz 
1020*8443f2d2SAndrzej Pietrasiewicz 	ret = usb_assign_descriptors(f, fs_printer_function,
1021*8443f2d2SAndrzej Pietrasiewicz 			hs_printer_function, NULL);
1022*8443f2d2SAndrzej Pietrasiewicz 	if (ret)
1023*8443f2d2SAndrzej Pietrasiewicz 		return ret;
1024*8443f2d2SAndrzej Pietrasiewicz 
1025*8443f2d2SAndrzej Pietrasiewicz 	dev->in_ep = in_ep;
1026*8443f2d2SAndrzej Pietrasiewicz 	dev->out_ep = out_ep;
1027*8443f2d2SAndrzej Pietrasiewicz 	return 0;
1028*8443f2d2SAndrzej Pietrasiewicz }
1029*8443f2d2SAndrzej Pietrasiewicz 
1030*8443f2d2SAndrzej Pietrasiewicz static void printer_func_unbind(struct usb_configuration *c,
1031*8443f2d2SAndrzej Pietrasiewicz 		struct usb_function *f)
1032*8443f2d2SAndrzej Pietrasiewicz {
1033*8443f2d2SAndrzej Pietrasiewicz 	usb_free_all_descriptors(f);
1034*8443f2d2SAndrzej Pietrasiewicz }
1035*8443f2d2SAndrzej Pietrasiewicz 
1036*8443f2d2SAndrzej Pietrasiewicz static int printer_func_set_alt(struct usb_function *f,
1037*8443f2d2SAndrzej Pietrasiewicz 		unsigned intf, unsigned alt)
1038*8443f2d2SAndrzej Pietrasiewicz {
1039*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev *dev = container_of(f, struct printer_dev, function);
1040*8443f2d2SAndrzej Pietrasiewicz 	int ret = -ENOTSUPP;
1041*8443f2d2SAndrzej Pietrasiewicz 
1042*8443f2d2SAndrzej Pietrasiewicz 	if (!alt)
1043*8443f2d2SAndrzej Pietrasiewicz 		ret = set_interface(dev, intf);
1044*8443f2d2SAndrzej Pietrasiewicz 
1045*8443f2d2SAndrzej Pietrasiewicz 	return ret;
1046*8443f2d2SAndrzej Pietrasiewicz }
1047*8443f2d2SAndrzej Pietrasiewicz 
1048*8443f2d2SAndrzej Pietrasiewicz static void printer_func_disable(struct usb_function *f)
1049*8443f2d2SAndrzej Pietrasiewicz {
1050*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev *dev = container_of(f, struct printer_dev, function);
1051*8443f2d2SAndrzej Pietrasiewicz 	unsigned long		flags;
1052*8443f2d2SAndrzej Pietrasiewicz 
1053*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "%s\n", __func__);
1054*8443f2d2SAndrzej Pietrasiewicz 
1055*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_irqsave(&dev->lock, flags);
1056*8443f2d2SAndrzej Pietrasiewicz 	printer_reset_interface(dev);
1057*8443f2d2SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&dev->lock, flags);
1058*8443f2d2SAndrzej Pietrasiewicz }
1059*8443f2d2SAndrzej Pietrasiewicz 
1060*8443f2d2SAndrzej Pietrasiewicz static void printer_cfg_unbind(struct usb_configuration *c)
1061*8443f2d2SAndrzej Pietrasiewicz {
1062*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev;
1063*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req;
1064*8443f2d2SAndrzej Pietrasiewicz 
1065*8443f2d2SAndrzej Pietrasiewicz 	dev = &usb_printer_gadget;
1066*8443f2d2SAndrzej Pietrasiewicz 
1067*8443f2d2SAndrzej Pietrasiewicz 	DBG(dev, "%s\n", __func__);
1068*8443f2d2SAndrzej Pietrasiewicz 
1069*8443f2d2SAndrzej Pietrasiewicz 	/* Remove sysfs files */
1070*8443f2d2SAndrzej Pietrasiewicz 	device_destroy(usb_gadget_class, g_printer_devno);
1071*8443f2d2SAndrzej Pietrasiewicz 
1072*8443f2d2SAndrzej Pietrasiewicz 	/* Remove Character Device */
1073*8443f2d2SAndrzej Pietrasiewicz 	cdev_del(&dev->printer_cdev);
1074*8443f2d2SAndrzej Pietrasiewicz 
1075*8443f2d2SAndrzej Pietrasiewicz 	/* we must already have been disconnected ... no i/o may be active */
1076*8443f2d2SAndrzej Pietrasiewicz 	WARN_ON(!list_empty(&dev->tx_reqs_active));
1077*8443f2d2SAndrzej Pietrasiewicz 	WARN_ON(!list_empty(&dev->rx_reqs_active));
1078*8443f2d2SAndrzej Pietrasiewicz 
1079*8443f2d2SAndrzej Pietrasiewicz 	/* Free all memory for this driver. */
1080*8443f2d2SAndrzej Pietrasiewicz 	while (!list_empty(&dev->tx_reqs)) {
1081*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->tx_reqs.next, struct usb_request,
1082*8443f2d2SAndrzej Pietrasiewicz 				list);
1083*8443f2d2SAndrzej Pietrasiewicz 		list_del(&req->list);
1084*8443f2d2SAndrzej Pietrasiewicz 		printer_req_free(dev->in_ep, req);
1085*8443f2d2SAndrzej Pietrasiewicz 	}
1086*8443f2d2SAndrzej Pietrasiewicz 
1087*8443f2d2SAndrzej Pietrasiewicz 	if (dev->current_rx_req != NULL)
1088*8443f2d2SAndrzej Pietrasiewicz 		printer_req_free(dev->out_ep, dev->current_rx_req);
1089*8443f2d2SAndrzej Pietrasiewicz 
1090*8443f2d2SAndrzej Pietrasiewicz 	while (!list_empty(&dev->rx_reqs)) {
1091*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->rx_reqs.next,
1092*8443f2d2SAndrzej Pietrasiewicz 				struct usb_request, list);
1093*8443f2d2SAndrzej Pietrasiewicz 		list_del(&req->list);
1094*8443f2d2SAndrzej Pietrasiewicz 		printer_req_free(dev->out_ep, req);
1095*8443f2d2SAndrzej Pietrasiewicz 	}
1096*8443f2d2SAndrzej Pietrasiewicz 
1097*8443f2d2SAndrzej Pietrasiewicz 	while (!list_empty(&dev->rx_buffers)) {
1098*8443f2d2SAndrzej Pietrasiewicz 		req = container_of(dev->rx_buffers.next,
1099*8443f2d2SAndrzej Pietrasiewicz 				struct usb_request, list);
1100*8443f2d2SAndrzej Pietrasiewicz 		list_del(&req->list);
1101*8443f2d2SAndrzej Pietrasiewicz 		printer_req_free(dev->out_ep, req);
1102*8443f2d2SAndrzej Pietrasiewicz 	}
1103*8443f2d2SAndrzej Pietrasiewicz }
1104*8443f2d2SAndrzej Pietrasiewicz 
1105*8443f2d2SAndrzej Pietrasiewicz static struct usb_configuration printer_cfg_driver = {
1106*8443f2d2SAndrzej Pietrasiewicz 	.label			= "printer",
1107*8443f2d2SAndrzej Pietrasiewicz 	.unbind			= printer_cfg_unbind,
1108*8443f2d2SAndrzej Pietrasiewicz 	.bConfigurationValue	= 1,
1109*8443f2d2SAndrzej Pietrasiewicz 	.bmAttributes		= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
1110*8443f2d2SAndrzej Pietrasiewicz };
1111*8443f2d2SAndrzej Pietrasiewicz 
1112*8443f2d2SAndrzej Pietrasiewicz static int __init printer_bind_config(struct usb_configuration *c)
1113*8443f2d2SAndrzej Pietrasiewicz {
1114*8443f2d2SAndrzej Pietrasiewicz 	struct usb_gadget	*gadget = c->cdev->gadget;
1115*8443f2d2SAndrzej Pietrasiewicz 	struct printer_dev	*dev;
1116*8443f2d2SAndrzej Pietrasiewicz 	int			status = -ENOMEM;
1117*8443f2d2SAndrzej Pietrasiewicz 	size_t			len;
1118*8443f2d2SAndrzej Pietrasiewicz 	u32			i;
1119*8443f2d2SAndrzej Pietrasiewicz 	struct usb_request	*req;
1120*8443f2d2SAndrzej Pietrasiewicz 
1121*8443f2d2SAndrzej Pietrasiewicz 	usb_ep_autoconfig_reset(gadget);
1122*8443f2d2SAndrzej Pietrasiewicz 
1123*8443f2d2SAndrzej Pietrasiewicz 	dev = &usb_printer_gadget;
1124*8443f2d2SAndrzej Pietrasiewicz 
1125*8443f2d2SAndrzej Pietrasiewicz 	dev->function.name = shortname;
1126*8443f2d2SAndrzej Pietrasiewicz 	dev->function.bind = printer_func_bind;
1127*8443f2d2SAndrzej Pietrasiewicz 	dev->function.setup = printer_func_setup;
1128*8443f2d2SAndrzej Pietrasiewicz 	dev->function.unbind = printer_func_unbind;
1129*8443f2d2SAndrzej Pietrasiewicz 	dev->function.set_alt = printer_func_set_alt;
1130*8443f2d2SAndrzej Pietrasiewicz 	dev->function.disable = printer_func_disable;
1131*8443f2d2SAndrzej Pietrasiewicz 
1132*8443f2d2SAndrzej Pietrasiewicz 	status = usb_add_function(c, &dev->function);
1133*8443f2d2SAndrzej Pietrasiewicz 	if (status)
1134*8443f2d2SAndrzej Pietrasiewicz 		return status;
1135*8443f2d2SAndrzej Pietrasiewicz 
1136*8443f2d2SAndrzej Pietrasiewicz 	/* Setup the sysfs files for the printer gadget. */
1137*8443f2d2SAndrzej Pietrasiewicz 	dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
1138*8443f2d2SAndrzej Pietrasiewicz 				  NULL, "g_printer");
1139*8443f2d2SAndrzej Pietrasiewicz 	if (IS_ERR(dev->pdev)) {
1140*8443f2d2SAndrzej Pietrasiewicz 		ERROR(dev, "Failed to create device: g_printer\n");
1141*8443f2d2SAndrzej Pietrasiewicz 		status = PTR_ERR(dev->pdev);
1142*8443f2d2SAndrzej Pietrasiewicz 		goto fail;
1143*8443f2d2SAndrzej Pietrasiewicz 	}
1144*8443f2d2SAndrzej Pietrasiewicz 
1145*8443f2d2SAndrzej Pietrasiewicz 	/*
1146*8443f2d2SAndrzej Pietrasiewicz 	 * Register a character device as an interface to a user mode
1147*8443f2d2SAndrzej Pietrasiewicz 	 * program that handles the printer specific functionality.
1148*8443f2d2SAndrzej Pietrasiewicz 	 */
1149*8443f2d2SAndrzej Pietrasiewicz 	cdev_init(&dev->printer_cdev, &printer_io_operations);
1150*8443f2d2SAndrzej Pietrasiewicz 	dev->printer_cdev.owner = THIS_MODULE;
1151*8443f2d2SAndrzej Pietrasiewicz 	status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
1152*8443f2d2SAndrzej Pietrasiewicz 	if (status) {
1153*8443f2d2SAndrzej Pietrasiewicz 		ERROR(dev, "Failed to open char device\n");
1154*8443f2d2SAndrzej Pietrasiewicz 		goto fail;
1155*8443f2d2SAndrzej Pietrasiewicz 	}
1156*8443f2d2SAndrzej Pietrasiewicz 
1157*8443f2d2SAndrzej Pietrasiewicz 	if (iPNPstring)
1158*8443f2d2SAndrzej Pietrasiewicz 		strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
1159*8443f2d2SAndrzej Pietrasiewicz 
1160*8443f2d2SAndrzej Pietrasiewicz 	len = strlen(pnp_string);
1161*8443f2d2SAndrzej Pietrasiewicz 	pnp_string[0] = (len >> 8) & 0xFF;
1162*8443f2d2SAndrzej Pietrasiewicz 	pnp_string[1] = len & 0xFF;
1163*8443f2d2SAndrzej Pietrasiewicz 
1164*8443f2d2SAndrzej Pietrasiewicz 	usb_gadget_set_selfpowered(gadget);
1165*8443f2d2SAndrzej Pietrasiewicz 
1166*8443f2d2SAndrzej Pietrasiewicz 	if (gadget_is_otg(gadget)) {
1167*8443f2d2SAndrzej Pietrasiewicz 		otg_descriptor.bmAttributes |= USB_OTG_HNP;
1168*8443f2d2SAndrzej Pietrasiewicz 		printer_cfg_driver.descriptors = otg_desc;
1169*8443f2d2SAndrzej Pietrasiewicz 		printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1170*8443f2d2SAndrzej Pietrasiewicz 	}
1171*8443f2d2SAndrzej Pietrasiewicz 
1172*8443f2d2SAndrzej Pietrasiewicz 	spin_lock_init(&dev->lock);
1173*8443f2d2SAndrzej Pietrasiewicz 	mutex_init(&dev->lock_printer_io);
1174*8443f2d2SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&dev->tx_reqs);
1175*8443f2d2SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&dev->tx_reqs_active);
1176*8443f2d2SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&dev->rx_reqs);
1177*8443f2d2SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&dev->rx_reqs_active);
1178*8443f2d2SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&dev->rx_buffers);
1179*8443f2d2SAndrzej Pietrasiewicz 	init_waitqueue_head(&dev->rx_wait);
1180*8443f2d2SAndrzej Pietrasiewicz 	init_waitqueue_head(&dev->tx_wait);
1181*8443f2d2SAndrzej Pietrasiewicz 	init_waitqueue_head(&dev->tx_flush_wait);
1182*8443f2d2SAndrzej Pietrasiewicz 
1183*8443f2d2SAndrzej Pietrasiewicz 	dev->interface = -1;
1184*8443f2d2SAndrzej Pietrasiewicz 	dev->printer_cdev_open = 0;
1185*8443f2d2SAndrzej Pietrasiewicz 	dev->printer_status = PRINTER_NOT_ERROR;
1186*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_req = NULL;
1187*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_bytes = 0;
1188*8443f2d2SAndrzej Pietrasiewicz 	dev->current_rx_buf = NULL;
1189*8443f2d2SAndrzej Pietrasiewicz 
1190*8443f2d2SAndrzej Pietrasiewicz 	for (i = 0; i < QLEN; i++) {
1191*8443f2d2SAndrzej Pietrasiewicz 		req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
1192*8443f2d2SAndrzej Pietrasiewicz 		if (!req) {
1193*8443f2d2SAndrzej Pietrasiewicz 			while (!list_empty(&dev->tx_reqs)) {
1194*8443f2d2SAndrzej Pietrasiewicz 				req = container_of(dev->tx_reqs.next,
1195*8443f2d2SAndrzej Pietrasiewicz 						struct usb_request, list);
1196*8443f2d2SAndrzej Pietrasiewicz 				list_del(&req->list);
1197*8443f2d2SAndrzej Pietrasiewicz 				printer_req_free(dev->in_ep, req);
1198*8443f2d2SAndrzej Pietrasiewicz 			}
1199*8443f2d2SAndrzej Pietrasiewicz 			return -ENOMEM;
1200*8443f2d2SAndrzej Pietrasiewicz 		}
1201*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->tx_reqs);
1202*8443f2d2SAndrzej Pietrasiewicz 	}
1203*8443f2d2SAndrzej Pietrasiewicz 
1204*8443f2d2SAndrzej Pietrasiewicz 	for (i = 0; i < QLEN; i++) {
1205*8443f2d2SAndrzej Pietrasiewicz 		req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
1206*8443f2d2SAndrzej Pietrasiewicz 		if (!req) {
1207*8443f2d2SAndrzej Pietrasiewicz 			while (!list_empty(&dev->rx_reqs)) {
1208*8443f2d2SAndrzej Pietrasiewicz 				req = container_of(dev->rx_reqs.next,
1209*8443f2d2SAndrzej Pietrasiewicz 						struct usb_request, list);
1210*8443f2d2SAndrzej Pietrasiewicz 				list_del(&req->list);
1211*8443f2d2SAndrzej Pietrasiewicz 				printer_req_free(dev->out_ep, req);
1212*8443f2d2SAndrzej Pietrasiewicz 			}
1213*8443f2d2SAndrzej Pietrasiewicz 			return -ENOMEM;
1214*8443f2d2SAndrzej Pietrasiewicz 		}
1215*8443f2d2SAndrzej Pietrasiewicz 		list_add(&req->list, &dev->rx_reqs);
1216*8443f2d2SAndrzej Pietrasiewicz 	}
1217*8443f2d2SAndrzej Pietrasiewicz 
1218*8443f2d2SAndrzej Pietrasiewicz 	/* finish hookup to lower layer ... */
1219*8443f2d2SAndrzej Pietrasiewicz 	dev->gadget = gadget;
1220*8443f2d2SAndrzej Pietrasiewicz 
1221*8443f2d2SAndrzej Pietrasiewicz 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
1222*8443f2d2SAndrzej Pietrasiewicz 	return 0;
1223*8443f2d2SAndrzej Pietrasiewicz 
1224*8443f2d2SAndrzej Pietrasiewicz fail:
1225*8443f2d2SAndrzej Pietrasiewicz 	printer_cfg_unbind(c);
1226*8443f2d2SAndrzej Pietrasiewicz 	return status;
1227*8443f2d2SAndrzej Pietrasiewicz }
1228*8443f2d2SAndrzej Pietrasiewicz 
1229*8443f2d2SAndrzej Pietrasiewicz static int printer_unbind(struct usb_composite_dev *cdev)
1230*8443f2d2SAndrzej Pietrasiewicz {
1231*8443f2d2SAndrzej Pietrasiewicz 	return 0;
1232*8443f2d2SAndrzej Pietrasiewicz }
1233*8443f2d2SAndrzej Pietrasiewicz 
1234*8443f2d2SAndrzej Pietrasiewicz static int __init printer_bind(struct usb_composite_dev *cdev)
1235*8443f2d2SAndrzej Pietrasiewicz {
1236*8443f2d2SAndrzej Pietrasiewicz 	int ret;
1237*8443f2d2SAndrzej Pietrasiewicz 
1238*8443f2d2SAndrzej Pietrasiewicz 	ret = usb_string_ids_tab(cdev, strings);
1239*8443f2d2SAndrzej Pietrasiewicz 	if (ret < 0)
1240*8443f2d2SAndrzej Pietrasiewicz 		return ret;
1241*8443f2d2SAndrzej Pietrasiewicz 	device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
1242*8443f2d2SAndrzej Pietrasiewicz 	device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
1243*8443f2d2SAndrzej Pietrasiewicz 	device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
1244*8443f2d2SAndrzej Pietrasiewicz 
1245*8443f2d2SAndrzej Pietrasiewicz 	ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
1246*8443f2d2SAndrzej Pietrasiewicz 	if (ret)
1247*8443f2d2SAndrzej Pietrasiewicz 		return ret;
1248*8443f2d2SAndrzej Pietrasiewicz 	usb_composite_overwrite_options(cdev, &coverwrite);
1249*8443f2d2SAndrzej Pietrasiewicz 	return ret;
1250*8443f2d2SAndrzej Pietrasiewicz }
1251*8443f2d2SAndrzej Pietrasiewicz 
1252*8443f2d2SAndrzej Pietrasiewicz static __refdata struct usb_composite_driver printer_driver = {
1253*8443f2d2SAndrzej Pietrasiewicz 	.name           = shortname,
1254*8443f2d2SAndrzej Pietrasiewicz 	.dev            = &device_desc,
1255*8443f2d2SAndrzej Pietrasiewicz 	.strings        = dev_strings,
1256*8443f2d2SAndrzej Pietrasiewicz 	.max_speed      = USB_SPEED_HIGH,
1257*8443f2d2SAndrzej Pietrasiewicz 	.bind		= printer_bind,
1258*8443f2d2SAndrzej Pietrasiewicz 	.unbind		= printer_unbind,
1259*8443f2d2SAndrzej Pietrasiewicz };
1260*8443f2d2SAndrzej Pietrasiewicz 
1261*8443f2d2SAndrzej Pietrasiewicz static int __init
1262*8443f2d2SAndrzej Pietrasiewicz init(void)
1263*8443f2d2SAndrzej Pietrasiewicz {
1264*8443f2d2SAndrzej Pietrasiewicz 	int status;
1265*8443f2d2SAndrzej Pietrasiewicz 
1266*8443f2d2SAndrzej Pietrasiewicz 	usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
1267*8443f2d2SAndrzej Pietrasiewicz 	if (IS_ERR(usb_gadget_class)) {
1268*8443f2d2SAndrzej Pietrasiewicz 		status = PTR_ERR(usb_gadget_class);
1269*8443f2d2SAndrzej Pietrasiewicz 		pr_err("unable to create usb_gadget class %d\n", status);
1270*8443f2d2SAndrzej Pietrasiewicz 		return status;
1271*8443f2d2SAndrzej Pietrasiewicz 	}
1272*8443f2d2SAndrzej Pietrasiewicz 
1273*8443f2d2SAndrzej Pietrasiewicz 	status = alloc_chrdev_region(&g_printer_devno, 0, 1,
1274*8443f2d2SAndrzej Pietrasiewicz 			"USB printer gadget");
1275*8443f2d2SAndrzej Pietrasiewicz 	if (status) {
1276*8443f2d2SAndrzej Pietrasiewicz 		pr_err("alloc_chrdev_region %d\n", status);
1277*8443f2d2SAndrzej Pietrasiewicz 		class_destroy(usb_gadget_class);
1278*8443f2d2SAndrzej Pietrasiewicz 		return status;
1279*8443f2d2SAndrzej Pietrasiewicz 	}
1280*8443f2d2SAndrzej Pietrasiewicz 
1281*8443f2d2SAndrzej Pietrasiewicz 	status = usb_composite_probe(&printer_driver);
1282*8443f2d2SAndrzej Pietrasiewicz 	if (status) {
1283*8443f2d2SAndrzej Pietrasiewicz 		class_destroy(usb_gadget_class);
1284*8443f2d2SAndrzej Pietrasiewicz 		unregister_chrdev_region(g_printer_devno, 1);
1285*8443f2d2SAndrzej Pietrasiewicz 		pr_err("usb_gadget_probe_driver %x\n", status);
1286*8443f2d2SAndrzej Pietrasiewicz 	}
1287*8443f2d2SAndrzej Pietrasiewicz 
1288*8443f2d2SAndrzej Pietrasiewicz 	return status;
1289*8443f2d2SAndrzej Pietrasiewicz }
1290*8443f2d2SAndrzej Pietrasiewicz module_init(init);
1291*8443f2d2SAndrzej Pietrasiewicz 
1292*8443f2d2SAndrzej Pietrasiewicz static void __exit
1293*8443f2d2SAndrzej Pietrasiewicz cleanup(void)
1294*8443f2d2SAndrzej Pietrasiewicz {
1295*8443f2d2SAndrzej Pietrasiewicz 	mutex_lock(&usb_printer_gadget.lock_printer_io);
1296*8443f2d2SAndrzej Pietrasiewicz 	usb_composite_unregister(&printer_driver);
1297*8443f2d2SAndrzej Pietrasiewicz 	unregister_chrdev_region(g_printer_devno, 1);
1298*8443f2d2SAndrzej Pietrasiewicz 	class_destroy(usb_gadget_class);
1299*8443f2d2SAndrzej Pietrasiewicz 	mutex_unlock(&usb_printer_gadget.lock_printer_io);
1300*8443f2d2SAndrzej Pietrasiewicz }
1301*8443f2d2SAndrzej Pietrasiewicz module_exit(cleanup);
1302*8443f2d2SAndrzej Pietrasiewicz 
1303*8443f2d2SAndrzej Pietrasiewicz MODULE_DESCRIPTION(DRIVER_DESC);
1304*8443f2d2SAndrzej Pietrasiewicz MODULE_AUTHOR("Craig Nadler");
1305*8443f2d2SAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
1306