]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/ulpt.c
This commit was generated by cvs2svn to compensate for changes in r44852,
[FreeBSD/FreeBSD.git] / sys / dev / usb / ulpt.c
1 /*      $NetBSD: ulpt.c,v 1.10 1999/01/08 11:58:25 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 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #if defined(__NetBSD__)
47 #include <sys/device.h>
48 #include <sys/ioctl.h>
49 #elif defined(__FreeBSD__)
50 #include <sys/ioccom.h>
51 #include <sys/module.h>
52 #include <sys/bus.h>
53 #endif
54 #include <sys/uio.h>
55 #include <sys/conf.h>
56 #include <sys/syslog.h>
57
58 #include <dev/usb/usb.h>
59 #include <dev/usb/usbdi.h>
60 #include <dev/usb/usbdi_util.h>
61 #include <dev/usb/usbdevs.h>
62 #include <dev/usb/usb_quirks.h>
63
64 #define TIMEOUT         hz*16   /* wait up to 16 seconds for a ready */
65 #define STEP            hz/4
66
67 #define LPTPRI          (PZERO+8)
68 #define ULPT_BSIZE      1024
69
70 #ifdef USB_DEBUG
71 #define DPRINTF(x)      if (ulptdebug) printf x
72 #define DPRINTFN(n,x)   if (ulptdebug>(n)) printf x
73 int     ulptdebug = 1;
74 #else
75 #define DPRINTF(x)
76 #define DPRINTFN(n,x)
77 #endif
78
79 #define UR_GET_DEVICE_ID 0
80 #define UR_GET_PORT_STATUS 1
81 #define UR_SOFT_RESET 2
82
83 #define LPS_NERR                0x08    /* printer no error */
84 #define LPS_SELECT              0x10    /* printer selected */
85 #define LPS_NOPAPER             0x20    /* printer out of paper */
86 #define LPS_INVERT      (LPS_SELECT|LPS_NERR)
87 #define LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
88
89 struct ulpt_softc {
90         bdevice sc_dev;
91         usbd_device_handle sc_udev;     /* device */
92         usbd_interface_handle sc_iface; /* interface */
93         int sc_ifaceno;
94         usbd_pipe_handle sc_bulkpipe;   /* bulk pipe */
95         int sc_bulk;
96
97         u_char sc_state;
98 #define ULPT_OPEN       0x01    /* device is open */
99 #define ULPT_OBUSY      0x02    /* printer is busy doing output */
100 #define ULPT_INIT       0x04    /* waiting to initialize for open */
101         u_char sc_flags;
102 #if defined(__NetBSD__)
103 #define ULPT_NOPRIME    0x40    /* don't prime on open */
104 #elif defined(__FreeBSD__)
105 /* values taken from i386/isa/lpt.c */
106 #define ULPT_POS_INIT   0x04    /* if we are a postive init signal */
107 #define ULPT_POS_ACK    0x08    /* if we are a positive going ack */
108 #define ULPT_NOPRIME    0x10    /* don't prime the printer at all */
109 #define ULPT_PRIMEOPEN  0x20    /* prime on every open */
110 #define ULPT_AUTOLF     0x40    /* tell printer to do an automatic lf */
111 #define ULPT_BYPASS     0x80    /* bypass  printer ready checks */
112 #endif
113         u_char sc_laststatus;
114 };
115
116 #if defined(__NetBSD__)
117 int ulptopen __P((dev_t, int, int, struct proc *));
118 int ulptclose __P((dev_t, int, int, struct proc *p));
119 int ulptwrite __P((dev_t, struct uio *uio, int));
120 int ulptioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
121 #elif defined(__FreeBSD__)
122 static d_open_t ulptopen;
123 static d_close_t ulptclose;
124 static d_write_t ulptwrite;
125 static d_ioctl_t ulptioctl;
126
127 #define ULPT_CDEV_MAJOR 113
128
129 static struct  cdevsw ulpt_cdevsw = {
130         ulptopen,       ulptclose,      noread,         ulptwrite,
131         ulptioctl,      nostop,         nullreset,      nodevtotty,
132         seltrue,        nommap,         nostrat,
133         "ulpt",         NULL,           -1
134 };
135 #endif
136
137 int ulpt_status __P((struct ulpt_softc *));
138 void ulpt_reset __P((struct ulpt_softc *));
139 int ulpt_statusmsg __P((u_char, struct ulpt_softc *));
140
141 #if defined(__NetBSD__)
142 #define ULPTUNIT(s)     (minor(s) & 0x1f)
143 #define ULPTFLAGS(s)    (minor(s) & 0xe0)
144 #elif defined(__FreeBSD__)
145 /* defines taken from i386/isa/lpt.c */
146 #define ULPTUNIT(s)     (minor(s) & 0x03)
147 #define ULPTFLAGS(s)    (minor(s) & 0xfc)
148 #endif
149
150 USB_DECLARE_DRIVER(ulpt);
151
152 USB_MATCH(ulpt)
153 {
154         USB_MATCH_START(ulpt, uaa);
155         usb_interface_descriptor_t *id;
156         
157         DPRINTFN(10,("ulpt_match\n"));
158         if (!uaa->iface)
159                 return (UMATCH_NONE);
160         id = usbd_get_interface_descriptor(uaa->iface);
161         if (id &&
162             id->bInterfaceClass == UCLASS_PRINTER &&
163             id->bInterfaceSubClass == USUBCLASS_PRINTER &&
164             (id->bInterfaceProtocol == UPROTO_PRINTER_UNI ||
165              id->bInterfaceProtocol == UPROTO_PRINTER_BI))
166                 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
167         return (UMATCH_NONE);
168 }
169
170 USB_ATTACH(ulpt)
171 {
172         USB_ATTACH_START(ulpt, sc, uaa);
173         usbd_device_handle dev = uaa->device;
174         usbd_interface_handle iface = uaa->iface;
175         usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
176 #if 0
177         usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
178         usb_device_request_t req;
179 #endif
180         char devinfo[1024];
181         usb_endpoint_descriptor_t *ed;
182         usbd_status r;
183         
184         DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
185         usbd_devinfo(dev, 0, devinfo);
186         USB_ATTACH_SETUP;
187         printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
188                devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
189
190         /* Figure out which endpoint is the bulk out endpoint. */
191         ed = usbd_interface2endpoint_descriptor(iface, 0);
192         if (!ed)
193                 goto nobulk;
194         if ((ed->bEndpointAddress & UE_IN) != UE_OUT ||
195             (ed->bmAttributes & UE_XFERTYPE) != UE_BULK) {
196                 /* In case we are using a bidir protocol... */
197                 ed = usbd_interface2endpoint_descriptor(iface, 1);
198                 if (!ed)
199                         goto nobulk;
200                 if ((ed->bEndpointAddress & UE_IN) != UE_OUT ||
201                     (ed->bmAttributes & UE_XFERTYPE) != UE_BULK)
202                         goto nobulk;
203         }
204         sc->sc_bulk = ed->bEndpointAddress;
205         DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_bulk));
206
207         sc->sc_iface = iface;
208         r = usbd_interface2device_handle(iface, &sc->sc_udev);
209         if (r != USBD_NORMAL_COMPLETION)
210                 USB_ATTACH_ERROR_RETURN;
211         sc->sc_ifaceno = id->bInterfaceNumber;
212
213 #if 0
214 XXX needs a different way to read the id string since the length
215 is unknown.  usbd_do_request() returns error on a short transfer.
216         req.bmRequestType = UT_READ_CLASS_INTERFACE;
217         req.bRequest = UR_GET_DEVICE_ID;
218         USETW(req.wValue, cd->bConfigurationValue);
219         USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
220         USETW(req.wLength, sizeof devinfo - 1);
221         r = usbd_do_request(dev, &req, devinfo);
222         if (r == USBD_NORMAL_COMPLETION) {
223                 int len;
224                 char *idstr;
225                 len = (devinfo[0] << 8) | (devinfo[1] & 0xff);
226                 /* devinfo now contains an IEEE-1284 device ID */
227                 idstr = devinfo+2;
228                 idstr[len] = 0;
229                 printf("%s: device id <%s>\n", USBDEVNAME(sc->sc_dev), idstr);
230         } else {
231                 printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
232         }
233 #endif
234
235         USB_ATTACH_SUCCESS_RETURN;
236
237  nobulk:
238         printf("%s: could not find bulk endpoint\n", USBDEVNAME(sc->sc_dev));
239         USB_ATTACH_ERROR_RETURN;
240 }
241
242 int
243 ulpt_status(sc)
244         struct ulpt_softc *sc;
245 {
246         usb_device_request_t req;
247         usbd_status r;
248         u_char status;
249
250         req.bmRequestType = UT_READ_CLASS_INTERFACE;
251         req.bRequest = UR_GET_PORT_STATUS;
252         USETW(req.wValue, 0);
253         USETW(req.wIndex, sc->sc_ifaceno);
254         USETW(req.wLength, 1);
255         r = usbd_do_request(sc->sc_udev, &req, &status);
256         DPRINTFN(1, ("ulpt_status: status=0x%02x r=%d\n", status, r));
257         if (r == USBD_NORMAL_COMPLETION)
258                 return (status);
259         else
260                 return (0);
261 }
262
263 void
264 ulpt_reset(sc)
265         struct ulpt_softc *sc;
266 {
267         usb_device_request_t req;
268
269         DPRINTFN(1, ("ulpt_reset\n"));
270         req.bmRequestType = UT_WRITE_CLASS_OTHER;
271         req.bRequest = UR_SOFT_RESET;
272         USETW(req.wValue, 0);
273         USETW(req.wIndex, sc->sc_ifaceno);
274         USETW(req.wLength, 0);
275         (void)usbd_do_request(sc->sc_udev, &req, 0);
276 }
277
278 /*
279  * Reset the printer, then wait until it's selected and not busy.
280  */
281 int
282 ulptopen(dev, flag, mode, p)
283         dev_t dev;
284         int flag;
285         int mode;
286         struct proc *p;
287 {
288         u_char flags = ULPTFLAGS(dev);
289         usbd_status r;
290         int spin, error;
291         USB_GET_SC_OPEN(ulpt, ULPTUNIT(dev), sc);
292
293         if (!sc || !sc->sc_iface)
294                 return ENXIO;
295
296         if (sc->sc_state)
297                 return EBUSY;
298
299         sc->sc_state = ULPT_INIT;
300         sc->sc_flags = flags;
301         DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags));
302
303 #if USB_DEBUG && defined(__FreeBSD__)
304         /* Ignoring these flags might not be a good idea */
305         if ((flags ^ ULPT_NOPRIME) != 0)
306                 DPRINTF(("flags ignored: %b\n", flags,
307                         "\20\3POS_INIT\4POS_ACK\6PRIME_OPEN\7AUTOLF\10BYPASS"));
308 #endif
309         if ((flags & ULPT_NOPRIME) == 0)
310                 ulpt_reset(sc);
311
312         for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
313                 if (spin >= TIMEOUT) {
314                         sc->sc_state = 0;
315                         return EBUSY;
316                 }
317
318                 /* wait 1/4 second, give up if we get a signal */
319                 error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP);
320                 if (error != EWOULDBLOCK) {
321                         sc->sc_state = 0;
322                         return error;
323                 }
324         }
325
326         r = usbd_open_pipe(sc->sc_iface, sc->sc_bulk, 0, &sc->sc_bulkpipe);
327         if (r != USBD_NORMAL_COMPLETION) {
328                 sc->sc_state = 0;
329                 return (EIO);
330         }
331
332         sc->sc_state = ULPT_OPEN;
333
334         DPRINTF(("ulptopen: done\n"));
335         return (0);
336 }
337
338 int
339 ulpt_statusmsg(status, sc)
340         u_char status;
341         struct ulpt_softc *sc;
342 {
343         u_char new;
344
345         status = (status ^ LPS_INVERT) & LPS_MASK;
346         new = status & ~sc->sc_laststatus;
347         sc->sc_laststatus = status;
348
349         if (new & LPS_SELECT)
350                 log(LOG_NOTICE, "%s: offline\n", USBDEVNAME(sc->sc_dev));
351         else if (new & LPS_NOPAPER)
352                 log(LOG_NOTICE, "%s: out of paper\n", USBDEVNAME(sc->sc_dev));
353         else if (new & LPS_NERR)
354                 log(LOG_NOTICE, "%s: output error\n", USBDEVNAME(sc->sc_dev));
355
356         return status;
357 }
358
359 int
360 ulptclose(dev, flag, mode, p)
361         dev_t dev;
362         int flag;
363         int mode;
364         struct proc *p;
365 {
366         USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
367
368         usbd_close_pipe(sc->sc_bulkpipe);
369
370         sc->sc_state = 0;
371
372         DPRINTF(("ulptclose: closed\n"));
373         return (0);
374 }
375
376 int
377 ulptwrite(dev, uio, flags)
378         dev_t dev;
379         struct uio *uio;
380         int flags;
381 {
382         size_t n;
383         int error = 0;
384         char buf[ULPT_BSIZE];
385         usbd_request_handle reqh;
386         usbd_status r;
387         USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
388
389         DPRINTF(("ulptwrite\n"));
390         reqh = usbd_alloc_request();
391         if (reqh == 0)
392                 return (ENOMEM);
393         while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) {
394                 ulpt_statusmsg(ulpt_status(sc), sc);
395                 error = uiomove(buf, n, uio);
396                 if (error)
397                         break;
398                 /* XXX use callback to enable interrupt? */
399                 r = usbd_setup_request(reqh, sc->sc_bulkpipe, 0, buf, n,
400                                        0, USBD_NO_TIMEOUT, 0);
401                 if (r != USBD_NORMAL_COMPLETION) {
402                         error = EIO;
403                         break;
404                 }
405                 DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n));
406                 r = usbd_sync_transfer(reqh);
407                 if (r != USBD_NORMAL_COMPLETION) {
408                         DPRINTF(("ulptwrite: error=%d\n", r));
409                         usbd_clear_endpoint_stall(sc->sc_bulkpipe);
410                         error = EIO;
411                         break;
412                 }
413         }
414         usbd_free_request(reqh);
415         return (error);
416 }
417
418 int
419 ulptioctl(dev, cmd, data, flag, p)
420         dev_t dev;
421         u_long cmd;
422         caddr_t data;
423         int flag;
424         struct proc *p;
425 {
426         int error = 0;
427
428         switch (cmd) {
429         default:
430                 error = ENODEV;
431         }
432
433         return error;
434 }
435
436 #if defined(__FreeBSD__)
437 static int
438 ulpt_detach(device_t self)
439 {       
440         const char *devinfo = device_get_desc(self);
441
442         DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
443         if (devinfo) {
444                 device_set_desc(self, NULL);
445                 free((void *)devinfo, M_USB);
446         }
447         return 0;
448 }
449
450 CDEV_DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass,
451                         ULPT_CDEV_MAJOR, ulpt_cdevsw, usbd_driver_load, 0);
452 #endif