xref: /dragonfly/sys/dev/misc/cmx/cmx.c (revision fcf6efefc03a35111797b109fa4994034ebe39ba)
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 $
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>
46 #include <sys/event.h>
47 #include <sys/conf.h>
48 #include <sys/fcntl.h>
49 #include <sys/uio.h>
50 #include <sys/types.h>
51 #include <sys/lock.h>
52 #include <sys/device.h>
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...) \
64           device_printf(dev, "%s: " fmt, __func__, ##args)
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
79 static char         BSRBITS[] = "\020"
80           "\01BULK_OUT_FULL"            /* 0x01 */
81           "\02BULK_IN_FULL"             /* 0x02 */
82           "\03(0x04)";                            /* 0x04 */
83 #ifdef CMX_INTR
84 static 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 */
94 static 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 */
104 static 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 
124 devclass_t cmx_devclass;
125 
126 static d_open_t               cmx_open;
127 static d_close_t    cmx_close;
128 static d_read_t               cmx_read;
129 static d_write_t    cmx_write;
130 static d_kqfilter_t cmx_kqfilter;
131 #ifdef CMX_INTR
132 static void                   cmx_intr(void *arg);
133 #endif
134 
135 static void cmx_filter_detach(struct knote *);
136 static int cmx_filter_read(struct knote *, long);
137 static int cmx_filter_write(struct knote *, long);
138 
139 static struct dev_ops cmx_ops = {
140           { "cmx", 0, 0 },
141           .d_open = cmx_open,
142           .d_close =          cmx_close,
143           .d_read = cmx_read,
144           .d_write =          cmx_write,
145           .d_kqfilter =       cmx_kqfilter
146 };
147 
148 /*
149  * Initialize the softc structure.  Must be called from
150  * the bus specific device allocation routine.
151  */
152 void
cmx_init_softc(device_t dev)153 cmx_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  */
168 int
cmx_alloc_resources(device_t dev)169 cmx_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  */
208 void
cmx_release_resources(device_t dev)209 cmx_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  */
241 int
cmx_attach(device_t dev)242 cmx_attach(device_t dev)
243 {
244           struct cmx_softc *sc = device_get_softc(dev);
245 
246           if (!sc || sc->dying)
247                     return ENXIO;
248 
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  */
265 int
cmx_detach(device_t dev)266 cmx_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);
280                     KNOTE(&sc->kq.ki_note, 0);
281           } else {
282                     CMX_UNLOCK(sc);
283           }
284 
285           wakeup(sc);
286           DEBUG_printf(dev, "releasing resources\n");
287           cmx_release_resources(dev);
288           dev_ops_remove_minor(&cmx_ops, device_get_unit(dev));
289 
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  */
302 static inline int
cmx_wait_BSR(struct cmx_softc * sc,uint8_t flags,int test)303 cmx_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  */
338 static inline int
cmx_sync_write_SCR(struct cmx_softc * sc,uint8_t val)339 cmx_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  */
360 static inline unsigned long
cmx_timeout_by_cmd(uint8_t cmd)361 cmx_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,
388  * wakes up the processes which are waiting in select()/poll()/kevent().
389  * Otherwise, reschedules itself with a delay of POLL_TICKS.
390  */
391 static void
cmx_tick(void * xsc)392 cmx_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);
400                     DEBUG_printf(sc->dev, "BSR=%pb%i\n", BSRBITS, bsr);
401                     if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
402                               sc->polling = 0;
403                               KNOTE(&sc->kq.ki_note, 0);
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  */
415 static int
cmx_open(struct dev_open_args * ap)416 cmx_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 
433           DEBUG_printf(sc->dev, "open (flags=%pb%i thread=%p)\n",
434                               MODEBITS, ap->a_oflags, curthread);
435           return 0;
436 }
437 
438 /*
439  * Close the character device.
440  */
441 static int
cmx_close(struct dev_close_args * ap)442 cmx_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);
461                     KNOTE(&sc->kq.ki_note, 0);
462                     CMX_LOCK(sc);
463           }
464           sc->open = 0;
465           CMX_UNLOCK(sc);
466 
467           DEBUG_printf(sc->dev, "close (flags=%pb%i thread=%p)\n",
468                               MODEBITS, ap->a_fflag, curthread);
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  */
479 static int
cmx_read(struct dev_read_args * ap)480 cmx_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 
493           DEBUG_printf(sc->dev, "called (len=%d flag=%pb%i)\n",
494                     uio->uio_resid, MODEBITS, ap->a_ioflag);
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);
502                     KNOTE(&sc->kq.ki_note, 0);
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  */
582 static int
cmx_write(struct dev_write_args * ap)583 cmx_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 
594           DEBUG_printf(sc->dev, "called (len=%d flag=%pb%i)\n",
595                               uio->uio_resid, MODEBITS, ap->a_ioflag);
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 
645 static struct filterops cmx_read_filterops =
646           { FILTEROP_ISFD, NULL, cmx_filter_detach, cmx_filter_read };
647 static struct filterops cmx_write_filterops =
648           { FILTEROP_ISFD, NULL, cmx_filter_detach, cmx_filter_write };
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  */
655 static int
cmx_kqfilter(struct dev_kqfilter_args * ap)656 cmx_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:
677                     ap->a_result = EOPNOTSUPP;
678                     return (0);
679           }
680 
681           klist = &sc->kq.ki_note;
682           knote_insert(klist, kn);
683 
684           return (0);
685 }
686 
687 static void
cmx_filter_detach(struct knote * kn)688 cmx_filter_detach(struct knote *kn)
689 {
690           struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
691           struct klist *klist = &sc->kq.ki_note;
692 
693           knote_remove(klist, kn);
694 }
695 
696 static int
cmx_filter_read(struct knote * kn,long hint)697 cmx_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) {
704                     kn->kn_flags |= (EV_EOF | EV_NODATA);
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 
724 static int
cmx_filter_write(struct knote * kn,long hint)725 cmx_filter_write(struct knote *kn, long hint)
726 {
727           return (1);
728 }
729 
730 #ifdef CMX_INTR
731 /*
732  * Interrupt handler.  Currently has no function except to
733  * print register status (if debugging is also enabled).
734  */
735 static void
cmx_intr(void * arg)736 cmx_intr(void *arg)
737 {
738           struct cmx_softc *sc = (struct cmx_softc *)arg;
739 
740           if (sc == NULL || sc->dying)
741                     return;
742 
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));
746 
747           return;
748 }
749 #endif
750 
751