diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/class/usblp.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/class/usblp.c')
-rw-r--r-- | drivers/usb/class/usblp.c | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c new file mode 100644 index 000000000000..bba22e97ea0f --- /dev/null +++ b/drivers/usb/class/usblp.c | |||
@@ -0,0 +1,1214 @@ | |||
1 | /* | ||
2 | * usblp.c Version 0.13 | ||
3 | * | ||
4 | * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> | ||
5 | * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> | ||
6 | * Copyright (c) 2000 Randy Dunlap <rddunlap@osdl.org> | ||
7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> | ||
8 | # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> | ||
9 | # Copyright (c) 2001 David Paschal <paschal@rcsis.com> | ||
10 | * | ||
11 | * USB Printer Device Class driver for USB printers and printer cables | ||
12 | * | ||
13 | * Sponsored by SuSE | ||
14 | * | ||
15 | * ChangeLog: | ||
16 | * v0.1 - thorough cleaning, URBification, almost a rewrite | ||
17 | * v0.2 - some more cleanups | ||
18 | * v0.3 - cleaner again, waitqueue fixes | ||
19 | * v0.4 - fixes in unidirectional mode | ||
20 | * v0.5 - add DEVICE_ID string support | ||
21 | * v0.6 - never time out | ||
22 | * v0.7 - fixed bulk-IN read and poll (David Paschal) | ||
23 | * v0.8 - add devfs support | ||
24 | * v0.9 - fix unplug-while-open paths | ||
25 | * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) | ||
26 | * v0.11 - add proto_bias option (Pete Zaitcev) | ||
27 | * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) | ||
28 | * v0.13 - alloc space for statusbuf (<status> not on stack); | ||
29 | * use usb_buffer_alloc() for read buf & write buf; | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * This program is free software; you can redistribute it and/or modify | ||
34 | * it under the terms of the GNU General Public License as published by | ||
35 | * the Free Software Foundation; either version 2 of the License, or | ||
36 | * (at your option) any later version. | ||
37 | * | ||
38 | * This program is distributed in the hope that it will be useful, | ||
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
41 | * GNU General Public License for more details. | ||
42 | * | ||
43 | * You should have received a copy of the GNU General Public License | ||
44 | * along with this program; if not, write to the Free Software | ||
45 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
46 | */ | ||
47 | |||
48 | #include <linux/module.h> | ||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/sched.h> | ||
51 | #include <linux/smp_lock.h> | ||
52 | #include <linux/signal.h> | ||
53 | #include <linux/poll.h> | ||
54 | #include <linux/init.h> | ||
55 | #include <linux/slab.h> | ||
56 | #include <linux/lp.h> | ||
57 | #undef DEBUG | ||
58 | #include <linux/usb.h> | ||
59 | |||
60 | /* | ||
61 | * Version Information | ||
62 | */ | ||
63 | #define DRIVER_VERSION "v0.13" | ||
64 | #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" | ||
65 | #define DRIVER_DESC "USB Printer Device Class driver" | ||
66 | |||
67 | #define USBLP_BUF_SIZE 8192 | ||
68 | #define USBLP_DEVICE_ID_SIZE 1024 | ||
69 | |||
70 | /* ioctls: */ | ||
71 | #define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ | ||
72 | #define IOCNR_GET_DEVICE_ID 1 | ||
73 | #define IOCNR_GET_PROTOCOLS 2 | ||
74 | #define IOCNR_SET_PROTOCOL 3 | ||
75 | #define IOCNR_HP_SET_CHANNEL 4 | ||
76 | #define IOCNR_GET_BUS_ADDRESS 5 | ||
77 | #define IOCNR_GET_VID_PID 6 | ||
78 | #define IOCNR_SOFT_RESET 7 | ||
79 | /* Get device_id string: */ | ||
80 | #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) | ||
81 | /* The following ioctls were added for http://hpoj.sourceforge.net: */ | ||
82 | /* Get two-int array: | ||
83 | * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), | ||
84 | * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ | ||
85 | #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) | ||
86 | /* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ | ||
87 | #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) | ||
88 | /* Set channel number (HP Vendor-specific command): */ | ||
89 | #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) | ||
90 | /* Get two-int array: [0]=bus number, [1]=device address: */ | ||
91 | #define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) | ||
92 | /* Get two-int array: [0]=vendor ID, [1]=product ID: */ | ||
93 | #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) | ||
94 | /* Perform class specific soft reset */ | ||
95 | #define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0); | ||
96 | |||
97 | /* | ||
98 | * A DEVICE_ID string may include the printer's serial number. | ||
99 | * It should end with a semi-colon (';'). | ||
100 | * An example from an HP 970C DeskJet printer is (this is one long string, | ||
101 | * with the serial number changed): | ||
102 | 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: ; | ||
103 | */ | ||
104 | |||
105 | /* | ||
106 | * USB Printer Requests | ||
107 | */ | ||
108 | |||
109 | #define USBLP_REQ_GET_ID 0x00 | ||
110 | #define USBLP_REQ_GET_STATUS 0x01 | ||
111 | #define USBLP_REQ_RESET 0x02 | ||
112 | #define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ | ||
113 | |||
114 | #define USBLP_MINORS 16 | ||
115 | #define USBLP_MINOR_BASE 0 | ||
116 | |||
117 | #define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ | ||
118 | |||
119 | #define USBLP_FIRST_PROTOCOL 1 | ||
120 | #define USBLP_LAST_PROTOCOL 3 | ||
121 | #define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) | ||
122 | |||
123 | /* | ||
124 | * some arbitrary status buffer size; | ||
125 | * need a status buffer that is allocated via kmalloc(), not on stack | ||
126 | */ | ||
127 | #define STATUS_BUF_SIZE 8 | ||
128 | |||
129 | struct usblp { | ||
130 | struct usb_device *dev; /* USB device */ | ||
131 | struct semaphore sem; /* locks this struct, especially "dev" */ | ||
132 | char *writebuf; /* write transfer_buffer */ | ||
133 | char *readbuf; /* read transfer_buffer */ | ||
134 | char *statusbuf; /* status transfer_buffer */ | ||
135 | struct urb *readurb, *writeurb; /* The urbs */ | ||
136 | wait_queue_head_t wait; /* Zzzzz ... */ | ||
137 | int readcount; /* Counter for reads */ | ||
138 | int ifnum; /* Interface number */ | ||
139 | struct usb_interface *intf; /* The interface */ | ||
140 | /* Alternate-setting numbers and endpoints for each protocol | ||
141 | * (7/1/{index=1,2,3}) that the device supports: */ | ||
142 | struct { | ||
143 | int alt_setting; | ||
144 | struct usb_endpoint_descriptor *epwrite; | ||
145 | struct usb_endpoint_descriptor *epread; | ||
146 | } protocol[USBLP_MAX_PROTOCOLS]; | ||
147 | int current_protocol; | ||
148 | int minor; /* minor number of device */ | ||
149 | int wcomplete; /* writing is completed */ | ||
150 | int rcomplete; /* reading is completed */ | ||
151 | unsigned int quirks; /* quirks flags */ | ||
152 | unsigned char used; /* True if open */ | ||
153 | unsigned char present; /* True if not disconnected */ | ||
154 | unsigned char bidir; /* interface is bidirectional */ | ||
155 | unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ | ||
156 | /* first 2 bytes are (big-endian) length */ | ||
157 | }; | ||
158 | |||
159 | #ifdef DEBUG | ||
160 | static void usblp_dump(struct usblp *usblp) { | ||
161 | int p; | ||
162 | |||
163 | dbg("usblp=0x%p", usblp); | ||
164 | dbg("dev=0x%p", usblp->dev); | ||
165 | dbg("present=%d", usblp->present); | ||
166 | dbg("readbuf=0x%p", usblp->readbuf); | ||
167 | dbg("writebuf=0x%p", usblp->writebuf); | ||
168 | dbg("readurb=0x%p", usblp->readurb); | ||
169 | dbg("writeurb=0x%p", usblp->writeurb); | ||
170 | dbg("readcount=%d", usblp->readcount); | ||
171 | dbg("ifnum=%d", usblp->ifnum); | ||
172 | for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { | ||
173 | dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); | ||
174 | dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); | ||
175 | dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); | ||
176 | } | ||
177 | dbg("current_protocol=%d", usblp->current_protocol); | ||
178 | dbg("minor=%d", usblp->minor); | ||
179 | dbg("wcomplete=%d", usblp->wcomplete); | ||
180 | dbg("rcomplete=%d", usblp->rcomplete); | ||
181 | dbg("quirks=%d", usblp->quirks); | ||
182 | dbg("used=%d", usblp->used); | ||
183 | dbg("bidir=%d", usblp->bidir); | ||
184 | dbg("device_id_string=\"%s\"", | ||
185 | usblp->device_id_string ? | ||
186 | usblp->device_id_string + 2 : | ||
187 | (unsigned char *)"(null)"); | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | /* Quirks: various printer quirks are handled by this table & its flags. */ | ||
192 | |||
193 | struct quirk_printer_struct { | ||
194 | __u16 vendorId; | ||
195 | __u16 productId; | ||
196 | unsigned int quirks; | ||
197 | }; | ||
198 | |||
199 | #define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ | ||
200 | #define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ | ||
201 | |||
202 | static struct quirk_printer_struct quirk_printers[] = { | ||
203 | { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ | ||
204 | { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ | ||
205 | { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ | ||
206 | { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ | ||
207 | { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ | ||
208 | { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ | ||
209 | { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ | ||
210 | { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ | ||
211 | { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ | ||
212 | { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ | ||
213 | { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ | ||
214 | { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ | ||
215 | { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ | ||
216 | { 0, 0 } | ||
217 | }; | ||
218 | |||
219 | static int usblp_select_alts(struct usblp *usblp); | ||
220 | static int usblp_set_protocol(struct usblp *usblp, int protocol); | ||
221 | static int usblp_cache_device_id_string(struct usblp *usblp); | ||
222 | |||
223 | /* forward reference to make our lives easier */ | ||
224 | static struct usb_driver usblp_driver; | ||
225 | static DECLARE_MUTEX(usblp_sem); /* locks the existence of usblp's */ | ||
226 | |||
227 | /* | ||
228 | * Functions for usblp control messages. | ||
229 | */ | ||
230 | |||
231 | static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) | ||
232 | { | ||
233 | int retval; | ||
234 | int index = usblp->ifnum; | ||
235 | |||
236 | /* High byte has the interface index. | ||
237 | Low byte has the alternate setting. | ||
238 | */ | ||
239 | if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) { | ||
240 | index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting; | ||
241 | } | ||
242 | |||
243 | retval = usb_control_msg(usblp->dev, | ||
244 | dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), | ||
245 | request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); | ||
246 | dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", | ||
247 | request, !!dir, recip, value, index, len, retval); | ||
248 | return retval < 0 ? retval : 0; | ||
249 | } | ||
250 | |||
251 | #define usblp_read_status(usblp, status)\ | ||
252 | usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) | ||
253 | #define usblp_get_id(usblp, config, id, maxlen)\ | ||
254 | usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) | ||
255 | #define usblp_reset(usblp)\ | ||
256 | usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) | ||
257 | |||
258 | #define usblp_hp_channel_change_request(usblp, channel, buffer) \ | ||
259 | usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) | ||
260 | |||
261 | /* | ||
262 | * See the description for usblp_select_alts() below for the usage | ||
263 | * explanation. Look into your /proc/bus/usb/devices and dmesg in | ||
264 | * case of any trouble. | ||
265 | */ | ||
266 | static int proto_bias = -1; | ||
267 | |||
268 | /* | ||
269 | * URB callback. | ||
270 | */ | ||
271 | |||
272 | static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs) | ||
273 | { | ||
274 | struct usblp *usblp = urb->context; | ||
275 | |||
276 | if (!usblp || !usblp->dev || !usblp->used || !usblp->present) | ||
277 | return; | ||
278 | |||
279 | if (unlikely(urb->status)) | ||
280 | warn("usblp%d: nonzero read/write bulk status received: %d", | ||
281 | usblp->minor, urb->status); | ||
282 | usblp->rcomplete = 1; | ||
283 | wake_up_interruptible(&usblp->wait); | ||
284 | } | ||
285 | |||
286 | static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs) | ||
287 | { | ||
288 | struct usblp *usblp = urb->context; | ||
289 | |||
290 | if (!usblp || !usblp->dev || !usblp->used || !usblp->present) | ||
291 | return; | ||
292 | |||
293 | if (unlikely(urb->status)) | ||
294 | warn("usblp%d: nonzero read/write bulk status received: %d", | ||
295 | usblp->minor, urb->status); | ||
296 | usblp->wcomplete = 1; | ||
297 | wake_up_interruptible(&usblp->wait); | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * Get and print printer errors. | ||
302 | */ | ||
303 | |||
304 | static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; | ||
305 | |||
306 | static int usblp_check_status(struct usblp *usblp, int err) | ||
307 | { | ||
308 | unsigned char status, newerr = 0; | ||
309 | int error; | ||
310 | |||
311 | error = usblp_read_status (usblp, usblp->statusbuf); | ||
312 | if (error < 0) { | ||
313 | err("usblp%d: error %d reading printer status", | ||
314 | usblp->minor, error); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | status = *usblp->statusbuf; | ||
319 | |||
320 | if (~status & LP_PERRORP) | ||
321 | newerr = 3; | ||
322 | if (status & LP_POUTPA) | ||
323 | newerr = 1; | ||
324 | if (~status & LP_PSELECD) | ||
325 | newerr = 2; | ||
326 | |||
327 | if (newerr != err) | ||
328 | info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); | ||
329 | |||
330 | return newerr; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * File op functions. | ||
335 | */ | ||
336 | |||
337 | static int usblp_open(struct inode *inode, struct file *file) | ||
338 | { | ||
339 | int minor = iminor(inode); | ||
340 | struct usblp *usblp; | ||
341 | struct usb_interface *intf; | ||
342 | int retval; | ||
343 | |||
344 | if (minor < 0) | ||
345 | return -ENODEV; | ||
346 | |||
347 | down (&usblp_sem); | ||
348 | |||
349 | retval = -ENODEV; | ||
350 | intf = usb_find_interface(&usblp_driver, minor); | ||
351 | if (!intf) { | ||
352 | goto out; | ||
353 | } | ||
354 | usblp = usb_get_intfdata (intf); | ||
355 | if (!usblp || !usblp->dev || !usblp->present) | ||
356 | goto out; | ||
357 | |||
358 | retval = -EBUSY; | ||
359 | if (usblp->used) | ||
360 | goto out; | ||
361 | |||
362 | /* | ||
363 | * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? | ||
364 | * This is #if 0-ed because we *don't* want to fail an open | ||
365 | * just because the printer is off-line. | ||
366 | */ | ||
367 | #if 0 | ||
368 | if ((retval = usblp_check_status(usblp, 0))) { | ||
369 | retval = retval > 1 ? -EIO : -ENOSPC; | ||
370 | goto out; | ||
371 | } | ||
372 | #else | ||
373 | retval = 0; | ||
374 | #endif | ||
375 | |||
376 | usblp->used = 1; | ||
377 | file->private_data = usblp; | ||
378 | |||
379 | usblp->writeurb->transfer_buffer_length = 0; | ||
380 | usblp->wcomplete = 1; /* we begin writeable */ | ||
381 | usblp->rcomplete = 0; | ||
382 | |||
383 | if (usblp->bidir) { | ||
384 | usblp->readcount = 0; | ||
385 | usblp->readurb->dev = usblp->dev; | ||
386 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { | ||
387 | retval = -EIO; | ||
388 | usblp->used = 0; | ||
389 | file->private_data = NULL; | ||
390 | } | ||
391 | } | ||
392 | out: | ||
393 | up (&usblp_sem); | ||
394 | return retval; | ||
395 | } | ||
396 | |||
397 | static void usblp_cleanup (struct usblp *usblp) | ||
398 | { | ||
399 | info("usblp%d: removed", usblp->minor); | ||
400 | |||
401 | kfree (usblp->device_id_string); | ||
402 | kfree (usblp->statusbuf); | ||
403 | usb_free_urb(usblp->writeurb); | ||
404 | usb_free_urb(usblp->readurb); | ||
405 | kfree (usblp); | ||
406 | } | ||
407 | |||
408 | static void usblp_unlink_urbs(struct usblp *usblp) | ||
409 | { | ||
410 | usb_kill_urb(usblp->writeurb); | ||
411 | if (usblp->bidir) | ||
412 | usb_kill_urb(usblp->readurb); | ||
413 | } | ||
414 | |||
415 | static int usblp_release(struct inode *inode, struct file *file) | ||
416 | { | ||
417 | struct usblp *usblp = file->private_data; | ||
418 | |||
419 | down (&usblp_sem); | ||
420 | usblp->used = 0; | ||
421 | if (usblp->present) { | ||
422 | usblp_unlink_urbs(usblp); | ||
423 | } else /* finish cleanup from disconnect */ | ||
424 | usblp_cleanup (usblp); | ||
425 | up (&usblp_sem); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | /* No kernel lock - fine */ | ||
430 | static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) | ||
431 | { | ||
432 | struct usblp *usblp = file->private_data; | ||
433 | poll_wait(file, &usblp->wait, wait); | ||
434 | return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) | ||
435 | | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); | ||
436 | } | ||
437 | |||
438 | static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
439 | { | ||
440 | struct usblp *usblp = file->private_data; | ||
441 | int length, err, i; | ||
442 | unsigned char newChannel; | ||
443 | int status; | ||
444 | int twoints[2]; | ||
445 | int retval = 0; | ||
446 | |||
447 | down (&usblp->sem); | ||
448 | if (!usblp->present) { | ||
449 | retval = -ENODEV; | ||
450 | goto done; | ||
451 | } | ||
452 | |||
453 | dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), | ||
454 | _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); | ||
455 | |||
456 | if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ | ||
457 | |||
458 | switch (_IOC_NR(cmd)) { | ||
459 | |||
460 | case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ | ||
461 | if (_IOC_DIR(cmd) != _IOC_READ) { | ||
462 | retval = -EINVAL; | ||
463 | goto done; | ||
464 | } | ||
465 | |||
466 | length = usblp_cache_device_id_string(usblp); | ||
467 | if (length < 0) { | ||
468 | retval = length; | ||
469 | goto done; | ||
470 | } | ||
471 | if (length > _IOC_SIZE(cmd)) | ||
472 | length = _IOC_SIZE(cmd); /* truncate */ | ||
473 | |||
474 | if (copy_to_user((void __user *) arg, | ||
475 | usblp->device_id_string, | ||
476 | (unsigned long) length)) { | ||
477 | retval = -EFAULT; | ||
478 | goto done; | ||
479 | } | ||
480 | |||
481 | break; | ||
482 | |||
483 | case IOCNR_GET_PROTOCOLS: | ||
484 | if (_IOC_DIR(cmd) != _IOC_READ || | ||
485 | _IOC_SIZE(cmd) < sizeof(twoints)) { | ||
486 | retval = -EINVAL; | ||
487 | goto done; | ||
488 | } | ||
489 | |||
490 | twoints[0] = usblp->current_protocol; | ||
491 | twoints[1] = 0; | ||
492 | for (i = USBLP_FIRST_PROTOCOL; | ||
493 | i <= USBLP_LAST_PROTOCOL; i++) { | ||
494 | if (usblp->protocol[i].alt_setting >= 0) | ||
495 | twoints[1] |= (1<<i); | ||
496 | } | ||
497 | |||
498 | if (copy_to_user((void __user *)arg, | ||
499 | (unsigned char *)twoints, | ||
500 | sizeof(twoints))) { | ||
501 | retval = -EFAULT; | ||
502 | goto done; | ||
503 | } | ||
504 | |||
505 | break; | ||
506 | |||
507 | case IOCNR_SET_PROTOCOL: | ||
508 | if (_IOC_DIR(cmd) != _IOC_WRITE) { | ||
509 | retval = -EINVAL; | ||
510 | goto done; | ||
511 | } | ||
512 | |||
513 | #ifdef DEBUG | ||
514 | if (arg == -10) { | ||
515 | usblp_dump(usblp); | ||
516 | break; | ||
517 | } | ||
518 | #endif | ||
519 | |||
520 | usblp_unlink_urbs(usblp); | ||
521 | retval = usblp_set_protocol(usblp, arg); | ||
522 | if (retval < 0) { | ||
523 | usblp_set_protocol(usblp, | ||
524 | usblp->current_protocol); | ||
525 | } | ||
526 | break; | ||
527 | |||
528 | case IOCNR_HP_SET_CHANNEL: | ||
529 | if (_IOC_DIR(cmd) != _IOC_WRITE || | ||
530 | le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 || | ||
531 | usblp->quirks & USBLP_QUIRK_BIDIR) { | ||
532 | retval = -EINVAL; | ||
533 | goto done; | ||
534 | } | ||
535 | |||
536 | err = usblp_hp_channel_change_request(usblp, | ||
537 | arg, &newChannel); | ||
538 | if (err < 0) { | ||
539 | err("usblp%d: error = %d setting " | ||
540 | "HP channel", | ||
541 | usblp->minor, err); | ||
542 | retval = -EIO; | ||
543 | goto done; | ||
544 | } | ||
545 | |||
546 | dbg("usblp%d requested/got HP channel %ld/%d", | ||
547 | usblp->minor, arg, newChannel); | ||
548 | break; | ||
549 | |||
550 | case IOCNR_GET_BUS_ADDRESS: | ||
551 | if (_IOC_DIR(cmd) != _IOC_READ || | ||
552 | _IOC_SIZE(cmd) < sizeof(twoints)) { | ||
553 | retval = -EINVAL; | ||
554 | goto done; | ||
555 | } | ||
556 | |||
557 | twoints[0] = usblp->dev->bus->busnum; | ||
558 | twoints[1] = usblp->dev->devnum; | ||
559 | if (copy_to_user((void __user *)arg, | ||
560 | (unsigned char *)twoints, | ||
561 | sizeof(twoints))) { | ||
562 | retval = -EFAULT; | ||
563 | goto done; | ||
564 | } | ||
565 | |||
566 | dbg("usblp%d is bus=%d, device=%d", | ||
567 | usblp->minor, twoints[0], twoints[1]); | ||
568 | break; | ||
569 | |||
570 | case IOCNR_GET_VID_PID: | ||
571 | if (_IOC_DIR(cmd) != _IOC_READ || | ||
572 | _IOC_SIZE(cmd) < sizeof(twoints)) { | ||
573 | retval = -EINVAL; | ||
574 | goto done; | ||
575 | } | ||
576 | |||
577 | twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor); | ||
578 | twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct); | ||
579 | if (copy_to_user((void __user *)arg, | ||
580 | (unsigned char *)twoints, | ||
581 | sizeof(twoints))) { | ||
582 | retval = -EFAULT; | ||
583 | goto done; | ||
584 | } | ||
585 | |||
586 | dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", | ||
587 | usblp->minor, twoints[0], twoints[1]); | ||
588 | break; | ||
589 | |||
590 | case IOCNR_SOFT_RESET: | ||
591 | if (_IOC_DIR(cmd) != _IOC_NONE) { | ||
592 | retval = -EINVAL; | ||
593 | goto done; | ||
594 | } | ||
595 | retval = usblp_reset(usblp); | ||
596 | break; | ||
597 | default: | ||
598 | retval = -ENOTTY; | ||
599 | } | ||
600 | else /* old-style ioctl value */ | ||
601 | switch (cmd) { | ||
602 | |||
603 | case LPGETSTATUS: | ||
604 | if (usblp_read_status(usblp, usblp->statusbuf)) { | ||
605 | err("usblp%d: failed reading printer status", usblp->minor); | ||
606 | retval = -EIO; | ||
607 | goto done; | ||
608 | } | ||
609 | status = *usblp->statusbuf; | ||
610 | if (copy_to_user ((void __user *)arg, &status, sizeof(int))) | ||
611 | retval = -EFAULT; | ||
612 | break; | ||
613 | |||
614 | default: | ||
615 | retval = -ENOTTY; | ||
616 | } | ||
617 | |||
618 | done: | ||
619 | up (&usblp->sem); | ||
620 | return retval; | ||
621 | } | ||
622 | |||
623 | static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
624 | { | ||
625 | DECLARE_WAITQUEUE(wait, current); | ||
626 | struct usblp *usblp = file->private_data; | ||
627 | int timeout, err = 0, transfer_length = 0; | ||
628 | size_t writecount = 0; | ||
629 | |||
630 | while (writecount < count) { | ||
631 | if (!usblp->wcomplete) { | ||
632 | barrier(); | ||
633 | if (file->f_flags & O_NONBLOCK) { | ||
634 | writecount += transfer_length; | ||
635 | return writecount ? writecount : -EAGAIN; | ||
636 | } | ||
637 | |||
638 | timeout = USBLP_WRITE_TIMEOUT; | ||
639 | add_wait_queue(&usblp->wait, &wait); | ||
640 | while ( 1==1 ) { | ||
641 | |||
642 | if (signal_pending(current)) { | ||
643 | remove_wait_queue(&usblp->wait, &wait); | ||
644 | return writecount ? writecount : -EINTR; | ||
645 | } | ||
646 | set_current_state(TASK_INTERRUPTIBLE); | ||
647 | if (timeout && !usblp->wcomplete) { | ||
648 | timeout = schedule_timeout(timeout); | ||
649 | } else { | ||
650 | set_current_state(TASK_RUNNING); | ||
651 | break; | ||
652 | } | ||
653 | } | ||
654 | remove_wait_queue(&usblp->wait, &wait); | ||
655 | } | ||
656 | |||
657 | down (&usblp->sem); | ||
658 | if (!usblp->present) { | ||
659 | up (&usblp->sem); | ||
660 | return -ENODEV; | ||
661 | } | ||
662 | |||
663 | if (usblp->writeurb->status != 0) { | ||
664 | if (usblp->quirks & USBLP_QUIRK_BIDIR) { | ||
665 | if (!usblp->wcomplete) | ||
666 | err("usblp%d: error %d writing to printer", | ||
667 | usblp->minor, usblp->writeurb->status); | ||
668 | err = usblp->writeurb->status; | ||
669 | } else | ||
670 | err = usblp_check_status(usblp, err); | ||
671 | up (&usblp->sem); | ||
672 | |||
673 | /* if the fault was due to disconnect, let khubd's | ||
674 | * call to usblp_disconnect() grab usblp->sem ... | ||
675 | */ | ||
676 | schedule (); | ||
677 | continue; | ||
678 | } | ||
679 | |||
680 | /* We must increment writecount here, and not at the | ||
681 | * end of the loop. Otherwise, the final loop iteration may | ||
682 | * be skipped, leading to incomplete printer output. | ||
683 | */ | ||
684 | writecount += transfer_length; | ||
685 | if (writecount == count) { | ||
686 | up(&usblp->sem); | ||
687 | break; | ||
688 | } | ||
689 | |||
690 | transfer_length=(count - writecount); | ||
691 | if (transfer_length > USBLP_BUF_SIZE) | ||
692 | transfer_length = USBLP_BUF_SIZE; | ||
693 | |||
694 | usblp->writeurb->transfer_buffer_length = transfer_length; | ||
695 | |||
696 | if (copy_from_user(usblp->writeurb->transfer_buffer, | ||
697 | buffer + writecount, transfer_length)) { | ||
698 | up(&usblp->sem); | ||
699 | return writecount ? writecount : -EFAULT; | ||
700 | } | ||
701 | |||
702 | usblp->writeurb->dev = usblp->dev; | ||
703 | usblp->wcomplete = 0; | ||
704 | err = usb_submit_urb(usblp->writeurb, GFP_KERNEL); | ||
705 | if (err) { | ||
706 | if (err != -ENOMEM) | ||
707 | count = -EIO; | ||
708 | else | ||
709 | count = writecount ? writecount : -ENOMEM; | ||
710 | up (&usblp->sem); | ||
711 | break; | ||
712 | } | ||
713 | up (&usblp->sem); | ||
714 | } | ||
715 | |||
716 | return count; | ||
717 | } | ||
718 | |||
719 | static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
720 | { | ||
721 | struct usblp *usblp = file->private_data; | ||
722 | DECLARE_WAITQUEUE(wait, current); | ||
723 | |||
724 | if (!usblp->bidir) | ||
725 | return -EINVAL; | ||
726 | |||
727 | down (&usblp->sem); | ||
728 | if (!usblp->present) { | ||
729 | count = -ENODEV; | ||
730 | goto done; | ||
731 | } | ||
732 | |||
733 | if (!usblp->rcomplete) { | ||
734 | barrier(); | ||
735 | |||
736 | if (file->f_flags & O_NONBLOCK) { | ||
737 | count = -EAGAIN; | ||
738 | goto done; | ||
739 | } | ||
740 | |||
741 | add_wait_queue(&usblp->wait, &wait); | ||
742 | while (1==1) { | ||
743 | if (signal_pending(current)) { | ||
744 | count = -EINTR; | ||
745 | remove_wait_queue(&usblp->wait, &wait); | ||
746 | goto done; | ||
747 | } | ||
748 | up (&usblp->sem); | ||
749 | set_current_state(TASK_INTERRUPTIBLE); | ||
750 | if (!usblp->rcomplete) { | ||
751 | schedule(); | ||
752 | } else { | ||
753 | set_current_state(TASK_RUNNING); | ||
754 | break; | ||
755 | } | ||
756 | down (&usblp->sem); | ||
757 | } | ||
758 | remove_wait_queue(&usblp->wait, &wait); | ||
759 | } | ||
760 | |||
761 | if (!usblp->present) { | ||
762 | count = -ENODEV; | ||
763 | goto done; | ||
764 | } | ||
765 | |||
766 | if (usblp->readurb->status) { | ||
767 | err("usblp%d: error %d reading from printer", | ||
768 | usblp->minor, usblp->readurb->status); | ||
769 | usblp->readurb->dev = usblp->dev; | ||
770 | usblp->readcount = 0; | ||
771 | usblp->rcomplete = 0; | ||
772 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) | ||
773 | dbg("error submitting urb"); | ||
774 | count = -EIO; | ||
775 | goto done; | ||
776 | } | ||
777 | |||
778 | count = count < usblp->readurb->actual_length - usblp->readcount ? | ||
779 | count : usblp->readurb->actual_length - usblp->readcount; | ||
780 | |||
781 | if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) { | ||
782 | count = -EFAULT; | ||
783 | goto done; | ||
784 | } | ||
785 | |||
786 | if ((usblp->readcount += count) == usblp->readurb->actual_length) { | ||
787 | usblp->readcount = 0; | ||
788 | usblp->readurb->dev = usblp->dev; | ||
789 | usblp->rcomplete = 0; | ||
790 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) { | ||
791 | count = -EIO; | ||
792 | goto done; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | done: | ||
797 | up (&usblp->sem); | ||
798 | return count; | ||
799 | } | ||
800 | |||
801 | /* | ||
802 | * Checks for printers that have quirks, such as requiring unidirectional | ||
803 | * communication but reporting bidirectional; currently some HP printers | ||
804 | * have this flaw (HP 810, 880, 895, etc.), or needing an init string | ||
805 | * sent at each open (like some Epsons). | ||
806 | * Returns 1 if found, 0 if not found. | ||
807 | * | ||
808 | * HP recommended that we use the bidirectional interface but | ||
809 | * don't attempt any bulk IN transfers from the IN endpoint. | ||
810 | * Here's some more detail on the problem: | ||
811 | * The problem is not that it isn't bidirectional though. The problem | ||
812 | * is that if you request a device ID, or status information, while | ||
813 | * the buffers are full, the return data will end up in the print data | ||
814 | * buffer. For example if you make sure you never request the device ID | ||
815 | * while you are sending print data, and you don't try to query the | ||
816 | * printer status every couple of milliseconds, you will probably be OK. | ||
817 | */ | ||
818 | static unsigned int usblp_quirks (__u16 vendor, __u16 product) | ||
819 | { | ||
820 | int i; | ||
821 | |||
822 | for (i = 0; quirk_printers[i].vendorId; i++) { | ||
823 | if (vendor == quirk_printers[i].vendorId && | ||
824 | product == quirk_printers[i].productId) | ||
825 | return quirk_printers[i].quirks; | ||
826 | } | ||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | static struct file_operations usblp_fops = { | ||
831 | .owner = THIS_MODULE, | ||
832 | .read = usblp_read, | ||
833 | .write = usblp_write, | ||
834 | .poll = usblp_poll, | ||
835 | .ioctl = usblp_ioctl, | ||
836 | .open = usblp_open, | ||
837 | .release = usblp_release, | ||
838 | }; | ||
839 | |||
840 | static struct usb_class_driver usblp_class = { | ||
841 | .name = "usb/lp%d", | ||
842 | .fops = &usblp_fops, | ||
843 | .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, | ||
844 | .minor_base = USBLP_MINOR_BASE, | ||
845 | }; | ||
846 | |||
847 | static int usblp_probe(struct usb_interface *intf, | ||
848 | const struct usb_device_id *id) | ||
849 | { | ||
850 | struct usb_device *dev = interface_to_usbdev (intf); | ||
851 | struct usblp *usblp = NULL; | ||
852 | int protocol; | ||
853 | int retval; | ||
854 | |||
855 | /* Malloc and start initializing usblp structure so we can use it | ||
856 | * directly. */ | ||
857 | if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) { | ||
858 | err("out of memory for usblp"); | ||
859 | goto abort; | ||
860 | } | ||
861 | memset(usblp, 0, sizeof(struct usblp)); | ||
862 | usblp->dev = dev; | ||
863 | init_MUTEX (&usblp->sem); | ||
864 | init_waitqueue_head(&usblp->wait); | ||
865 | usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; | ||
866 | usblp->intf = intf; | ||
867 | |||
868 | usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); | ||
869 | if (!usblp->writeurb) { | ||
870 | err("out of memory"); | ||
871 | goto abort; | ||
872 | } | ||
873 | usblp->readurb = usb_alloc_urb(0, GFP_KERNEL); | ||
874 | if (!usblp->readurb) { | ||
875 | err("out of memory"); | ||
876 | goto abort; | ||
877 | } | ||
878 | |||
879 | /* Malloc device ID string buffer to the largest expected length, | ||
880 | * since we can re-query it on an ioctl and a dynamic string | ||
881 | * could change in length. */ | ||
882 | if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { | ||
883 | err("out of memory for device_id_string"); | ||
884 | goto abort; | ||
885 | } | ||
886 | |||
887 | usblp->writebuf = usblp->readbuf = NULL; | ||
888 | usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; | ||
889 | usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; | ||
890 | /* Malloc write & read buffers. We somewhat wastefully | ||
891 | * malloc both regardless of bidirectionality, because the | ||
892 | * alternate setting can be changed later via an ioctl. */ | ||
893 | if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE, | ||
894 | GFP_KERNEL, &usblp->writeurb->transfer_dma))) { | ||
895 | err("out of memory for write buf"); | ||
896 | goto abort; | ||
897 | } | ||
898 | if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE, | ||
899 | GFP_KERNEL, &usblp->readurb->transfer_dma))) { | ||
900 | err("out of memory for read buf"); | ||
901 | goto abort; | ||
902 | } | ||
903 | |||
904 | /* Allocate buffer for printer status */ | ||
905 | usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL); | ||
906 | if (!usblp->statusbuf) { | ||
907 | err("out of memory for statusbuf"); | ||
908 | goto abort; | ||
909 | } | ||
910 | |||
911 | /* Lookup quirks for this printer. */ | ||
912 | usblp->quirks = usblp_quirks( | ||
913 | le16_to_cpu(dev->descriptor.idVendor), | ||
914 | le16_to_cpu(dev->descriptor.idProduct)); | ||
915 | |||
916 | /* Analyze and pick initial alternate settings and endpoints. */ | ||
917 | protocol = usblp_select_alts(usblp); | ||
918 | if (protocol < 0) { | ||
919 | dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", | ||
920 | le16_to_cpu(dev->descriptor.idVendor), | ||
921 | le16_to_cpu(dev->descriptor.idProduct)); | ||
922 | goto abort; | ||
923 | } | ||
924 | |||
925 | /* Setup the selected alternate setting and endpoints. */ | ||
926 | if (usblp_set_protocol(usblp, protocol) < 0) | ||
927 | goto abort; | ||
928 | |||
929 | /* Retrieve and store the device ID string. */ | ||
930 | usblp_cache_device_id_string(usblp); | ||
931 | |||
932 | #ifdef DEBUG | ||
933 | usblp_check_status(usblp, 0); | ||
934 | #endif | ||
935 | |||
936 | info("usblp%d: USB %sdirectional printer dev %d " | ||
937 | "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X", | ||
938 | usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, | ||
939 | usblp->ifnum, | ||
940 | usblp->protocol[usblp->current_protocol].alt_setting, | ||
941 | usblp->current_protocol, | ||
942 | le16_to_cpu(usblp->dev->descriptor.idVendor), | ||
943 | le16_to_cpu(usblp->dev->descriptor.idProduct)); | ||
944 | |||
945 | usb_set_intfdata (intf, usblp); | ||
946 | |||
947 | usblp->present = 1; | ||
948 | |||
949 | retval = usb_register_dev(intf, &usblp_class); | ||
950 | if (retval) { | ||
951 | err("Not able to get a minor for this device."); | ||
952 | goto abort_intfdata; | ||
953 | } | ||
954 | usblp->minor = intf->minor; | ||
955 | |||
956 | return 0; | ||
957 | |||
958 | abort_intfdata: | ||
959 | usb_set_intfdata (intf, NULL); | ||
960 | abort: | ||
961 | if (usblp) { | ||
962 | if (usblp->writebuf) | ||
963 | usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, | ||
964 | usblp->writebuf, usblp->writeurb->transfer_dma); | ||
965 | if (usblp->readbuf) | ||
966 | usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, | ||
967 | usblp->readbuf, usblp->writeurb->transfer_dma); | ||
968 | kfree(usblp->statusbuf); | ||
969 | kfree(usblp->device_id_string); | ||
970 | usb_free_urb(usblp->writeurb); | ||
971 | usb_free_urb(usblp->readurb); | ||
972 | kfree(usblp); | ||
973 | } | ||
974 | return -EIO; | ||
975 | } | ||
976 | |||
977 | /* | ||
978 | * We are a "new" style driver with usb_device_id table, | ||
979 | * but our requirements are too intricate for simple match to handle. | ||
980 | * | ||
981 | * The "proto_bias" option may be used to specify the preferred protocol | ||
982 | * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device | ||
983 | * supports the preferred protocol, then we bind to it. | ||
984 | * | ||
985 | * The best interface for us is 7/1/2, because it is compatible | ||
986 | * with a stream of characters. If we find it, we bind to it. | ||
987 | * | ||
988 | * Note that the people from hpoj.sourceforge.net need to be able to | ||
989 | * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. | ||
990 | * | ||
991 | * Failing 7/1/2, we look for 7/1/3, even though it's probably not | ||
992 | * stream-compatible, because this matches the behaviour of the old code. | ||
993 | * | ||
994 | * If nothing else, we bind to 7/1/1 - the unidirectional interface. | ||
995 | */ | ||
996 | static int usblp_select_alts(struct usblp *usblp) | ||
997 | { | ||
998 | struct usb_interface *if_alt; | ||
999 | struct usb_host_interface *ifd; | ||
1000 | struct usb_endpoint_descriptor *epd, *epwrite, *epread; | ||
1001 | int p, i, e; | ||
1002 | |||
1003 | if_alt = usblp->intf; | ||
1004 | |||
1005 | for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) | ||
1006 | usblp->protocol[p].alt_setting = -1; | ||
1007 | |||
1008 | /* Find out what we have. */ | ||
1009 | for (i = 0; i < if_alt->num_altsetting; i++) { | ||
1010 | ifd = &if_alt->altsetting[i]; | ||
1011 | |||
1012 | if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) | ||
1013 | continue; | ||
1014 | |||
1015 | if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL || | ||
1016 | ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) | ||
1017 | continue; | ||
1018 | |||
1019 | /* Look for bulk OUT and IN endpoints. */ | ||
1020 | epwrite = epread = NULL; | ||
1021 | for (e = 0; e < ifd->desc.bNumEndpoints; e++) { | ||
1022 | epd = &ifd->endpoint[e].desc; | ||
1023 | |||
1024 | if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!= | ||
1025 | USB_ENDPOINT_XFER_BULK) | ||
1026 | continue; | ||
1027 | |||
1028 | if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) { | ||
1029 | if (!epwrite) | ||
1030 | epwrite = epd; | ||
1031 | |||
1032 | } else { | ||
1033 | if (!epread) | ||
1034 | epread = epd; | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | /* Ignore buggy hardware without the right endpoints. */ | ||
1039 | if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) | ||
1040 | continue; | ||
1041 | |||
1042 | /* Turn off reads for 7/1/1 (unidirectional) interfaces | ||
1043 | * and buggy bidirectional printers. */ | ||
1044 | if (ifd->desc.bInterfaceProtocol == 1) { | ||
1045 | epread = NULL; | ||
1046 | } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { | ||
1047 | info("Disabling reads from problem bidirectional " | ||
1048 | "printer on usblp%d", usblp->minor); | ||
1049 | epread = NULL; | ||
1050 | } | ||
1051 | |||
1052 | usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = | ||
1053 | ifd->desc.bAlternateSetting; | ||
1054 | usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite; | ||
1055 | usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread; | ||
1056 | } | ||
1057 | |||
1058 | /* If our requested protocol is supported, then use it. */ | ||
1059 | if (proto_bias >= USBLP_FIRST_PROTOCOL && | ||
1060 | proto_bias <= USBLP_LAST_PROTOCOL && | ||
1061 | usblp->protocol[proto_bias].alt_setting != -1) | ||
1062 | return proto_bias; | ||
1063 | |||
1064 | /* Ordering is important here. */ | ||
1065 | if (usblp->protocol[2].alt_setting != -1) | ||
1066 | return 2; | ||
1067 | if (usblp->protocol[1].alt_setting != -1) | ||
1068 | return 1; | ||
1069 | if (usblp->protocol[3].alt_setting != -1) | ||
1070 | return 3; | ||
1071 | |||
1072 | /* If nothing is available, then don't bind to this device. */ | ||
1073 | return -1; | ||
1074 | } | ||
1075 | |||
1076 | static int usblp_set_protocol(struct usblp *usblp, int protocol) | ||
1077 | { | ||
1078 | int r, alts; | ||
1079 | |||
1080 | if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) | ||
1081 | return -EINVAL; | ||
1082 | |||
1083 | alts = usblp->protocol[protocol].alt_setting; | ||
1084 | if (alts < 0) | ||
1085 | return -EINVAL; | ||
1086 | r = usb_set_interface(usblp->dev, usblp->ifnum, alts); | ||
1087 | if (r < 0) { | ||
1088 | err("can't set desired altsetting %d on interface %d", | ||
1089 | alts, usblp->ifnum); | ||
1090 | return r; | ||
1091 | } | ||
1092 | |||
1093 | usb_fill_bulk_urb(usblp->writeurb, usblp->dev, | ||
1094 | usb_sndbulkpipe(usblp->dev, | ||
1095 | usblp->protocol[protocol].epwrite->bEndpointAddress), | ||
1096 | usblp->writebuf, 0, | ||
1097 | usblp_bulk_write, usblp); | ||
1098 | |||
1099 | usblp->bidir = (usblp->protocol[protocol].epread != NULL); | ||
1100 | if (usblp->bidir) | ||
1101 | usb_fill_bulk_urb(usblp->readurb, usblp->dev, | ||
1102 | usb_rcvbulkpipe(usblp->dev, | ||
1103 | usblp->protocol[protocol].epread->bEndpointAddress), | ||
1104 | usblp->readbuf, USBLP_BUF_SIZE, | ||
1105 | usblp_bulk_read, usblp); | ||
1106 | |||
1107 | usblp->current_protocol = protocol; | ||
1108 | dbg("usblp%d set protocol %d", usblp->minor, protocol); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /* Retrieves and caches device ID string. | ||
1113 | * Returns length, including length bytes but not null terminator. | ||
1114 | * On error, returns a negative errno value. */ | ||
1115 | static int usblp_cache_device_id_string(struct usblp *usblp) | ||
1116 | { | ||
1117 | int err, length; | ||
1118 | |||
1119 | err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1); | ||
1120 | if (err < 0) { | ||
1121 | dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", | ||
1122 | usblp->minor, err); | ||
1123 | usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; | ||
1124 | return -EIO; | ||
1125 | } | ||
1126 | |||
1127 | /* First two bytes are length in big-endian. | ||
1128 | * They count themselves, and we copy them into | ||
1129 | * the user's buffer. */ | ||
1130 | length = be16_to_cpu(*((__be16 *)usblp->device_id_string)); | ||
1131 | if (length < 2) | ||
1132 | length = 2; | ||
1133 | else if (length >= USBLP_DEVICE_ID_SIZE) | ||
1134 | length = USBLP_DEVICE_ID_SIZE - 1; | ||
1135 | usblp->device_id_string[length] = '\0'; | ||
1136 | |||
1137 | dbg("usblp%d Device ID string [len=%d]=\"%s\"", | ||
1138 | usblp->minor, length, &usblp->device_id_string[2]); | ||
1139 | |||
1140 | return length; | ||
1141 | } | ||
1142 | |||
1143 | static void usblp_disconnect(struct usb_interface *intf) | ||
1144 | { | ||
1145 | struct usblp *usblp = usb_get_intfdata (intf); | ||
1146 | |||
1147 | usb_deregister_dev(intf, &usblp_class); | ||
1148 | |||
1149 | if (!usblp || !usblp->dev) { | ||
1150 | err("bogus disconnect"); | ||
1151 | BUG (); | ||
1152 | } | ||
1153 | |||
1154 | down (&usblp_sem); | ||
1155 | down (&usblp->sem); | ||
1156 | usblp->present = 0; | ||
1157 | usb_set_intfdata (intf, NULL); | ||
1158 | |||
1159 | usblp_unlink_urbs(usblp); | ||
1160 | usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, | ||
1161 | usblp->writebuf, usblp->writeurb->transfer_dma); | ||
1162 | usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, | ||
1163 | usblp->readbuf, usblp->readurb->transfer_dma); | ||
1164 | up (&usblp->sem); | ||
1165 | |||
1166 | if (!usblp->used) | ||
1167 | usblp_cleanup (usblp); | ||
1168 | up (&usblp_sem); | ||
1169 | } | ||
1170 | |||
1171 | static struct usb_device_id usblp_ids [] = { | ||
1172 | { USB_DEVICE_INFO(7, 1, 1) }, | ||
1173 | { USB_DEVICE_INFO(7, 1, 2) }, | ||
1174 | { USB_DEVICE_INFO(7, 1, 3) }, | ||
1175 | { USB_INTERFACE_INFO(7, 1, 1) }, | ||
1176 | { USB_INTERFACE_INFO(7, 1, 2) }, | ||
1177 | { USB_INTERFACE_INFO(7, 1, 3) }, | ||
1178 | { } /* Terminating entry */ | ||
1179 | }; | ||
1180 | |||
1181 | MODULE_DEVICE_TABLE (usb, usblp_ids); | ||
1182 | |||
1183 | static struct usb_driver usblp_driver = { | ||
1184 | .owner = THIS_MODULE, | ||
1185 | .name = "usblp", | ||
1186 | .probe = usblp_probe, | ||
1187 | .disconnect = usblp_disconnect, | ||
1188 | .id_table = usblp_ids, | ||
1189 | }; | ||
1190 | |||
1191 | static int __init usblp_init(void) | ||
1192 | { | ||
1193 | int retval; | ||
1194 | retval = usb_register(&usblp_driver); | ||
1195 | if (retval) | ||
1196 | goto out; | ||
1197 | info(DRIVER_VERSION ": " DRIVER_DESC); | ||
1198 | out: | ||
1199 | return retval; | ||
1200 | } | ||
1201 | |||
1202 | static void __exit usblp_exit(void) | ||
1203 | { | ||
1204 | usb_deregister(&usblp_driver); | ||
1205 | } | ||
1206 | |||
1207 | module_init(usblp_init); | ||
1208 | module_exit(usblp_exit); | ||
1209 | |||
1210 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
1211 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
1212 | module_param(proto_bias, int, S_IRUGO | S_IWUSR); | ||
1213 | MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); | ||
1214 | MODULE_LICENSE("GPL"); | ||