xref: /openbmc/linux/drivers/usb/class/usblp.c (revision d32fd6bb9f2bc8178cdd65ebec1ad670a8bfa241)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
3317c67b8SPete Zaitcev  * usblp.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
6a2531293SPavel Machek  * Copyright (c) 1999 Pavel Machek	<pavel@ucw.cz>
7f4b09ebcSAdrian Bunk  * Copyright (c) 2000 Randy Dunlap	<rdunlap@xenotime.net>
81da177e4SLinus Torvalds  * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
91da177e4SLinus Torvalds  # Copyright (c) 2001 Pete Zaitcev	<zaitcev@redhat.com>
101da177e4SLinus Torvalds  # Copyright (c) 2001 David Paschal	<paschal@rcsis.com>
118e695cdbSOliver Neukum  * Copyright (c) 2006 Oliver Neukum	<oliver@neukum.name>
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * USB Printer Device Class driver for USB printers and printer cables
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  * Sponsored by SuSE
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * ChangeLog:
181da177e4SLinus Torvalds  *	v0.1 - thorough cleaning, URBification, almost a rewrite
191da177e4SLinus Torvalds  *	v0.2 - some more cleanups
201da177e4SLinus Torvalds  *	v0.3 - cleaner again, waitqueue fixes
211da177e4SLinus Torvalds  *	v0.4 - fixes in unidirectional mode
221da177e4SLinus Torvalds  *	v0.5 - add DEVICE_ID string support
231da177e4SLinus Torvalds  *	v0.6 - never time out
241da177e4SLinus Torvalds  *	v0.7 - fixed bulk-IN read and poll (David Paschal)
251da177e4SLinus Torvalds  *	v0.8 - add devfs support
261da177e4SLinus Torvalds  *	v0.9 - fix unplug-while-open paths
271da177e4SLinus Torvalds  *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
281da177e4SLinus Torvalds  *	v0.11 - add proto_bias option (Pete Zaitcev)
291da177e4SLinus Torvalds  *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
301da177e4SLinus Torvalds  *	v0.13 - alloc space for statusbuf (<status> not on stack);
31997ea58eSDaniel Mack  *		use usb_alloc_coherent() for read buf & write buf;
32283face8SPete Zaitcev  *      none  - Maintained in Linux kernel after v0.13
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #include <linux/module.h>
361da177e4SLinus Torvalds #include <linux/kernel.h>
37174cd4b1SIngo Molnar #include <linux/sched/signal.h>
381da177e4SLinus Torvalds #include <linux/signal.h>
391da177e4SLinus Torvalds #include <linux/poll.h>
401da177e4SLinus Torvalds #include <linux/slab.h>
411da177e4SLinus Torvalds #include <linux/lp.h>
424186ecf8SArjan van de Ven #include <linux/mutex.h>
431da177e4SLinus Torvalds #undef DEBUG
441da177e4SLinus Torvalds #include <linux/usb.h>
45298b992fSKrzysztof Opasiak #include <linux/usb/ch9.h>
46305e7be5SManuel Zerpies #include <linux/ratelimit.h>
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /*
491da177e4SLinus Torvalds  * Version Information
501da177e4SLinus Torvalds  */
511da177e4SLinus Torvalds #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
521da177e4SLinus Torvalds #define DRIVER_DESC "USB Printer Device Class driver"
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define USBLP_BUF_SIZE		8192
55317c67b8SPete Zaitcev #define USBLP_BUF_SIZE_IN	1024
561da177e4SLinus Torvalds #define USBLP_DEVICE_ID_SIZE	1024
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /* ioctls: */
591da177e4SLinus Torvalds #define IOCNR_GET_DEVICE_ID		1
601da177e4SLinus Torvalds #define IOCNR_GET_PROTOCOLS		2
611da177e4SLinus Torvalds #define IOCNR_SET_PROTOCOL		3
621da177e4SLinus Torvalds #define IOCNR_HP_SET_CHANNEL		4
631da177e4SLinus Torvalds #define IOCNR_GET_BUS_ADDRESS		5
641da177e4SLinus Torvalds #define IOCNR_GET_VID_PID		6
651da177e4SLinus Torvalds #define IOCNR_SOFT_RESET		7
661da177e4SLinus Torvalds /* Get device_id string: */
671da177e4SLinus Torvalds #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
68298b992fSKrzysztof Opasiak /* The following ioctls were added for http://hpoj.sourceforge.net:
69298b992fSKrzysztof Opasiak  * Get two-int array:
70298b992fSKrzysztof Opasiak  * [0]=current protocol
71298b992fSKrzysztof Opasiak  *     (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
72298b992fSKrzysztof Opasiak  *         3=USB_CLASS_PRINTER/1/3),
73298b992fSKrzysztof Opasiak  * [1]=supported protocol mask (mask&(1<<n)!=0 means
74298b992fSKrzysztof Opasiak  *     USB_CLASS_PRINTER/1/n supported):
75298b992fSKrzysztof Opasiak  */
761da177e4SLinus Torvalds #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
77298b992fSKrzysztof Opasiak /*
78298b992fSKrzysztof Opasiak  * Set protocol
79298b992fSKrzysztof Opasiak  *     (arg: 1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
80298b992fSKrzysztof Opasiak  *         3=USB_CLASS_PRINTER/1/3):
81298b992fSKrzysztof Opasiak  */
821da177e4SLinus Torvalds #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
831da177e4SLinus Torvalds /* Set channel number (HP Vendor-specific command): */
841da177e4SLinus Torvalds #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
851da177e4SLinus Torvalds /* Get two-int array: [0]=bus number, [1]=device address: */
861da177e4SLinus Torvalds #define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
871da177e4SLinus Torvalds /* Get two-int array: [0]=vendor ID, [1]=product ID: */
881da177e4SLinus Torvalds #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
891da177e4SLinus Torvalds /* Perform class specific soft reset */
901da177e4SLinus Torvalds #define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /*
931da177e4SLinus Torvalds  * A DEVICE_ID string may include the printer's serial number.
941da177e4SLinus Torvalds  * It should end with a semi-colon (';').
951da177e4SLinus Torvalds  * An example from an HP 970C DeskJet printer is (this is one long string,
961da177e4SLinus Torvalds  * with the serial number changed):
971da177e4SLinus Torvalds MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ:                    ;
981da177e4SLinus Torvalds  */
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds /*
1011da177e4SLinus Torvalds  * USB Printer Requests
1021da177e4SLinus Torvalds  */
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds #define USBLP_REQ_GET_ID			0x00
1051da177e4SLinus Torvalds #define USBLP_REQ_GET_STATUS			0x01
1061da177e4SLinus Torvalds #define USBLP_REQ_RESET				0x02
1071da177e4SLinus Torvalds #define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds #define USBLP_MINORS		16
1101da177e4SLinus Torvalds #define USBLP_MINOR_BASE	0
1111da177e4SLinus Torvalds 
112283face8SPete Zaitcev #define USBLP_CTL_TIMEOUT	5000			/* 5 seconds */
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds #define USBLP_FIRST_PROTOCOL	1
1151da177e4SLinus Torvalds #define USBLP_LAST_PROTOCOL	3
1161da177e4SLinus Torvalds #define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds /*
1191da177e4SLinus Torvalds  * some arbitrary status buffer size;
1201da177e4SLinus Torvalds  * need a status buffer that is allocated via kmalloc(), not on stack
1211da177e4SLinus Torvalds  */
1221da177e4SLinus Torvalds #define STATUS_BUF_SIZE		8
1231da177e4SLinus Torvalds 
124317c67b8SPete Zaitcev /*
125317c67b8SPete Zaitcev  * Locks down the locking order:
126317c67b8SPete Zaitcev  * ->wmut locks wstatus.
127317c67b8SPete Zaitcev  * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection,
128317c67b8SPete Zaitcev  * [rw]status. We only touch status when we know the side idle.
129317c67b8SPete Zaitcev  * ->lock locks what interrupt accesses.
130317c67b8SPete Zaitcev  */
1311da177e4SLinus Torvalds struct usblp {
1321da177e4SLinus Torvalds 	struct usb_device	*dev;			/* USB device */
133317c67b8SPete Zaitcev 	struct mutex		wmut;
134317c67b8SPete Zaitcev 	struct mutex		mut;
135317c67b8SPete Zaitcev 	spinlock_t		lock;		/* locks rcomplete, wcomplete */
1361da177e4SLinus Torvalds 	char			*readbuf;		/* read transfer_buffer */
1371da177e4SLinus Torvalds 	char			*statusbuf;		/* status transfer_buffer */
138317c67b8SPete Zaitcev 	struct usb_anchor	urbs;
139317c67b8SPete Zaitcev 	wait_queue_head_t	rwait, wwait;
1401da177e4SLinus Torvalds 	int			readcount;		/* Counter for reads */
1411da177e4SLinus Torvalds 	int			ifnum;			/* Interface number */
1421da177e4SLinus Torvalds 	struct usb_interface	*intf;			/* The interface */
143298b992fSKrzysztof Opasiak 	/*
144298b992fSKrzysztof Opasiak 	 * Alternate-setting numbers and endpoints for each protocol
145298b992fSKrzysztof Opasiak 	 * (USB_CLASS_PRINTER/1/{index=1,2,3}) that the device supports:
146298b992fSKrzysztof Opasiak 	 */
1471da177e4SLinus Torvalds 	struct {
1481da177e4SLinus Torvalds 		int				alt_setting;
1491da177e4SLinus Torvalds 		struct usb_endpoint_descriptor	*epwrite;
1501da177e4SLinus Torvalds 		struct usb_endpoint_descriptor	*epread;
1511da177e4SLinus Torvalds 	}			protocol[USBLP_MAX_PROTOCOLS];
1521da177e4SLinus Torvalds 	int			current_protocol;
1531da177e4SLinus Torvalds 	int			minor;			/* minor number of device */
154317c67b8SPete Zaitcev 	int			wcomplete, rcomplete;
155317c67b8SPete Zaitcev 	int			wstatus;	/* bytes written or error */
156317c67b8SPete Zaitcev 	int			rstatus;	/* bytes ready or error */
1571da177e4SLinus Torvalds 	unsigned int		quirks;			/* quirks flags */
1587f477358SPete Zaitcev 	unsigned int		flags;			/* mode flags */
1591da177e4SLinus Torvalds 	unsigned char		used;			/* True if open */
1601da177e4SLinus Torvalds 	unsigned char		present;		/* True if not disconnected */
1611da177e4SLinus Torvalds 	unsigned char		bidir;			/* interface is bidirectional */
1627f477358SPete Zaitcev 	unsigned char		no_paper;		/* Paper Out happened */
1631da177e4SLinus Torvalds 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
1641da177e4SLinus Torvalds 							/* first 2 bytes are (big-endian) length */
1651da177e4SLinus Torvalds };
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #ifdef DEBUG
usblp_dump(struct usblp * usblp)168916de027SNicolas Kaiser static void usblp_dump(struct usblp *usblp)
169916de027SNicolas Kaiser {
1704f306309SGreg Kroah-Hartman 	struct device *dev = &usblp->intf->dev;
1711da177e4SLinus Torvalds 	int p;
1721da177e4SLinus Torvalds 
1734f306309SGreg Kroah-Hartman 	dev_dbg(dev, "usblp=0x%p\n", usblp);
1744f306309SGreg Kroah-Hartman 	dev_dbg(dev, "dev=0x%p\n", usblp->dev);
1754f306309SGreg Kroah-Hartman 	dev_dbg(dev, "present=%d\n", usblp->present);
1764f306309SGreg Kroah-Hartman 	dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf);
1774f306309SGreg Kroah-Hartman 	dev_dbg(dev, "readcount=%d\n", usblp->readcount);
1784f306309SGreg Kroah-Hartman 	dev_dbg(dev, "ifnum=%d\n", usblp->ifnum);
1791da177e4SLinus Torvalds 	for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
1804f306309SGreg Kroah-Hartman 		dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p,
1814f306309SGreg Kroah-Hartman 			usblp->protocol[p].alt_setting);
1824f306309SGreg Kroah-Hartman 		dev_dbg(dev, "protocol[%d].epwrite=%p\n", p,
1834f306309SGreg Kroah-Hartman 			usblp->protocol[p].epwrite);
1844f306309SGreg Kroah-Hartman 		dev_dbg(dev, "protocol[%d].epread=%p\n", p,
1854f306309SGreg Kroah-Hartman 			usblp->protocol[p].epread);
1861da177e4SLinus Torvalds 	}
1874f306309SGreg Kroah-Hartman 	dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol);
1884f306309SGreg Kroah-Hartman 	dev_dbg(dev, "minor=%d\n", usblp->minor);
1894f306309SGreg Kroah-Hartman 	dev_dbg(dev, "wstatus=%d\n", usblp->wstatus);
1904f306309SGreg Kroah-Hartman 	dev_dbg(dev, "rstatus=%d\n", usblp->rstatus);
1914f306309SGreg Kroah-Hartman 	dev_dbg(dev, "quirks=%d\n", usblp->quirks);
1924f306309SGreg Kroah-Hartman 	dev_dbg(dev, "used=%d\n", usblp->used);
1934f306309SGreg Kroah-Hartman 	dev_dbg(dev, "bidir=%d\n", usblp->bidir);
1944f306309SGreg Kroah-Hartman 	dev_dbg(dev, "device_id_string=\"%s\"\n",
1951da177e4SLinus Torvalds 		usblp->device_id_string ?
1961da177e4SLinus Torvalds 			usblp->device_id_string + 2 :
1971da177e4SLinus Torvalds 			(unsigned char *)"(null)");
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds #endif
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds /* Quirks: various printer quirks are handled by this table & its flags. */
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds struct quirk_printer_struct {
2041da177e4SLinus Torvalds 	__u16 vendorId;
2051da177e4SLinus Torvalds 	__u16 productId;
2061da177e4SLinus Torvalds 	unsigned int quirks;
2071da177e4SLinus Torvalds };
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds #define USBLP_QUIRK_BIDIR	0x1	/* reports bidir but requires unidirectional mode (no INs/reads) */
2101da177e4SLinus Torvalds #define USBLP_QUIRK_USB_INIT	0x2	/* needs vendor USB init string */
2115ec71db5SAlan Stern #define USBLP_QUIRK_BAD_CLASS	0x4	/* descriptor uses vendor-specific Class or SubClass */
2121da177e4SLinus Torvalds 
2134c4c9432SArjan van de Ven static const struct quirk_printer_struct quirk_printers[] = {
2141da177e4SLinus Torvalds 	{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
2151da177e4SLinus Torvalds 	{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
2161da177e4SLinus Torvalds 	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
2171da177e4SLinus Torvalds 	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
2181da177e4SLinus Torvalds 	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
2191da177e4SLinus Torvalds 	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
2201da177e4SLinus Torvalds 	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */
2211da177e4SLinus Torvalds 	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */
2221da177e4SLinus Torvalds 	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
2231da177e4SLinus Torvalds 	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
2241da177e4SLinus Torvalds 	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
2251da177e4SLinus Torvalds 	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
2261da177e4SLinus Torvalds 	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
2274f45d038SMartin Williges 	{ 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */
22806a743bfSBrandon Philips 	{ 0x04f9, 0x000d, USBLP_QUIRK_BIDIR }, /* Brother Industries, Ltd HL-1440 Laser Printer */
2295ec71db5SAlan Stern 	{ 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */
2301da177e4SLinus Torvalds 	{ 0, 0 }
2311da177e4SLinus Torvalds };
2321da177e4SLinus Torvalds 
233317c67b8SPete Zaitcev static int usblp_wwait(struct usblp *usblp, int nonblock);
234317c67b8SPete Zaitcev static int usblp_wtest(struct usblp *usblp, int nonblock);
235317c67b8SPete Zaitcev static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
236317c67b8SPete Zaitcev static int usblp_rtest(struct usblp *usblp, int nonblock);
237317c67b8SPete Zaitcev static int usblp_submit_read(struct usblp *usblp);
2381da177e4SLinus Torvalds static int usblp_select_alts(struct usblp *usblp);
2391da177e4SLinus Torvalds static int usblp_set_protocol(struct usblp *usblp, int protocol);
2401da177e4SLinus Torvalds static int usblp_cache_device_id_string(struct usblp *usblp);
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds /* forward reference to make our lives easier */
2431da177e4SLinus Torvalds static struct usb_driver usblp_driver;
2444186ecf8SArjan van de Ven static DEFINE_MUTEX(usblp_mutex);	/* locks the existence of usblp's */
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds /*
2471da177e4SLinus Torvalds  * Functions for usblp control messages.
2481da177e4SLinus Torvalds  */
2491da177e4SLinus Torvalds 
usblp_ctrl_msg(struct usblp * usblp,int request,int type,int dir,int recip,int value,void * buf,int len)2501da177e4SLinus Torvalds static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	int retval;
2531da177e4SLinus Torvalds 	int index = usblp->ifnum;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	/* High byte has the interface index.
2561da177e4SLinus Torvalds 	   Low byte has the alternate setting.
2571da177e4SLinus Torvalds 	 */
258916de027SNicolas Kaiser 	if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS))
2591da177e4SLinus Torvalds 		index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	retval = usb_control_msg(usblp->dev,
2621da177e4SLinus Torvalds 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
263283face8SPete Zaitcev 		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
2644f306309SGreg Kroah-Hartman 	dev_dbg(&usblp->intf->dev,
2654f306309SGreg Kroah-Hartman 		"usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n",
2661da177e4SLinus Torvalds 		request, !!dir, recip, value, index, len, retval);
2671da177e4SLinus Torvalds 	return retval < 0 ? retval : 0;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds #define usblp_read_status(usblp, status)\
2711da177e4SLinus Torvalds 	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
2721da177e4SLinus Torvalds #define usblp_get_id(usblp, config, id, maxlen)\
2731da177e4SLinus Torvalds 	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
2741da177e4SLinus Torvalds #define usblp_reset(usblp)\
2751da177e4SLinus Torvalds 	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
2761da177e4SLinus Torvalds 
usblp_hp_channel_change_request(struct usblp * usblp,int channel,u8 * new_channel)277020a1f45SJohan Hovold static int usblp_hp_channel_change_request(struct usblp *usblp, int channel, u8 *new_channel)
278020a1f45SJohan Hovold {
279020a1f45SJohan Hovold 	u8 *buf;
280020a1f45SJohan Hovold 	int ret;
281020a1f45SJohan Hovold 
282020a1f45SJohan Hovold 	buf = kzalloc(1, GFP_KERNEL);
283020a1f45SJohan Hovold 	if (!buf)
284020a1f45SJohan Hovold 		return -ENOMEM;
285020a1f45SJohan Hovold 
286020a1f45SJohan Hovold 	ret = usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST,
287020a1f45SJohan Hovold 			USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE,
288020a1f45SJohan Hovold 			channel, buf, 1);
289020a1f45SJohan Hovold 	if (ret == 0)
290020a1f45SJohan Hovold 		*new_channel = buf[0];
291020a1f45SJohan Hovold 
292020a1f45SJohan Hovold 	kfree(buf);
293020a1f45SJohan Hovold 
294020a1f45SJohan Hovold 	return ret;
295020a1f45SJohan Hovold }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds /*
2981da177e4SLinus Torvalds  * See the description for usblp_select_alts() below for the usage
29921470e32SMauro Carvalho Chehab  * explanation.  Look into your /sys/kernel/debug/usb/devices and dmesg in
3001da177e4SLinus Torvalds  * case of any trouble.
3011da177e4SLinus Torvalds  */
3021da177e4SLinus Torvalds static int proto_bias = -1;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds /*
3051da177e4SLinus Torvalds  * URB callback.
3061da177e4SLinus Torvalds  */
3071da177e4SLinus Torvalds 
usblp_bulk_read(struct urb * urb)3087d12e780SDavid Howells static void usblp_bulk_read(struct urb *urb)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds 	struct usblp *usblp = urb->context;
31118ac3016SGreg Kroah-Hartman 	int status = urb->status;
3120f5f7aceSSebastian Andrzej Siewior 	unsigned long flags;
3131da177e4SLinus Torvalds 
314317c67b8SPete Zaitcev 	if (usblp->present && usblp->used) {
31518ac3016SGreg Kroah-Hartman 		if (status)
316317c67b8SPete Zaitcev 			printk(KERN_WARNING "usblp%d: "
317317c67b8SPete Zaitcev 			    "nonzero read bulk status received: %d\n",
31818ac3016SGreg Kroah-Hartman 			    usblp->minor, status);
319317c67b8SPete Zaitcev 	}
3200f5f7aceSSebastian Andrzej Siewior 	spin_lock_irqsave(&usblp->lock, flags);
32118ac3016SGreg Kroah-Hartman 	if (status < 0)
32218ac3016SGreg Kroah-Hartman 		usblp->rstatus = status;
323317c67b8SPete Zaitcev 	else
324317c67b8SPete Zaitcev 		usblp->rstatus = urb->actual_length;
3251da177e4SLinus Torvalds 	usblp->rcomplete = 1;
326317c67b8SPete Zaitcev 	wake_up(&usblp->rwait);
3270f5f7aceSSebastian Andrzej Siewior 	spin_unlock_irqrestore(&usblp->lock, flags);
328317c67b8SPete Zaitcev 
329317c67b8SPete Zaitcev 	usb_free_urb(urb);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
usblp_bulk_write(struct urb * urb)3327d12e780SDavid Howells static void usblp_bulk_write(struct urb *urb)
3331da177e4SLinus Torvalds {
3341da177e4SLinus Torvalds 	struct usblp *usblp = urb->context;
33518ac3016SGreg Kroah-Hartman 	int status = urb->status;
3360f5f7aceSSebastian Andrzej Siewior 	unsigned long flags;
3371da177e4SLinus Torvalds 
338317c67b8SPete Zaitcev 	if (usblp->present && usblp->used) {
33918ac3016SGreg Kroah-Hartman 		if (status)
340317c67b8SPete Zaitcev 			printk(KERN_WARNING "usblp%d: "
341317c67b8SPete Zaitcev 			    "nonzero write bulk status received: %d\n",
34218ac3016SGreg Kroah-Hartman 			    usblp->minor, status);
343317c67b8SPete Zaitcev 	}
3440f5f7aceSSebastian Andrzej Siewior 	spin_lock_irqsave(&usblp->lock, flags);
34518ac3016SGreg Kroah-Hartman 	if (status < 0)
34618ac3016SGreg Kroah-Hartman 		usblp->wstatus = status;
347317c67b8SPete Zaitcev 	else
348317c67b8SPete Zaitcev 		usblp->wstatus = urb->actual_length;
3497f477358SPete Zaitcev 	usblp->no_paper = 0;
3501da177e4SLinus Torvalds 	usblp->wcomplete = 1;
351317c67b8SPete Zaitcev 	wake_up(&usblp->wwait);
3520f5f7aceSSebastian Andrzej Siewior 	spin_unlock_irqrestore(&usblp->lock, flags);
353317c67b8SPete Zaitcev 
354317c67b8SPete Zaitcev 	usb_free_urb(urb);
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds /*
3581da177e4SLinus Torvalds  * Get and print printer errors.
3591da177e4SLinus Torvalds  */
3601da177e4SLinus Torvalds 
3614c4c9432SArjan van de Ven static const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
3621da177e4SLinus Torvalds 
usblp_check_status(struct usblp * usblp,int err)3631da177e4SLinus Torvalds static int usblp_check_status(struct usblp *usblp, int err)
3641da177e4SLinus Torvalds {
3651da177e4SLinus Torvalds 	unsigned char status, newerr = 0;
3661da177e4SLinus Torvalds 	int error;
3671da177e4SLinus Torvalds 
368fc401e69SPete Zaitcev 	mutex_lock(&usblp->mut);
369fc401e69SPete Zaitcev 	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
370fc401e69SPete Zaitcev 		mutex_unlock(&usblp->mut);
371305e7be5SManuel Zerpies 		printk_ratelimited(KERN_ERR
372317c67b8SPete Zaitcev 				"usblp%d: error %d reading printer status\n",
3731da177e4SLinus Torvalds 				usblp->minor, error);
3741da177e4SLinus Torvalds 		return 0;
3751da177e4SLinus Torvalds 	}
3761da177e4SLinus Torvalds 	status = *usblp->statusbuf;
377fc401e69SPete Zaitcev 	mutex_unlock(&usblp->mut);
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	if (~status & LP_PERRORP)
3801da177e4SLinus Torvalds 		newerr = 3;
3811da177e4SLinus Torvalds 	if (status & LP_POUTPA)
3821da177e4SLinus Torvalds 		newerr = 1;
3831da177e4SLinus Torvalds 	if (~status & LP_PSELECD)
3841da177e4SLinus Torvalds 		newerr = 2;
3851da177e4SLinus Torvalds 
386317c67b8SPete Zaitcev 	if (newerr != err) {
387317c67b8SPete Zaitcev 		printk(KERN_INFO "usblp%d: %s\n",
388317c67b8SPete Zaitcev 		   usblp->minor, usblp_messages[newerr]);
389317c67b8SPete Zaitcev 	}
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	return newerr;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
handle_bidir(struct usblp * usblp)394516077c1SOliver Neukum static int handle_bidir(struct usblp *usblp)
395516077c1SOliver Neukum {
3963a90f818SOliver Neukum 	if (usblp->bidir && usblp->used) {
397317c67b8SPete Zaitcev 		if (usblp_submit_read(usblp) < 0)
398516077c1SOliver Neukum 			return -EIO;
399516077c1SOliver Neukum 	}
400516077c1SOliver Neukum 	return 0;
401516077c1SOliver Neukum }
402516077c1SOliver Neukum 
4031da177e4SLinus Torvalds /*
4041da177e4SLinus Torvalds  * File op functions.
4051da177e4SLinus Torvalds  */
4061da177e4SLinus Torvalds 
usblp_open(struct inode * inode,struct file * file)4071da177e4SLinus Torvalds static int usblp_open(struct inode *inode, struct file *file)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	int minor = iminor(inode);
4101da177e4SLinus Torvalds 	struct usblp *usblp;
4111da177e4SLinus Torvalds 	struct usb_interface *intf;
4121da177e4SLinus Torvalds 	int retval;
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	if (minor < 0)
4151da177e4SLinus Torvalds 		return -ENODEV;
4161da177e4SLinus Torvalds 
4174186ecf8SArjan van de Ven 	mutex_lock(&usblp_mutex);
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	retval = -ENODEV;
4201da177e4SLinus Torvalds 	intf = usb_find_interface(&usblp_driver, minor);
421916de027SNicolas Kaiser 	if (!intf)
4221da177e4SLinus Torvalds 		goto out;
4231da177e4SLinus Torvalds 	usblp = usb_get_intfdata(intf);
4241da177e4SLinus Torvalds 	if (!usblp || !usblp->dev || !usblp->present)
4251da177e4SLinus Torvalds 		goto out;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	retval = -EBUSY;
4281da177e4SLinus Torvalds 	if (usblp->used)
4291da177e4SLinus Torvalds 		goto out;
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	/*
4327f477358SPete Zaitcev 	 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
4337f477358SPete Zaitcev 	 *  - We do not want persistent state which close(2) does not clear
4347f477358SPete Zaitcev 	 *  - It is not used anyway, according to CUPS people
4351da177e4SLinus Torvalds 	 */
4361da177e4SLinus Torvalds 
437d0532184SOliver Neukum 	retval = usb_autopm_get_interface(intf);
438d0532184SOliver Neukum 	if (retval < 0)
439d0532184SOliver Neukum 		goto out;
4401da177e4SLinus Torvalds 	usblp->used = 1;
4411da177e4SLinus Torvalds 	file->private_data = usblp;
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	usblp->wcomplete = 1; /* we begin writeable */
444317c67b8SPete Zaitcev 	usblp->wstatus = 0;
4451da177e4SLinus Torvalds 	usblp->rcomplete = 0;
4461da177e4SLinus Torvalds 
447516077c1SOliver Neukum 	if (handle_bidir(usblp) < 0) {
44819028690SOliver Neukum 		usb_autopm_put_interface(intf);
44997cb95d1SPete Zaitcev 		usblp->used = 0;
4501da177e4SLinus Torvalds 		file->private_data = NULL;
451516077c1SOliver Neukum 		retval = -EIO;
4521da177e4SLinus Torvalds 	}
4531da177e4SLinus Torvalds out:
4544186ecf8SArjan van de Ven 	mutex_unlock(&usblp_mutex);
4551da177e4SLinus Torvalds 	return retval;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
usblp_cleanup(struct usblp * usblp)4581da177e4SLinus Torvalds static void usblp_cleanup(struct usblp *usblp)
4591da177e4SLinus Torvalds {
460317c67b8SPete Zaitcev 	printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
4611da177e4SLinus Torvalds 
462317c67b8SPete Zaitcev 	kfree(usblp->readbuf);
4631da177e4SLinus Torvalds 	kfree(usblp->device_id_string);
4641da177e4SLinus Torvalds 	kfree(usblp->statusbuf);
4657a759197SJohan Hovold 	usb_put_intf(usblp->intf);
4661da177e4SLinus Torvalds 	kfree(usblp);
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds 
usblp_unlink_urbs(struct usblp * usblp)4691da177e4SLinus Torvalds static void usblp_unlink_urbs(struct usblp *usblp)
4701da177e4SLinus Torvalds {
471317c67b8SPete Zaitcev 	usb_kill_anchored_urbs(&usblp->urbs);
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
usblp_release(struct inode * inode,struct file * file)4741da177e4SLinus Torvalds static int usblp_release(struct inode *inode, struct file *file)
4751da177e4SLinus Torvalds {
4761da177e4SLinus Torvalds 	struct usblp *usblp = file->private_data;
4771da177e4SLinus Torvalds 
4787f477358SPete Zaitcev 	usblp->flags &= ~LP_ABORT;
4797f477358SPete Zaitcev 
4804186ecf8SArjan van de Ven 	mutex_lock(&usblp_mutex);
4811da177e4SLinus Torvalds 	usblp->used = 0;
4829a315358SJohan Hovold 	if (usblp->present)
4831da177e4SLinus Torvalds 		usblp_unlink_urbs(usblp);
4849a315358SJohan Hovold 
485d0532184SOliver Neukum 	usb_autopm_put_interface(usblp->intf);
4869a315358SJohan Hovold 
4879a315358SJohan Hovold 	if (!usblp->present)		/* finish cleanup from disconnect */
488296a193bSOliver Neukum 		usblp_cleanup(usblp);	/* any URBs must be dead */
489296a193bSOliver Neukum 
4904186ecf8SArjan van de Ven 	mutex_unlock(&usblp_mutex);
4911da177e4SLinus Torvalds 	return 0;
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds /* No kernel lock - fine */
usblp_poll(struct file * file,struct poll_table_struct * wait)495afc9a42bSAl Viro static __poll_t usblp_poll(struct file *file, struct poll_table_struct *wait)
4961da177e4SLinus Torvalds {
4979de2c43aSPete Zaitcev 	struct usblp *usblp = file->private_data;
4989de2c43aSPete Zaitcev 	__poll_t ret = 0;
499317c67b8SPete Zaitcev 	unsigned long flags;
500317c67b8SPete Zaitcev 
501317c67b8SPete Zaitcev 	/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
502317c67b8SPete Zaitcev 	poll_wait(file, &usblp->rwait, wait);
503317c67b8SPete Zaitcev 	poll_wait(file, &usblp->wwait, wait);
5049de2c43aSPete Zaitcev 
5059de2c43aSPete Zaitcev 	mutex_lock(&usblp->mut);
5069de2c43aSPete Zaitcev 	if (!usblp->present)
5079de2c43aSPete Zaitcev 		ret |= EPOLLHUP;
5089de2c43aSPete Zaitcev 	mutex_unlock(&usblp->mut);
5099de2c43aSPete Zaitcev 
510317c67b8SPete Zaitcev 	spin_lock_irqsave(&usblp->lock, flags);
5119de2c43aSPete Zaitcev 	if (usblp->bidir && usblp->rcomplete)
5129de2c43aSPete Zaitcev 		ret |= EPOLLIN  | EPOLLRDNORM;
5139de2c43aSPete Zaitcev 	if (usblp->no_paper || usblp->wcomplete)
5149de2c43aSPete Zaitcev 		ret |= EPOLLOUT | EPOLLWRNORM;
515317c67b8SPete Zaitcev 	spin_unlock_irqrestore(&usblp->lock, flags);
516317c67b8SPete Zaitcev 	return ret;
5171da177e4SLinus Torvalds }
5181da177e4SLinus Torvalds 
usblp_ioctl(struct file * file,unsigned int cmd,unsigned long arg)519318e479eSPete Zaitcev static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
5201da177e4SLinus Torvalds {
5211da177e4SLinus Torvalds 	struct usblp *usblp = file->private_data;
5221da177e4SLinus Torvalds 	int length, err, i;
5231da177e4SLinus Torvalds 	unsigned char newChannel;
5241da177e4SLinus Torvalds 	int status;
5251da177e4SLinus Torvalds 	int twoints[2];
5261da177e4SLinus Torvalds 	int retval = 0;
5271da177e4SLinus Torvalds 
5288e422669SOliver Neukum 	mutex_lock(&usblp->mut);
5291da177e4SLinus Torvalds 	if (!usblp->present) {
5301da177e4SLinus Torvalds 		retval = -ENODEV;
5311da177e4SLinus Torvalds 		goto done;
5321da177e4SLinus Torvalds 	}
5331da177e4SLinus Torvalds 
5344f306309SGreg Kroah-Hartman 	dev_dbg(&usblp->intf->dev,
5354f306309SGreg Kroah-Hartman 		"usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd,
5364f306309SGreg Kroah-Hartman 		_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 		switch (_IOC_NR(cmd)) {
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds 		case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
5431da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_READ) {
5441da177e4SLinus Torvalds 				retval = -EINVAL;
5451da177e4SLinus Torvalds 				goto done;
5461da177e4SLinus Torvalds 			}
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 			length = usblp_cache_device_id_string(usblp);
5491da177e4SLinus Torvalds 			if (length < 0) {
5501da177e4SLinus Torvalds 				retval = length;
5511da177e4SLinus Torvalds 				goto done;
5521da177e4SLinus Torvalds 			}
5531da177e4SLinus Torvalds 			if (length > _IOC_SIZE(cmd))
5541da177e4SLinus Torvalds 				length = _IOC_SIZE(cmd); /* truncate */
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 			if (copy_to_user((void __user *) arg,
5571da177e4SLinus Torvalds 					usblp->device_id_string,
5581da177e4SLinus Torvalds 					(unsigned long) length)) {
5591da177e4SLinus Torvalds 				retval = -EFAULT;
5601da177e4SLinus Torvalds 				goto done;
5611da177e4SLinus Torvalds 			}
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 			break;
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 		case IOCNR_GET_PROTOCOLS:
5661da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_READ ||
5671da177e4SLinus Torvalds 			    _IOC_SIZE(cmd) < sizeof(twoints)) {
5681da177e4SLinus Torvalds 				retval = -EINVAL;
5691da177e4SLinus Torvalds 				goto done;
5701da177e4SLinus Torvalds 			}
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 			twoints[0] = usblp->current_protocol;
5731da177e4SLinus Torvalds 			twoints[1] = 0;
5741da177e4SLinus Torvalds 			for (i = USBLP_FIRST_PROTOCOL;
5751da177e4SLinus Torvalds 			     i <= USBLP_LAST_PROTOCOL; i++) {
5761da177e4SLinus Torvalds 				if (usblp->protocol[i].alt_setting >= 0)
5771da177e4SLinus Torvalds 					twoints[1] |= (1<<i);
5781da177e4SLinus Torvalds 			}
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 			if (copy_to_user((void __user *)arg,
5811da177e4SLinus Torvalds 					(unsigned char *)twoints,
5821da177e4SLinus Torvalds 					sizeof(twoints))) {
5831da177e4SLinus Torvalds 				retval = -EFAULT;
5841da177e4SLinus Torvalds 				goto done;
5851da177e4SLinus Torvalds 			}
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 			break;
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds 		case IOCNR_SET_PROTOCOL:
5901da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_WRITE) {
5911da177e4SLinus Torvalds 				retval = -EINVAL;
5921da177e4SLinus Torvalds 				goto done;
5931da177e4SLinus Torvalds 			}
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds #ifdef DEBUG
5961da177e4SLinus Torvalds 			if (arg == -10) {
5971da177e4SLinus Torvalds 				usblp_dump(usblp);
5981da177e4SLinus Torvalds 				break;
5991da177e4SLinus Torvalds 			}
6001da177e4SLinus Torvalds #endif
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 			usblp_unlink_urbs(usblp);
6031da177e4SLinus Torvalds 			retval = usblp_set_protocol(usblp, arg);
6041da177e4SLinus Torvalds 			if (retval < 0) {
6051da177e4SLinus Torvalds 				usblp_set_protocol(usblp,
6061da177e4SLinus Torvalds 					usblp->current_protocol);
6071da177e4SLinus Torvalds 			}
6081da177e4SLinus Torvalds 			break;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 		case IOCNR_HP_SET_CHANNEL:
6111da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_WRITE ||
6121da177e4SLinus Torvalds 			    le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 ||
6131da177e4SLinus Torvalds 			    usblp->quirks & USBLP_QUIRK_BIDIR) {
6141da177e4SLinus Torvalds 				retval = -EINVAL;
6151da177e4SLinus Torvalds 				goto done;
6161da177e4SLinus Torvalds 			}
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 			err = usblp_hp_channel_change_request(usblp,
6191da177e4SLinus Torvalds 				arg, &newChannel);
6201da177e4SLinus Torvalds 			if (err < 0) {
6219908a32eSGreg Kroah-Hartman 				dev_err(&usblp->dev->dev,
6229908a32eSGreg Kroah-Hartman 					"usblp%d: error = %d setting "
6239908a32eSGreg Kroah-Hartman 					"HP channel\n",
6241da177e4SLinus Torvalds 					usblp->minor, err);
6251da177e4SLinus Torvalds 				retval = -EIO;
6261da177e4SLinus Torvalds 				goto done;
6271da177e4SLinus Torvalds 			}
6281da177e4SLinus Torvalds 
6294f306309SGreg Kroah-Hartman 			dev_dbg(&usblp->intf->dev,
6304f306309SGreg Kroah-Hartman 				"usblp%d requested/got HP channel %ld/%d\n",
6311da177e4SLinus Torvalds 				usblp->minor, arg, newChannel);
6321da177e4SLinus Torvalds 			break;
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds 		case IOCNR_GET_BUS_ADDRESS:
6351da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_READ ||
6361da177e4SLinus Torvalds 			    _IOC_SIZE(cmd) < sizeof(twoints)) {
6371da177e4SLinus Torvalds 				retval = -EINVAL;
6381da177e4SLinus Torvalds 				goto done;
6391da177e4SLinus Torvalds 			}
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 			twoints[0] = usblp->dev->bus->busnum;
6421da177e4SLinus Torvalds 			twoints[1] = usblp->dev->devnum;
6431da177e4SLinus Torvalds 			if (copy_to_user((void __user *)arg,
6441da177e4SLinus Torvalds 					(unsigned char *)twoints,
6451da177e4SLinus Torvalds 					sizeof(twoints))) {
6461da177e4SLinus Torvalds 				retval = -EFAULT;
6471da177e4SLinus Torvalds 				goto done;
6481da177e4SLinus Torvalds 			}
6491da177e4SLinus Torvalds 
6504f306309SGreg Kroah-Hartman 			dev_dbg(&usblp->intf->dev,
6514f306309SGreg Kroah-Hartman 				"usblp%d is bus=%d, device=%d\n",
6521da177e4SLinus Torvalds 				usblp->minor, twoints[0], twoints[1]);
6531da177e4SLinus Torvalds 			break;
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 		case IOCNR_GET_VID_PID:
6561da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_READ ||
6571da177e4SLinus Torvalds 			    _IOC_SIZE(cmd) < sizeof(twoints)) {
6581da177e4SLinus Torvalds 				retval = -EINVAL;
6591da177e4SLinus Torvalds 				goto done;
6601da177e4SLinus Torvalds 			}
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 			twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor);
6631da177e4SLinus Torvalds 			twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);
6641da177e4SLinus Torvalds 			if (copy_to_user((void __user *)arg,
6651da177e4SLinus Torvalds 					(unsigned char *)twoints,
6661da177e4SLinus Torvalds 					sizeof(twoints))) {
6671da177e4SLinus Torvalds 				retval = -EFAULT;
6681da177e4SLinus Torvalds 				goto done;
6691da177e4SLinus Torvalds 			}
6701da177e4SLinus Torvalds 
6714f306309SGreg Kroah-Hartman 			dev_dbg(&usblp->intf->dev,
6724f306309SGreg Kroah-Hartman 				"usblp%d is VID=0x%4.4X, PID=0x%4.4X\n",
6731da177e4SLinus Torvalds 				usblp->minor, twoints[0], twoints[1]);
6741da177e4SLinus Torvalds 			break;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 		case IOCNR_SOFT_RESET:
6771da177e4SLinus Torvalds 			if (_IOC_DIR(cmd) != _IOC_NONE) {
6781da177e4SLinus Torvalds 				retval = -EINVAL;
6791da177e4SLinus Torvalds 				goto done;
6801da177e4SLinus Torvalds 			}
6811da177e4SLinus Torvalds 			retval = usblp_reset(usblp);
6821da177e4SLinus Torvalds 			break;
6831da177e4SLinus Torvalds 		default:
6841da177e4SLinus Torvalds 			retval = -ENOTTY;
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 	else	/* old-style ioctl value */
6871da177e4SLinus Torvalds 		switch (cmd) {
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 		case LPGETSTATUS:
6902fcdbdfdSGreg Kroah-Hartman 			retval = usblp_read_status(usblp, usblp->statusbuf);
6912fcdbdfdSGreg Kroah-Hartman 			if (retval) {
692305e7be5SManuel Zerpies 				printk_ratelimited(KERN_ERR "usblp%d:"
693317c67b8SPete Zaitcev 					    "failed reading printer status (%d)\n",
694317c67b8SPete Zaitcev 					    usblp->minor, retval);
6951da177e4SLinus Torvalds 				retval = -EIO;
6961da177e4SLinus Torvalds 				goto done;
6971da177e4SLinus Torvalds 			}
6981da177e4SLinus Torvalds 			status = *usblp->statusbuf;
6991da177e4SLinus Torvalds 			if (copy_to_user((void __user *)arg, &status, sizeof(int)))
7001da177e4SLinus Torvalds 				retval = -EFAULT;
7011da177e4SLinus Torvalds 			break;
7021da177e4SLinus Torvalds 
7037f477358SPete Zaitcev 		case LPABORT:
7047f477358SPete Zaitcev 			if (arg)
7057f477358SPete Zaitcev 				usblp->flags |= LP_ABORT;
7067f477358SPete Zaitcev 			else
7077f477358SPete Zaitcev 				usblp->flags &= ~LP_ABORT;
7087f477358SPete Zaitcev 			break;
7097f477358SPete Zaitcev 
7101da177e4SLinus Torvalds 		default:
7111da177e4SLinus Torvalds 			retval = -ENOTTY;
7121da177e4SLinus Torvalds 		}
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds done:
7158e422669SOliver Neukum 	mutex_unlock(&usblp->mut);
7161da177e4SLinus Torvalds 	return retval;
7171da177e4SLinus Torvalds }
7181da177e4SLinus Torvalds 
usblp_new_writeurb(struct usblp * usblp,int transfer_length)71942cb967fSPete Zaitcev static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
72042cb967fSPete Zaitcev {
72142cb967fSPete Zaitcev 	struct urb *urb;
72242cb967fSPete Zaitcev 	char *writebuf;
72342cb967fSPete Zaitcev 
7242fcdbdfdSGreg Kroah-Hartman 	writebuf = kmalloc(transfer_length, GFP_KERNEL);
7252fcdbdfdSGreg Kroah-Hartman 	if (writebuf == NULL)
72642cb967fSPete Zaitcev 		return NULL;
7272fcdbdfdSGreg Kroah-Hartman 	urb = usb_alloc_urb(0, GFP_KERNEL);
7282fcdbdfdSGreg Kroah-Hartman 	if (urb == NULL) {
72942cb967fSPete Zaitcev 		kfree(writebuf);
73042cb967fSPete Zaitcev 		return NULL;
73142cb967fSPete Zaitcev 	}
73242cb967fSPete Zaitcev 
73342cb967fSPete Zaitcev 	usb_fill_bulk_urb(urb, usblp->dev,
73442cb967fSPete Zaitcev 		usb_sndbulkpipe(usblp->dev,
73542cb967fSPete Zaitcev 		 usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
73642cb967fSPete Zaitcev 		writebuf, transfer_length, usblp_bulk_write, usblp);
73742cb967fSPete Zaitcev 	urb->transfer_flags |= URB_FREE_BUFFER;
73842cb967fSPete Zaitcev 
73942cb967fSPete Zaitcev 	return urb;
74042cb967fSPete Zaitcev }
74142cb967fSPete Zaitcev 
usblp_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)7421da177e4SLinus Torvalds static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
7431da177e4SLinus Torvalds {
7441da177e4SLinus Torvalds 	struct usblp *usblp = file->private_data;
745317c67b8SPete Zaitcev 	struct urb *writeurb;
746317c67b8SPete Zaitcev 	int rv;
747317c67b8SPete Zaitcev 	int transfer_length;
748317c67b8SPete Zaitcev 	ssize_t writecount = 0;
749317c67b8SPete Zaitcev 
750317c67b8SPete Zaitcev 	if (mutex_lock_interruptible(&usblp->wmut)) {
751317c67b8SPete Zaitcev 		rv = -EINTR;
752317c67b8SPete Zaitcev 		goto raise_biglock;
753317c67b8SPete Zaitcev 	}
754317c67b8SPete Zaitcev 	if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0)
755317c67b8SPete Zaitcev 		goto raise_wait;
7561da177e4SLinus Torvalds 
7571da177e4SLinus Torvalds 	while (writecount < count) {
758317c67b8SPete Zaitcev 		/*
759317c67b8SPete Zaitcev 		 * Step 1: Submit next block.
7601da177e4SLinus Torvalds 		 */
761317c67b8SPete Zaitcev 		if ((transfer_length = count - writecount) > USBLP_BUF_SIZE)
7621da177e4SLinus Torvalds 			transfer_length = USBLP_BUF_SIZE;
7631da177e4SLinus Torvalds 
764317c67b8SPete Zaitcev 		rv = -ENOMEM;
7652fcdbdfdSGreg Kroah-Hartman 		writeurb = usblp_new_writeurb(usblp, transfer_length);
7662fcdbdfdSGreg Kroah-Hartman 		if (writeurb == NULL)
767317c67b8SPete Zaitcev 			goto raise_urb;
768317c67b8SPete Zaitcev 		usb_anchor_urb(writeurb, &usblp->urbs);
7691da177e4SLinus Torvalds 
77042cb967fSPete Zaitcev 		if (copy_from_user(writeurb->transfer_buffer,
7711da177e4SLinus Torvalds 				   buffer + writecount, transfer_length)) {
772317c67b8SPete Zaitcev 			rv = -EFAULT;
773317c67b8SPete Zaitcev 			goto raise_badaddr;
7741da177e4SLinus Torvalds 		}
7751da177e4SLinus Torvalds 
776317c67b8SPete Zaitcev 		spin_lock_irq(&usblp->lock);
7771da177e4SLinus Torvalds 		usblp->wcomplete = 0;
778317c67b8SPete Zaitcev 		spin_unlock_irq(&usblp->lock);
779317c67b8SPete Zaitcev 		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
780317c67b8SPete Zaitcev 			usblp->wstatus = 0;
781317c67b8SPete Zaitcev 			spin_lock_irq(&usblp->lock);
7827f477358SPete Zaitcev 			usblp->no_paper = 0;
7836c8df79fSOliver Neukum 			usblp->wcomplete = 1;
784317c67b8SPete Zaitcev 			wake_up(&usblp->wwait);
785317c67b8SPete Zaitcev 			spin_unlock_irq(&usblp->lock);
786317c67b8SPete Zaitcev 			if (rv != -ENOMEM)
787317c67b8SPete Zaitcev 				rv = -EIO;
788317c67b8SPete Zaitcev 			goto raise_submit;
7891da177e4SLinus Torvalds 		}
7901da177e4SLinus Torvalds 
791317c67b8SPete Zaitcev 		/*
792317c67b8SPete Zaitcev 		 * Step 2: Wait for transfer to end, collect results.
793317c67b8SPete Zaitcev 		 */
794317c67b8SPete Zaitcev 		rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
795317c67b8SPete Zaitcev 		if (rv < 0) {
79610e48522SPete Zaitcev 			if (rv == -EAGAIN) {
79710e48522SPete Zaitcev 				/* Presume that it's going to complete well. */
79810e48522SPete Zaitcev 				writecount += transfer_length;
79910e48522SPete Zaitcev 			}
8007f477358SPete Zaitcev 			if (rv == -ENOSPC) {
8017f477358SPete Zaitcev 				spin_lock_irq(&usblp->lock);
8027f477358SPete Zaitcev 				usblp->no_paper = 1;	/* Mark for poll(2) */
8037f477358SPete Zaitcev 				spin_unlock_irq(&usblp->lock);
8047f477358SPete Zaitcev 				writecount += transfer_length;
8057f477358SPete Zaitcev 			}
80610e48522SPete Zaitcev 			/* Leave URB dangling, to be cleaned on close. */
807317c67b8SPete Zaitcev 			goto collect_error;
8081da177e4SLinus Torvalds 		}
8091da177e4SLinus Torvalds 
810317c67b8SPete Zaitcev 		if (usblp->wstatus < 0) {
811317c67b8SPete Zaitcev 			rv = -EIO;
812317c67b8SPete Zaitcev 			goto collect_error;
813317c67b8SPete Zaitcev 		}
814317c67b8SPete Zaitcev 		/*
815317c67b8SPete Zaitcev 		 * This is critical: it must be our URB, not other writer's.
816317c67b8SPete Zaitcev 		 * The wmut exists mainly to cover us here.
817317c67b8SPete Zaitcev 		 */
818317c67b8SPete Zaitcev 		writecount += usblp->wstatus;
819317c67b8SPete Zaitcev 	}
820317c67b8SPete Zaitcev 
821317c67b8SPete Zaitcev 	mutex_unlock(&usblp->wmut);
822317c67b8SPete Zaitcev 	return writecount;
823317c67b8SPete Zaitcev 
824317c67b8SPete Zaitcev raise_submit:
825317c67b8SPete Zaitcev raise_badaddr:
826317c67b8SPete Zaitcev 	usb_unanchor_urb(writeurb);
827317c67b8SPete Zaitcev 	usb_free_urb(writeurb);
828317c67b8SPete Zaitcev raise_urb:
829317c67b8SPete Zaitcev raise_wait:
830317c67b8SPete Zaitcev collect_error:		/* Out of raise sequence */
831317c67b8SPete Zaitcev 	mutex_unlock(&usblp->wmut);
832317c67b8SPete Zaitcev raise_biglock:
833317c67b8SPete Zaitcev 	return writecount ? writecount : rv;
834317c67b8SPete Zaitcev }
835317c67b8SPete Zaitcev 
836317c67b8SPete Zaitcev /*
837317c67b8SPete Zaitcev  * Notice that we fail to restart in a few cases: on EFAULT, on restart
838317c67b8SPete Zaitcev  * error, etc. This is the historical behaviour. In all such cases we return
839317c67b8SPete Zaitcev  * EIO, and applications loop in order to get the new read going.
840317c67b8SPete Zaitcev  */
usblp_read(struct file * file,char __user * buffer,size_t len,loff_t * ppos)841317c67b8SPete Zaitcev static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
8421da177e4SLinus Torvalds {
8431da177e4SLinus Torvalds 	struct usblp *usblp = file->private_data;
844317c67b8SPete Zaitcev 	ssize_t count;
845317c67b8SPete Zaitcev 	ssize_t avail;
846317c67b8SPete Zaitcev 	int rv;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (!usblp->bidir)
8491da177e4SLinus Torvalds 		return -EINVAL;
8501da177e4SLinus Torvalds 
851317c67b8SPete Zaitcev 	rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
852317c67b8SPete Zaitcev 	if (rv < 0)
853317c67b8SPete Zaitcev 		return rv;
8541da177e4SLinus Torvalds 
8559cdabcb3SOliver Neukum 	if (!usblp->present) {
8569cdabcb3SOliver Neukum 		count = -ENODEV;
8579cdabcb3SOliver Neukum 		goto done;
8589cdabcb3SOliver Neukum 	}
8599cdabcb3SOliver Neukum 
860317c67b8SPete Zaitcev 	if ((avail = usblp->rstatus) < 0) {
861317c67b8SPete Zaitcev 		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
862317c67b8SPete Zaitcev 		    usblp->minor, (int)avail);
863317c67b8SPete Zaitcev 		usblp_submit_read(usblp);
8641da177e4SLinus Torvalds 		count = -EIO;
8651da177e4SLinus Torvalds 		goto done;
8661da177e4SLinus Torvalds 	}
8671da177e4SLinus Torvalds 
868317c67b8SPete Zaitcev 	count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
869317c67b8SPete Zaitcev 	if (count != 0 &&
870317c67b8SPete Zaitcev 	    copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) {
8711da177e4SLinus Torvalds 		count = -EFAULT;
8721da177e4SLinus Torvalds 		goto done;
8731da177e4SLinus Torvalds 	}
8741da177e4SLinus Torvalds 
875317c67b8SPete Zaitcev 	if ((usblp->readcount += count) == avail) {
876317c67b8SPete Zaitcev 		if (usblp_submit_read(usblp) < 0) {
877317c67b8SPete Zaitcev 			/* We don't want to leak USB return codes into errno. */
878317c67b8SPete Zaitcev 			if (count == 0)
8791da177e4SLinus Torvalds 				count = -EIO;
8801da177e4SLinus Torvalds 			goto done;
8811da177e4SLinus Torvalds 		}
8821da177e4SLinus Torvalds 	}
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds done:
8858e422669SOliver Neukum 	mutex_unlock(&usblp->mut);
8861da177e4SLinus Torvalds 	return count;
8871da177e4SLinus Torvalds }
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds /*
890317c67b8SPete Zaitcev  * Wait for the write path to come idle.
891317c67b8SPete Zaitcev  * This is called under the ->wmut, so the idle path stays idle.
892317c67b8SPete Zaitcev  *
893317c67b8SPete Zaitcev  * Our write path has a peculiar property: it does not buffer like a tty,
894317c67b8SPete Zaitcev  * but waits for the write to succeed. This allows our ->release to bug out
895317c67b8SPete Zaitcev  * without waiting for writes to drain. But it obviously does not work
896317c67b8SPete Zaitcev  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
897317c67b8SPete Zaitcev  * select(2) or poll(2) to wait for the buffer to drain before closing.
898317c67b8SPete Zaitcev  * Alternatively, set blocking mode with fcntl and issue a zero-size write.
899317c67b8SPete Zaitcev  */
usblp_wwait(struct usblp * usblp,int nonblock)900317c67b8SPete Zaitcev static int usblp_wwait(struct usblp *usblp, int nonblock)
901317c67b8SPete Zaitcev {
902317c67b8SPete Zaitcev 	DECLARE_WAITQUEUE(waita, current);
903317c67b8SPete Zaitcev 	int rc;
9047f477358SPete Zaitcev 	int err = 0;
905317c67b8SPete Zaitcev 
906317c67b8SPete Zaitcev 	add_wait_queue(&usblp->wwait, &waita);
907317c67b8SPete Zaitcev 	for (;;) {
908317c67b8SPete Zaitcev 		if (mutex_lock_interruptible(&usblp->mut)) {
909317c67b8SPete Zaitcev 			rc = -EINTR;
910317c67b8SPete Zaitcev 			break;
911317c67b8SPete Zaitcev 		}
91219cd80a2SJiri Slaby 		set_current_state(TASK_INTERRUPTIBLE);
9137f477358SPete Zaitcev 		rc = usblp_wtest(usblp, nonblock);
914317c67b8SPete Zaitcev 		mutex_unlock(&usblp->mut);
9157f477358SPete Zaitcev 		if (rc <= 0)
9167f477358SPete Zaitcev 			break;
9177f477358SPete Zaitcev 
918dd44be6bSPete Zaitcev 		if (schedule_timeout(msecs_to_jiffies(1500)) == 0) {
9197f477358SPete Zaitcev 			if (usblp->flags & LP_ABORT) {
9207f477358SPete Zaitcev 				err = usblp_check_status(usblp, err);
9217f477358SPete Zaitcev 				if (err == 1) {	/* Paper out */
9227f477358SPete Zaitcev 					rc = -ENOSPC;
923317c67b8SPete Zaitcev 					break;
924317c67b8SPete Zaitcev 				}
9257f477358SPete Zaitcev 			} else {
926dd44be6bSPete Zaitcev 				/* Prod the printer, Gentoo#251237. */
927dd44be6bSPete Zaitcev 				mutex_lock(&usblp->mut);
928dd44be6bSPete Zaitcev 				usblp_read_status(usblp, usblp->statusbuf);
929dd44be6bSPete Zaitcev 				mutex_unlock(&usblp->mut);
930dd44be6bSPete Zaitcev 			}
931317c67b8SPete Zaitcev 		}
9327f477358SPete Zaitcev 	}
933317c67b8SPete Zaitcev 	set_current_state(TASK_RUNNING);
934317c67b8SPete Zaitcev 	remove_wait_queue(&usblp->wwait, &waita);
935317c67b8SPete Zaitcev 	return rc;
936317c67b8SPete Zaitcev }
937317c67b8SPete Zaitcev 
usblp_wtest(struct usblp * usblp,int nonblock)938317c67b8SPete Zaitcev static int usblp_wtest(struct usblp *usblp, int nonblock)
939317c67b8SPete Zaitcev {
940317c67b8SPete Zaitcev 	unsigned long flags;
941317c67b8SPete Zaitcev 
942317c67b8SPete Zaitcev 	if (!usblp->present)
943317c67b8SPete Zaitcev 		return -ENODEV;
944317c67b8SPete Zaitcev 	if (signal_pending(current))
945317c67b8SPete Zaitcev 		return -EINTR;
946317c67b8SPete Zaitcev 	spin_lock_irqsave(&usblp->lock, flags);
947317c67b8SPete Zaitcev 	if (usblp->wcomplete) {
948317c67b8SPete Zaitcev 		spin_unlock_irqrestore(&usblp->lock, flags);
949317c67b8SPete Zaitcev 		return 0;
950317c67b8SPete Zaitcev 	}
951317c67b8SPete Zaitcev 	spin_unlock_irqrestore(&usblp->lock, flags);
952317c67b8SPete Zaitcev 	if (nonblock)
953317c67b8SPete Zaitcev 		return -EAGAIN;
954317c67b8SPete Zaitcev 	return 1;
955317c67b8SPete Zaitcev }
956317c67b8SPete Zaitcev 
957317c67b8SPete Zaitcev /*
958317c67b8SPete Zaitcev  * Wait for read bytes to become available. This probably should have been
959317c67b8SPete Zaitcev  * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
960317c67b8SPete Zaitcev  * name for functions which lock and return.
961317c67b8SPete Zaitcev  *
962317c67b8SPete Zaitcev  * We do not use wait_event_interruptible because it makes locking iffy.
963317c67b8SPete Zaitcev  */
usblp_rwait_and_lock(struct usblp * usblp,int nonblock)964317c67b8SPete Zaitcev static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
965317c67b8SPete Zaitcev {
966317c67b8SPete Zaitcev 	DECLARE_WAITQUEUE(waita, current);
967317c67b8SPete Zaitcev 	int rc;
968317c67b8SPete Zaitcev 
969317c67b8SPete Zaitcev 	add_wait_queue(&usblp->rwait, &waita);
970317c67b8SPete Zaitcev 	for (;;) {
971317c67b8SPete Zaitcev 		if (mutex_lock_interruptible(&usblp->mut)) {
972317c67b8SPete Zaitcev 			rc = -EINTR;
973317c67b8SPete Zaitcev 			break;
974317c67b8SPete Zaitcev 		}
975317c67b8SPete Zaitcev 		set_current_state(TASK_INTERRUPTIBLE);
976317c67b8SPete Zaitcev 		if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
977317c67b8SPete Zaitcev 			mutex_unlock(&usblp->mut);
978317c67b8SPete Zaitcev 			break;
979317c67b8SPete Zaitcev 		}
980317c67b8SPete Zaitcev 		if (rc == 0)	/* Keep it locked */
981317c67b8SPete Zaitcev 			break;
982317c67b8SPete Zaitcev 		mutex_unlock(&usblp->mut);
983317c67b8SPete Zaitcev 		schedule();
984317c67b8SPete Zaitcev 	}
985317c67b8SPete Zaitcev 	set_current_state(TASK_RUNNING);
986317c67b8SPete Zaitcev 	remove_wait_queue(&usblp->rwait, &waita);
987317c67b8SPete Zaitcev 	return rc;
988317c67b8SPete Zaitcev }
989317c67b8SPete Zaitcev 
usblp_rtest(struct usblp * usblp,int nonblock)990317c67b8SPete Zaitcev static int usblp_rtest(struct usblp *usblp, int nonblock)
991317c67b8SPete Zaitcev {
992317c67b8SPete Zaitcev 	unsigned long flags;
993317c67b8SPete Zaitcev 
994317c67b8SPete Zaitcev 	if (!usblp->present)
995317c67b8SPete Zaitcev 		return -ENODEV;
996317c67b8SPete Zaitcev 	if (signal_pending(current))
997317c67b8SPete Zaitcev 		return -EINTR;
998317c67b8SPete Zaitcev 	spin_lock_irqsave(&usblp->lock, flags);
999317c67b8SPete Zaitcev 	if (usblp->rcomplete) {
1000317c67b8SPete Zaitcev 		spin_unlock_irqrestore(&usblp->lock, flags);
1001317c67b8SPete Zaitcev 		return 0;
1002317c67b8SPete Zaitcev 	}
1003317c67b8SPete Zaitcev 	spin_unlock_irqrestore(&usblp->lock, flags);
1004317c67b8SPete Zaitcev 	if (nonblock)
1005317c67b8SPete Zaitcev 		return -EAGAIN;
1006317c67b8SPete Zaitcev 	return 1;
1007317c67b8SPete Zaitcev }
1008317c67b8SPete Zaitcev 
1009317c67b8SPete Zaitcev /*
1010317c67b8SPete Zaitcev  * Please check ->bidir and other such things outside for now.
1011317c67b8SPete Zaitcev  */
usblp_submit_read(struct usblp * usblp)1012317c67b8SPete Zaitcev static int usblp_submit_read(struct usblp *usblp)
1013317c67b8SPete Zaitcev {
1014317c67b8SPete Zaitcev 	struct urb *urb;
1015317c67b8SPete Zaitcev 	unsigned long flags;
1016317c67b8SPete Zaitcev 	int rc;
1017317c67b8SPete Zaitcev 
1018317c67b8SPete Zaitcev 	rc = -ENOMEM;
10192fcdbdfdSGreg Kroah-Hartman 	urb = usb_alloc_urb(0, GFP_KERNEL);
10202fcdbdfdSGreg Kroah-Hartman 	if (urb == NULL)
1021317c67b8SPete Zaitcev 		goto raise_urb;
1022317c67b8SPete Zaitcev 
1023317c67b8SPete Zaitcev 	usb_fill_bulk_urb(urb, usblp->dev,
1024317c67b8SPete Zaitcev 		usb_rcvbulkpipe(usblp->dev,
1025317c67b8SPete Zaitcev 		  usblp->protocol[usblp->current_protocol].epread->bEndpointAddress),
1026317c67b8SPete Zaitcev 		usblp->readbuf, USBLP_BUF_SIZE_IN,
1027317c67b8SPete Zaitcev 		usblp_bulk_read, usblp);
1028317c67b8SPete Zaitcev 	usb_anchor_urb(urb, &usblp->urbs);
1029317c67b8SPete Zaitcev 
1030317c67b8SPete Zaitcev 	spin_lock_irqsave(&usblp->lock, flags);
1031317c67b8SPete Zaitcev 	usblp->readcount = 0; /* XXX Why here? */
1032317c67b8SPete Zaitcev 	usblp->rcomplete = 0;
1033317c67b8SPete Zaitcev 	spin_unlock_irqrestore(&usblp->lock, flags);
1034317c67b8SPete Zaitcev 	if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
10354f306309SGreg Kroah-Hartman 		dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);
1036317c67b8SPete Zaitcev 		spin_lock_irqsave(&usblp->lock, flags);
1037317c67b8SPete Zaitcev 		usblp->rstatus = rc;
1038317c67b8SPete Zaitcev 		usblp->rcomplete = 1;
1039317c67b8SPete Zaitcev 		spin_unlock_irqrestore(&usblp->lock, flags);
1040317c67b8SPete Zaitcev 		goto raise_submit;
1041317c67b8SPete Zaitcev 	}
1042317c67b8SPete Zaitcev 
1043317c67b8SPete Zaitcev 	return 0;
1044317c67b8SPete Zaitcev 
1045317c67b8SPete Zaitcev raise_submit:
1046317c67b8SPete Zaitcev 	usb_unanchor_urb(urb);
1047317c67b8SPete Zaitcev 	usb_free_urb(urb);
1048317c67b8SPete Zaitcev raise_urb:
1049317c67b8SPete Zaitcev 	return rc;
1050317c67b8SPete Zaitcev }
1051317c67b8SPete Zaitcev 
1052317c67b8SPete Zaitcev /*
10531da177e4SLinus Torvalds  * Checks for printers that have quirks, such as requiring unidirectional
10541da177e4SLinus Torvalds  * communication but reporting bidirectional; currently some HP printers
10551da177e4SLinus Torvalds  * have this flaw (HP 810, 880, 895, etc.), or needing an init string
10561da177e4SLinus Torvalds  * sent at each open (like some Epsons).
10571da177e4SLinus Torvalds  * Returns 1 if found, 0 if not found.
10581da177e4SLinus Torvalds  *
10591da177e4SLinus Torvalds  * HP recommended that we use the bidirectional interface but
10601da177e4SLinus Torvalds  * don't attempt any bulk IN transfers from the IN endpoint.
10611da177e4SLinus Torvalds  * Here's some more detail on the problem:
10621da177e4SLinus Torvalds  * The problem is not that it isn't bidirectional though. The problem
10631da177e4SLinus Torvalds  * is that if you request a device ID, or status information, while
10641da177e4SLinus Torvalds  * the buffers are full, the return data will end up in the print data
10651da177e4SLinus Torvalds  * buffer. For example if you make sure you never request the device ID
10661da177e4SLinus Torvalds  * while you are sending print data, and you don't try to query the
10671da177e4SLinus Torvalds  * printer status every couple of milliseconds, you will probably be OK.
10681da177e4SLinus Torvalds  */
usblp_quirks(__u16 vendor,__u16 product)10691da177e4SLinus Torvalds static unsigned int usblp_quirks(__u16 vendor, __u16 product)
10701da177e4SLinus Torvalds {
10711da177e4SLinus Torvalds 	int i;
10721da177e4SLinus Torvalds 
10731da177e4SLinus Torvalds 	for (i = 0; quirk_printers[i].vendorId; i++) {
10741da177e4SLinus Torvalds 		if (vendor == quirk_printers[i].vendorId &&
10751da177e4SLinus Torvalds 		    product == quirk_printers[i].productId)
10761da177e4SLinus Torvalds 			return quirk_printers[i].quirks;
10771da177e4SLinus Torvalds 	}
10781da177e4SLinus Torvalds 	return 0;
10791da177e4SLinus Torvalds }
10801da177e4SLinus Torvalds 
1081066202ddSLuiz Fernando N. Capitulino static const struct file_operations usblp_fops = {
10821da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
10831da177e4SLinus Torvalds 	.read =		usblp_read,
10841da177e4SLinus Torvalds 	.write =	usblp_write,
10851da177e4SLinus Torvalds 	.poll =		usblp_poll,
1086318e479eSPete Zaitcev 	.unlocked_ioctl =	usblp_ioctl,
1087318e479eSPete Zaitcev 	.compat_ioctl =		usblp_ioctl,
10881da177e4SLinus Torvalds 	.open =		usblp_open,
10891da177e4SLinus Torvalds 	.release =	usblp_release,
10906038f373SArnd Bergmann 	.llseek =	noop_llseek,
10911da177e4SLinus Torvalds };
10921da177e4SLinus Torvalds 
usblp_devnode(const struct device * dev,umode_t * mode)10935033ac5cSGreg Kroah-Hartman static char *usblp_devnode(const struct device *dev, umode_t *mode)
1094f7a386c5SKay Sievers {
1095f7a386c5SKay Sievers 	return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
1096f7a386c5SKay Sievers }
1097f7a386c5SKay Sievers 
10981da177e4SLinus Torvalds static struct usb_class_driver usblp_class = {
1099d6e5bcf4SGreg Kroah-Hartman 	.name =		"lp%d",
1100e454cea2SKay Sievers 	.devnode =	usblp_devnode,
11011da177e4SLinus Torvalds 	.fops =		&usblp_fops,
11021da177e4SLinus Torvalds 	.minor_base =	USBLP_MINOR_BASE,
11031da177e4SLinus Torvalds };
11041da177e4SLinus Torvalds 
ieee1284_id_show(struct device * dev,struct device_attribute * attr,char * buf)11057f26ee4bSGreg Kroah-Hartman static ssize_t ieee1284_id_show(struct device *dev, struct device_attribute *attr, char *buf)
1106a9714c84SDavid Woodhouse {
1107a9714c84SDavid Woodhouse 	struct usb_interface *intf = to_usb_interface(dev);
1108a9714c84SDavid Woodhouse 	struct usblp *usblp = usb_get_intfdata(intf);
1109a9714c84SDavid Woodhouse 
1110a9714c84SDavid Woodhouse 	if (usblp->device_id_string[0] == 0 &&
1111a9714c84SDavid Woodhouse 	    usblp->device_id_string[1] == 0)
1112a9714c84SDavid Woodhouse 		return 0;
1113a9714c84SDavid Woodhouse 
1114a9714c84SDavid Woodhouse 	return sprintf(buf, "%s", usblp->device_id_string+2);
1115a9714c84SDavid Woodhouse }
1116a9714c84SDavid Woodhouse 
11177f26ee4bSGreg Kroah-Hartman static DEVICE_ATTR_RO(ieee1284_id);
1118a9714c84SDavid Woodhouse 
111902c4d45dSGreg Kroah-Hartman static struct attribute *usblp_attrs[] = {
112002c4d45dSGreg Kroah-Hartman 	&dev_attr_ieee1284_id.attr,
112102c4d45dSGreg Kroah-Hartman 	NULL,
112202c4d45dSGreg Kroah-Hartman };
112302c4d45dSGreg Kroah-Hartman ATTRIBUTE_GROUPS(usblp);
112402c4d45dSGreg Kroah-Hartman 
usblp_probe(struct usb_interface * intf,const struct usb_device_id * id)11251da177e4SLinus Torvalds static int usblp_probe(struct usb_interface *intf,
11261da177e4SLinus Torvalds 		       const struct usb_device_id *id)
11271da177e4SLinus Torvalds {
11281da177e4SLinus Torvalds 	struct usb_device *dev = interface_to_usbdev(intf);
112949b707b9SJulia Lawall 	struct usblp *usblp;
11301da177e4SLinus Torvalds 	int protocol;
11311da177e4SLinus Torvalds 	int retval;
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	/* Malloc and start initializing usblp structure so we can use it
11341da177e4SLinus Torvalds 	 * directly. */
113549b707b9SJulia Lawall 	usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL);
113649b707b9SJulia Lawall 	if (!usblp) {
1137317c67b8SPete Zaitcev 		retval = -ENOMEM;
113849b707b9SJulia Lawall 		goto abort_ret;
11391da177e4SLinus Torvalds 	}
11401da177e4SLinus Torvalds 	usblp->dev = dev;
1141317c67b8SPete Zaitcev 	mutex_init(&usblp->wmut);
11428e422669SOliver Neukum 	mutex_init(&usblp->mut);
1143317c67b8SPete Zaitcev 	spin_lock_init(&usblp->lock);
1144317c67b8SPete Zaitcev 	init_waitqueue_head(&usblp->rwait);
1145317c67b8SPete Zaitcev 	init_waitqueue_head(&usblp->wwait);
1146317c67b8SPete Zaitcev 	init_usb_anchor(&usblp->urbs);
11471da177e4SLinus Torvalds 	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
11487a759197SJohan Hovold 	usblp->intf = usb_get_intf(intf);
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	/* Malloc device ID string buffer to the largest expected length,
11511da177e4SLinus Torvalds 	 * since we can re-query it on an ioctl and a dynamic string
11521da177e4SLinus Torvalds 	 * could change in length. */
11531da177e4SLinus Torvalds 	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
1154317c67b8SPete Zaitcev 		retval = -ENOMEM;
11551da177e4SLinus Torvalds 		goto abort;
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds 
1158317c67b8SPete Zaitcev 	/*
1159317c67b8SPete Zaitcev 	 * Allocate read buffer. We somewhat wastefully
11601da177e4SLinus Torvalds 	 * malloc both regardless of bidirectionality, because the
1161317c67b8SPete Zaitcev 	 * alternate setting can be changed later via an ioctl.
1162317c67b8SPete Zaitcev 	 */
1163317c67b8SPete Zaitcev 	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
1164317c67b8SPete Zaitcev 		retval = -ENOMEM;
11651da177e4SLinus Torvalds 		goto abort;
11661da177e4SLinus Torvalds 	}
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	/* Allocate buffer for printer status */
11691da177e4SLinus Torvalds 	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
11701da177e4SLinus Torvalds 	if (!usblp->statusbuf) {
1171317c67b8SPete Zaitcev 		retval = -ENOMEM;
11721da177e4SLinus Torvalds 		goto abort;
11731da177e4SLinus Torvalds 	}
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 	/* Lookup quirks for this printer. */
11761da177e4SLinus Torvalds 	usblp->quirks = usblp_quirks(
11771da177e4SLinus Torvalds 		le16_to_cpu(dev->descriptor.idVendor),
11781da177e4SLinus Torvalds 		le16_to_cpu(dev->descriptor.idProduct));
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	/* Analyze and pick initial alternate settings and endpoints. */
11811da177e4SLinus Torvalds 	protocol = usblp_select_alts(usblp);
11821da177e4SLinus Torvalds 	if (protocol < 0) {
11834f306309SGreg Kroah-Hartman 		dev_dbg(&intf->dev,
11844f306309SGreg Kroah-Hartman 			"incompatible printer-class device 0x%4.4X/0x%4.4X\n",
11851da177e4SLinus Torvalds 			le16_to_cpu(dev->descriptor.idVendor),
11861da177e4SLinus Torvalds 			le16_to_cpu(dev->descriptor.idProduct));
1187317c67b8SPete Zaitcev 		retval = -ENODEV;
11881da177e4SLinus Torvalds 		goto abort;
11891da177e4SLinus Torvalds 	}
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds 	/* Setup the selected alternate setting and endpoints. */
1192317c67b8SPete Zaitcev 	if (usblp_set_protocol(usblp, protocol) < 0) {
1193317c67b8SPete Zaitcev 		retval = -ENODEV;	/* ->probe isn't ->ioctl */
11941da177e4SLinus Torvalds 		goto abort;
1195317c67b8SPete Zaitcev 	}
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds 	/* Retrieve and store the device ID string. */
11981da177e4SLinus Torvalds 	usblp_cache_device_id_string(usblp);
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds #ifdef DEBUG
12011da177e4SLinus Torvalds 	usblp_check_status(usblp, 0);
12021da177e4SLinus Torvalds #endif
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 	usb_set_intfdata(intf, usblp);
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 	usblp->present = 1;
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	retval = usb_register_dev(intf, &usblp_class);
12091da177e4SLinus Torvalds 	if (retval) {
12104f306309SGreg Kroah-Hartman 		dev_err(&intf->dev,
12114f306309SGreg Kroah-Hartman 			"usblp: Not able to get a minor (base %u, slice default): %d\n",
1212317c67b8SPete Zaitcev 			USBLP_MINOR_BASE, retval);
12131da177e4SLinus Torvalds 		goto abort_intfdata;
12141da177e4SLinus Torvalds 	}
12151da177e4SLinus Torvalds 	usblp->minor = intf->minor;
12164f306309SGreg Kroah-Hartman 	dev_info(&intf->dev,
12174f306309SGreg Kroah-Hartman 		"usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
1218a9714c84SDavid Woodhouse 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
1219a9714c84SDavid Woodhouse 		usblp->ifnum,
1220a9714c84SDavid Woodhouse 		usblp->protocol[usblp->current_protocol].alt_setting,
1221a9714c84SDavid Woodhouse 		usblp->current_protocol,
1222a9714c84SDavid Woodhouse 		le16_to_cpu(usblp->dev->descriptor.idVendor),
1223a9714c84SDavid Woodhouse 		le16_to_cpu(usblp->dev->descriptor.idProduct));
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds 	return 0;
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds abort_intfdata:
12281da177e4SLinus Torvalds 	usb_set_intfdata(intf, NULL);
12291da177e4SLinus Torvalds abort:
1230317c67b8SPete Zaitcev 	kfree(usblp->readbuf);
12311da177e4SLinus Torvalds 	kfree(usblp->statusbuf);
12321da177e4SLinus Torvalds 	kfree(usblp->device_id_string);
12337a759197SJohan Hovold 	usb_put_intf(usblp->intf);
12341da177e4SLinus Torvalds 	kfree(usblp);
123549b707b9SJulia Lawall abort_ret:
1236317c67b8SPete Zaitcev 	return retval;
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds /*
12401da177e4SLinus Torvalds  * We are a "new" style driver with usb_device_id table,
12411da177e4SLinus Torvalds  * but our requirements are too intricate for simple match to handle.
12421da177e4SLinus Torvalds  *
12431da177e4SLinus Torvalds  * The "proto_bias" option may be used to specify the preferred protocol
1244298b992fSKrzysztof Opasiak  * for all USB printers (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
1245298b992fSKrzysztof Opasiak  * 3=USB_CLASS_PRINTER/1/3).  If the device supports the preferred protocol,
1246298b992fSKrzysztof Opasiak  * then we bind to it.
12471da177e4SLinus Torvalds  *
1248298b992fSKrzysztof Opasiak  * The best interface for us is USB_CLASS_PRINTER/1/2, because it
1249298b992fSKrzysztof Opasiak  * is compatible with a stream of characters. If we find it, we bind to it.
12501da177e4SLinus Torvalds  *
12511da177e4SLinus Torvalds  * Note that the people from hpoj.sourceforge.net need to be able to
1252298b992fSKrzysztof Opasiak  * bind to USB_CLASS_PRINTER/1/3 (MLC/1284.4), so we provide them ioctls
1253298b992fSKrzysztof Opasiak  * for this purpose.
12541da177e4SLinus Torvalds  *
1255298b992fSKrzysztof Opasiak  * Failing USB_CLASS_PRINTER/1/2, we look for USB_CLASS_PRINTER/1/3,
1256298b992fSKrzysztof Opasiak  * even though it's probably not stream-compatible, because this matches
1257298b992fSKrzysztof Opasiak  * the behaviour of the old code.
12581da177e4SLinus Torvalds  *
1259298b992fSKrzysztof Opasiak  * If nothing else, we bind to USB_CLASS_PRINTER/1/1
1260298b992fSKrzysztof Opasiak  * - the unidirectional interface.
12611da177e4SLinus Torvalds  */
usblp_select_alts(struct usblp * usblp)12621da177e4SLinus Torvalds static int usblp_select_alts(struct usblp *usblp)
12631da177e4SLinus Torvalds {
12641da177e4SLinus Torvalds 	struct usb_interface *if_alt;
12651da177e4SLinus Torvalds 	struct usb_host_interface *ifd;
12665370860aSJohan Hovold 	struct usb_endpoint_descriptor *epwrite, *epread;
12675370860aSJohan Hovold 	int p, i;
12685370860aSJohan Hovold 	int res;
12691da177e4SLinus Torvalds 
12701da177e4SLinus Torvalds 	if_alt = usblp->intf;
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
12731da177e4SLinus Torvalds 		usblp->protocol[p].alt_setting = -1;
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	/* Find out what we have. */
12761da177e4SLinus Torvalds 	for (i = 0; i < if_alt->num_altsetting; i++) {
12771da177e4SLinus Torvalds 		ifd = &if_alt->altsetting[i];
12781da177e4SLinus Torvalds 
1279298b992fSKrzysztof Opasiak 		if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER ||
1280298b992fSKrzysztof Opasiak 		    ifd->desc.bInterfaceSubClass != 1)
12815ec71db5SAlan Stern 			if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS))
12821da177e4SLinus Torvalds 				continue;
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 		if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL ||
12851da177e4SLinus Torvalds 		    ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL)
12861da177e4SLinus Torvalds 			continue;
12871da177e4SLinus Torvalds 
12885370860aSJohan Hovold 		/* Look for the expected bulk endpoints. */
12895370860aSJohan Hovold 		if (ifd->desc.bInterfaceProtocol > 1) {
12905370860aSJohan Hovold 			res = usb_find_common_endpoints(ifd,
12915370860aSJohan Hovold 					&epread, &epwrite, NULL, NULL);
12925370860aSJohan Hovold 		} else {
12935370860aSJohan Hovold 			epread = NULL;
12945370860aSJohan Hovold 			res = usb_find_bulk_out_endpoint(ifd, &epwrite);
12951da177e4SLinus Torvalds 		}
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds 		/* Ignore buggy hardware without the right endpoints. */
12985370860aSJohan Hovold 		if (res)
12991da177e4SLinus Torvalds 			continue;
13001da177e4SLinus Torvalds 
13015370860aSJohan Hovold 		/* Turn off reads for buggy bidirectional printers. */
13025370860aSJohan Hovold 		if (usblp->quirks & USBLP_QUIRK_BIDIR) {
1303317c67b8SPete Zaitcev 			printk(KERN_INFO "usblp%d: Disabling reads from "
1304317c67b8SPete Zaitcev 			    "problematic bidirectional printer\n",
1305317c67b8SPete Zaitcev 			    usblp->minor);
13061da177e4SLinus Torvalds 			epread = NULL;
13071da177e4SLinus Torvalds 		}
13081da177e4SLinus Torvalds 
13091da177e4SLinus Torvalds 		usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting =
13101da177e4SLinus Torvalds 				ifd->desc.bAlternateSetting;
13111da177e4SLinus Torvalds 		usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite;
13121da177e4SLinus Torvalds 		usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread;
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 	/* If our requested protocol is supported, then use it. */
13161da177e4SLinus Torvalds 	if (proto_bias >= USBLP_FIRST_PROTOCOL &&
13171da177e4SLinus Torvalds 	    proto_bias <= USBLP_LAST_PROTOCOL &&
13181da177e4SLinus Torvalds 	    usblp->protocol[proto_bias].alt_setting != -1)
13191da177e4SLinus Torvalds 		return proto_bias;
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 	/* Ordering is important here. */
13221da177e4SLinus Torvalds 	if (usblp->protocol[2].alt_setting != -1)
13231da177e4SLinus Torvalds 		return 2;
13241da177e4SLinus Torvalds 	if (usblp->protocol[1].alt_setting != -1)
13251da177e4SLinus Torvalds 		return 1;
13261da177e4SLinus Torvalds 	if (usblp->protocol[3].alt_setting != -1)
13271da177e4SLinus Torvalds 		return 3;
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 	/* If nothing is available, then don't bind to this device. */
13301da177e4SLinus Torvalds 	return -1;
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds 
usblp_set_protocol(struct usblp * usblp,int protocol)13331da177e4SLinus Torvalds static int usblp_set_protocol(struct usblp *usblp, int protocol)
13341da177e4SLinus Torvalds {
13351da177e4SLinus Torvalds 	int r, alts;
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
13381da177e4SLinus Torvalds 		return -EINVAL;
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds 	alts = usblp->protocol[protocol].alt_setting;
13411da177e4SLinus Torvalds 	if (alts < 0)
13421da177e4SLinus Torvalds 		return -EINVAL;
1343*77af0434SJun Yan 
1344*77af0434SJun Yan 	/* Don't unnecessarily set the interface if there's a single alt. */
1345*77af0434SJun Yan 	if (usblp->intf->num_altsetting > 1) {
13461da177e4SLinus Torvalds 		r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
13471da177e4SLinus Torvalds 		if (r < 0) {
1348317c67b8SPete Zaitcev 			printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
13491da177e4SLinus Torvalds 				alts, usblp->ifnum);
13501da177e4SLinus Torvalds 			return r;
13511da177e4SLinus Torvalds 		}
1352d8c6edfaSJeremy Figgins 	}
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
13551da177e4SLinus Torvalds 	usblp->current_protocol = protocol;
13564f306309SGreg Kroah-Hartman 	dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n",
13574f306309SGreg Kroah-Hartman 		usblp->minor, protocol);
13581da177e4SLinus Torvalds 	return 0;
13591da177e4SLinus Torvalds }
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds /* Retrieves and caches device ID string.
13621da177e4SLinus Torvalds  * Returns length, including length bytes but not null terminator.
13631da177e4SLinus Torvalds  * On error, returns a negative errno value. */
usblp_cache_device_id_string(struct usblp * usblp)13641da177e4SLinus Torvalds static int usblp_cache_device_id_string(struct usblp *usblp)
13651da177e4SLinus Torvalds {
13661da177e4SLinus Torvalds 	int err, length;
13671da177e4SLinus Torvalds 
13681da177e4SLinus Torvalds 	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
13691da177e4SLinus Torvalds 	if (err < 0) {
13704f306309SGreg Kroah-Hartman 		dev_dbg(&usblp->intf->dev,
13714f306309SGreg Kroah-Hartman 			"usblp%d: error = %d reading IEEE-1284 Device ID string\n",
13721da177e4SLinus Torvalds 			usblp->minor, err);
13731da177e4SLinus Torvalds 		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
13741da177e4SLinus Torvalds 		return -EIO;
13751da177e4SLinus Torvalds 	}
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 	/* First two bytes are length in big-endian.
13781da177e4SLinus Torvalds 	 * They count themselves, and we copy them into
13791da177e4SLinus Torvalds 	 * the user's buffer. */
13801da177e4SLinus Torvalds 	length = be16_to_cpu(*((__be16 *)usblp->device_id_string));
13811da177e4SLinus Torvalds 	if (length < 2)
13821da177e4SLinus Torvalds 		length = 2;
13831da177e4SLinus Torvalds 	else if (length >= USBLP_DEVICE_ID_SIZE)
13841da177e4SLinus Torvalds 		length = USBLP_DEVICE_ID_SIZE - 1;
13851da177e4SLinus Torvalds 	usblp->device_id_string[length] = '\0';
13861da177e4SLinus Torvalds 
13874f306309SGreg Kroah-Hartman 	dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n",
13881da177e4SLinus Torvalds 		usblp->minor, length, &usblp->device_id_string[2]);
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	return length;
13911da177e4SLinus Torvalds }
13921da177e4SLinus Torvalds 
usblp_disconnect(struct usb_interface * intf)13931da177e4SLinus Torvalds static void usblp_disconnect(struct usb_interface *intf)
13941da177e4SLinus Torvalds {
13951da177e4SLinus Torvalds 	struct usblp *usblp = usb_get_intfdata(intf);
13961da177e4SLinus Torvalds 
13971da177e4SLinus Torvalds 	usb_deregister_dev(intf, &usblp_class);
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds 	if (!usblp || !usblp->dev) {
14009908a32eSGreg Kroah-Hartman 		dev_err(&intf->dev, "bogus disconnect\n");
14011da177e4SLinus Torvalds 		BUG();
14021da177e4SLinus Torvalds 	}
14031da177e4SLinus Torvalds 
14044186ecf8SArjan van de Ven 	mutex_lock(&usblp_mutex);
14058e422669SOliver Neukum 	mutex_lock(&usblp->mut);
14061da177e4SLinus Torvalds 	usblp->present = 0;
1407317c67b8SPete Zaitcev 	wake_up(&usblp->wwait);
1408317c67b8SPete Zaitcev 	wake_up(&usblp->rwait);
14091da177e4SLinus Torvalds 	usb_set_intfdata(intf, NULL);
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	usblp_unlink_urbs(usblp);
14128e422669SOliver Neukum 	mutex_unlock(&usblp->mut);
1413296a193bSOliver Neukum 	usb_poison_anchored_urbs(&usblp->urbs);
14141da177e4SLinus Torvalds 
14151da177e4SLinus Torvalds 	if (!usblp->used)
14161da177e4SLinus Torvalds 		usblp_cleanup(usblp);
1417296a193bSOliver Neukum 
14184186ecf8SArjan van de Ven 	mutex_unlock(&usblp_mutex);
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds 
usblp_suspend(struct usb_interface * intf,pm_message_t message)1421516077c1SOliver Neukum static int usblp_suspend(struct usb_interface *intf, pm_message_t message)
1422516077c1SOliver Neukum {
1423516077c1SOliver Neukum 	struct usblp *usblp = usb_get_intfdata(intf);
1424516077c1SOliver Neukum 
1425516077c1SOliver Neukum 	usblp_unlink_urbs(usblp);
1426317c67b8SPete Zaitcev #if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
1427317c67b8SPete Zaitcev 	/* not strictly necessary, but just in case */
1428317c67b8SPete Zaitcev 	wake_up(&usblp->wwait);
1429317c67b8SPete Zaitcev 	wake_up(&usblp->rwait);
1430317c67b8SPete Zaitcev #endif
1431516077c1SOliver Neukum 
1432516077c1SOliver Neukum 	return 0;
1433516077c1SOliver Neukum }
1434516077c1SOliver Neukum 
usblp_resume(struct usb_interface * intf)1435516077c1SOliver Neukum static int usblp_resume(struct usb_interface *intf)
1436516077c1SOliver Neukum {
1437516077c1SOliver Neukum 	struct usblp *usblp = usb_get_intfdata(intf);
1438516077c1SOliver Neukum 	int r;
1439516077c1SOliver Neukum 
1440516077c1SOliver Neukum 	r = handle_bidir(usblp);
1441516077c1SOliver Neukum 
1442516077c1SOliver Neukum 	return r;
1443516077c1SOliver Neukum }
1444516077c1SOliver Neukum 
14456ef4852bSNémeth Márton static const struct usb_device_id usblp_ids[] = {
1446298b992fSKrzysztof Opasiak 	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) },
1447298b992fSKrzysztof Opasiak 	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) },
1448298b992fSKrzysztof Opasiak 	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) },
1449298b992fSKrzysztof Opasiak 	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },
1450298b992fSKrzysztof Opasiak 	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },
1451298b992fSKrzysztof Opasiak 	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },
14525ec71db5SAlan Stern 	{ USB_DEVICE(0x04b8, 0x0202) },	/* Seiko Epson Receipt Printer M129C */
14531da177e4SLinus Torvalds 	{ }						/* Terminating entry */
14541da177e4SLinus Torvalds };
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds MODULE_DEVICE_TABLE(usb, usblp_ids);
14571da177e4SLinus Torvalds 
14581da177e4SLinus Torvalds static struct usb_driver usblp_driver = {
14591da177e4SLinus Torvalds 	.name =		"usblp",
14601da177e4SLinus Torvalds 	.probe =	usblp_probe,
14611da177e4SLinus Torvalds 	.disconnect =	usblp_disconnect,
1462516077c1SOliver Neukum 	.suspend =	usblp_suspend,
1463516077c1SOliver Neukum 	.resume =	usblp_resume,
14641da177e4SLinus Torvalds 	.id_table =	usblp_ids,
146502c4d45dSGreg Kroah-Hartman 	.dev_groups =	usblp_groups,
1466d0532184SOliver Neukum 	.supports_autosuspend =	1,
14671da177e4SLinus Torvalds };
14681da177e4SLinus Torvalds 
146965db4305SGreg Kroah-Hartman module_usb_driver(usblp_driver);
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
14721da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
14731da177e4SLinus Torvalds module_param(proto_bias, int, S_IRUGO | S_IWUSR);
14741da177e4SLinus Torvalds MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
14751da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1476