162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * usblp.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
662306a36Sopenharmony_ci * Copyright (c) 1999 Pavel Machek	<pavel@ucw.cz>
762306a36Sopenharmony_ci * Copyright (c) 2000 Randy Dunlap	<rdunlap@xenotime.net>
862306a36Sopenharmony_ci * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
962306a36Sopenharmony_ci # Copyright (c) 2001 Pete Zaitcev	<zaitcev@redhat.com>
1062306a36Sopenharmony_ci # Copyright (c) 2001 David Paschal	<paschal@rcsis.com>
1162306a36Sopenharmony_ci * Copyright (c) 2006 Oliver Neukum	<oliver@neukum.name>
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * USB Printer Device Class driver for USB printers and printer cables
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Sponsored by SuSE
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * ChangeLog:
1862306a36Sopenharmony_ci *	v0.1 - thorough cleaning, URBification, almost a rewrite
1962306a36Sopenharmony_ci *	v0.2 - some more cleanups
2062306a36Sopenharmony_ci *	v0.3 - cleaner again, waitqueue fixes
2162306a36Sopenharmony_ci *	v0.4 - fixes in unidirectional mode
2262306a36Sopenharmony_ci *	v0.5 - add DEVICE_ID string support
2362306a36Sopenharmony_ci *	v0.6 - never time out
2462306a36Sopenharmony_ci *	v0.7 - fixed bulk-IN read and poll (David Paschal)
2562306a36Sopenharmony_ci *	v0.8 - add devfs support
2662306a36Sopenharmony_ci *	v0.9 - fix unplug-while-open paths
2762306a36Sopenharmony_ci *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
2862306a36Sopenharmony_ci *	v0.11 - add proto_bias option (Pete Zaitcev)
2962306a36Sopenharmony_ci *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
3062306a36Sopenharmony_ci *	v0.13 - alloc space for statusbuf (<status> not on stack);
3162306a36Sopenharmony_ci *		use usb_alloc_coherent() for read buf & write buf;
3262306a36Sopenharmony_ci *      none  - Maintained in Linux kernel after v0.13
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/module.h>
3662306a36Sopenharmony_ci#include <linux/kernel.h>
3762306a36Sopenharmony_ci#include <linux/sched/signal.h>
3862306a36Sopenharmony_ci#include <linux/signal.h>
3962306a36Sopenharmony_ci#include <linux/poll.h>
4062306a36Sopenharmony_ci#include <linux/slab.h>
4162306a36Sopenharmony_ci#include <linux/lp.h>
4262306a36Sopenharmony_ci#include <linux/mutex.h>
4362306a36Sopenharmony_ci#undef DEBUG
4462306a36Sopenharmony_ci#include <linux/usb.h>
4562306a36Sopenharmony_ci#include <linux/usb/ch9.h>
4662306a36Sopenharmony_ci#include <linux/ratelimit.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * Version Information
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
5262306a36Sopenharmony_ci#define DRIVER_DESC "USB Printer Device Class driver"
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define USBLP_BUF_SIZE		8192
5562306a36Sopenharmony_ci#define USBLP_BUF_SIZE_IN	1024
5662306a36Sopenharmony_ci#define USBLP_DEVICE_ID_SIZE	1024
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* ioctls: */
5962306a36Sopenharmony_ci#define IOCNR_GET_DEVICE_ID		1
6062306a36Sopenharmony_ci#define IOCNR_GET_PROTOCOLS		2
6162306a36Sopenharmony_ci#define IOCNR_SET_PROTOCOL		3
6262306a36Sopenharmony_ci#define IOCNR_HP_SET_CHANNEL		4
6362306a36Sopenharmony_ci#define IOCNR_GET_BUS_ADDRESS		5
6462306a36Sopenharmony_ci#define IOCNR_GET_VID_PID		6
6562306a36Sopenharmony_ci#define IOCNR_SOFT_RESET		7
6662306a36Sopenharmony_ci/* Get device_id string: */
6762306a36Sopenharmony_ci#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
6862306a36Sopenharmony_ci/* The following ioctls were added for http://hpoj.sourceforge.net:
6962306a36Sopenharmony_ci * Get two-int array:
7062306a36Sopenharmony_ci * [0]=current protocol
7162306a36Sopenharmony_ci *     (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
7262306a36Sopenharmony_ci *         3=USB_CLASS_PRINTER/1/3),
7362306a36Sopenharmony_ci * [1]=supported protocol mask (mask&(1<<n)!=0 means
7462306a36Sopenharmony_ci *     USB_CLASS_PRINTER/1/n supported):
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_ci#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Set protocol
7962306a36Sopenharmony_ci *     (arg: 1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
8062306a36Sopenharmony_ci *         3=USB_CLASS_PRINTER/1/3):
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_ci#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
8362306a36Sopenharmony_ci/* Set channel number (HP Vendor-specific command): */
8462306a36Sopenharmony_ci#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
8562306a36Sopenharmony_ci/* Get two-int array: [0]=bus number, [1]=device address: */
8662306a36Sopenharmony_ci#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
8762306a36Sopenharmony_ci/* Get two-int array: [0]=vendor ID, [1]=product ID: */
8862306a36Sopenharmony_ci#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
8962306a36Sopenharmony_ci/* Perform class specific soft reset */
9062306a36Sopenharmony_ci#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * A DEVICE_ID string may include the printer's serial number.
9462306a36Sopenharmony_ci * It should end with a semi-colon (';').
9562306a36Sopenharmony_ci * An example from an HP 970C DeskJet printer is (this is one long string,
9662306a36Sopenharmony_ci * with the serial number changed):
9762306a36Sopenharmony_ciMFG: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:                    ;
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * USB Printer Requests
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define USBLP_REQ_GET_ID			0x00
10562306a36Sopenharmony_ci#define USBLP_REQ_GET_STATUS			0x01
10662306a36Sopenharmony_ci#define USBLP_REQ_RESET				0x02
10762306a36Sopenharmony_ci#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define USBLP_MINORS		16
11062306a36Sopenharmony_ci#define USBLP_MINOR_BASE	0
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define USBLP_CTL_TIMEOUT	5000			/* 5 seconds */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define USBLP_FIRST_PROTOCOL	1
11562306a36Sopenharmony_ci#define USBLP_LAST_PROTOCOL	3
11662306a36Sopenharmony_ci#define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * some arbitrary status buffer size;
12062306a36Sopenharmony_ci * need a status buffer that is allocated via kmalloc(), not on stack
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci#define STATUS_BUF_SIZE		8
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * Locks down the locking order:
12662306a36Sopenharmony_ci * ->wmut locks wstatus.
12762306a36Sopenharmony_ci * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection,
12862306a36Sopenharmony_ci * [rw]status. We only touch status when we know the side idle.
12962306a36Sopenharmony_ci * ->lock locks what interrupt accesses.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistruct usblp {
13262306a36Sopenharmony_ci	struct usb_device	*dev;			/* USB device */
13362306a36Sopenharmony_ci	struct mutex		wmut;
13462306a36Sopenharmony_ci	struct mutex		mut;
13562306a36Sopenharmony_ci	spinlock_t		lock;		/* locks rcomplete, wcomplete */
13662306a36Sopenharmony_ci	char			*readbuf;		/* read transfer_buffer */
13762306a36Sopenharmony_ci	char			*statusbuf;		/* status transfer_buffer */
13862306a36Sopenharmony_ci	struct usb_anchor	urbs;
13962306a36Sopenharmony_ci	wait_queue_head_t	rwait, wwait;
14062306a36Sopenharmony_ci	int			readcount;		/* Counter for reads */
14162306a36Sopenharmony_ci	int			ifnum;			/* Interface number */
14262306a36Sopenharmony_ci	struct usb_interface	*intf;			/* The interface */
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * Alternate-setting numbers and endpoints for each protocol
14562306a36Sopenharmony_ci	 * (USB_CLASS_PRINTER/1/{index=1,2,3}) that the device supports:
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	struct {
14862306a36Sopenharmony_ci		int				alt_setting;
14962306a36Sopenharmony_ci		struct usb_endpoint_descriptor	*epwrite;
15062306a36Sopenharmony_ci		struct usb_endpoint_descriptor	*epread;
15162306a36Sopenharmony_ci	}			protocol[USBLP_MAX_PROTOCOLS];
15262306a36Sopenharmony_ci	int			current_protocol;
15362306a36Sopenharmony_ci	int			minor;			/* minor number of device */
15462306a36Sopenharmony_ci	int			wcomplete, rcomplete;
15562306a36Sopenharmony_ci	int			wstatus;	/* bytes written or error */
15662306a36Sopenharmony_ci	int			rstatus;	/* bytes ready or error */
15762306a36Sopenharmony_ci	unsigned int		quirks;			/* quirks flags */
15862306a36Sopenharmony_ci	unsigned int		flags;			/* mode flags */
15962306a36Sopenharmony_ci	unsigned char		used;			/* True if open */
16062306a36Sopenharmony_ci	unsigned char		present;		/* True if not disconnected */
16162306a36Sopenharmony_ci	unsigned char		bidir;			/* interface is bidirectional */
16262306a36Sopenharmony_ci	unsigned char		no_paper;		/* Paper Out happened */
16362306a36Sopenharmony_ci	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
16462306a36Sopenharmony_ci							/* first 2 bytes are (big-endian) length */
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#ifdef DEBUG
16862306a36Sopenharmony_cistatic void usblp_dump(struct usblp *usblp)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct device *dev = &usblp->intf->dev;
17162306a36Sopenharmony_ci	int p;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	dev_dbg(dev, "usblp=0x%p\n", usblp);
17462306a36Sopenharmony_ci	dev_dbg(dev, "dev=0x%p\n", usblp->dev);
17562306a36Sopenharmony_ci	dev_dbg(dev, "present=%d\n", usblp->present);
17662306a36Sopenharmony_ci	dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf);
17762306a36Sopenharmony_ci	dev_dbg(dev, "readcount=%d\n", usblp->readcount);
17862306a36Sopenharmony_ci	dev_dbg(dev, "ifnum=%d\n", usblp->ifnum);
17962306a36Sopenharmony_ci	for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
18062306a36Sopenharmony_ci		dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p,
18162306a36Sopenharmony_ci			usblp->protocol[p].alt_setting);
18262306a36Sopenharmony_ci		dev_dbg(dev, "protocol[%d].epwrite=%p\n", p,
18362306a36Sopenharmony_ci			usblp->protocol[p].epwrite);
18462306a36Sopenharmony_ci		dev_dbg(dev, "protocol[%d].epread=%p\n", p,
18562306a36Sopenharmony_ci			usblp->protocol[p].epread);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci	dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol);
18862306a36Sopenharmony_ci	dev_dbg(dev, "minor=%d\n", usblp->minor);
18962306a36Sopenharmony_ci	dev_dbg(dev, "wstatus=%d\n", usblp->wstatus);
19062306a36Sopenharmony_ci	dev_dbg(dev, "rstatus=%d\n", usblp->rstatus);
19162306a36Sopenharmony_ci	dev_dbg(dev, "quirks=%d\n", usblp->quirks);
19262306a36Sopenharmony_ci	dev_dbg(dev, "used=%d\n", usblp->used);
19362306a36Sopenharmony_ci	dev_dbg(dev, "bidir=%d\n", usblp->bidir);
19462306a36Sopenharmony_ci	dev_dbg(dev, "device_id_string=\"%s\"\n",
19562306a36Sopenharmony_ci		usblp->device_id_string ?
19662306a36Sopenharmony_ci			usblp->device_id_string + 2 :
19762306a36Sopenharmony_ci			(unsigned char *)"(null)");
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci#endif
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Quirks: various printer quirks are handled by this table & its flags. */
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct quirk_printer_struct {
20462306a36Sopenharmony_ci	__u16 vendorId;
20562306a36Sopenharmony_ci	__u16 productId;
20662306a36Sopenharmony_ci	unsigned int quirks;
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define USBLP_QUIRK_BIDIR	0x1	/* reports bidir but requires unidirectional mode (no INs/reads) */
21062306a36Sopenharmony_ci#define USBLP_QUIRK_USB_INIT	0x2	/* needs vendor USB init string */
21162306a36Sopenharmony_ci#define USBLP_QUIRK_BAD_CLASS	0x4	/* descriptor uses vendor-specific Class or SubClass */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic const struct quirk_printer_struct quirk_printers[] = {
21462306a36Sopenharmony_ci	{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
21562306a36Sopenharmony_ci	{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
21662306a36Sopenharmony_ci	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
21762306a36Sopenharmony_ci	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
21862306a36Sopenharmony_ci	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
21962306a36Sopenharmony_ci	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
22062306a36Sopenharmony_ci	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */
22162306a36Sopenharmony_ci	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */
22262306a36Sopenharmony_ci	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
22362306a36Sopenharmony_ci	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
22462306a36Sopenharmony_ci	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
22562306a36Sopenharmony_ci	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
22662306a36Sopenharmony_ci	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
22762306a36Sopenharmony_ci	{ 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */
22862306a36Sopenharmony_ci	{ 0x04f9, 0x000d, USBLP_QUIRK_BIDIR }, /* Brother Industries, Ltd HL-1440 Laser Printer */
22962306a36Sopenharmony_ci	{ 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */
23062306a36Sopenharmony_ci	{ 0, 0 }
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int usblp_wwait(struct usblp *usblp, int nonblock);
23462306a36Sopenharmony_cistatic int usblp_wtest(struct usblp *usblp, int nonblock);
23562306a36Sopenharmony_cistatic int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
23662306a36Sopenharmony_cistatic int usblp_rtest(struct usblp *usblp, int nonblock);
23762306a36Sopenharmony_cistatic int usblp_submit_read(struct usblp *usblp);
23862306a36Sopenharmony_cistatic int usblp_select_alts(struct usblp *usblp);
23962306a36Sopenharmony_cistatic int usblp_set_protocol(struct usblp *usblp, int protocol);
24062306a36Sopenharmony_cistatic int usblp_cache_device_id_string(struct usblp *usblp);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/* forward reference to make our lives easier */
24362306a36Sopenharmony_cistatic struct usb_driver usblp_driver;
24462306a36Sopenharmony_cistatic DEFINE_MUTEX(usblp_mutex);	/* locks the existence of usblp's */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/*
24762306a36Sopenharmony_ci * Functions for usblp control messages.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	int retval;
25362306a36Sopenharmony_ci	int index = usblp->ifnum;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* High byte has the interface index.
25662306a36Sopenharmony_ci	   Low byte has the alternate setting.
25762306a36Sopenharmony_ci	 */
25862306a36Sopenharmony_ci	if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS))
25962306a36Sopenharmony_ci		index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	retval = usb_control_msg(usblp->dev,
26262306a36Sopenharmony_ci		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
26362306a36Sopenharmony_ci		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
26462306a36Sopenharmony_ci	dev_dbg(&usblp->intf->dev,
26562306a36Sopenharmony_ci		"usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n",
26662306a36Sopenharmony_ci		request, !!dir, recip, value, index, len, retval);
26762306a36Sopenharmony_ci	return retval < 0 ? retval : 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#define usblp_read_status(usblp, status)\
27162306a36Sopenharmony_ci	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
27262306a36Sopenharmony_ci#define usblp_get_id(usblp, config, id, maxlen)\
27362306a36Sopenharmony_ci	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
27462306a36Sopenharmony_ci#define usblp_reset(usblp)\
27562306a36Sopenharmony_ci	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int usblp_hp_channel_change_request(struct usblp *usblp, int channel, u8 *new_channel)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	u8 *buf;
28062306a36Sopenharmony_ci	int ret;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	buf = kzalloc(1, GFP_KERNEL);
28362306a36Sopenharmony_ci	if (!buf)
28462306a36Sopenharmony_ci		return -ENOMEM;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	ret = usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST,
28762306a36Sopenharmony_ci			USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE,
28862306a36Sopenharmony_ci			channel, buf, 1);
28962306a36Sopenharmony_ci	if (ret == 0)
29062306a36Sopenharmony_ci		*new_channel = buf[0];
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	kfree(buf);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/*
29862306a36Sopenharmony_ci * See the description for usblp_select_alts() below for the usage
29962306a36Sopenharmony_ci * explanation.  Look into your /sys/kernel/debug/usb/devices and dmesg in
30062306a36Sopenharmony_ci * case of any trouble.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic int proto_bias = -1;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/*
30562306a36Sopenharmony_ci * URB callback.
30662306a36Sopenharmony_ci */
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic void usblp_bulk_read(struct urb *urb)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct usblp *usblp = urb->context;
31162306a36Sopenharmony_ci	int status = urb->status;
31262306a36Sopenharmony_ci	unsigned long flags;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (usblp->present && usblp->used) {
31562306a36Sopenharmony_ci		if (status)
31662306a36Sopenharmony_ci			printk(KERN_WARNING "usblp%d: "
31762306a36Sopenharmony_ci			    "nonzero read bulk status received: %d\n",
31862306a36Sopenharmony_ci			    usblp->minor, status);
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
32162306a36Sopenharmony_ci	if (status < 0)
32262306a36Sopenharmony_ci		usblp->rstatus = status;
32362306a36Sopenharmony_ci	else
32462306a36Sopenharmony_ci		usblp->rstatus = urb->actual_length;
32562306a36Sopenharmony_ci	usblp->rcomplete = 1;
32662306a36Sopenharmony_ci	wake_up(&usblp->rwait);
32762306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	usb_free_urb(urb);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic void usblp_bulk_write(struct urb *urb)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct usblp *usblp = urb->context;
33562306a36Sopenharmony_ci	int status = urb->status;
33662306a36Sopenharmony_ci	unsigned long flags;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (usblp->present && usblp->used) {
33962306a36Sopenharmony_ci		if (status)
34062306a36Sopenharmony_ci			printk(KERN_WARNING "usblp%d: "
34162306a36Sopenharmony_ci			    "nonzero write bulk status received: %d\n",
34262306a36Sopenharmony_ci			    usblp->minor, status);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
34562306a36Sopenharmony_ci	if (status < 0)
34662306a36Sopenharmony_ci		usblp->wstatus = status;
34762306a36Sopenharmony_ci	else
34862306a36Sopenharmony_ci		usblp->wstatus = urb->actual_length;
34962306a36Sopenharmony_ci	usblp->no_paper = 0;
35062306a36Sopenharmony_ci	usblp->wcomplete = 1;
35162306a36Sopenharmony_ci	wake_up(&usblp->wwait);
35262306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	usb_free_urb(urb);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci/*
35862306a36Sopenharmony_ci * Get and print printer errors.
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int usblp_check_status(struct usblp *usblp, int err)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	unsigned char status, newerr = 0;
36662306a36Sopenharmony_ci	int error;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	mutex_lock(&usblp->mut);
36962306a36Sopenharmony_ci	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
37062306a36Sopenharmony_ci		mutex_unlock(&usblp->mut);
37162306a36Sopenharmony_ci		printk_ratelimited(KERN_ERR
37262306a36Sopenharmony_ci				"usblp%d: error %d reading printer status\n",
37362306a36Sopenharmony_ci				usblp->minor, error);
37462306a36Sopenharmony_ci		return 0;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci	status = *usblp->statusbuf;
37762306a36Sopenharmony_ci	mutex_unlock(&usblp->mut);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (~status & LP_PERRORP)
38062306a36Sopenharmony_ci		newerr = 3;
38162306a36Sopenharmony_ci	if (status & LP_POUTPA)
38262306a36Sopenharmony_ci		newerr = 1;
38362306a36Sopenharmony_ci	if (~status & LP_PSELECD)
38462306a36Sopenharmony_ci		newerr = 2;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (newerr != err) {
38762306a36Sopenharmony_ci		printk(KERN_INFO "usblp%d: %s\n",
38862306a36Sopenharmony_ci		   usblp->minor, usblp_messages[newerr]);
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return newerr;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic int handle_bidir(struct usblp *usblp)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	if (usblp->bidir && usblp->used) {
39762306a36Sopenharmony_ci		if (usblp_submit_read(usblp) < 0)
39862306a36Sopenharmony_ci			return -EIO;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/*
40462306a36Sopenharmony_ci * File op functions.
40562306a36Sopenharmony_ci */
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int usblp_open(struct inode *inode, struct file *file)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	int minor = iminor(inode);
41062306a36Sopenharmony_ci	struct usblp *usblp;
41162306a36Sopenharmony_ci	struct usb_interface *intf;
41262306a36Sopenharmony_ci	int retval;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (minor < 0)
41562306a36Sopenharmony_ci		return -ENODEV;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	mutex_lock(&usblp_mutex);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	retval = -ENODEV;
42062306a36Sopenharmony_ci	intf = usb_find_interface(&usblp_driver, minor);
42162306a36Sopenharmony_ci	if (!intf)
42262306a36Sopenharmony_ci		goto out;
42362306a36Sopenharmony_ci	usblp = usb_get_intfdata(intf);
42462306a36Sopenharmony_ci	if (!usblp || !usblp->dev || !usblp->present)
42562306a36Sopenharmony_ci		goto out;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	retval = -EBUSY;
42862306a36Sopenharmony_ci	if (usblp->used)
42962306a36Sopenharmony_ci		goto out;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*
43262306a36Sopenharmony_ci	 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
43362306a36Sopenharmony_ci	 *  - We do not want persistent state which close(2) does not clear
43462306a36Sopenharmony_ci	 *  - It is not used anyway, according to CUPS people
43562306a36Sopenharmony_ci	 */
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	retval = usb_autopm_get_interface(intf);
43862306a36Sopenharmony_ci	if (retval < 0)
43962306a36Sopenharmony_ci		goto out;
44062306a36Sopenharmony_ci	usblp->used = 1;
44162306a36Sopenharmony_ci	file->private_data = usblp;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	usblp->wcomplete = 1; /* we begin writeable */
44462306a36Sopenharmony_ci	usblp->wstatus = 0;
44562306a36Sopenharmony_ci	usblp->rcomplete = 0;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (handle_bidir(usblp) < 0) {
44862306a36Sopenharmony_ci		usb_autopm_put_interface(intf);
44962306a36Sopenharmony_ci		usblp->used = 0;
45062306a36Sopenharmony_ci		file->private_data = NULL;
45162306a36Sopenharmony_ci		retval = -EIO;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ciout:
45462306a36Sopenharmony_ci	mutex_unlock(&usblp_mutex);
45562306a36Sopenharmony_ci	return retval;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic void usblp_cleanup(struct usblp *usblp)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	kfree(usblp->readbuf);
46362306a36Sopenharmony_ci	kfree(usblp->device_id_string);
46462306a36Sopenharmony_ci	kfree(usblp->statusbuf);
46562306a36Sopenharmony_ci	usb_put_intf(usblp->intf);
46662306a36Sopenharmony_ci	kfree(usblp);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void usblp_unlink_urbs(struct usblp *usblp)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	usb_kill_anchored_urbs(&usblp->urbs);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic int usblp_release(struct inode *inode, struct file *file)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct usblp *usblp = file->private_data;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	usblp->flags &= ~LP_ABORT;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	mutex_lock(&usblp_mutex);
48162306a36Sopenharmony_ci	usblp->used = 0;
48262306a36Sopenharmony_ci	if (usblp->present)
48362306a36Sopenharmony_ci		usblp_unlink_urbs(usblp);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	usb_autopm_put_interface(usblp->intf);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!usblp->present)		/* finish cleanup from disconnect */
48862306a36Sopenharmony_ci		usblp_cleanup(usblp);	/* any URBs must be dead */
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	mutex_unlock(&usblp_mutex);
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/* No kernel lock - fine */
49562306a36Sopenharmony_cistatic __poll_t usblp_poll(struct file *file, struct poll_table_struct *wait)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct usblp *usblp = file->private_data;
49862306a36Sopenharmony_ci	__poll_t ret = 0;
49962306a36Sopenharmony_ci	unsigned long flags;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
50262306a36Sopenharmony_ci	poll_wait(file, &usblp->rwait, wait);
50362306a36Sopenharmony_ci	poll_wait(file, &usblp->wwait, wait);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	mutex_lock(&usblp->mut);
50662306a36Sopenharmony_ci	if (!usblp->present)
50762306a36Sopenharmony_ci		ret |= EPOLLHUP;
50862306a36Sopenharmony_ci	mutex_unlock(&usblp->mut);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
51162306a36Sopenharmony_ci	if (usblp->bidir && usblp->rcomplete)
51262306a36Sopenharmony_ci		ret |= EPOLLIN  | EPOLLRDNORM;
51362306a36Sopenharmony_ci	if (usblp->no_paper || usblp->wcomplete)
51462306a36Sopenharmony_ci		ret |= EPOLLOUT | EPOLLWRNORM;
51562306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
51662306a36Sopenharmony_ci	return ret;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct usblp *usblp = file->private_data;
52262306a36Sopenharmony_ci	int length, err, i;
52362306a36Sopenharmony_ci	unsigned char newChannel;
52462306a36Sopenharmony_ci	int status;
52562306a36Sopenharmony_ci	int twoints[2];
52662306a36Sopenharmony_ci	int retval = 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	mutex_lock(&usblp->mut);
52962306a36Sopenharmony_ci	if (!usblp->present) {
53062306a36Sopenharmony_ci		retval = -ENODEV;
53162306a36Sopenharmony_ci		goto done;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	dev_dbg(&usblp->intf->dev,
53562306a36Sopenharmony_ci		"usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd,
53662306a36Sopenharmony_ci		_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		switch (_IOC_NR(cmd)) {
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
54362306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_READ) {
54462306a36Sopenharmony_ci				retval = -EINVAL;
54562306a36Sopenharmony_ci				goto done;
54662306a36Sopenharmony_ci			}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci			length = usblp_cache_device_id_string(usblp);
54962306a36Sopenharmony_ci			if (length < 0) {
55062306a36Sopenharmony_ci				retval = length;
55162306a36Sopenharmony_ci				goto done;
55262306a36Sopenharmony_ci			}
55362306a36Sopenharmony_ci			if (length > _IOC_SIZE(cmd))
55462306a36Sopenharmony_ci				length = _IOC_SIZE(cmd); /* truncate */
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci			if (copy_to_user((void __user *) arg,
55762306a36Sopenharmony_ci					usblp->device_id_string,
55862306a36Sopenharmony_ci					(unsigned long) length)) {
55962306a36Sopenharmony_ci				retval = -EFAULT;
56062306a36Sopenharmony_ci				goto done;
56162306a36Sopenharmony_ci			}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		case IOCNR_GET_PROTOCOLS:
56662306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_READ ||
56762306a36Sopenharmony_ci			    _IOC_SIZE(cmd) < sizeof(twoints)) {
56862306a36Sopenharmony_ci				retval = -EINVAL;
56962306a36Sopenharmony_ci				goto done;
57062306a36Sopenharmony_ci			}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci			twoints[0] = usblp->current_protocol;
57362306a36Sopenharmony_ci			twoints[1] = 0;
57462306a36Sopenharmony_ci			for (i = USBLP_FIRST_PROTOCOL;
57562306a36Sopenharmony_ci			     i <= USBLP_LAST_PROTOCOL; i++) {
57662306a36Sopenharmony_ci				if (usblp->protocol[i].alt_setting >= 0)
57762306a36Sopenharmony_ci					twoints[1] |= (1<<i);
57862306a36Sopenharmony_ci			}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci			if (copy_to_user((void __user *)arg,
58162306a36Sopenharmony_ci					(unsigned char *)twoints,
58262306a36Sopenharmony_ci					sizeof(twoints))) {
58362306a36Sopenharmony_ci				retval = -EFAULT;
58462306a36Sopenharmony_ci				goto done;
58562306a36Sopenharmony_ci			}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			break;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		case IOCNR_SET_PROTOCOL:
59062306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_WRITE) {
59162306a36Sopenharmony_ci				retval = -EINVAL;
59262306a36Sopenharmony_ci				goto done;
59362306a36Sopenharmony_ci			}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci#ifdef DEBUG
59662306a36Sopenharmony_ci			if (arg == -10) {
59762306a36Sopenharmony_ci				usblp_dump(usblp);
59862306a36Sopenharmony_ci				break;
59962306a36Sopenharmony_ci			}
60062306a36Sopenharmony_ci#endif
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci			usblp_unlink_urbs(usblp);
60362306a36Sopenharmony_ci			retval = usblp_set_protocol(usblp, arg);
60462306a36Sopenharmony_ci			if (retval < 0) {
60562306a36Sopenharmony_ci				usblp_set_protocol(usblp,
60662306a36Sopenharmony_ci					usblp->current_protocol);
60762306a36Sopenharmony_ci			}
60862306a36Sopenharmony_ci			break;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		case IOCNR_HP_SET_CHANNEL:
61162306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_WRITE ||
61262306a36Sopenharmony_ci			    le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 ||
61362306a36Sopenharmony_ci			    usblp->quirks & USBLP_QUIRK_BIDIR) {
61462306a36Sopenharmony_ci				retval = -EINVAL;
61562306a36Sopenharmony_ci				goto done;
61662306a36Sopenharmony_ci			}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci			err = usblp_hp_channel_change_request(usblp,
61962306a36Sopenharmony_ci				arg, &newChannel);
62062306a36Sopenharmony_ci			if (err < 0) {
62162306a36Sopenharmony_ci				dev_err(&usblp->dev->dev,
62262306a36Sopenharmony_ci					"usblp%d: error = %d setting "
62362306a36Sopenharmony_ci					"HP channel\n",
62462306a36Sopenharmony_ci					usblp->minor, err);
62562306a36Sopenharmony_ci				retval = -EIO;
62662306a36Sopenharmony_ci				goto done;
62762306a36Sopenharmony_ci			}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci			dev_dbg(&usblp->intf->dev,
63062306a36Sopenharmony_ci				"usblp%d requested/got HP channel %ld/%d\n",
63162306a36Sopenharmony_ci				usblp->minor, arg, newChannel);
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		case IOCNR_GET_BUS_ADDRESS:
63562306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_READ ||
63662306a36Sopenharmony_ci			    _IOC_SIZE(cmd) < sizeof(twoints)) {
63762306a36Sopenharmony_ci				retval = -EINVAL;
63862306a36Sopenharmony_ci				goto done;
63962306a36Sopenharmony_ci			}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci			twoints[0] = usblp->dev->bus->busnum;
64262306a36Sopenharmony_ci			twoints[1] = usblp->dev->devnum;
64362306a36Sopenharmony_ci			if (copy_to_user((void __user *)arg,
64462306a36Sopenharmony_ci					(unsigned char *)twoints,
64562306a36Sopenharmony_ci					sizeof(twoints))) {
64662306a36Sopenharmony_ci				retval = -EFAULT;
64762306a36Sopenharmony_ci				goto done;
64862306a36Sopenharmony_ci			}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci			dev_dbg(&usblp->intf->dev,
65162306a36Sopenharmony_ci				"usblp%d is bus=%d, device=%d\n",
65262306a36Sopenharmony_ci				usblp->minor, twoints[0], twoints[1]);
65362306a36Sopenharmony_ci			break;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		case IOCNR_GET_VID_PID:
65662306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_READ ||
65762306a36Sopenharmony_ci			    _IOC_SIZE(cmd) < sizeof(twoints)) {
65862306a36Sopenharmony_ci				retval = -EINVAL;
65962306a36Sopenharmony_ci				goto done;
66062306a36Sopenharmony_ci			}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci			twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor);
66362306a36Sopenharmony_ci			twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);
66462306a36Sopenharmony_ci			if (copy_to_user((void __user *)arg,
66562306a36Sopenharmony_ci					(unsigned char *)twoints,
66662306a36Sopenharmony_ci					sizeof(twoints))) {
66762306a36Sopenharmony_ci				retval = -EFAULT;
66862306a36Sopenharmony_ci				goto done;
66962306a36Sopenharmony_ci			}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci			dev_dbg(&usblp->intf->dev,
67262306a36Sopenharmony_ci				"usblp%d is VID=0x%4.4X, PID=0x%4.4X\n",
67362306a36Sopenharmony_ci				usblp->minor, twoints[0], twoints[1]);
67462306a36Sopenharmony_ci			break;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		case IOCNR_SOFT_RESET:
67762306a36Sopenharmony_ci			if (_IOC_DIR(cmd) != _IOC_NONE) {
67862306a36Sopenharmony_ci				retval = -EINVAL;
67962306a36Sopenharmony_ci				goto done;
68062306a36Sopenharmony_ci			}
68162306a36Sopenharmony_ci			retval = usblp_reset(usblp);
68262306a36Sopenharmony_ci			break;
68362306a36Sopenharmony_ci		default:
68462306a36Sopenharmony_ci			retval = -ENOTTY;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci	else	/* old-style ioctl value */
68762306a36Sopenharmony_ci		switch (cmd) {
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		case LPGETSTATUS:
69062306a36Sopenharmony_ci			retval = usblp_read_status(usblp, usblp->statusbuf);
69162306a36Sopenharmony_ci			if (retval) {
69262306a36Sopenharmony_ci				printk_ratelimited(KERN_ERR "usblp%d:"
69362306a36Sopenharmony_ci					    "failed reading printer status (%d)\n",
69462306a36Sopenharmony_ci					    usblp->minor, retval);
69562306a36Sopenharmony_ci				retval = -EIO;
69662306a36Sopenharmony_ci				goto done;
69762306a36Sopenharmony_ci			}
69862306a36Sopenharmony_ci			status = *usblp->statusbuf;
69962306a36Sopenharmony_ci			if (copy_to_user((void __user *)arg, &status, sizeof(int)))
70062306a36Sopenharmony_ci				retval = -EFAULT;
70162306a36Sopenharmony_ci			break;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		case LPABORT:
70462306a36Sopenharmony_ci			if (arg)
70562306a36Sopenharmony_ci				usblp->flags |= LP_ABORT;
70662306a36Sopenharmony_ci			else
70762306a36Sopenharmony_ci				usblp->flags &= ~LP_ABORT;
70862306a36Sopenharmony_ci			break;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		default:
71162306a36Sopenharmony_ci			retval = -ENOTTY;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cidone:
71562306a36Sopenharmony_ci	mutex_unlock(&usblp->mut);
71662306a36Sopenharmony_ci	return retval;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct urb *urb;
72262306a36Sopenharmony_ci	char *writebuf;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	writebuf = kmalloc(transfer_length, GFP_KERNEL);
72562306a36Sopenharmony_ci	if (writebuf == NULL)
72662306a36Sopenharmony_ci		return NULL;
72762306a36Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_KERNEL);
72862306a36Sopenharmony_ci	if (urb == NULL) {
72962306a36Sopenharmony_ci		kfree(writebuf);
73062306a36Sopenharmony_ci		return NULL;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, usblp->dev,
73462306a36Sopenharmony_ci		usb_sndbulkpipe(usblp->dev,
73562306a36Sopenharmony_ci		 usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
73662306a36Sopenharmony_ci		writebuf, transfer_length, usblp_bulk_write, usblp);
73762306a36Sopenharmony_ci	urb->transfer_flags |= URB_FREE_BUFFER;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	return urb;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct usblp *usblp = file->private_data;
74562306a36Sopenharmony_ci	struct urb *writeurb;
74662306a36Sopenharmony_ci	int rv;
74762306a36Sopenharmony_ci	int transfer_length;
74862306a36Sopenharmony_ci	ssize_t writecount = 0;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (mutex_lock_interruptible(&usblp->wmut)) {
75162306a36Sopenharmony_ci		rv = -EINTR;
75262306a36Sopenharmony_ci		goto raise_biglock;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci	if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0)
75562306a36Sopenharmony_ci		goto raise_wait;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	while (writecount < count) {
75862306a36Sopenharmony_ci		/*
75962306a36Sopenharmony_ci		 * Step 1: Submit next block.
76062306a36Sopenharmony_ci		 */
76162306a36Sopenharmony_ci		if ((transfer_length = count - writecount) > USBLP_BUF_SIZE)
76262306a36Sopenharmony_ci			transfer_length = USBLP_BUF_SIZE;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		rv = -ENOMEM;
76562306a36Sopenharmony_ci		writeurb = usblp_new_writeurb(usblp, transfer_length);
76662306a36Sopenharmony_ci		if (writeurb == NULL)
76762306a36Sopenharmony_ci			goto raise_urb;
76862306a36Sopenharmony_ci		usb_anchor_urb(writeurb, &usblp->urbs);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		if (copy_from_user(writeurb->transfer_buffer,
77162306a36Sopenharmony_ci				   buffer + writecount, transfer_length)) {
77262306a36Sopenharmony_ci			rv = -EFAULT;
77362306a36Sopenharmony_ci			goto raise_badaddr;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		spin_lock_irq(&usblp->lock);
77762306a36Sopenharmony_ci		usblp->wcomplete = 0;
77862306a36Sopenharmony_ci		spin_unlock_irq(&usblp->lock);
77962306a36Sopenharmony_ci		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
78062306a36Sopenharmony_ci			usblp->wstatus = 0;
78162306a36Sopenharmony_ci			spin_lock_irq(&usblp->lock);
78262306a36Sopenharmony_ci			usblp->no_paper = 0;
78362306a36Sopenharmony_ci			usblp->wcomplete = 1;
78462306a36Sopenharmony_ci			wake_up(&usblp->wwait);
78562306a36Sopenharmony_ci			spin_unlock_irq(&usblp->lock);
78662306a36Sopenharmony_ci			if (rv != -ENOMEM)
78762306a36Sopenharmony_ci				rv = -EIO;
78862306a36Sopenharmony_ci			goto raise_submit;
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci		/*
79262306a36Sopenharmony_ci		 * Step 2: Wait for transfer to end, collect results.
79362306a36Sopenharmony_ci		 */
79462306a36Sopenharmony_ci		rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
79562306a36Sopenharmony_ci		if (rv < 0) {
79662306a36Sopenharmony_ci			if (rv == -EAGAIN) {
79762306a36Sopenharmony_ci				/* Presume that it's going to complete well. */
79862306a36Sopenharmony_ci				writecount += transfer_length;
79962306a36Sopenharmony_ci			}
80062306a36Sopenharmony_ci			if (rv == -ENOSPC) {
80162306a36Sopenharmony_ci				spin_lock_irq(&usblp->lock);
80262306a36Sopenharmony_ci				usblp->no_paper = 1;	/* Mark for poll(2) */
80362306a36Sopenharmony_ci				spin_unlock_irq(&usblp->lock);
80462306a36Sopenharmony_ci				writecount += transfer_length;
80562306a36Sopenharmony_ci			}
80662306a36Sopenharmony_ci			/* Leave URB dangling, to be cleaned on close. */
80762306a36Sopenharmony_ci			goto collect_error;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		if (usblp->wstatus < 0) {
81162306a36Sopenharmony_ci			rv = -EIO;
81262306a36Sopenharmony_ci			goto collect_error;
81362306a36Sopenharmony_ci		}
81462306a36Sopenharmony_ci		/*
81562306a36Sopenharmony_ci		 * This is critical: it must be our URB, not other writer's.
81662306a36Sopenharmony_ci		 * The wmut exists mainly to cover us here.
81762306a36Sopenharmony_ci		 */
81862306a36Sopenharmony_ci		writecount += usblp->wstatus;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	mutex_unlock(&usblp->wmut);
82262306a36Sopenharmony_ci	return writecount;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ciraise_submit:
82562306a36Sopenharmony_ciraise_badaddr:
82662306a36Sopenharmony_ci	usb_unanchor_urb(writeurb);
82762306a36Sopenharmony_ci	usb_free_urb(writeurb);
82862306a36Sopenharmony_ciraise_urb:
82962306a36Sopenharmony_ciraise_wait:
83062306a36Sopenharmony_cicollect_error:		/* Out of raise sequence */
83162306a36Sopenharmony_ci	mutex_unlock(&usblp->wmut);
83262306a36Sopenharmony_ciraise_biglock:
83362306a36Sopenharmony_ci	return writecount ? writecount : rv;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/*
83762306a36Sopenharmony_ci * Notice that we fail to restart in a few cases: on EFAULT, on restart
83862306a36Sopenharmony_ci * error, etc. This is the historical behaviour. In all such cases we return
83962306a36Sopenharmony_ci * EIO, and applications loop in order to get the new read going.
84062306a36Sopenharmony_ci */
84162306a36Sopenharmony_cistatic ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct usblp *usblp = file->private_data;
84462306a36Sopenharmony_ci	ssize_t count;
84562306a36Sopenharmony_ci	ssize_t avail;
84662306a36Sopenharmony_ci	int rv;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (!usblp->bidir)
84962306a36Sopenharmony_ci		return -EINVAL;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
85262306a36Sopenharmony_ci	if (rv < 0)
85362306a36Sopenharmony_ci		return rv;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (!usblp->present) {
85662306a36Sopenharmony_ci		count = -ENODEV;
85762306a36Sopenharmony_ci		goto done;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if ((avail = usblp->rstatus) < 0) {
86162306a36Sopenharmony_ci		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
86262306a36Sopenharmony_ci		    usblp->minor, (int)avail);
86362306a36Sopenharmony_ci		usblp_submit_read(usblp);
86462306a36Sopenharmony_ci		count = -EIO;
86562306a36Sopenharmony_ci		goto done;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
86962306a36Sopenharmony_ci	if (count != 0 &&
87062306a36Sopenharmony_ci	    copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) {
87162306a36Sopenharmony_ci		count = -EFAULT;
87262306a36Sopenharmony_ci		goto done;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if ((usblp->readcount += count) == avail) {
87662306a36Sopenharmony_ci		if (usblp_submit_read(usblp) < 0) {
87762306a36Sopenharmony_ci			/* We don't want to leak USB return codes into errno. */
87862306a36Sopenharmony_ci			if (count == 0)
87962306a36Sopenharmony_ci				count = -EIO;
88062306a36Sopenharmony_ci			goto done;
88162306a36Sopenharmony_ci		}
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cidone:
88562306a36Sopenharmony_ci	mutex_unlock(&usblp->mut);
88662306a36Sopenharmony_ci	return count;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci/*
89062306a36Sopenharmony_ci * Wait for the write path to come idle.
89162306a36Sopenharmony_ci * This is called under the ->wmut, so the idle path stays idle.
89262306a36Sopenharmony_ci *
89362306a36Sopenharmony_ci * Our write path has a peculiar property: it does not buffer like a tty,
89462306a36Sopenharmony_ci * but waits for the write to succeed. This allows our ->release to bug out
89562306a36Sopenharmony_ci * without waiting for writes to drain. But it obviously does not work
89662306a36Sopenharmony_ci * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
89762306a36Sopenharmony_ci * select(2) or poll(2) to wait for the buffer to drain before closing.
89862306a36Sopenharmony_ci * Alternatively, set blocking mode with fcntl and issue a zero-size write.
89962306a36Sopenharmony_ci */
90062306a36Sopenharmony_cistatic int usblp_wwait(struct usblp *usblp, int nonblock)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	DECLARE_WAITQUEUE(waita, current);
90362306a36Sopenharmony_ci	int rc;
90462306a36Sopenharmony_ci	int err = 0;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	add_wait_queue(&usblp->wwait, &waita);
90762306a36Sopenharmony_ci	for (;;) {
90862306a36Sopenharmony_ci		if (mutex_lock_interruptible(&usblp->mut)) {
90962306a36Sopenharmony_ci			rc = -EINTR;
91062306a36Sopenharmony_ci			break;
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
91362306a36Sopenharmony_ci		rc = usblp_wtest(usblp, nonblock);
91462306a36Sopenharmony_ci		mutex_unlock(&usblp->mut);
91562306a36Sopenharmony_ci		if (rc <= 0)
91662306a36Sopenharmony_ci			break;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci		if (schedule_timeout(msecs_to_jiffies(1500)) == 0) {
91962306a36Sopenharmony_ci			if (usblp->flags & LP_ABORT) {
92062306a36Sopenharmony_ci				err = usblp_check_status(usblp, err);
92162306a36Sopenharmony_ci				if (err == 1) {	/* Paper out */
92262306a36Sopenharmony_ci					rc = -ENOSPC;
92362306a36Sopenharmony_ci					break;
92462306a36Sopenharmony_ci				}
92562306a36Sopenharmony_ci			} else {
92662306a36Sopenharmony_ci				/* Prod the printer, Gentoo#251237. */
92762306a36Sopenharmony_ci				mutex_lock(&usblp->mut);
92862306a36Sopenharmony_ci				usblp_read_status(usblp, usblp->statusbuf);
92962306a36Sopenharmony_ci				mutex_unlock(&usblp->mut);
93062306a36Sopenharmony_ci			}
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci	set_current_state(TASK_RUNNING);
93462306a36Sopenharmony_ci	remove_wait_queue(&usblp->wwait, &waita);
93562306a36Sopenharmony_ci	return rc;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int usblp_wtest(struct usblp *usblp, int nonblock)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	unsigned long flags;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (!usblp->present)
94362306a36Sopenharmony_ci		return -ENODEV;
94462306a36Sopenharmony_ci	if (signal_pending(current))
94562306a36Sopenharmony_ci		return -EINTR;
94662306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
94762306a36Sopenharmony_ci	if (usblp->wcomplete) {
94862306a36Sopenharmony_ci		spin_unlock_irqrestore(&usblp->lock, flags);
94962306a36Sopenharmony_ci		return 0;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
95262306a36Sopenharmony_ci	if (nonblock)
95362306a36Sopenharmony_ci		return -EAGAIN;
95462306a36Sopenharmony_ci	return 1;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci/*
95862306a36Sopenharmony_ci * Wait for read bytes to become available. This probably should have been
95962306a36Sopenharmony_ci * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
96062306a36Sopenharmony_ci * name for functions which lock and return.
96162306a36Sopenharmony_ci *
96262306a36Sopenharmony_ci * We do not use wait_event_interruptible because it makes locking iffy.
96362306a36Sopenharmony_ci */
96462306a36Sopenharmony_cistatic int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	DECLARE_WAITQUEUE(waita, current);
96762306a36Sopenharmony_ci	int rc;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	add_wait_queue(&usblp->rwait, &waita);
97062306a36Sopenharmony_ci	for (;;) {
97162306a36Sopenharmony_ci		if (mutex_lock_interruptible(&usblp->mut)) {
97262306a36Sopenharmony_ci			rc = -EINTR;
97362306a36Sopenharmony_ci			break;
97462306a36Sopenharmony_ci		}
97562306a36Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
97662306a36Sopenharmony_ci		if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
97762306a36Sopenharmony_ci			mutex_unlock(&usblp->mut);
97862306a36Sopenharmony_ci			break;
97962306a36Sopenharmony_ci		}
98062306a36Sopenharmony_ci		if (rc == 0)	/* Keep it locked */
98162306a36Sopenharmony_ci			break;
98262306a36Sopenharmony_ci		mutex_unlock(&usblp->mut);
98362306a36Sopenharmony_ci		schedule();
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci	set_current_state(TASK_RUNNING);
98662306a36Sopenharmony_ci	remove_wait_queue(&usblp->rwait, &waita);
98762306a36Sopenharmony_ci	return rc;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic int usblp_rtest(struct usblp *usblp, int nonblock)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	unsigned long flags;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (!usblp->present)
99562306a36Sopenharmony_ci		return -ENODEV;
99662306a36Sopenharmony_ci	if (signal_pending(current))
99762306a36Sopenharmony_ci		return -EINTR;
99862306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
99962306a36Sopenharmony_ci	if (usblp->rcomplete) {
100062306a36Sopenharmony_ci		spin_unlock_irqrestore(&usblp->lock, flags);
100162306a36Sopenharmony_ci		return 0;
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
100462306a36Sopenharmony_ci	if (nonblock)
100562306a36Sopenharmony_ci		return -EAGAIN;
100662306a36Sopenharmony_ci	return 1;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci/*
101062306a36Sopenharmony_ci * Please check ->bidir and other such things outside for now.
101162306a36Sopenharmony_ci */
101262306a36Sopenharmony_cistatic int usblp_submit_read(struct usblp *usblp)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	struct urb *urb;
101562306a36Sopenharmony_ci	unsigned long flags;
101662306a36Sopenharmony_ci	int rc;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	rc = -ENOMEM;
101962306a36Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_KERNEL);
102062306a36Sopenharmony_ci	if (urb == NULL)
102162306a36Sopenharmony_ci		goto raise_urb;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, usblp->dev,
102462306a36Sopenharmony_ci		usb_rcvbulkpipe(usblp->dev,
102562306a36Sopenharmony_ci		  usblp->protocol[usblp->current_protocol].epread->bEndpointAddress),
102662306a36Sopenharmony_ci		usblp->readbuf, USBLP_BUF_SIZE_IN,
102762306a36Sopenharmony_ci		usblp_bulk_read, usblp);
102862306a36Sopenharmony_ci	usb_anchor_urb(urb, &usblp->urbs);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	spin_lock_irqsave(&usblp->lock, flags);
103162306a36Sopenharmony_ci	usblp->readcount = 0; /* XXX Why here? */
103262306a36Sopenharmony_ci	usblp->rcomplete = 0;
103362306a36Sopenharmony_ci	spin_unlock_irqrestore(&usblp->lock, flags);
103462306a36Sopenharmony_ci	if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
103562306a36Sopenharmony_ci		dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);
103662306a36Sopenharmony_ci		spin_lock_irqsave(&usblp->lock, flags);
103762306a36Sopenharmony_ci		usblp->rstatus = rc;
103862306a36Sopenharmony_ci		usblp->rcomplete = 1;
103962306a36Sopenharmony_ci		spin_unlock_irqrestore(&usblp->lock, flags);
104062306a36Sopenharmony_ci		goto raise_submit;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	return 0;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ciraise_submit:
104662306a36Sopenharmony_ci	usb_unanchor_urb(urb);
104762306a36Sopenharmony_ci	usb_free_urb(urb);
104862306a36Sopenharmony_ciraise_urb:
104962306a36Sopenharmony_ci	return rc;
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci/*
105362306a36Sopenharmony_ci * Checks for printers that have quirks, such as requiring unidirectional
105462306a36Sopenharmony_ci * communication but reporting bidirectional; currently some HP printers
105562306a36Sopenharmony_ci * have this flaw (HP 810, 880, 895, etc.), or needing an init string
105662306a36Sopenharmony_ci * sent at each open (like some Epsons).
105762306a36Sopenharmony_ci * Returns 1 if found, 0 if not found.
105862306a36Sopenharmony_ci *
105962306a36Sopenharmony_ci * HP recommended that we use the bidirectional interface but
106062306a36Sopenharmony_ci * don't attempt any bulk IN transfers from the IN endpoint.
106162306a36Sopenharmony_ci * Here's some more detail on the problem:
106262306a36Sopenharmony_ci * The problem is not that it isn't bidirectional though. The problem
106362306a36Sopenharmony_ci * is that if you request a device ID, or status information, while
106462306a36Sopenharmony_ci * the buffers are full, the return data will end up in the print data
106562306a36Sopenharmony_ci * buffer. For example if you make sure you never request the device ID
106662306a36Sopenharmony_ci * while you are sending print data, and you don't try to query the
106762306a36Sopenharmony_ci * printer status every couple of milliseconds, you will probably be OK.
106862306a36Sopenharmony_ci */
106962306a36Sopenharmony_cistatic unsigned int usblp_quirks(__u16 vendor, __u16 product)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	int i;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	for (i = 0; quirk_printers[i].vendorId; i++) {
107462306a36Sopenharmony_ci		if (vendor == quirk_printers[i].vendorId &&
107562306a36Sopenharmony_ci		    product == quirk_printers[i].productId)
107662306a36Sopenharmony_ci			return quirk_printers[i].quirks;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci	return 0;
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_cistatic const struct file_operations usblp_fops = {
108262306a36Sopenharmony_ci	.owner =	THIS_MODULE,
108362306a36Sopenharmony_ci	.read =		usblp_read,
108462306a36Sopenharmony_ci	.write =	usblp_write,
108562306a36Sopenharmony_ci	.poll =		usblp_poll,
108662306a36Sopenharmony_ci	.unlocked_ioctl =	usblp_ioctl,
108762306a36Sopenharmony_ci	.compat_ioctl =		usblp_ioctl,
108862306a36Sopenharmony_ci	.open =		usblp_open,
108962306a36Sopenharmony_ci	.release =	usblp_release,
109062306a36Sopenharmony_ci	.llseek =	noop_llseek,
109162306a36Sopenharmony_ci};
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic char *usblp_devnode(const struct device *dev, umode_t *mode)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic struct usb_class_driver usblp_class = {
109962306a36Sopenharmony_ci	.name =		"lp%d",
110062306a36Sopenharmony_ci	.devnode =	usblp_devnode,
110162306a36Sopenharmony_ci	.fops =		&usblp_fops,
110262306a36Sopenharmony_ci	.minor_base =	USBLP_MINOR_BASE,
110362306a36Sopenharmony_ci};
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic ssize_t ieee1284_id_show(struct device *dev, struct device_attribute *attr, char *buf)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
110862306a36Sopenharmony_ci	struct usblp *usblp = usb_get_intfdata(intf);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (usblp->device_id_string[0] == 0 &&
111162306a36Sopenharmony_ci	    usblp->device_id_string[1] == 0)
111262306a36Sopenharmony_ci		return 0;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	return sprintf(buf, "%s", usblp->device_id_string+2);
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ieee1284_id);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic struct attribute *usblp_attrs[] = {
112062306a36Sopenharmony_ci	&dev_attr_ieee1284_id.attr,
112162306a36Sopenharmony_ci	NULL,
112262306a36Sopenharmony_ci};
112362306a36Sopenharmony_ciATTRIBUTE_GROUPS(usblp);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_cistatic int usblp_probe(struct usb_interface *intf,
112662306a36Sopenharmony_ci		       const struct usb_device_id *id)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(intf);
112962306a36Sopenharmony_ci	struct usblp *usblp;
113062306a36Sopenharmony_ci	int protocol;
113162306a36Sopenharmony_ci	int retval;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* Malloc and start initializing usblp structure so we can use it
113462306a36Sopenharmony_ci	 * directly. */
113562306a36Sopenharmony_ci	usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL);
113662306a36Sopenharmony_ci	if (!usblp) {
113762306a36Sopenharmony_ci		retval = -ENOMEM;
113862306a36Sopenharmony_ci		goto abort_ret;
113962306a36Sopenharmony_ci	}
114062306a36Sopenharmony_ci	usblp->dev = dev;
114162306a36Sopenharmony_ci	mutex_init(&usblp->wmut);
114262306a36Sopenharmony_ci	mutex_init(&usblp->mut);
114362306a36Sopenharmony_ci	spin_lock_init(&usblp->lock);
114462306a36Sopenharmony_ci	init_waitqueue_head(&usblp->rwait);
114562306a36Sopenharmony_ci	init_waitqueue_head(&usblp->wwait);
114662306a36Sopenharmony_ci	init_usb_anchor(&usblp->urbs);
114762306a36Sopenharmony_ci	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
114862306a36Sopenharmony_ci	usblp->intf = usb_get_intf(intf);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/* Malloc device ID string buffer to the largest expected length,
115162306a36Sopenharmony_ci	 * since we can re-query it on an ioctl and a dynamic string
115262306a36Sopenharmony_ci	 * could change in length. */
115362306a36Sopenharmony_ci	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
115462306a36Sopenharmony_ci		retval = -ENOMEM;
115562306a36Sopenharmony_ci		goto abort;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/*
115962306a36Sopenharmony_ci	 * Allocate read buffer. We somewhat wastefully
116062306a36Sopenharmony_ci	 * malloc both regardless of bidirectionality, because the
116162306a36Sopenharmony_ci	 * alternate setting can be changed later via an ioctl.
116262306a36Sopenharmony_ci	 */
116362306a36Sopenharmony_ci	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
116462306a36Sopenharmony_ci		retval = -ENOMEM;
116562306a36Sopenharmony_ci		goto abort;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* Allocate buffer for printer status */
116962306a36Sopenharmony_ci	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
117062306a36Sopenharmony_ci	if (!usblp->statusbuf) {
117162306a36Sopenharmony_ci		retval = -ENOMEM;
117262306a36Sopenharmony_ci		goto abort;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Lookup quirks for this printer. */
117662306a36Sopenharmony_ci	usblp->quirks = usblp_quirks(
117762306a36Sopenharmony_ci		le16_to_cpu(dev->descriptor.idVendor),
117862306a36Sopenharmony_ci		le16_to_cpu(dev->descriptor.idProduct));
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Analyze and pick initial alternate settings and endpoints. */
118162306a36Sopenharmony_ci	protocol = usblp_select_alts(usblp);
118262306a36Sopenharmony_ci	if (protocol < 0) {
118362306a36Sopenharmony_ci		dev_dbg(&intf->dev,
118462306a36Sopenharmony_ci			"incompatible printer-class device 0x%4.4X/0x%4.4X\n",
118562306a36Sopenharmony_ci			le16_to_cpu(dev->descriptor.idVendor),
118662306a36Sopenharmony_ci			le16_to_cpu(dev->descriptor.idProduct));
118762306a36Sopenharmony_ci		retval = -ENODEV;
118862306a36Sopenharmony_ci		goto abort;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	/* Setup the selected alternate setting and endpoints. */
119262306a36Sopenharmony_ci	if (usblp_set_protocol(usblp, protocol) < 0) {
119362306a36Sopenharmony_ci		retval = -ENODEV;	/* ->probe isn't ->ioctl */
119462306a36Sopenharmony_ci		goto abort;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* Retrieve and store the device ID string. */
119862306a36Sopenharmony_ci	usblp_cache_device_id_string(usblp);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci#ifdef DEBUG
120162306a36Sopenharmony_ci	usblp_check_status(usblp, 0);
120262306a36Sopenharmony_ci#endif
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	usb_set_intfdata(intf, usblp);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	usblp->present = 1;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	retval = usb_register_dev(intf, &usblp_class);
120962306a36Sopenharmony_ci	if (retval) {
121062306a36Sopenharmony_ci		dev_err(&intf->dev,
121162306a36Sopenharmony_ci			"usblp: Not able to get a minor (base %u, slice default): %d\n",
121262306a36Sopenharmony_ci			USBLP_MINOR_BASE, retval);
121362306a36Sopenharmony_ci		goto abort_intfdata;
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci	usblp->minor = intf->minor;
121662306a36Sopenharmony_ci	dev_info(&intf->dev,
121762306a36Sopenharmony_ci		"usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
121862306a36Sopenharmony_ci		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
121962306a36Sopenharmony_ci		usblp->ifnum,
122062306a36Sopenharmony_ci		usblp->protocol[usblp->current_protocol].alt_setting,
122162306a36Sopenharmony_ci		usblp->current_protocol,
122262306a36Sopenharmony_ci		le16_to_cpu(usblp->dev->descriptor.idVendor),
122362306a36Sopenharmony_ci		le16_to_cpu(usblp->dev->descriptor.idProduct));
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return 0;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ciabort_intfdata:
122862306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
122962306a36Sopenharmony_ciabort:
123062306a36Sopenharmony_ci	kfree(usblp->readbuf);
123162306a36Sopenharmony_ci	kfree(usblp->statusbuf);
123262306a36Sopenharmony_ci	kfree(usblp->device_id_string);
123362306a36Sopenharmony_ci	usb_put_intf(usblp->intf);
123462306a36Sopenharmony_ci	kfree(usblp);
123562306a36Sopenharmony_ciabort_ret:
123662306a36Sopenharmony_ci	return retval;
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci/*
124062306a36Sopenharmony_ci * We are a "new" style driver with usb_device_id table,
124162306a36Sopenharmony_ci * but our requirements are too intricate for simple match to handle.
124262306a36Sopenharmony_ci *
124362306a36Sopenharmony_ci * The "proto_bias" option may be used to specify the preferred protocol
124462306a36Sopenharmony_ci * for all USB printers (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
124562306a36Sopenharmony_ci * 3=USB_CLASS_PRINTER/1/3).  If the device supports the preferred protocol,
124662306a36Sopenharmony_ci * then we bind to it.
124762306a36Sopenharmony_ci *
124862306a36Sopenharmony_ci * The best interface for us is USB_CLASS_PRINTER/1/2, because it
124962306a36Sopenharmony_ci * is compatible with a stream of characters. If we find it, we bind to it.
125062306a36Sopenharmony_ci *
125162306a36Sopenharmony_ci * Note that the people from hpoj.sourceforge.net need to be able to
125262306a36Sopenharmony_ci * bind to USB_CLASS_PRINTER/1/3 (MLC/1284.4), so we provide them ioctls
125362306a36Sopenharmony_ci * for this purpose.
125462306a36Sopenharmony_ci *
125562306a36Sopenharmony_ci * Failing USB_CLASS_PRINTER/1/2, we look for USB_CLASS_PRINTER/1/3,
125662306a36Sopenharmony_ci * even though it's probably not stream-compatible, because this matches
125762306a36Sopenharmony_ci * the behaviour of the old code.
125862306a36Sopenharmony_ci *
125962306a36Sopenharmony_ci * If nothing else, we bind to USB_CLASS_PRINTER/1/1
126062306a36Sopenharmony_ci * - the unidirectional interface.
126162306a36Sopenharmony_ci */
126262306a36Sopenharmony_cistatic int usblp_select_alts(struct usblp *usblp)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	struct usb_interface *if_alt;
126562306a36Sopenharmony_ci	struct usb_host_interface *ifd;
126662306a36Sopenharmony_ci	struct usb_endpoint_descriptor *epwrite, *epread;
126762306a36Sopenharmony_ci	int p, i;
126862306a36Sopenharmony_ci	int res;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if_alt = usblp->intf;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
127362306a36Sopenharmony_ci		usblp->protocol[p].alt_setting = -1;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* Find out what we have. */
127662306a36Sopenharmony_ci	for (i = 0; i < if_alt->num_altsetting; i++) {
127762306a36Sopenharmony_ci		ifd = &if_alt->altsetting[i];
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci		if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER ||
128062306a36Sopenharmony_ci		    ifd->desc.bInterfaceSubClass != 1)
128162306a36Sopenharmony_ci			if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS))
128262306a36Sopenharmony_ci				continue;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci		if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL ||
128562306a36Sopenharmony_ci		    ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL)
128662306a36Sopenharmony_ci			continue;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci		/* Look for the expected bulk endpoints. */
128962306a36Sopenharmony_ci		if (ifd->desc.bInterfaceProtocol > 1) {
129062306a36Sopenharmony_ci			res = usb_find_common_endpoints(ifd,
129162306a36Sopenharmony_ci					&epread, &epwrite, NULL, NULL);
129262306a36Sopenharmony_ci		} else {
129362306a36Sopenharmony_ci			epread = NULL;
129462306a36Sopenharmony_ci			res = usb_find_bulk_out_endpoint(ifd, &epwrite);
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		/* Ignore buggy hardware without the right endpoints. */
129862306a36Sopenharmony_ci		if (res)
129962306a36Sopenharmony_ci			continue;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		/* Turn off reads for buggy bidirectional printers. */
130262306a36Sopenharmony_ci		if (usblp->quirks & USBLP_QUIRK_BIDIR) {
130362306a36Sopenharmony_ci			printk(KERN_INFO "usblp%d: Disabling reads from "
130462306a36Sopenharmony_ci			    "problematic bidirectional printer\n",
130562306a36Sopenharmony_ci			    usblp->minor);
130662306a36Sopenharmony_ci			epread = NULL;
130762306a36Sopenharmony_ci		}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting =
131062306a36Sopenharmony_ci				ifd->desc.bAlternateSetting;
131162306a36Sopenharmony_ci		usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite;
131262306a36Sopenharmony_ci		usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/* If our requested protocol is supported, then use it. */
131662306a36Sopenharmony_ci	if (proto_bias >= USBLP_FIRST_PROTOCOL &&
131762306a36Sopenharmony_ci	    proto_bias <= USBLP_LAST_PROTOCOL &&
131862306a36Sopenharmony_ci	    usblp->protocol[proto_bias].alt_setting != -1)
131962306a36Sopenharmony_ci		return proto_bias;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* Ordering is important here. */
132262306a36Sopenharmony_ci	if (usblp->protocol[2].alt_setting != -1)
132362306a36Sopenharmony_ci		return 2;
132462306a36Sopenharmony_ci	if (usblp->protocol[1].alt_setting != -1)
132562306a36Sopenharmony_ci		return 1;
132662306a36Sopenharmony_ci	if (usblp->protocol[3].alt_setting != -1)
132762306a36Sopenharmony_ci		return 3;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	/* If nothing is available, then don't bind to this device. */
133062306a36Sopenharmony_ci	return -1;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic int usblp_set_protocol(struct usblp *usblp, int protocol)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	int r, alts;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
133862306a36Sopenharmony_ci		return -EINVAL;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* Don't unnecessarily set the interface if there's a single alt. */
134162306a36Sopenharmony_ci	if (usblp->intf->num_altsetting > 1) {
134262306a36Sopenharmony_ci		alts = usblp->protocol[protocol].alt_setting;
134362306a36Sopenharmony_ci		if (alts < 0)
134462306a36Sopenharmony_ci			return -EINVAL;
134562306a36Sopenharmony_ci		r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
134662306a36Sopenharmony_ci		if (r < 0) {
134762306a36Sopenharmony_ci			printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
134862306a36Sopenharmony_ci				alts, usblp->ifnum);
134962306a36Sopenharmony_ci			return r;
135062306a36Sopenharmony_ci		}
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
135462306a36Sopenharmony_ci	usblp->current_protocol = protocol;
135562306a36Sopenharmony_ci	dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n",
135662306a36Sopenharmony_ci		usblp->minor, protocol);
135762306a36Sopenharmony_ci	return 0;
135862306a36Sopenharmony_ci}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci/* Retrieves and caches device ID string.
136162306a36Sopenharmony_ci * Returns length, including length bytes but not null terminator.
136262306a36Sopenharmony_ci * On error, returns a negative errno value. */
136362306a36Sopenharmony_cistatic int usblp_cache_device_id_string(struct usblp *usblp)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	int err, length;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
136862306a36Sopenharmony_ci	if (err < 0) {
136962306a36Sopenharmony_ci		dev_dbg(&usblp->intf->dev,
137062306a36Sopenharmony_ci			"usblp%d: error = %d reading IEEE-1284 Device ID string\n",
137162306a36Sopenharmony_ci			usblp->minor, err);
137262306a36Sopenharmony_ci		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
137362306a36Sopenharmony_ci		return -EIO;
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* First two bytes are length in big-endian.
137762306a36Sopenharmony_ci	 * They count themselves, and we copy them into
137862306a36Sopenharmony_ci	 * the user's buffer. */
137962306a36Sopenharmony_ci	length = be16_to_cpu(*((__be16 *)usblp->device_id_string));
138062306a36Sopenharmony_ci	if (length < 2)
138162306a36Sopenharmony_ci		length = 2;
138262306a36Sopenharmony_ci	else if (length >= USBLP_DEVICE_ID_SIZE)
138362306a36Sopenharmony_ci		length = USBLP_DEVICE_ID_SIZE - 1;
138462306a36Sopenharmony_ci	usblp->device_id_string[length] = '\0';
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n",
138762306a36Sopenharmony_ci		usblp->minor, length, &usblp->device_id_string[2]);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	return length;
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void usblp_disconnect(struct usb_interface *intf)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	struct usblp *usblp = usb_get_intfdata(intf);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	usb_deregister_dev(intf, &usblp_class);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (!usblp || !usblp->dev) {
139962306a36Sopenharmony_ci		dev_err(&intf->dev, "bogus disconnect\n");
140062306a36Sopenharmony_ci		BUG();
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	mutex_lock(&usblp_mutex);
140462306a36Sopenharmony_ci	mutex_lock(&usblp->mut);
140562306a36Sopenharmony_ci	usblp->present = 0;
140662306a36Sopenharmony_ci	wake_up(&usblp->wwait);
140762306a36Sopenharmony_ci	wake_up(&usblp->rwait);
140862306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	usblp_unlink_urbs(usblp);
141162306a36Sopenharmony_ci	mutex_unlock(&usblp->mut);
141262306a36Sopenharmony_ci	usb_poison_anchored_urbs(&usblp->urbs);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (!usblp->used)
141562306a36Sopenharmony_ci		usblp_cleanup(usblp);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	mutex_unlock(&usblp_mutex);
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic int usblp_suspend(struct usb_interface *intf, pm_message_t message)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	struct usblp *usblp = usb_get_intfdata(intf);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	usblp_unlink_urbs(usblp);
142562306a36Sopenharmony_ci#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
142662306a36Sopenharmony_ci	/* not strictly necessary, but just in case */
142762306a36Sopenharmony_ci	wake_up(&usblp->wwait);
142862306a36Sopenharmony_ci	wake_up(&usblp->rwait);
142962306a36Sopenharmony_ci#endif
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	return 0;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic int usblp_resume(struct usb_interface *intf)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	struct usblp *usblp = usb_get_intfdata(intf);
143762306a36Sopenharmony_ci	int r;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	r = handle_bidir(usblp);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	return r;
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic const struct usb_device_id usblp_ids[] = {
144562306a36Sopenharmony_ci	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) },
144662306a36Sopenharmony_ci	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) },
144762306a36Sopenharmony_ci	{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) },
144862306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },
144962306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },
145062306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },
145162306a36Sopenharmony_ci	{ USB_DEVICE(0x04b8, 0x0202) },	/* Seiko Epson Receipt Printer M129C */
145262306a36Sopenharmony_ci	{ }						/* Terminating entry */
145362306a36Sopenharmony_ci};
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usblp_ids);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic struct usb_driver usblp_driver = {
145862306a36Sopenharmony_ci	.name =		"usblp",
145962306a36Sopenharmony_ci	.probe =	usblp_probe,
146062306a36Sopenharmony_ci	.disconnect =	usblp_disconnect,
146162306a36Sopenharmony_ci	.suspend =	usblp_suspend,
146262306a36Sopenharmony_ci	.resume =	usblp_resume,
146362306a36Sopenharmony_ci	.id_table =	usblp_ids,
146462306a36Sopenharmony_ci	.dev_groups =	usblp_groups,
146562306a36Sopenharmony_ci	.supports_autosuspend =	1,
146662306a36Sopenharmony_ci};
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cimodule_usb_driver(usblp_driver);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
147162306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
147262306a36Sopenharmony_cimodule_param(proto_bias, int, S_IRUGO | S_IWUSR);
147362306a36Sopenharmony_ciMODULE_PARM_DESC(proto_bias, "Favourite protocol number");
147462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1475