]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ppbus/ppi.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / ppbus / ppi.c
1 /*-
2  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 #include "opt_ppb_1284.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/conf.h>
38 #include <sys/kernel.h>
39 #include <sys/uio.h>
40 #include <sys/fcntl.h>
41
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/rman.h>
45
46 #include <dev/ppbus/ppbconf.h>
47 #include <dev/ppbus/ppb_msq.h>
48
49 #ifdef PERIPH_1284
50 #include <dev/ppbus/ppb_1284.h>
51 #endif
52
53 #include <dev/ppbus/ppi.h>
54
55 #include "ppbus_if.h"
56
57 #include <dev/ppbus/ppbio.h>
58
59 #define BUFSIZE         512
60
61 struct ppi_data {
62
63     int         ppi_unit;
64     int         ppi_flags;
65 #define HAVE_PPBUS      (1<<0)
66 #define HAD_PPBUS       (1<<1)
67
68     int         ppi_count;
69     int         ppi_mode;                       /* IEEE1284 mode */
70     char        ppi_buffer[BUFSIZE];
71
72 #ifdef PERIPH_1284
73     struct resource *intr_resource;     /* interrupt resource */
74     void *intr_cookie;                  /* interrupt registration cookie */
75 #endif /* PERIPH_1284 */
76 };
77
78 #define DEVTOSOFTC(dev) \
79         ((struct ppi_data *)device_get_softc(dev))
80 #define UNITOSOFTC(unit) \
81         ((struct ppi_data *)devclass_get_softc(ppi_devclass, (unit)))
82 #define UNITODEVICE(unit) \
83         (devclass_get_device(ppi_devclass, (unit)))
84
85 static devclass_t ppi_devclass;
86
87 static  d_open_t        ppiopen;
88 static  d_close_t       ppiclose;
89 static  d_ioctl_t       ppiioctl;
90 static  d_write_t       ppiwrite;
91 static  d_read_t        ppiread;
92
93 static struct cdevsw ppi_cdevsw = {
94         .d_version =    D_VERSION,
95         .d_flags =      D_NEEDGIANT,
96         .d_open =       ppiopen,
97         .d_close =      ppiclose,
98         .d_read =       ppiread,
99         .d_write =      ppiwrite,
100         .d_ioctl =      ppiioctl,
101         .d_name =       "ppi",
102 };
103
104 #ifdef PERIPH_1284
105
106 static void
107 ppi_enable_intr(device_t ppidev)
108 {
109         char r;
110         device_t ppbus = device_get_parent(ppidev);
111
112         r = ppb_rctr(ppbus);
113         ppb_wctr(ppbus, r | IRQENABLE);
114
115         return;
116 }
117
118 static void
119 ppi_disable_intr(device_t ppidev)
120 {
121         char r;
122         device_t ppbus = device_get_parent(ppidev);
123
124         r = ppb_rctr(ppbus);
125         ppb_wctr(ppbus, r & ~IRQENABLE);
126
127         return;
128 }
129
130 #endif /* PERIPH_1284 */
131
132 static void
133 ppi_identify(driver_t *driver, device_t parent)
134 {
135
136         device_t dev;
137
138         dev = device_find_child(parent, "ppi", -1);
139         if (!dev)
140                 BUS_ADD_CHILD(parent, 0, "ppi", -1);
141 }
142
143 /*
144  * ppi_probe()
145  */
146 static int
147 ppi_probe(device_t dev)
148 {
149         struct ppi_data *ppi;
150
151         /* probe is always ok */
152         device_set_desc(dev, "Parallel I/O");
153
154         ppi = DEVTOSOFTC(dev);
155
156         return (0);
157 }
158
159 /*
160  * ppi_attach()
161  */
162 static int
163 ppi_attach(device_t dev)
164 {
165 #ifdef PERIPH_1284
166         uintptr_t irq;
167         int zero = 0;
168         struct ppi_data *ppi = DEVTOSOFTC(dev);
169
170         /* retrive the irq */
171         BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq);
172
173         /* declare our interrupt handler */
174         ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ,
175                                                 &zero, irq, irq, 1, RF_ACTIVE);
176 #endif /* PERIPH_1284 */
177
178         make_dev(&ppi_cdevsw, device_get_unit(dev),     /* XXX cleanup */
179                  UID_ROOT, GID_WHEEL,
180                  0600, "ppi%d", device_get_unit(dev));
181
182         return (0);
183 }
184
185 #ifdef PERIPH_1284
186 /*
187  * Cable
188  * -----
189  *
190  * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
191  *
192  * nStrobe   <-> nAck           1  <-> 10
193  * nAutofd   <-> Busy           11 <-> 14
194  * nSelectin <-> Select         17 <-> 13
195  * nInit     <-> nFault         15 <-> 16
196  *
197  */
198 static void
199 ppiintr(void *arg)
200 {
201         device_t ppidev = (device_t)arg;
202         device_t ppbus = device_get_parent(ppidev);
203         struct ppi_data *ppi = DEVTOSOFTC(ppidev);
204
205         ppi_disable_intr(ppidev);
206
207         switch (ppb_1284_get_state(ppbus)) {
208
209         /* accept IEEE1284 negotiation then wakeup a waiting process to
210          * continue negotiation at process level */
211         case PPB_FORWARD_IDLE:
212                 /* Event 1 */
213                 if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
214                                                         (SELECT | nBUSY)) {
215                         /* IEEE1284 negotiation */
216 #ifdef DEBUG_1284
217                         printf("N");
218 #endif
219
220                         /* Event 2 - prepare for reading the ext. value */
221                         ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
222
223                         ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
224
225                 } else {
226 #ifdef DEBUG_1284
227                         printf("0x%x", ppb_rstr(ppbus));
228 #endif
229                         ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
230                         break;
231                 }
232
233                 /* wake up any process waiting for negotiation from
234                  * remote master host */
235
236                 /* XXX should set a variable to warn the process about
237                  * the interrupt */
238
239                 wakeup(ppi);
240                 break;
241         default:
242 #ifdef DEBUG_1284
243                 printf("?%d", ppb_1284_get_state(ppbus));
244 #endif
245                 ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
246                 ppb_set_mode(ppbus, PPB_COMPATIBLE);
247                 break;
248         }
249
250         ppi_enable_intr(ppidev);
251
252         return;
253 }
254 #endif /* PERIPH_1284 */
255
256 static int
257 ppiopen(struct cdev *dev, int flags, int fmt, struct thread *td)
258 {
259         u_int unit = minor(dev);
260         struct ppi_data *ppi = UNITOSOFTC(unit);
261         device_t ppidev = UNITODEVICE(unit);
262         device_t ppbus = device_get_parent(ppidev);
263         int res;
264
265         if (!ppi)
266                 return (ENXIO);
267
268         if (!(ppi->ppi_flags & HAVE_PPBUS)) {
269                 if ((res = ppb_request_bus(ppbus, ppidev,
270                         (flags & O_NONBLOCK) ? PPB_DONTWAIT :
271                                                 (PPB_WAIT | PPB_INTR))))
272                         return (res);
273
274                 ppi->ppi_flags |= HAVE_PPBUS;
275
276 #ifdef PERIPH_1284
277                 if (ppi->intr_resource) {
278                         /* register our interrupt handler */
279                         bus_setup_intr(ppidev, ppi->intr_resource, 
280                                        INTR_TYPE_TTY, NULL, ppiintr, dev,
281                                        &ppi->intr_cookie);
282                 }
283 #endif /* PERIPH_1284 */
284         }
285         ppi->ppi_count += 1;
286
287         return (0);
288 }
289
290 static int
291 ppiclose(struct cdev *dev, int flags, int fmt, struct thread *td)
292 {
293         u_int unit = minor(dev);
294         struct ppi_data *ppi = UNITOSOFTC(unit);
295         device_t ppidev = UNITODEVICE(unit);
296         device_t ppbus = device_get_parent(ppidev);
297
298         ppi->ppi_count --;
299         if (!ppi->ppi_count) {
300
301 #ifdef PERIPH_1284
302                 switch (ppb_1284_get_state(ppbus)) {
303                 case PPB_PERIPHERAL_IDLE:
304                         ppb_peripheral_terminate(ppbus, 0);
305                         break;
306                 case PPB_REVERSE_IDLE:
307                 case PPB_EPP_IDLE:
308                 case PPB_ECP_FORWARD_IDLE:
309                 default:
310                         ppb_1284_terminate(ppbus);
311                         break;
312                 }
313 #endif /* PERIPH_1284 */
314
315                 /* unregistration of interrupt forced by release */
316                 ppb_release_bus(ppbus, ppidev);
317
318                 ppi->ppi_flags &= ~HAVE_PPBUS;
319         }
320
321         return (0);
322 }
323
324 /*
325  * ppiread()
326  *
327  * IEEE1284 compliant read.
328  *
329  * First, try negotiation to BYTE then NIBBLE mode
330  * If no data is available, wait for it otherwise transfer as much as possible
331  */
332 static int
333 ppiread(struct cdev *dev, struct uio *uio, int ioflag)
334 {
335 #ifdef PERIPH_1284
336         u_int unit = minor(dev);
337         struct ppi_data *ppi = UNITOSOFTC(unit);
338         device_t ppidev = UNITODEVICE(unit);
339         device_t ppbus = device_get_parent(ppidev);
340         int len, error = 0;
341
342         switch (ppb_1284_get_state(ppbus)) {
343         case PPB_PERIPHERAL_IDLE:
344                 ppb_peripheral_terminate(ppbus, 0);
345                 /* FALLTHROUGH */
346
347         case PPB_FORWARD_IDLE:
348                 /* if can't negotiate NIBBLE mode then try BYTE mode,
349                  * the peripheral may be a computer
350                  */
351                 if ((ppb_1284_negociate(ppbus,
352                         ppi->ppi_mode = PPB_NIBBLE, 0))) {
353
354                         /* XXX Wait 2 seconds to let the remote host some
355                          * time to terminate its interrupt
356                          */
357                         tsleep(ppi, PPBPRI, "ppiread", 2*hz);
358                         
359                         if ((error = ppb_1284_negociate(ppbus,
360                                 ppi->ppi_mode = PPB_BYTE, 0)))
361                                 return (error);
362                 }
363                 break;
364
365         case PPB_REVERSE_IDLE:
366         case PPB_EPP_IDLE:
367         case PPB_ECP_FORWARD_IDLE:
368         default:
369                 break;
370         }
371
372 #ifdef DEBUG_1284
373         printf("N");
374 #endif
375         /* read data */
376         len = 0;
377         while (uio->uio_resid) {
378                 if ((error = ppb_1284_read(ppbus, ppi->ppi_mode,
379                         ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
380                         &len))) {
381                         goto error;
382                 }
383
384                 if (!len)
385                         goto error;             /* no more data */
386
387 #ifdef DEBUG_1284
388                 printf("d");
389 #endif
390                 if ((error = uiomove(ppi->ppi_buffer, len, uio)))
391                         goto error;
392         }
393
394 error:
395
396 #else /* PERIPH_1284 */
397         int error = ENODEV;
398 #endif
399
400         return (error);
401 }
402
403 /*
404  * ppiwrite()
405  *
406  * IEEE1284 compliant write
407  *
408  * Actually, this is the peripheral side of a remote IEEE1284 read
409  *
410  * The first part of the negotiation (IEEE1284 device detection) is
411  * done at interrupt level, then the remaining is done by the writing
412  * process
413  *
414  * Once negotiation done, transfer data
415  */
416 static int
417 ppiwrite(struct cdev *dev, struct uio *uio, int ioflag)
418 {
419 #ifdef PERIPH_1284
420         u_int unit = minor(dev);
421         struct ppi_data *ppi = UNITOSOFTC(unit);
422         device_t ppidev = UNITODEVICE(unit);
423         device_t ppbus = device_get_parent(ppidev);
424         int len, error = 0, sent;
425
426 #if 0
427         int ret;
428
429         #define ADDRESS         MS_PARAM(0, 0, MS_TYP_PTR)
430         #define LENGTH          MS_PARAM(0, 1, MS_TYP_INT)
431
432         struct ppb_microseq msq[] = {
433                   { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
434                   MS_RET(0)
435         };
436
437         /* negotiate ECP mode */
438         if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
439                 printf("ppiwrite: ECP negotiation failed\n");
440         }
441
442         while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
443                 uiomove(ppi->ppi_buffer, len, uio);
444
445                 ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
446
447                 error = ppb_MS_microseq(ppbus, msq, &ret);
448         }
449 #endif
450
451         /* we have to be peripheral to be able to send data, so
452          * wait for the appropriate state
453          */
454         if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
455                 ppb_1284_terminate(ppbus);
456
457         while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
458                 /* XXX should check a variable before sleeping */
459 #ifdef DEBUG_1284
460                 printf("s");
461 #endif
462
463                 ppi_enable_intr(ppidev);
464
465                 /* sleep until IEEE1284 negotiation starts */
466                 error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
467
468                 switch (error) {
469                 case 0:
470                         /* negotiate peripheral side with BYTE mode */
471                         ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
472                         break;
473                 case EWOULDBLOCK:
474                         break;
475                 default:
476                         goto error;
477                 }
478         }
479 #ifdef DEBUG_1284
480         printf("N");
481 #endif
482
483         /* negotiation done, write bytes to master host */
484         while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
485                 uiomove(ppi->ppi_buffer, len, uio);
486                 if ((error = byte_peripheral_write(ppbus,
487                                                 ppi->ppi_buffer, len, &sent)))
488                         goto error;
489 #ifdef DEBUG_1284
490                 printf("d");
491 #endif
492         }
493
494 error:
495
496 #else /* PERIPH_1284 */
497         int error = ENODEV;
498 #endif
499
500         return (error);
501 }
502
503 static int
504 ppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
505 {
506         u_int unit = minor(dev);
507         device_t ppidev = UNITODEVICE(unit);
508         device_t ppbus = device_get_parent(ppidev);
509         int error = 0;
510         u_int8_t *val = (u_int8_t *)data;
511
512         switch (cmd) {
513
514         case PPIGDATA:                  /* get data register */
515                 *val = ppb_rdtr(ppbus);
516                 break;
517         case PPIGSTATUS:                /* get status bits */
518                 *val = ppb_rstr(ppbus);
519                 break;
520         case PPIGCTRL:                  /* get control bits */
521                 *val = ppb_rctr(ppbus);
522                 break;
523         case PPIGEPPD:                  /* get EPP data bits */
524                 *val = ppb_repp_D(ppbus);
525                 break;
526         case PPIGECR:                   /* get ECP bits */
527                 *val = ppb_recr(ppbus);
528                 break;
529         case PPIGFIFO:                  /* read FIFO */
530                 *val = ppb_rfifo(ppbus);
531                 break;
532         case PPISDATA:                  /* set data register */
533                 ppb_wdtr(ppbus, *val);
534                 break;
535         case PPISSTATUS:                /* set status bits */
536                 ppb_wstr(ppbus, *val);
537                 break;
538         case PPISCTRL:                  /* set control bits */
539                 ppb_wctr(ppbus, *val);
540                 break;
541         case PPISEPPD:                  /* set EPP data bits */
542                 ppb_wepp_D(ppbus, *val);
543                 break;
544         case PPISECR:                   /* set ECP bits */
545                 ppb_wecr(ppbus, *val);
546                 break;
547         case PPISFIFO:                  /* write FIFO */
548                 ppb_wfifo(ppbus, *val);
549                 break;
550         case PPIGEPPA:                  /* get EPP address bits */
551                 *val = ppb_repp_A(ppbus);
552                 break;
553         case PPISEPPA:                  /* set EPP address bits */
554                 ppb_wepp_A(ppbus, *val);
555                 break;
556         default:
557                 error = ENOTTY;
558                 break;
559         }
560     
561         return (error);
562 }
563
564 static device_method_t ppi_methods[] = {
565         /* device interface */
566         DEVMETHOD(device_identify,      ppi_identify),
567         DEVMETHOD(device_probe,         ppi_probe),
568         DEVMETHOD(device_attach,        ppi_attach),
569
570         { 0, 0 }
571 };
572
573 static driver_t ppi_driver = {
574         "ppi",
575         ppi_methods,
576         sizeof(struct ppi_data),
577 };
578 DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0);
579 MODULE_DEPEND(ppi, ppbus, 1, 1, 1);