]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/ulpt.c
This commit was generated by cvs2svn to compensate for changes in r56889,
[FreeBSD/FreeBSD.git] / sys / dev / usb / ulpt.c
1 /*      $NetBSD: ulpt.c,v 1.29 1999/11/17 23:00:50 augustss Exp $       */
2 /*      $FreeBSD$       */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@carlstedt.se) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 /*
42  * Printer Class spec: http://www.usb.org/developers/data/usbprn10.pdf
43  */
44
45 /* XXX Note in the manpage the ULPT_NOPRIME version of the printer */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/proc.h>
50 #include <sys/kernel.h>
51 #if defined(__NetBSD__)
52 #include <sys/device.h>
53 #include <sys/ioctl.h>
54 #elif defined(__FreeBSD__)
55 #include <sys/ioccom.h>
56 #include <sys/module.h>
57 #include <sys/bus.h>
58 #endif
59 #include <sys/uio.h>
60 #include <sys/conf.h>
61 #include <sys/vnode.h>
62 #include <sys/syslog.h>
63
64 #include <dev/usb/usb.h>
65 #include <dev/usb/usbdi.h>
66 #include <dev/usb/usbdi_util.h>
67 #include <dev/usb/usbdevs.h>
68 #include <dev/usb/usb_quirks.h>
69
70 #define TIMEOUT         hz*16   /* wait up to 16 seconds for a ready */
71 #define STEP            hz/4
72
73 #define LPTPRI          (PZERO+8)
74 #define ULPT_BSIZE      16384
75
76 #ifdef ULPT_DEBUG
77 #define DPRINTF(x)      if (ulptdebug) logprintf x
78 #define DPRINTFN(n,x)   if (ulptdebug>(n)) logprintf x
79 int     ulptdebug = 0;
80 #else
81 #define DPRINTF(x)
82 #define DPRINTFN(n,x)
83 #endif
84
85 #define UR_GET_DEVICE_ID 0
86 #define UR_GET_PORT_STATUS 1
87 #define UR_SOFT_RESET 2
88
89 #define LPS_NERR                0x08    /* printer no error */
90 #define LPS_SELECT              0x10    /* printer selected */
91 #define LPS_NOPAPER             0x20    /* printer out of paper */
92 #define LPS_INVERT      (LPS_SELECT|LPS_NERR)
93 #define LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
94
95 struct ulpt_softc {
96         USBBASEDEVICE sc_dev;
97         usbd_device_handle sc_udev;     /* device */
98         usbd_interface_handle sc_iface; /* interface */
99         int sc_ifaceno;
100         usbd_pipe_handle sc_bulkpipe;   /* bulk pipe */
101         int sc_bulk;
102
103         u_char sc_state;
104 #define ULPT_OPEN       0x01    /* device is open */
105 #define ULPT_OBUSY      0x02    /* printer is busy doing output */
106 #define ULPT_INIT       0x04    /* waiting to initialize for open */
107         u_char sc_flags;
108 #define ULPT_NOPRIME    0x40    /* don't prime on open */
109         u_char sc_laststatus;
110
111         int sc_refcnt;
112         u_char sc_dying;
113
114 #if defined(__FreeBSD__)
115         dev_t dev;
116         dev_t dev_noprime;
117 #endif
118 };
119
120 #if defined(__NetBSD__) || defined(__OpenBSD__)
121 cdev_decl(ulpt);
122 #elif defined(__FreeBSD__)
123 static d_open_t ulptopen;
124 static d_close_t ulptclose;
125 static d_write_t ulptwrite;
126 static d_ioctl_t ulptioctl;
127
128 #define ULPT_CDEV_MAJOR 113
129
130 static struct cdevsw ulpt_cdevsw = {
131         /* open */      ulptopen,
132         /* close */     ulptclose,
133         /* read */      noread,
134         /* write */     ulptwrite,
135         /* ioctl */     ulptioctl,
136         /* poll */      nopoll,
137         /* mmap */      nommap,
138         /* strategy */  nostrategy,
139         /* name */      "ulpt",
140         /* maj */       ULPT_CDEV_MAJOR,
141         /* dump */      nodump,
142         /* psize */     nopsize,
143         /* flags */     0,
144         /* bmaj */      -1
145 };
146 #endif
147
148 void ulpt_disco __P((void *));
149
150 int ulpt_do_write __P((struct ulpt_softc *, struct uio *uio, int));
151 int ulpt_status __P((struct ulpt_softc *));
152 void ulpt_reset __P((struct ulpt_softc *));
153 int ulpt_statusmsg __P((u_char, struct ulpt_softc *));
154
155 void ieee1284_print_id __P((char *));
156
157 #define ULPTUNIT(s)     (minor(s) & 0x1f)
158 #define ULPTFLAGS(s)    (minor(s) & 0xe0)
159
160
161 USB_DECLARE_DRIVER(ulpt);
162
163 USB_MATCH(ulpt)
164 {
165         USB_MATCH_START(ulpt, uaa);
166         usb_interface_descriptor_t *id;
167         
168         DPRINTFN(10,("ulpt_match\n"));
169         if (uaa->iface == NULL)
170                 return (UMATCH_NONE);
171         id = usbd_get_interface_descriptor(uaa->iface);
172         if (id != NULL &&
173             id->bInterfaceClass == UCLASS_PRINTER &&
174             id->bInterfaceSubClass == USUBCLASS_PRINTER &&
175             (id->bInterfaceProtocol == UPROTO_PRINTER_UNI ||
176              id->bInterfaceProtocol == UPROTO_PRINTER_BI))
177                 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
178         return (UMATCH_NONE);
179 }
180
181 USB_ATTACH(ulpt)
182 {
183         USB_ATTACH_START(ulpt, sc, uaa);
184         usbd_device_handle dev = uaa->device;
185         usbd_interface_handle iface = uaa->iface;
186         usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
187         char devinfo[1024];
188         usb_endpoint_descriptor_t *ed;
189         usbd_status err;
190         
191         DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
192         usbd_devinfo(dev, 0, devinfo);
193         USB_ATTACH_SETUP;
194         printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
195                devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
196
197         /* Figure out which endpoint is the bulk out endpoint. */
198         ed = usbd_interface2endpoint_descriptor(iface, 0);
199         if (ed == NULL)
200                 goto nobulk;
201         if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT ||
202             (ed->bmAttributes & UE_XFERTYPE) != UE_BULK) {
203                 /* In case we are using a bidir protocol... */
204                 ed = usbd_interface2endpoint_descriptor(iface, 1);
205                 if (ed == NULL)
206                         goto nobulk;
207                 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT ||
208                     (ed->bmAttributes & UE_XFERTYPE) != UE_BULK)
209                         goto nobulk;
210         }
211         sc->sc_bulk = ed->bEndpointAddress;
212         DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_bulk));
213
214         sc->sc_iface = iface;
215         err = usbd_interface2device_handle(iface, &sc->sc_udev);
216         if (err) {
217                 sc->sc_dying = 1;
218                 USB_ATTACH_ERROR_RETURN;
219         }
220         sc->sc_ifaceno = id->bInterfaceNumber;
221
222 #if 0
223 /*
224  * This code is disabled because for some mysterious it causes
225  * printing not to work.  But only sometimes, and mostly with
226  * UHCI and less often with OHCI.  *sigh*
227  */
228         {
229         usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
230         usb_device_request_t req;
231         int len, alen;
232
233         req.bmRequestType = UT_READ_CLASS_INTERFACE;
234         req.bRequest = UR_GET_DEVICE_ID;
235         USETW(req.wValue, cd->bConfigurationValue);
236         USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
237         USETW(req.wLength, sizeof devinfo - 1);
238         err = usbd_do_request_flags(dev, &req, devinfo, USBD_SHORT_XFER_OK,
239                   &alen);
240         if (err) {
241                 printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
242         } else if (alen <= 2) {
243                 printf("%s: empty device id, no printer connected?\n",
244                        USBDEVNAME(sc->sc_dev));
245         } else {
246                 /* devinfo now contains an IEEE-1284 device ID */
247                 len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
248                 if (len > sizeof devinfo - 3)
249                         len = sizeof devinfo - 3;
250                 devinfo[len] = 0;
251                 printf("%s: device id <", USBDEVNAME(sc->sc_dev));
252                 ieee1284_print_id(devinfo+2);
253                 printf(">\n");
254         }
255         }
256 #endif
257
258 #if defined(__FreeBSD__)
259         sc->dev = make_dev(&ulpt_cdevsw, device_get_unit(self),
260                 UID_ROOT, GID_OPERATOR, 0644, "ulpt%d", device_get_unit(self));
261         sc->dev_noprime = make_dev(&ulpt_cdevsw,
262                 device_get_unit(self)|ULPT_NOPRIME,
263                 UID_ROOT, GID_OPERATOR, 0644, "unlpt%d", device_get_unit(self));
264 #endif
265
266         USB_ATTACH_SUCCESS_RETURN;
267
268  nobulk:
269         printf("%s: could not find bulk endpoint\n", USBDEVNAME(sc->sc_dev));
270         sc->sc_dying = 1;
271         USB_ATTACH_ERROR_RETURN;
272 }
273
274 #if defined(__NetBSD__) || defined(__OpenBSD__)
275 int
276 ulpt_activate(self, act)
277         device_ptr_t self;
278         enum devact act;
279 {
280         struct ulpt_softc *sc = (struct ulpt_softc *)self;
281
282         switch (act) {
283         case DVACT_ACTIVATE:
284                 return (EOPNOTSUPP);
285                 break;
286
287         case DVACT_DEACTIVATE:
288                 sc->sc_dying = 1;
289                 break;
290         }
291         return (0);
292 }
293 #endif
294
295 USB_DETACH(ulpt)
296 {
297         USB_DETACH_START(ulpt, sc);
298         int s;
299 #if defined(__NetBSD__) || defined(__OpenBSD__)
300         int maj, mn;
301 #elif defined(__FreeBSD__)
302         struct vnode *vp;
303 #endif
304
305 #if defined(__NetBSD__) || defined(__OpenBSD__)
306         DPRINTF(("ulpt_detach: sc=%p flags=%d\n", sc, flags));
307 #elif defined(__FreeBSD__)
308         DPRINTF(("ulpt_detach: sc=%p\n", sc));
309 #endif
310
311         sc->sc_dying = 1;
312         if (sc->sc_bulkpipe != NULL)
313                 usbd_abort_pipe(sc->sc_bulkpipe);
314
315         s = splusb();
316         if (--sc->sc_refcnt >= 0) {
317                 /* There is noone to wake, aborting the pipe is enough */
318                 /* Wait for processes to go away. */
319                 usb_detach_wait(USBDEV(sc->sc_dev));
320         }
321         splx(s);
322
323 #if defined(__NetBSD__) || defined(__OpenBSD__)
324         /* locate the major number */
325         for (maj = 0; maj < nchrdev; maj++)
326                 if (cdevsw[maj].d_open == ulptopen)
327                         break;
328
329         /* Nuke the vnodes for any open instances (calls close). */
330         mn = self->dv_unit;
331         vdevgone(maj, mn, mn, VCHR);
332 #elif defined(__FreeBSD__)
333         vp = SLIST_FIRST(&sc->dev->si_hlist);
334         if (vp)
335                 VOP_REVOKE(vp, REVOKEALL);
336         vp = SLIST_FIRST(&sc->dev_noprime->si_hlist);
337         if (vp)
338                 VOP_REVOKE(vp, REVOKEALL);
339
340         destroy_dev(sc->dev);
341         destroy_dev(sc->dev_noprime);
342 #endif
343
344         return (0);
345 }
346
347 int
348 ulpt_status(sc)
349         struct ulpt_softc *sc;
350 {
351         usb_device_request_t req;
352         usbd_status err;
353         u_char status;
354
355         req.bmRequestType = UT_READ_CLASS_INTERFACE;
356         req.bRequest = UR_GET_PORT_STATUS;
357         USETW(req.wValue, 0);
358         USETW(req.wIndex, sc->sc_ifaceno);
359         USETW(req.wLength, 1);
360         err = usbd_do_request(sc->sc_udev, &req, &status);
361         DPRINTFN(1, ("ulpt_status: status=0x%02x err=%d\n", status, err));
362         if (!err)
363                 return (status);
364         else
365                 return (0);
366 }
367
368 void
369 ulpt_reset(sc)
370         struct ulpt_softc *sc;
371 {
372         usb_device_request_t req;
373
374         DPRINTFN(1, ("ulpt_reset\n"));
375         req.bmRequestType = UT_WRITE_CLASS_OTHER;
376         req.bRequest = UR_SOFT_RESET;
377         USETW(req.wValue, 0);
378         USETW(req.wIndex, sc->sc_ifaceno);
379         USETW(req.wLength, 0);
380         (void)usbd_do_request(sc->sc_udev, &req, 0);
381 }
382
383 /*
384  * Reset the printer, then wait until it's selected and not busy.
385  */
386 int
387 ulptopen(dev, flag, mode, p)
388         dev_t dev;
389         int flag;
390         int mode;
391         struct proc *p;
392 {
393         u_char flags = ULPTFLAGS(dev);
394         struct ulpt_softc *sc;
395         usbd_status err;
396         int spin, error;
397
398         USB_GET_SC_OPEN(ulpt, ULPTUNIT(dev), sc);
399
400         if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
401                 return (ENXIO);
402
403         if (sc->sc_state)
404                 return (EBUSY);
405
406         sc->sc_state = ULPT_INIT;
407         sc->sc_flags = flags;
408         DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags));
409
410 #if defined(ULPT_DEBUG) && defined(__FreeBSD__)
411         /* Ignoring these flags might not be a good idea */
412         if ((flags & ~ULPT_NOPRIME) != 0)
413                 printf("ulptopen: flags ignored: %b\n", flags,
414                         "\20\3POS_INIT\4POS_ACK\6PRIME_OPEN\7AUTOLF\10BYPASS");
415 #endif
416
417
418         if ((flags & ULPT_NOPRIME) == 0)
419                 ulpt_reset(sc);
420
421         for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
422                 if (spin >= TIMEOUT) {
423                         sc->sc_state = 0;
424                         return (EBUSY);
425                 }
426
427                 /* wait 1/4 second, give up if we get a signal */
428                 error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP);
429                 if (error != EWOULDBLOCK) {
430                         sc->sc_state = 0;
431                         return (error);
432                 }
433         }
434
435         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulk, 0, &sc->sc_bulkpipe);
436         if (err) {
437                 sc->sc_state = 0;
438                 return (EIO);
439         }
440
441         sc->sc_state = ULPT_OPEN;
442
443         DPRINTF(("ulptopen: done\n"));
444         return (0);
445 }
446
447 int
448 ulpt_statusmsg(status, sc)
449         u_char status;
450         struct ulpt_softc *sc;
451 {
452         u_char new;
453
454         status = (status ^ LPS_INVERT) & LPS_MASK;
455         new = status & ~sc->sc_laststatus;
456         sc->sc_laststatus = status;
457
458         if (new & LPS_SELECT)
459                 log(LOG_NOTICE, "%s: offline\n", USBDEVNAME(sc->sc_dev));
460         else if (new & LPS_NOPAPER)
461                 log(LOG_NOTICE, "%s: out of paper\n", USBDEVNAME(sc->sc_dev));
462         else if (new & LPS_NERR)
463                 log(LOG_NOTICE, "%s: output error\n", USBDEVNAME(sc->sc_dev));
464
465         return (status);
466 }
467
468 int
469 ulptclose(dev, flag, mode, p)
470         dev_t dev;
471         int flag;
472         int mode;
473         struct proc *p;
474 {
475         struct ulpt_softc *sc;
476
477         USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
478
479         if (sc->sc_state != ULPT_OPEN)
480                 /* We are being forced to close before the open completed. */
481                 return (0);
482
483         usbd_close_pipe(sc->sc_bulkpipe);
484         sc->sc_bulkpipe = 0;
485
486         sc->sc_state = 0;
487
488         DPRINTF(("ulptclose: closed\n"));
489         return (0);
490 }
491
492 int
493 ulpt_do_write(sc, uio, flags)
494         struct ulpt_softc *sc;
495         struct uio *uio;
496         int flags;
497 {
498         u_int32_t n;
499         int error = 0;
500         void *bufp;
501         usbd_xfer_handle xfer;
502         usbd_status err;
503
504         DPRINTF(("ulptwrite\n"));
505         xfer = usbd_alloc_xfer(sc->sc_udev);
506         if (xfer == NULL)
507                 return (ENOMEM);
508         bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
509         if (bufp == NULL) {
510                 usbd_free_xfer(xfer);
511                 return (ENOMEM);
512         }
513         while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) {
514                 ulpt_statusmsg(ulpt_status(sc), sc);
515                 error = uiomove(bufp, n, uio);
516                 if (error)
517                         break;
518                 DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n));
519                 err = usbd_bulk_transfer(xfer, sc->sc_bulkpipe, USBD_NO_COPY, 
520                           USBD_NO_TIMEOUT, bufp, &n, "ulptwr");
521                 if (err) {
522                         DPRINTF(("ulptwrite: error=%d\n", err));
523                         error = EIO;
524                         break;
525                 }
526         }
527         usbd_free_xfer(xfer);
528
529         return (error);
530 }
531
532 int
533 ulptwrite(dev, uio, flags)
534         dev_t dev;
535         struct uio *uio;
536         int flags;
537 {
538         struct ulpt_softc *sc;
539         int error;
540
541         USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
542
543         if (sc->sc_dying)
544                 return (EIO);
545
546         sc->sc_refcnt++;
547         error = ulpt_do_write(sc, uio, flags);
548         if (--sc->sc_refcnt < 0)
549                 usb_detach_wakeup(USBDEV(sc->sc_dev));
550         return (error);
551 }
552
553 int
554 ulptioctl(dev, cmd, data, flag, p)
555         dev_t dev;
556         u_long cmd;
557         caddr_t data;
558         int flag;
559         struct proc *p;
560 {
561         int error = 0;
562
563         switch (cmd) {
564         default:
565                 error = ENODEV;
566         }
567
568         return (error);
569 }
570
571 #if 0
572 /* XXX This does not belong here. */
573 /*
574  * Print select parts of a IEEE 1284 device ID.
575  */
576 void
577 ieee1284_print_id(str)
578         char *str;
579 {
580         char *p, *q;
581
582         for (p = str-1; p; p = strchr(p, ';')) {
583                 p++;            /* skip ';' */
584                 if (strncmp(p, "MFG:", 4) == 0 ||
585                     strncmp(p, "MANUFACTURER:", 14) == 0 ||
586                     strncmp(p, "MDL:", 4) == 0 ||
587                     strncmp(p, "MODEL:", 6) == 0) {
588                         q = strchr(p, ';');
589                         if (q)
590                                 printf("%.*s", (int)(q - p + 1), p);
591                 }
592         }
593 }
594 #endif
595
596 #if defined(__FreeBSD__)
597 DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass, usbd_driver_load, 0);
598 #endif