iwn{,fw}.4: Remove trailing whitespace and an unneeded .Pp
[dragonfly.git] / sys / dev / misc / cmx / cmx.c
CommitLineData
c4bf625e
HT
1/*-
2 * Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
3 * Copyright (c) 2000-2004 OMNIKEY GmbH (www.omnikey.com)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: src/sys/dev/cmx/cmx.c,v 1.1 2008/03/06 08:09:45 rink Exp $
d54592ee 29 * $DragonFly: src/sys/dev/misc/cmx/cmx.c,v 1.2 2008/08/08 18:33:11 hasso Exp $
c4bf625e
HT
30 */
31
32/*
33 * OMNIKEY CardMan 4040 a.k.a. CardMan eXtended (cmx) driver.
34 * This is a PCMCIA based smartcard reader which seems to work
35 * like an I/O port mapped USB CCID smartcard device.
36 *
37 * I/O originally based on Linux driver version 1.1.0 by OMNIKEY.
38 * Dual GPL/BSD. Almost all of the code has been rewritten.
39 * $Omnikey: cm4040_cs.c,v 1.7 2004/10/04 09:08:50 jp Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/sockio.h>
46#include <sys/mbuf.h>
3546e044 47#include <sys/event.h>
c4bf625e
HT
48#include <sys/conf.h>
49#include <sys/fcntl.h>
50#include <sys/uio.h>
51#include <sys/selinfo.h>
52#include <sys/types.h>
53#include <sys/lock.h>
54#include <sys/device.h>
55#include <sys/thread2.h>
56
57#include <sys/module.h>
58#include <sys/bus.h>
59#include <sys/resource.h>
60#include <sys/rman.h>
61
62#include "cmxvar.h"
63#include "cmxreg.h"
64
65#ifdef CMX_DEBUG
66#define DEBUG_printf(dev, fmt, args...) \
67 device_printf(dev, "%s: " fmt, __FUNCTION__, ##args)
68#else
69#define DEBUG_printf(dev, fmt, args...)
70#endif
71
72#define SPIN_COUNT 1000
73#define WAIT_TICKS (hz/100)
74#define POLL_TICKS (hz/10)
75
76/* possibly bogus */
77#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*hz)
78#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*hz)
79#define CCID_DRIVER_MINIMUM_TIMEOUT (3*hz)
80
81#ifdef CMX_DEBUG
82static char BSRBITS[] = "\020"
83 "\01BULK_OUT_FULL" /* 0x01 */
84 "\02BULK_IN_FULL" /* 0x02 */
85 "\03(0x04)"; /* 0x04 */
86#ifdef CMX_INTR
87static char SCRBITS[] = "\020"
88 "\01POWER_DOWN" /* 0x01 */
89 "\02PULSE_INTERRUPT" /* 0x02 */
90 "\03HOST_TO_READER_DONE" /* 0x04 */
91 "\04READER_TO_HOST_DONE" /* 0x08 */
92 "\05ACK_NOTIFY" /* 0x10 */
93 "\06EN_NOTIFY" /* 0x20 */
94 "\07ABORT" /* 0x40 */
95 "\10HOST_TO_READER_START"; /* 0x80 */
96#endif /* CMX_INTR */
97static char POLLBITS[] = "\020"
98 "\01POLLIN" /* 0x0001 */
99 "\02POLLPRI" /* 0x0002 */
100 "\03POLLOUT" /* 0x0004 */
101 "\04POLLERR" /* 0x0008 */
102 "\05POLLHUP" /* 0x0010 */
103 "\06POLLINVAL" /* 0x0020 */
104 "\07POLLRDNORM" /* 0x0040 */
105 "\10POLLRDBAND" /* 0x0080 */
106 "\11POLLWRBAND"; /* 0x0100 */
107static char MODEBITS[] = "\020"
108 "\01READ" /* 0x0001 */
109 "\02WRITE" /* 0x0002 */
110 "\03NONBLOCK" /* 0x0004 */
111 "\04APPEND" /* 0x0008 */
112 "\05SHLOCK" /* 0x0010 */
113 "\06EXLOCK" /* 0x0020 */
114 "\07ASYNC" /* 0x0040 */
115 "\10FSYNC" /* 0x0080 */
116 "\11NOFOLLOW" /* 0x0100 */
117 "\12CREAT" /* 0x0200 */
118 "\13TRUNK" /* 0x0400 */
119 "\14EXCL" /* 0x0800 */
120 "\15(0x1000)" /* 0x1000 */
121 "\16(0x2000)" /* 0x2000 */
122 "\17HASLOCK" /* 0x4000 */
123 "\20NOCTTY" /* 0x8000 */
124 "\21DIRECT"; /* 0x00010000 */
125#endif /* CMX_DEBUG */
126
127devclass_t cmx_devclass;
128
129static d_open_t cmx_open;
130static d_close_t cmx_close;
131static d_read_t cmx_read;
132static d_write_t cmx_write;
3546e044 133static d_kqfilter_t cmx_kqfilter;
c4bf625e
HT
134#ifdef CMX_INTR
135static void cmx_intr(void *arg);
136#endif
137
3546e044
SG
138static void cmx_filter_detach(struct knote *);
139static int cmx_filter_read(struct knote *, long);
140static int cmx_filter_write(struct knote *, long);
141
c4bf625e
HT
142#define CDEV_MAJOR 185
143static struct dev_ops cmx_ops = {
3546e044 144 { "cmx", CDEV_MAJOR, D_KQFILTER },
c4bf625e
HT
145 .d_open = cmx_open,
146 .d_close = cmx_close,
147 .d_read = cmx_read,
148 .d_write = cmx_write,
3546e044 149 .d_kqfilter = cmx_kqfilter
c4bf625e
HT
150};
151
152/*
153 * Initialize the softc structure. Must be called from
154 * the bus specific device allocation routine.
155 */
156void
157cmx_init_softc(device_t dev)
158{
159 struct cmx_softc *sc = device_get_softc(dev);
160 sc->dev = dev;
161 sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
162}
163
164/*
165 * Allocate driver resources. Must be called from the
166 * bus specific device allocation routine. Caller must
167 * ensure to call cmx_release_resources to free the
168 * resources when detaching.
169 * Return zero if successful, and ENOMEM if the resources
170 * could not be allocated.
171 */
172int
173cmx_alloc_resources(device_t dev)
174{
175 struct cmx_softc *sc = device_get_softc(dev);
176#ifdef CMX_INTR
177 int rv;
178#endif
179
180 sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
181 &sc->ioport_rid, RF_ACTIVE);
182 if (!sc->ioport) {
183 device_printf(dev, "failed to allocate io port\n");
184 return ENOMEM;
185 }
186 sc->bst = rman_get_bustag(sc->ioport);
187 sc->bsh = rman_get_bushandle(sc->ioport);
188
189#ifdef CMX_INTR
190 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
191 &sc->irq_rid, RF_ACTIVE);
192 if (!sc->irq) {
193 device_printf(dev, "failed to allocate irq\n");
194 return ENOMEM;
195 }
196 if ((rv = bus_setup_intr(dev, sc->irq, 0, cmx_intr, sc,
197 &sc->ih, NULL)) != 0) {
198 device_printf(dev, "failed to set up irq\n");
199 return ENOMEM;
200 }
201#endif
202
203 lockinit(&sc->mtx, "cmx softc lock", 0, LK_CANRECURSE);
204 callout_init(&sc->ch);
205
206 return 0;
207}
208
209/*
210 * Release the resources allocated by cmx_allocate_resources.
211 */
212void
213cmx_release_resources(device_t dev)
214{
215 struct cmx_softc *sc = device_get_softc(dev);
216
217 lockuninit(&sc->mtx);
218
219#ifdef CMX_INTR
220 if (sc->ih) {
221 bus_teardown_intr(dev, sc->irq, sc->ih);
222 sc->ih = NULL;
223 }
224 if (sc->irq) {
225 bus_release_resource(dev, SYS_RES_IRQ,
226 sc->irq_rid, sc->irq);
227 sc->irq = NULL;
228 }
229#endif
230
231 if (sc->ioport) {
232 bus_deactivate_resource(dev, SYS_RES_IOPORT,
233 sc->ioport_rid, sc->ioport);
234 bus_release_resource(dev, SYS_RES_IOPORT,
235 sc->ioport_rid, sc->ioport);
236 sc->ioport = NULL;
237 }
238 return;
239}
240
241/*
242 * Bus independant device attachment routine. Creates the
243 * character device node.
244 */
245int
246cmx_attach(device_t dev)
247{
248 struct cmx_softc *sc = device_get_softc(dev);
249
250 if (!sc || sc->dying)
251 return ENXIO;
252
c4bf625e
HT
253 sc->cdev = make_dev(&cmx_ops, 0, UID_ROOT, GID_WHEEL, 0600,
254 "cmx%d", device_get_unit(dev));
255 if (!sc->cdev) {
256 device_printf(dev, "failed to create character device\n");
257 return ENOMEM;
258 }
259 sc->cdev->si_drv1 = sc;
260
261 return 0;
262}
263
264/*
265 * Bus independant device detachment routine. Makes sure all
266 * allocated resources are freed, callouts disabled and waiting
267 * processes unblocked.
268 */
269int
270cmx_detach(device_t dev)
271{
272 struct cmx_softc *sc = device_get_softc(dev);
273
274 DEBUG_printf(dev, "called\n");
275
276 sc->dying = 1;
277
278 CMX_LOCK(sc);
279 if (sc->polling) {
280 DEBUG_printf(sc->dev, "disabling polling\n");
281 callout_stop(&sc->ch);
282 sc->polling = 0;
283 CMX_UNLOCK(sc);
37fcf290 284 KNOTE(&sc->sel.si_note, 0);
c4bf625e
HT
285 } else {
286 CMX_UNLOCK(sc);
287 }
288
289 wakeup(sc);
c4bf625e
HT
290 DEBUG_printf(dev, "releasing resources\n");
291 cmx_release_resources(dev);
cd29885a 292 dev_ops_remove_minor(&cmx_ops, device_get_unit(dev));
d54592ee 293
c4bf625e
HT
294 return 0;
295}
296
297/*
298 * Wait for buffer status register events. If test is non-zero,
299 * wait until flags are set, otherwise wait until flags are unset.
300 * Will spin SPIN_COUNT times, then sleep until timeout is reached.
301 * Returns zero if event happened, EIO if the timeout was reached,
302 * and ENXIO if the device was detached in the meantime. When that
303 * happens, the caller must quit immediately, since a detach is
304 * in progress.
305 */
306static inline int
307cmx_wait_BSR(struct cmx_softc *sc, uint8_t flags, int test)
308{
309 int rv;
310
311 for (int i = 0; i < SPIN_COUNT; i++) {
312 if (cmx_test_BSR(sc, flags, test))
313 return 0;
314 }
315
316 for (int i = 0; i * WAIT_TICKS < sc->timeout; i++) {
317 if (cmx_test_BSR(sc, flags, test))
318 return 0;
319 rv = tsleep(sc, PCATCH, "cmx", WAIT_TICKS);
320 /*
321 * Currently, the only reason for waking up with
322 * rv == 0 is when we are detaching, in which
323 * case sc->dying is always 1.
324 */
325 if (sc->dying)
326 return ENXIO;
327 if (rv != EAGAIN)
328 return rv;
329 }
330
331 /* timeout */
332 return EIO;
333}
334
335/*
336 * Set the sync control register to val. Before and after writing
337 * to the SCR, we wait for the BSR to not signal BULK_OUT_FULL.
338 * Returns zero if successful, or whatever errors cmx_wait_BSR can
339 * return. ENXIO signals that the device has been detached in the
340 * meantime, and that we should leave the kernel immediately.
341 */
342static inline int
343cmx_sync_write_SCR(struct cmx_softc *sc, uint8_t val)
344{
345 int rv = 0;
346
347 if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
348 return rv;
349 }
350
351 cmx_write_SCR(sc, val);
352
353 if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
354 return rv;
355 }
356
357 return 0;
358}
359
360/*
361 * Returns a suitable timeout value based on the given command byte.
362 * Some commands appear to need longer timeout values than others.
363 */
364static inline unsigned long
365cmx_timeout_by_cmd(uint8_t cmd)
366{
367 switch (cmd) {
368 case CMD_PC_TO_RDR_XFRBLOCK:
369 case CMD_PC_TO_RDR_SECURE:
370 case CMD_PC_TO_RDR_TEST_SECURE:
371 case CMD_PC_TO_RDR_OK_SECURE:
372 return CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
373
374 case CMD_PC_TO_RDR_ICCPOWERON:
375 return CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
376
377 case CMD_PC_TO_RDR_GETSLOTSTATUS:
378 case CMD_PC_TO_RDR_ICCPOWEROFF:
379 case CMD_PC_TO_RDR_GETPARAMETERS:
380 case CMD_PC_TO_RDR_RESETPARAMETERS:
381 case CMD_PC_TO_RDR_SETPARAMETERS:
382 case CMD_PC_TO_RDR_ESCAPE:
383 case CMD_PC_TO_RDR_ICCCLOCK:
384 default:
385 return CCID_DRIVER_MINIMUM_TIMEOUT;
386 }
387}
388
389/*
390 * Periodical callout routine, polling the reader for data
391 * availability. If the reader signals data ready for reading,
392 * wakes up the processes which are waiting in select()/poll().
393 * Otherwise, reschedules itself with a delay of POLL_TICKS.
394 */
395static void
396cmx_tick(void *xsc)
397{
398 struct cmx_softc *sc = xsc;
399 uint8_t bsr;
400
401 CMX_LOCK(sc);
402 if (sc->polling && !sc->dying) {
403 bsr = cmx_read_BSR(sc);
404 DEBUG_printf(sc->dev, "BSR=%b\n", bsr, BSRBITS);
405 if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
406 sc->polling = 0;
37fcf290 407 KNOTE(&sc->sel.si_note, 0);
c4bf625e
HT
408 } else {
409 callout_reset(&sc->ch, POLL_TICKS, cmx_tick, sc);
410 }
411 }
412 CMX_UNLOCK(sc);
413}
414
415/*
416 * Open the character device. Only a single process may open the
417 * device at a time.
418 */
419static int
420cmx_open(struct dev_open_args *ap)
421{
422 cdev_t dev = ap->a_head.a_dev;
423 struct cmx_softc *sc;
424
425 sc = devclass_get_softc(cmx_devclass, minor(dev));
426 if (sc == NULL || sc->dying)
427 return ENXIO;
428
429 CMX_LOCK(sc);
430 if (sc->open) {
431 CMX_UNLOCK(sc);
432 return EBUSY;
433 }
434 sc->open = 1;
435 CMX_UNLOCK(sc);
436
437 DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n",
438 ap->a_oflags, MODEBITS, curthread);
439 return 0;
440}
441
442/*
443 * Close the character device.
444 */
445static int
446cmx_close(struct dev_close_args *ap)
447{
448 cdev_t dev = ap->a_head.a_dev;
449 struct cmx_softc *sc;
450
451 sc = devclass_get_softc(cmx_devclass, minor(dev));
452 if (sc == NULL || sc->dying)
453 return ENXIO;
454
455 CMX_LOCK(sc);
456 if (!sc->open) {
457 CMX_UNLOCK(sc);
458 return EINVAL;
459 }
460 if (sc->polling) {
461 DEBUG_printf(sc->dev, "disabling polling\n");
462 callout_stop(&sc->ch);
463 sc->polling = 0;
464 CMX_UNLOCK(sc);
37fcf290 465 KNOTE(&sc->sel.si_note, 0);
c4bf625e
HT
466 CMX_LOCK(sc);
467 }
468 sc->open = 0;
469 CMX_UNLOCK(sc);
470
471 DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n",
472 ap->a_fflag, MODEBITS, curthread);
473 return 0;
474}
475
476/*
477 * Read from the character device.
478 * Returns zero if successful, ENXIO if dying, EINVAL if an attempt
479 * was made to read less than CMX_MIN_RDLEN bytes or less than the
480 * device has available, or any of the errors that cmx_sync_write_SCR
481 * can return. Partial reads are not supported.
482 */
483static int
484cmx_read(struct dev_read_args *ap)
485{
486 cdev_t dev = ap->a_head.a_dev;
487 struct cmx_softc *sc;
488 struct uio *uio = ap->a_uio;
489 unsigned long bytes_left;
490 uint8_t uc;
491 int rv, amnt, offset;
492
493 sc = devclass_get_softc(cmx_devclass, minor(dev));
494 if (sc == NULL || sc->dying)
495 return ENXIO;
496
497 DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
498 uio->uio_resid, ap->a_ioflag, MODEBITS);
499
500 CMX_LOCK(sc);
501 if (sc->polling) {
502 DEBUG_printf(sc->dev, "disabling polling\n");
503 callout_stop(&sc->ch);
504 sc->polling = 0;
505 CMX_UNLOCK(sc);
37fcf290 506 KNOTE(&sc->sel.si_note, 0);
c4bf625e
HT
507 } else {
508 CMX_UNLOCK(sc);
509 }
510
511 if (uio->uio_resid == 0) {
512 return 0;
513 }
514
515 if (uio->uio_resid < CMX_MIN_RDLEN) {
516 return EINVAL;
517 }
518
519 if (ap->a_ioflag & O_NONBLOCK) {
520 if (cmx_test_BSR(sc, BSR_BULK_IN_FULL, 0)) {
521 return EAGAIN;
522 }
523 }
524
525 for (int i = 0; i < 5; i++) {
526 if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
527 return rv;
528 }
529 sc->buf[i] = cmx_read_DTR(sc);
530 DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", i, sc->buf[i]);
531 }
532
533 bytes_left = CMX_MIN_RDLEN +
534 (0x000000FF&((char)sc->buf[1])) +
535 (0x0000FF00&((char)sc->buf[2] << 8)) +
536 (0x00FF0000&((char)sc->buf[3] << 16)) +
537 (0xFF000000&((char)sc->buf[4] << 24));
538 DEBUG_printf(sc->dev, "msgsz=%lu\n", bytes_left);
539
540 if (uio->uio_resid < bytes_left) {
541 return EINVAL;
542 }
543
544 offset = 5; /* prefetched header */
545 while (bytes_left > 0) {
546 amnt = MIN(bytes_left, sizeof(sc->buf));
547
548 for (int i = offset; i < amnt; i++) {
549 if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1))!=0) {
550 return rv;
551 }
552 sc->buf[i] = cmx_read_DTR(sc);
553 DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
554 i, sc->buf[i]);
555 }
556
557 if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
558 DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
559 return rv;
560 }
561
562 if (offset)
563 offset = 0;
564 bytes_left -= amnt;
565 }
566
567 if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
568 return rv;
569 }
570
571 if ((rv = cmx_sync_write_SCR(sc, SCR_READER_TO_HOST_DONE)) != 0) {
572 return rv;
573 }
574
575 uc = cmx_read_DTR(sc);
576 DEBUG_printf(sc->dev, "success (DTR=%02x)\n", uc);
577 return 0;
578}
579
580/*
581 * Write to the character device.
582 * Returns zero if successful, NXIO if dying, EINVAL if less data
583 * written than CMX_MIN_WRLEN, or any of the errors that cmx_sync_SCR
584 * can return.
585 */
586static int
587cmx_write(struct dev_write_args *ap)
588{
589 cdev_t dev = ap->a_head.a_dev;
590 struct cmx_softc *sc;
591 struct uio *uio = ap->a_uio;
592 int rv, amnt;
593
594 sc = devclass_get_softc(cmx_devclass, minor(dev));
595 if (sc == NULL || sc->dying)
596 return ENXIO;
597
598 DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
599 uio->uio_resid, ap->a_ioflag, MODEBITS);
600
601 if (uio->uio_resid == 0) {
602 return 0;
603 }
604
605 if (uio->uio_resid < CMX_MIN_WRLEN) {
606 return EINVAL;
607 }
608
609 if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_START)) != 0) {
610 return rv;
611 }
612
613 sc->timeout = 0;
614 while (uio->uio_resid > 0) {
615 amnt = MIN(uio->uio_resid, sizeof(sc->buf));
616
617 if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
618 DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
619 /* wildly guessed attempt to notify device */
620 sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
621 cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE);
622 return rv;
623 }
624
625 if (sc->timeout == 0) {
626 sc->timeout = cmx_timeout_by_cmd(sc->buf[0]);
627 DEBUG_printf(sc->dev, "cmd=%02x timeout=%lu\n",
628 sc->buf[0], sc->timeout);
629 }
630
631 for (int i = 0; i < amnt; i++) {
632 if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0))!=0) {
633 return rv;
634 }
635 cmx_write_DTR(sc, sc->buf[i]);
636 DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
637 i, sc->buf[i]);
638 }
639 }
640
641 if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE)) != 0) {
642 return rv;
643 }
644
645 DEBUG_printf(sc->dev, "success\n");
646 return 0;
647}
648
3546e044
SG
649static struct filterops cmx_read_filterops =
650 { 1, NULL, cmx_filter_detach, cmx_filter_read };
651static struct filterops cmx_write_filterops =
652 { 1, NULL, cmx_filter_detach, cmx_filter_write };
653
654/*
655 * Kevent handler. Writing is always possible, reading is only possible
656 * if BSR_BULK_IN_FULL is set. Will start the cmx_tick callout and
657 * set sc->polling.
658 */
659static int
660cmx_kqfilter(struct dev_kqfilter_args *ap)
661{
662 cdev_t dev = ap->a_head.a_dev;
663 struct knote *kn = ap->a_kn;
664 struct cmx_softc *sc;
665 struct klist *klist;
666
667 ap->a_result = 0;
668
669 sc = devclass_get_softc(cmx_devclass, minor(dev));
670
671 switch (kn->kn_filter) {
672 case EVFILT_READ:
673 kn->kn_fop = &cmx_read_filterops;
674 kn->kn_hook = (caddr_t)sc;
675 break;
676 case EVFILT_WRITE:
677 kn->kn_fop = &cmx_write_filterops;
678 kn->kn_hook = (caddr_t)sc;
679 break;
680 default:
b287d649 681 ap->a_result = EOPNOTSUPP;
3546e044
SG
682 return (0);
683 }
684
685 crit_enter();
686 klist = &sc->sel.si_note;
687 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
688 crit_exit();
689
690 return (0);
691}
692
693static void
694cmx_filter_detach(struct knote *kn)
695{
696 struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
697 struct klist *klist;
698
699 crit_enter();
700 klist = &sc->sel.si_note;
701 SLIST_REMOVE(klist, kn, knote, kn_selnext);
702 crit_exit();
703}
704
705static int
706cmx_filter_read(struct knote *kn, long hint)
707{
708 struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
709 int ready = 0;
710 uint8_t bsr = 0;
711
712 if (sc == NULL || sc->dying) {
713 kn->kn_flags |= EV_EOF;
714 return (1);
715 }
716
717 bsr = cmx_read_BSR(sc);
718 if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
719 ready = 1;
720 } else {
721 CMX_LOCK(sc);
722 if (!sc->polling) {
723 sc->polling = 1;
724 callout_reset(&sc->ch, POLL_TICKS,
725 cmx_tick, sc);
726 }
727 CMX_UNLOCK(sc);
728 }
729
730 return (ready);
731}
732
733static int
734cmx_filter_write(struct knote *kn, long hint)
735{
736 return (1);
737}
738
c4bf625e
HT
739#ifdef CMX_INTR
740/*
741 * Interrupt handler. Currently has no function except to
742 * print register status (if debugging is also enabled).
743 */
744static void
745cmx_intr(void *arg)
746{
747 struct cmx_softc *sc = (struct cmx_softc *)arg;
748
749 if (sc == NULL || sc->dying)
750 return;
751
752 DEBUG_printf(sc->dev, "received interrupt (SCR=%b BSR=%b)\n",
753 cmx_read_SCR(sc), SCRBITS,
754 cmx_read_BSR(sc), BSRBITS);
755
756 return;
757}
758#endif
759