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