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