File:
[DragonFly] /
src /
sys /
dev /
misc /
ppi /
ppi.c
Revision
1.7:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:17 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
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: * $FreeBSD: src/sys/dev/ppbus/ppi.c,v 1.21.2.3 2000/08/07 18:24:43 peter Exp $
27: * $DragonFly: src/sys/dev/misc/ppi/ppi.c,v 1.7 2004/05/13 23:49:17 dillon Exp $
28: *
29: */
30: #include "opt_ppb_1284.h"
31:
32: #include <sys/param.h>
33: #include <sys/systm.h>
34: #include <sys/module.h>
35: #include <sys/bus.h>
36: #include <sys/conf.h>
37: #include <sys/kernel.h>
38: #include <sys/uio.h>
39: #include <sys/fcntl.h>
40:
41: #include <machine/clock.h>
42: #include <machine/bus.h>
43: #include <machine/resource.h>
44: #include <sys/rman.h>
45:
46: #include <bus/ppbus/ppbconf.h>
47: #include <bus/ppbus/ppb_msq.h>
48:
49: #ifdef PERIPH_1284
50: #include <bus/ppbus/ppb_1284.h>
51: #endif
52:
53: #include "ppi.h"
54:
55: #include "ppbus_if.h"
56:
57: #include <bus/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: #define CDEV_MAJOR 82
94: static struct cdevsw ppi_cdevsw = {
95: /* name */ "ppi",
96: /* maj */ CDEV_MAJOR,
97: /* flags */ 0,
98: /* port */ NULL,
99: /* clone */ NULL,
100:
101: /* open */ ppiopen,
102: /* close */ ppiclose,
103: /* read */ ppiread,
104: /* write */ ppiwrite,
105: /* ioctl */ ppiioctl,
106: /* poll */ nopoll,
107: /* mmap */ nommap,
108: /* strategy */ nostrategy,
109: /* dump */ nodump,
110: /* psize */ nopsize
111: };
112:
113: #ifdef PERIPH_1284
114:
115: static void
116: ppi_enable_intr(device_t ppidev)
117: {
118: char r;
119: device_t ppbus = device_get_parent(ppidev);
120:
121: r = ppb_rctr(ppbus);
122: ppb_wctr(ppbus, r | IRQENABLE);
123:
124: return;
125: }
126:
127: static void
128: ppi_disable_intr(device_t ppidev)
129: {
130: char r;
131: device_t ppbus = device_get_parent(ppidev);
132:
133: r = ppb_rctr(ppbus);
134: ppb_wctr(ppbus, r & ~IRQENABLE);
135:
136: return;
137: }
138:
139: #endif /* PERIPH_1284 */
140:
141: static void
142: ppi_identify(driver_t *driver, device_t parent)
143: {
144:
145: BUS_ADD_CHILD(parent, 0, "ppi", 0);
146: }
147:
148: /*
149: * ppi_probe()
150: */
151: static int
152: ppi_probe(device_t dev)
153: {
154: struct ppi_data *ppi;
155:
156: /* probe is always ok */
157: device_set_desc(dev, "Parallel I/O");
158:
159: ppi = DEVTOSOFTC(dev);
160: bzero(ppi, sizeof(struct ppi_data));
161:
162: return (0);
163: }
164:
165: /*
166: * ppi_attach()
167: */
168: static int
169: ppi_attach(device_t dev)
170: {
171: #ifdef PERIPH_1284
172: uintptr_t irq;
173: int zero = 0;
174: struct ppi_data *ppi = DEVTOSOFTC(dev);
175:
176: /* retrive the irq */
177: BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq);
178:
179: /* declare our interrupt handler */
180: ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ,
181: &zero, irq, irq, 1, RF_ACTIVE);
182: #endif /* PERIPH_1284 */
183:
184: make_dev(&ppi_cdevsw, device_get_unit(dev), /* XXX cleanup */
185: UID_ROOT, GID_WHEEL,
186: 0600, "ppi%d", device_get_unit(dev));
187:
188: return (0);
189: }
190:
191: #ifdef PERIPH_1284
192: /*
193: * Cable
194: * -----
195: *
196: * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
197: *
198: * nStrobe <-> nAck 1 <-> 10
199: * nAutofd <-> Busy 11 <-> 14
200: * nSelectin <-> Select 17 <-> 13
201: * nInit <-> nFault 15 <-> 16
202: *
203: */
204: static void
205: ppiintr(void *arg)
206: {
207: device_t ppidev = (device_t)arg;
208: device_t ppbus = device_get_parent(ppidev);
209: struct ppi_data *ppi = DEVTOSOFTC(ppidev);
210:
211: ppi_disable_intr(ppidev);
212:
213: switch (ppb_1284_get_state(ppbus)) {
214:
215: /* accept IEEE1284 negociation then wakeup an waiting process to
216: * continue negociation at process level */
217: case PPB_FORWARD_IDLE:
218: /* Event 1 */
219: if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
220: (SELECT | nBUSY)) {
221: /* IEEE1284 negociation */
222: #ifdef DEBUG_1284
223: printf("N");
224: #endif
225:
226: /* Event 2 - prepare for reading the ext. value */
227: ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
228:
229: ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
230:
231: } else {
232: #ifdef DEBUG_1284
233: printf("0x%x", ppb_rstr(ppbus));
234: #endif
235: ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
236: break;
237: }
238:
239: /* wake up any process waiting for negociation from
240: * remote master host */
241:
242: /* XXX should set a variable to warn the process about
243: * the interrupt */
244:
245: wakeup(ppi);
246: break;
247: default:
248: #ifdef DEBUG_1284
249: printf("?%d", ppb_1284_get_state(ppbus));
250: #endif
251: ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
252: ppb_set_mode(ppbus, PPB_COMPATIBLE);
253: break;
254: }
255:
256: ppi_enable_intr(ppidev);
257:
258: return;
259: }
260: #endif /* PERIPH_1284 */
261:
262: static int
263: ppiopen(dev_t dev, int flags, int fmt, d_thread_t *td)
264: {
265: u_int unit = minor(dev);
266: struct ppi_data *ppi = UNITOSOFTC(unit);
267: device_t ppidev = UNITODEVICE(unit);
268: device_t ppbus = device_get_parent(ppidev);
269: int res;
270:
271: if (!ppi)
272: return (ENXIO);
273:
274: if (!(ppi->ppi_flags & HAVE_PPBUS)) {
275: if ((res = ppb_request_bus(ppbus, ppidev,
276: (flags & O_NONBLOCK) ? PPB_DONTWAIT :
277: (PPB_WAIT | PPB_INTR))))
278: return (res);
279:
280: ppi->ppi_flags |= HAVE_PPBUS;
281:
282: #ifdef PERIPH_1284
283: if (ppi->intr_resource) {
284: /* register our interrupt handler */
285: BUS_SETUP_INTR(device_get_parent(ppidev), ppidev, ppi->intr_resource,
286: INTR_TYPE_TTY, ppiintr, dev, &ppi->intr_cookie);
287: }
288: #endif /* PERIPH_1284 */
289: }
290: ppi->ppi_count += 1;
291:
292: return (0);
293: }
294:
295: static int
296: ppiclose(dev_t dev, int flags, int fmt, d_thread_t *td)
297: {
298: u_int unit = minor(dev);
299: struct ppi_data *ppi = UNITOSOFTC(unit);
300: device_t ppidev = UNITODEVICE(unit);
301: device_t ppbus = device_get_parent(ppidev);
302:
303: ppi->ppi_count --;
304: if (!ppi->ppi_count) {
305:
306: #ifdef PERIPH_1284
307: switch (ppb_1284_get_state(ppbus)) {
308: case PPB_PERIPHERAL_IDLE:
309: ppb_peripheral_terminate(ppbus, 0);
310: break;
311: case PPB_REVERSE_IDLE:
312: case PPB_EPP_IDLE:
313: case PPB_ECP_FORWARD_IDLE:
314: default:
315: ppb_1284_terminate(ppbus);
316: break;
317: }
318: #endif /* PERIPH_1284 */
319:
320: /* unregistration of interrupt forced by release */
321: ppb_release_bus(ppbus, ppidev);
322:
323: ppi->ppi_flags &= ~HAVE_PPBUS;
324: }
325:
326: return (0);
327: }
328:
329: /*
330: * ppiread()
331: *
332: * IEEE1284 compliant read.
333: *
334: * First, try negociation to BYTE then NIBBLE mode
335: * If no data is available, wait for it otherwise transfer as much as possible
336: */
337: static int
338: ppiread(dev_t dev, struct uio *uio, int ioflag)
339: {
340: #ifdef PERIPH_1284
341: u_int unit = minor(dev);
342: struct ppi_data *ppi = UNITOSOFTC(unit);
343: device_t ppidev = UNITODEVICE(unit);
344: device_t ppbus = device_get_parent(ppidev);
345: int len, error = 0;
346:
347: switch (ppb_1284_get_state(ppbus)) {
348: case PPB_PERIPHERAL_IDLE:
349: ppb_peripheral_terminate(ppbus, 0);
350: /* fall throught */
351:
352: case PPB_FORWARD_IDLE:
353: /* if can't negociate NIBBLE mode then try BYTE mode,
354: * the peripheral may be a computer
355: */
356: if ((ppb_1284_negociate(ppbus,
357: ppi->ppi_mode = PPB_NIBBLE, 0))) {
358:
359: /* XXX Wait 2 seconds to let the remote host some
360: * time to terminate its interrupt
361: */
362: tsleep(ppi, 0, "ppiread", 2*hz);
363:
364: if ((error = ppb_1284_negociate(ppbus,
365: ppi->ppi_mode = PPB_BYTE, 0)))
366: return (error);
367: }
368: break;
369:
370: case PPB_REVERSE_IDLE:
371: case PPB_EPP_IDLE:
372: case PPB_ECP_FORWARD_IDLE:
373: default:
374: break;
375: }
376:
377: #ifdef DEBUG_1284
378: printf("N");
379: #endif
380: /* read data */
381: len = 0;
382: while (uio->uio_resid) {
383: if ((error = ppb_1284_read(ppbus, ppi->ppi_mode,
384: ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
385: &len))) {
386: goto error;
387: }
388:
389: if (!len)
390: goto error; /* no more data */
391:
392: #ifdef DEBUG_1284
393: printf("d");
394: #endif
395: if ((error = uiomove(ppi->ppi_buffer, len, uio)))
396: goto error;
397: }
398:
399: error:
400:
401: #else /* PERIPH_1284 */
402: int error = ENODEV;
403: #endif
404:
405: return (error);
406: }
407:
408: /*
409: * ppiwrite()
410: *
411: * IEEE1284 compliant write
412: *
413: * Actually, this is the peripheral side of a remote IEEE1284 read
414: *
415: * The first part of the negociation (IEEE1284 device detection) is
416: * done at interrupt level, then the remaining is done by the writing
417: * process
418: *
419: * Once negociation done, transfer data
420: */
421: static int
422: ppiwrite(dev_t dev, struct uio *uio, int ioflag)
423: {
424: #ifdef PERIPH_1284
425: u_int unit = minor(dev);
426: struct ppi_data *ppi = UNITOSOFTC(unit);
427: device_t ppidev = UNITODEVICE(unit);
428: device_t ppbus = device_get_parent(ppidev);
429: int len, error = 0, sent;
430:
431: #if 0
432: int ret;
433:
434: #define ADDRESS MS_PARAM(0, 0, MS_TYP_PTR)
435: #define LENGTH MS_PARAM(0, 1, MS_TYP_INT)
436:
437: struct ppb_microseq msq[] = {
438: { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
439: MS_RET(0)
440: };
441:
442: /* negociate ECP mode */
443: if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
444: printf("ppiwrite: ECP negociation failed\n");
445: }
446:
447: while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
448: uiomove(ppi->ppi_buffer, len, uio);
449:
450: ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
451:
452: error = ppb_MS_microseq(ppbus, msq, &ret);
453: }
454: #endif
455:
456: /* we have to be peripheral to be able to send data, so
457: * wait for the appropriate state
458: */
459: if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
460: ppb_1284_terminate(ppbus);
461:
462: while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
463: /* XXX should check a variable before sleeping */
464: #ifdef DEBUG_1284
465: printf("s");
466: #endif
467:
468: ppi_enable_intr(ppidev);
469:
470: /* sleep until IEEE1284 negociation starts */
471: error = tsleep(ppi, PCATCH, "ppiwrite", 0);
472:
473: switch (error) {
474: case 0:
475: /* negociate peripheral side with BYTE mode */
476: ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
477: break;
478: case EWOULDBLOCK:
479: break;
480: default:
481: goto error;
482: }
483: }
484: #ifdef DEBUG_1284
485: printf("N");
486: #endif
487:
488: /* negociation done, write bytes to master host */
489: while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
490: uiomove(ppi->ppi_buffer, len, uio);
491: if ((error = byte_peripheral_write(ppbus,
492: ppi->ppi_buffer, len, &sent)))
493: goto error;
494: #ifdef DEBUG_1284
495: printf("d");
496: #endif
497: }
498:
499: error:
500:
501: #else /* PERIPH_1284 */
502: int error = ENODEV;
503: #endif
504:
505: return (error);
506: }
507:
508: static int
509: ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, d_thread_t *td)
510: {
511: u_int unit = minor(dev);
512: device_t ppidev = UNITODEVICE(unit);
513: device_t ppbus = device_get_parent(ppidev);
514: int error = 0;
515: u_int8_t *val = (u_int8_t *)data;
516:
517: switch (cmd) {
518:
519: case PPIGDATA: /* get data register */
520: *val = ppb_rdtr(ppbus);
521: break;
522: case PPIGSTATUS: /* get status bits */
523: *val = ppb_rstr(ppbus);
524: break;
525: case PPIGCTRL: /* get control bits */
526: *val = ppb_rctr(ppbus);
527: break;
528: case PPIGEPPD: /* get EPP data bits */
529: *val = ppb_repp_D(ppbus);
530: break;
531: case PPIGECR: /* get ECP bits */
532: *val = ppb_recr(ppbus);
533: break;
534: case PPIGFIFO: /* read FIFO */
535: *val = ppb_rfifo(ppbus);
536: break;
537: case PPISDATA: /* set data register */
538: ppb_wdtr(ppbus, *val);
539: break;
540: case PPISSTATUS: /* set status bits */
541: ppb_wstr(ppbus, *val);
542: break;
543: case PPISCTRL: /* set control bits */
544: ppb_wctr(ppbus, *val);
545: break;
546: case PPISEPPD: /* set EPP data bits */
547: ppb_wepp_D(ppbus, *val);
548: break;
549: case PPISECR: /* set ECP bits */
550: ppb_wecr(ppbus, *val);
551: break;
552: case PPISFIFO: /* write FIFO */
553: ppb_wfifo(ppbus, *val);
554: break;
555: case PPIGEPPA: /* get EPP address bits */
556: *val = ppb_repp_A(ppbus);
557: break;
558: case PPISEPPA: /* set EPP address bits */
559: ppb_wepp_A(ppbus, *val);
560: break;
561: default:
562: error = ENOTTY;
563: break;
564: }
565:
566: return (error);
567: }
568:
569: static device_method_t ppi_methods[] = {
570: /* device interface */
571: DEVMETHOD(device_identify, ppi_identify),
572: DEVMETHOD(device_probe, ppi_probe),
573: DEVMETHOD(device_attach, ppi_attach),
574:
575: { 0, 0 }
576: };
577:
578: static driver_t ppi_driver = {
579: "ppi",
580: ppi_methods,
581: sizeof(struct ppi_data),
582: };
583: DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0);