~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/usb/printer.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * printer.c  Version 0.6
  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      <randy.dunlap@intel.com>
  7  * Copyright (c) 2000 Vojtech Pavlik    <vojtech@suse.cz>
  8  *
  9  * USB Printer Device Class driver for USB printers and printer cables
 10  *
 11  * Sponsored by SuSE
 12  *
 13  * ChangeLog:
 14  *      v0.1 - thorough cleaning, URBification, almost a rewrite
 15  *      v0.2 - some more cleanups
 16  *      v0.3 - cleaner again, waitqueue fixes
 17  *      v0.4 - fixes in unidirectional mode
 18  *      v0.5 - add DEVICE_ID string support
 19  *      v0.6 - never time out
 20  */
 21 
 22 /*
 23  * This program is free software; you can redistribute it and/or modify
 24  * it under the terms of the GNU General Public License as published by
 25  * the Free Software Foundation; either version 2 of the License, or
 26  * (at your option) any later version.
 27  *
 28  * This program is distributed in the hope that it will be useful,
 29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 31  * GNU General Public License for more details.
 32  *
 33  * You should have received a copy of the GNU General Public License
 34  * along with this program; if not, write to the Free Software
 35  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 36  */
 37 
 38 #include <linux/module.h>
 39 #include <linux/kernel.h>
 40 #include <linux/sched.h>
 41 #include <linux/smp_lock.h>
 42 #include <linux/signal.h>
 43 #include <linux/poll.h>
 44 #include <linux/init.h>
 45 #include <linux/malloc.h>
 46 #include <linux/lp.h>
 47 #undef DEBUG
 48 #include <linux/usb.h>
 49 
 50 #define USBLP_BUF_SIZE          8192
 51 #define DEVICE_ID_SIZE          1024
 52 
 53 #define IOCNR_GET_DEVICE_ID     1
 54 #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */
 55 #define LPGETSTATUS             0x060b          /* same as in drivers/char/lp.c */
 56 
 57 /*
 58  * A DEVICE_ID string may include the printer's serial number.
 59  * It should end with a semi-colon (';').
 60  * An example from an HP 970C DeskJet printer is (this is one long string,
 61  * with the serial number changed):
 62 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:                    ;
 63  */
 64 
 65 /*
 66  * USB Printer Requests
 67  */
 68 
 69 #define USBLP_REQ_GET_ID        0x00
 70 #define USBLP_REQ_GET_STATUS    0x01
 71 #define USBLP_REQ_RESET         0x02
 72 
 73 #define USBLP_MINORS            16
 74 #define USBLP_MINOR_BASE        0
 75 
 76 #define USBLP_WRITE_TIMEOUT     (5*HZ)                  /* 5 seconds */
 77 
 78 struct usblp {
 79         struct usb_device       *dev;                   /* USB device */
 80         struct urb              readurb, writeurb;      /* The urbs */
 81         wait_queue_head_t       wait;                   /* Zzzzz ... */
 82         int                     readcount;              /* Counter for reads */
 83         int                     ifnum;                  /* Interface number */
 84         int                     minor;                  /* minor number of device */
 85         unsigned int            quirks;                 /* quirks flags */
 86         unsigned char           used;                   /* True if open */
 87         unsigned char           bidir;                  /* interface is bidirectional */
 88         unsigned char           *device_id_string;      /* IEEE 1284 DEVICE ID string (ptr) */
 89                                                         /* first 2 bytes are (big-endian) length */
 90 };
 91 
 92 static struct usblp *usblp_table[USBLP_MINORS];
 93 
 94 /* Quirks: various printer quirks are handled by this table & its flags. */
 95 
 96 struct quirk_printer_struct {
 97         __u16 vendorId;
 98         __u16 productId;
 99         unsigned int quirks;
100 };
101 
102 #define USBLP_QUIRK_BIDIR       0x1     /* reports bidir but requires unidirectional mode (no INs/reads) */
103 #define USBLP_QUIRK_USB_INIT    0x2     /* needs vendor USB init string */
104 
105 static struct quirk_printer_struct quirk_printers[] = {
106         { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
107         { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
108         { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
109         { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
110         { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
111         { 0, 0 }
112 };
113 
114 /*
115  * Functions for usblp control messages.
116  */
117 
118 static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len)
119 {
120         int retval = usb_control_msg(usblp->dev,
121                 dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
122                 request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5);
123         dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
124                 request, !!dir, recip, value, len, retval);
125         return retval < 0 ? retval : 0;
126 }
127 
128 #define usblp_read_status(usblp, status)\
129         usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
130 #define usblp_get_id(usblp, config, id, maxlen)\
131         usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
132 #define usblp_reset(usblp)\
133         usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
134 
135 /*
136  * URB callback.
137  */
138 
139 static void usblp_bulk(struct urb *urb)
140 {
141         struct usblp *usblp = urb->context;
142 
143         if (!usblp || !usblp->dev || !usblp->used)
144                 return;
145 
146         if (urb->status)
147                 warn("usblp%d: nonzero read/write bulk status received: %d",
148                         usblp->minor, urb->status);
149 
150         wake_up_interruptible(&usblp->wait);
151 }
152 
153 /*
154  * Get and print printer errors.
155  */
156 
157 static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
158 
159 static int usblp_check_status(struct usblp *usblp, int err)
160 {
161         unsigned char status, newerr = 0;
162 
163         if (usblp_read_status(usblp, &status)) {
164                 err("usblp%d: failed reading printer status", usblp->minor);
165                 return 0;
166         }
167 
168         if (~status & LP_PERRORP) {
169                 newerr = 3;
170                 if (status & LP_POUTPA) newerr = 1;
171                 if (~status & LP_PSELECD) newerr = 2;
172         }
173 
174         if (newerr != err)
175                 info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
176 
177         return newerr;
178 }
179 
180 /*
181  * File op functions.
182  */
183 
184 static int usblp_open(struct inode *inode, struct file *file)
185 {
186         int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
187         struct usblp *usblp;
188         int retval;
189 
190         if (minor < 0 || minor >= USBLP_MINORS)
191                 return -ENODEV;
192 
193         lock_kernel();
194         usblp  = usblp_table[minor];
195 
196         retval = -ENODEV;
197         if (!usblp || !usblp->dev)
198                 goto out;
199 
200         retval = -EBUSY;
201         if (usblp->used)
202                 goto out;
203 
204         /*
205          * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
206          * This is #if 0-ed because we *don't* want to fail an open
207          * just because the printer is off-line.
208          */
209 #if 0
210         if ((retval = usblp_check_status(usblp, 0))) {
211                 retval = retval > 1 ? -EIO : -ENOSPC;
212                 goto out;
213         }
214 #else
215         retval = 0;     
216 #endif
217 
218         usblp->used = 1;
219         file->private_data = usblp;
220 
221         usblp->writeurb.transfer_buffer_length = 0;
222         usblp->writeurb.status = 0;
223 
224         if (usblp->bidir) {
225                 usblp->readcount = 0;
226                 usblp->readurb.dev = usblp->dev;
227                 usb_submit_urb(&usblp->readurb);
228         }
229 out:
230         unlock_kernel();
231         return retval;
232 }
233 
234 static int usblp_release(struct inode *inode, struct file *file)
235 {
236         struct usblp *usblp = file->private_data;
237 
238         usblp->used = 0;
239 
240         if (usblp->dev) {
241                 if (usblp->bidir)
242                         usb_unlink_urb(&usblp->readurb);
243                 usb_unlink_urb(&usblp->writeurb);
244                 return 0;
245         }
246 
247         usblp_table[usblp->minor] = NULL;
248         kfree(usblp->device_id_string);
249         kfree(usblp);
250 
251         return 0;
252 }
253 
254 /* No kernel lock - fine */
255 static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
256 {
257         struct usblp *usblp = file->private_data;
258         poll_wait(file, &usblp->wait, wait);
259         return ((usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
260                               | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
261 }
262 
263 static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
264 {
265         struct usblp *usblp = file->private_data;
266         int length, err;
267         unsigned char status;
268 
269         if (_IOC_TYPE(cmd) == 'P')      /* new-style ioctl number */
270         
271                 switch (_IOC_NR(cmd)) {
272 
273                         case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
274                                 if (_IOC_DIR(cmd) != _IOC_READ)
275                                         return -EINVAL;
276 
277                                 err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
278                                 if (err < 0) {
279                                         dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
280                                                 usblp->minor, err);
281                                         usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
282                                         return -EIO;
283                                 }
284 
285                                 length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
286                                 if (length < DEVICE_ID_SIZE)
287                                         usblp->device_id_string[length] = '\0';
288                                 else
289                                         usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
290 
291                                 dbg ("usblp%d Device ID string [%d/max %d]='%s'",
292                                         usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
293 
294                                 if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
295 
296                                 if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
297                                         return -EFAULT;
298 
299                                 break;
300 
301                         default:
302                                 return -EINVAL;
303                 }
304         else    /* old-style ioctl value */
305                 switch (cmd) {
306 
307                         case LPGETSTATUS:
308                                 if (usblp_read_status(usblp, &status)) {
309                                         err("usblp%d: failed reading printer status", usblp->minor);
310                                         return -EIO;
311                                 }
312                                 if (copy_to_user ((unsigned char *)arg, &status, 1))
313                                         return -EFAULT;
314                                 break;
315 
316                         default:
317                                 return -EINVAL;
318                 }
319 
320         return 0;
321 }
322 
323 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
324 {
325         struct usblp *usblp = file->private_data;
326         int timeout, err = 0, writecount = 0;
327 
328         while (writecount < count) {
329 
330                 if (usblp->writeurb.status == -EINPROGRESS) {
331 
332                         if (file->f_flags & O_NONBLOCK)
333                                 return -EAGAIN;
334 
335                         timeout = USBLP_WRITE_TIMEOUT;
336                         while (timeout && usblp->writeurb.status == -EINPROGRESS) {
337 
338                                 if (signal_pending(current))
339                                         return writecount ? writecount : -EINTR;
340 
341                                 timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
342                         }
343                 }
344 
345                 if (!usblp->dev)
346                         return -ENODEV;
347 
348                 if (usblp->writeurb.status) {
349                         if (usblp->quirks & USBLP_QUIRK_BIDIR) {
350                                 if (usblp->writeurb.status != -EINPROGRESS)
351                                         err("usblp%d: error %d writing to printer",
352                                                 usblp->minor, usblp->writeurb.status);
353                                 err = usblp->writeurb.status;
354                                 continue;
355                         }
356                         else {
357                                 err = usblp_check_status(usblp, err);
358                                 continue;
359                         }
360                 }
361 
362                 writecount += usblp->writeurb.transfer_buffer_length;
363                 usblp->writeurb.transfer_buffer_length = 0;
364 
365                 if (writecount == count)
366                         continue;
367 
368                 usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
369                                                          (count - writecount) : USBLP_BUF_SIZE;
370 
371                 if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
372                                 usblp->writeurb.transfer_buffer_length)) return -EFAULT;
373 
374                 usblp->writeurb.dev = usblp->dev;
375                 usb_submit_urb(&usblp->writeurb);
376         }
377 
378         return count;
379 }
380 
381 static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
382 {
383         struct usblp *usblp = file->private_data;
384 
385         if (!usblp->bidir)
386                 return -EINVAL;
387 
388         if (usblp->readurb.status == -EINPROGRESS) {
389 
390                 if (file->f_flags & O_NONBLOCK)
391                         return -EAGAIN;
392 
393                 while (usblp->readurb.status == -EINPROGRESS) {
394                         if (signal_pending(current))
395                                 return -EINTR;
396                         interruptible_sleep_on(&usblp->wait);
397                 }
398         }
399 
400         if (!usblp->dev)
401                 return -ENODEV;
402 
403         if (usblp->readurb.status) {
404                 err("usblp%d: error %d reading from printer",
405                         usblp->minor, usblp->readurb.status);
406                 usblp->readurb.dev = usblp->dev;
407                 usb_submit_urb(&usblp->readurb);
408                 return -EIO;
409         }
410 
411         count = count < usblp->readurb.actual_length - usblp->readcount ?
412                 count : usblp->readurb.actual_length - usblp->readcount;
413 
414         if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
415                 return -EFAULT;
416 
417         if ((usblp->readcount += count) == usblp->readurb.actual_length) {
418                 usblp->readcount = 0;
419                 usblp->readurb.dev = usblp->dev;
420                 usb_submit_urb(&usblp->readurb);
421         }
422 
423         return count;
424 }
425 
426 /*
427  * Checks for printers that have quirks, such as requiring unidirectional
428  * communication but reporting bidirectional; currently some HP printers
429  * have this flaw (HP 810, 880, 895, etc.), or needing an init string
430  * sent at each open (like some Epsons).
431  * Returns 1 if found, 0 if not found.
432  *
433  * HP recommended that we use the bidirectional interface but
434  * don't attempt any bulk IN transfers from the IN endpoint.
435  * Here's some more detail on the problem:
436  * The problem is not that it isn't bidirectional though. The problem
437  * is that if you request a device ID, or status information, while
438  * the buffers are full, the return data will end up in the print data
439  * buffer. For example if you make sure you never request the device ID
440  * while you are sending print data, and you don't try to query the
441  * printer status every couple of milliseconds, you will probably be OK.
442  */
443 static unsigned int usblp_quirks (__u16 vendor, __u16 product)
444 {
445         int i;
446 
447         for (i = 0; quirk_printers[i].vendorId; i++) {
448                 if (vendor == quirk_printers[i].vendorId &&
449                     product == quirk_printers[i].productId)
450                         return quirk_printers[i].quirks;
451         }
452         return 0;
453 }
454 
455 static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
456                          const struct usb_device_id *id)
457 {
458         struct usb_interface_descriptor *interface;
459         struct usb_endpoint_descriptor *epread, *epwrite;
460         struct usblp *usblp;
461         int minor, i, bidir = 0, quirks;
462         int alts = dev->actconfig->interface[ifnum].act_altsetting;
463         int length, err;
464         char *buf;
465 
466         /* If a bidirectional interface exists, use it. */
467         for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
468 
469                 interface = &dev->actconfig->interface[ifnum].altsetting[i];
470 
471                 if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
472                     interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 ||
473                    (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
474                         continue;
475 
476                 if (interface->bInterfaceProtocol > 1) {
477                         bidir = 1;
478                         alts = i;
479                         break;
480                 }
481         }
482 
483         interface = &dev->actconfig->interface[ifnum].altsetting[alts];
484         if (usb_set_interface(dev, ifnum, alts))
485                 err("can't set desired altsetting %d on interface %d", alts, ifnum);
486 
487         epwrite = interface->endpoint + 0;
488         epread = bidir ? interface->endpoint + 1 : NULL;
489 
490         if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
491                 if (interface->bNumEndpoints == 1)
492                         return NULL;
493                 epwrite = interface->endpoint + 1;
494                 epread = bidir ? interface->endpoint + 0 : NULL;
495         }
496 
497         if ((epwrite->bEndpointAddress & 0x80) == 0x80)
498                 return NULL;
499 
500         if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
501                 return NULL;
502 
503         for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
504         if (usblp_table[minor]) {
505                 err("no more free usblp devices");
506                 return NULL;
507         }
508 
509         if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
510                 err("out of memory");
511                 return NULL;
512         }
513         memset(usblp, 0, sizeof(struct usblp));
514 
515         /* lookup quirks for this printer */
516         quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
517 
518         if (bidir && (quirks & USBLP_QUIRK_BIDIR)) {
519                 bidir = 0;
520                 epread = NULL;
521                 info ("Disabling reads from problem bidirectional printer on usblp%d",
522                         minor);
523         }
524 
525         usblp->dev = dev;
526         usblp->ifnum = ifnum;
527         usblp->minor = minor;
528         usblp->bidir = bidir;
529         usblp->quirks = quirks;
530 
531         init_waitqueue_head(&usblp->wait);
532 
533         if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
534                 err("out of memory");
535                 kfree(usblp);
536                 return NULL;
537         }
538 
539         if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
540                 err("out of memory");
541                 kfree(usblp);
542                 kfree(buf);
543                 return NULL;
544         }
545 
546         FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
547                 buf, 0, usblp_bulk, usblp);
548 
549         if (bidir)
550                 FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
551                         buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
552 
553         /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
554         err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
555         if (err >= 0) {
556                 length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
557                 if (length < DEVICE_ID_SIZE)
558                         usblp->device_id_string[length] = '\0';
559                 else
560                         usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
561                 dbg ("usblp%d Device ID string [%d]=%s",
562                         minor, length, &usblp->device_id_string[2]);
563         }
564         else {
565                 err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
566                         minor, err);
567                 usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
568         }
569 
570 #ifdef DEBUG
571         usblp_check_status(usblp, 0);
572 #endif
573 
574         info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
575                 minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
576 
577         return usblp_table[minor] = usblp;
578 }
579 
580 static void usblp_disconnect(struct usb_device *dev, void *ptr)
581 {
582         struct usblp *usblp = ptr;
583 
584         if (!usblp || !usblp->dev) {
585                 err("disconnect on nonexisting interface");
586                 return;
587         }
588 
589         usblp->dev = NULL;
590 
591         usb_unlink_urb(&usblp->writeurb);
592         if (usblp->bidir)
593                 usb_unlink_urb(&usblp->readurb);
594 
595         kfree(usblp->writeurb.transfer_buffer);
596 
597         if (usblp->used) return;
598 
599         kfree(usblp->device_id_string);
600 
601         usblp_table[usblp->minor] = NULL;
602         kfree(usblp);
603 }
604 
605 static struct file_operations usblp_fops = {
606         owner:          THIS_MODULE,
607         read:           usblp_read,
608         write:          usblp_write,
609         poll:           usblp_poll,
610         ioctl:          usblp_ioctl,
611         open:           usblp_open,
612         release:        usblp_release,
613 };
614 
615 static struct usb_device_id usblp_ids [] = {
616         { USB_INTERFACE_INFO(7, 1, 1) },
617         { USB_INTERFACE_INFO(7, 1, 2) },
618         { USB_INTERFACE_INFO(7, 1, 3) },
619         { }                                             /* Terminating entry */
620 };
621 
622 MODULE_DEVICE_TABLE (usb, usblp_ids);
623 
624 static struct usb_driver usblp_driver = {
625         name:           "usblp",
626         probe:          usblp_probe,
627         disconnect:     usblp_disconnect,
628         fops:           &usblp_fops,
629         minor:          USBLP_MINOR_BASE,
630         id_table:       usblp_ids,
631 };
632 
633 static int __init usblp_init(void)
634 {
635         if (usb_register(&usblp_driver))
636                 return -1;
637         return 0;
638 }
639 
640 static void __exit usblp_exit(void)
641 {
642         usb_deregister(&usblp_driver);
643 }
644 
645 module_init(usblp_init);
646 module_exit(usblp_exit);
647 
648 MODULE_AUTHOR("Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap");
649 MODULE_DESCRIPTION("USB Printer Device Class driver");
650 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.