1176868Srink/*- 2176868Srink * Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch> 3176868Srink * Copyright (c) 2000-2004 OMNIKEY GmbH (www.omnikey.com) 4176868Srink * All rights reserved. 5176868Srink * 6176868Srink * Redistribution and use in source and binary forms, with or without 7176868Srink * modification, are permitted provided that the following conditions 8176868Srink * are met: 9176868Srink * 1. Redistributions of source code must retain the above copyright 10176868Srink * notice unmodified, this list of conditions, and the following 11176868Srink * disclaimer. 12176868Srink * 2. Redistributions in binary form must reproduce the above copyright 13176868Srink * notice, this list of conditions and the following disclaimer in the 14176868Srink * documentation and/or other materials provided with the distribution. 15176868Srink * 16176868Srink * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17176868Srink * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18176868Srink * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19176868Srink * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20176868Srink * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21176868Srink * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22176868Srink * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23176868Srink * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24176868Srink * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25176868Srink * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26176868Srink * SUCH DAMAGE. 27176868Srink */ 28176868Srink 29176868Srink#include <sys/cdefs.h> 30176868Srink__FBSDID("$FreeBSD: releng/10.2/sys/dev/cmx/cmx.c 176868 2008-03-06 08:09:45Z rink $"); 31176868Srink 32176868Srink/* 33176868Srink * OMNIKEY CardMan 4040 a.k.a. CardMan eXtended (cmx) driver. 34176868Srink * This is a PCMCIA based smartcard reader which seems to work 35176868Srink * like an I/O port mapped USB CCID smartcard device. 36176868Srink * 37176868Srink * I/O originally based on Linux driver version 1.1.0 by OMNIKEY. 38176868Srink * Dual GPL/BSD. Almost all of the code has been rewritten. 39176868Srink * $Omnikey: cm4040_cs.c,v 1.7 2004/10/04 09:08:50 jp Exp $ 40176868Srink */ 41176868Srink 42176868Srink#include <sys/param.h> 43176868Srink#include <sys/systm.h> 44176868Srink#include <sys/kernel.h> 45176868Srink#include <sys/sockio.h> 46176868Srink#include <sys/mbuf.h> 47176868Srink#include <sys/poll.h> 48176868Srink#include <sys/conf.h> 49176868Srink#include <sys/fcntl.h> 50176868Srink#include <sys/uio.h> 51176868Srink#include <sys/selinfo.h> 52176868Srink 53176868Srink#include <sys/module.h> 54176868Srink#include <sys/bus.h> 55176868Srink 56176868Srink#include <machine/bus.h> 57176868Srink#include <machine/resource.h> 58176868Srink#include <sys/rman.h> 59176868Srink 60176868Srink#include <dev/cmx/cmxvar.h> 61176868Srink#include <dev/cmx/cmxreg.h> 62176868Srink 63176868Srink#ifdef CMX_DEBUG 64176868Srink#define DEBUG_printf(dev, fmt, args...) \ 65176868Srink device_printf(dev, "%s: " fmt, __FUNCTION__, ##args) 66176868Srink#else 67176868Srink#define DEBUG_printf(dev, fmt, args...) 68176868Srink#endif 69176868Srink 70176868Srink#define SPIN_COUNT 1000 71176868Srink#define WAIT_TICKS (hz/100) 72176868Srink#define POLL_TICKS (hz/10) 73176868Srink 74176868Srink/* possibly bogus */ 75176868Srink#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*hz) 76176868Srink#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*hz) 77176868Srink#define CCID_DRIVER_MINIMUM_TIMEOUT (3*hz) 78176868Srink 79176868Srink#ifdef CMX_DEBUG 80176868Srinkstatic char BSRBITS[] = "\020" 81176868Srink "\01BULK_OUT_FULL" /* 0x01 */ 82176868Srink "\02BULK_IN_FULL" /* 0x02 */ 83176868Srink "\03(0x04)"; /* 0x04 */ 84176868Srink#ifdef CMX_INTR 85176868Srinkstatic char SCRBITS[] = "\020" 86176868Srink "\01POWER_DOWN" /* 0x01 */ 87176868Srink "\02PULSE_INTERRUPT" /* 0x02 */ 88176868Srink "\03HOST_TO_READER_DONE" /* 0x04 */ 89176868Srink "\04READER_TO_HOST_DONE" /* 0x08 */ 90176868Srink "\05ACK_NOTIFY" /* 0x10 */ 91176868Srink "\06EN_NOTIFY" /* 0x20 */ 92176868Srink "\07ABORT" /* 0x40 */ 93176868Srink "\10HOST_TO_READER_START"; /* 0x80 */ 94176868Srink#endif /* CMX_INTR */ 95176868Srinkstatic char POLLBITS[] = "\020" 96176868Srink "\01POLLIN" /* 0x0001 */ 97176868Srink "\02POLLPRI" /* 0x0002 */ 98176868Srink "\03POLLOUT" /* 0x0004 */ 99176868Srink "\04POLLERR" /* 0x0008 */ 100176868Srink "\05POLLHUP" /* 0x0010 */ 101176868Srink "\06POLLINVAL" /* 0x0020 */ 102176868Srink "\07POLLRDNORM" /* 0x0040 */ 103176868Srink "\10POLLRDBAND" /* 0x0080 */ 104176868Srink "\11POLLWRBAND"; /* 0x0100 */ 105176868Srinkstatic char MODEBITS[] = "\020" 106176868Srink "\01READ" /* 0x0001 */ 107176868Srink "\02WRITE" /* 0x0002 */ 108176868Srink "\03NONBLOCK" /* 0x0004 */ 109176868Srink "\04APPEND" /* 0x0008 */ 110176868Srink "\05SHLOCK" /* 0x0010 */ 111176868Srink "\06EXLOCK" /* 0x0020 */ 112176868Srink "\07ASYNC" /* 0x0040 */ 113176868Srink "\10FSYNC" /* 0x0080 */ 114176868Srink "\11NOFOLLOW" /* 0x0100 */ 115176868Srink "\12CREAT" /* 0x0200 */ 116176868Srink "\13TRUNK" /* 0x0400 */ 117176868Srink "\14EXCL" /* 0x0800 */ 118176868Srink "\15(0x1000)" /* 0x1000 */ 119176868Srink "\16(0x2000)" /* 0x2000 */ 120176868Srink "\17HASLOCK" /* 0x4000 */ 121176868Srink "\20NOCTTY" /* 0x8000 */ 122176868Srink "\21DIRECT"; /* 0x00010000 */ 123176868Srink#endif /* CMX_DEBUG */ 124176868Srink 125176868Srinkdevclass_t cmx_devclass; 126176868Srink 127176868Srinkstatic d_open_t cmx_open; 128176868Srinkstatic d_close_t cmx_close; 129176868Srinkstatic d_read_t cmx_read; 130176868Srinkstatic d_write_t cmx_write; 131176868Srinkstatic d_poll_t cmx_poll; 132176868Srink#ifdef CMX_INTR 133176868Srinkstatic void cmx_intr(void *arg); 134176868Srink#endif 135176868Srink 136176868Srinkstatic struct cdevsw cmx_cdevsw = { 137176868Srink .d_version = D_VERSION, 138176868Srink .d_open = cmx_open, 139176868Srink .d_close = cmx_close, 140176868Srink .d_read = cmx_read, 141176868Srink .d_write = cmx_write, 142176868Srink .d_poll = cmx_poll, 143176868Srink .d_name = "cmx", 144176868Srink}; 145176868Srink 146176868Srink/* 147176868Srink * Initialize the softc structure. Must be called from 148176868Srink * the bus specific device allocation routine. 149176868Srink */ 150176868Srinkvoid 151176868Srinkcmx_init_softc(device_t dev) 152176868Srink{ 153176868Srink struct cmx_softc *sc = device_get_softc(dev); 154176868Srink sc->dev = dev; 155176868Srink sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; 156176868Srink} 157176868Srink 158176868Srink/* 159176868Srink * Allocate driver resources. Must be called from the 160176868Srink * bus specific device allocation routine. Caller must 161176868Srink * ensure to call cmx_release_resources to free the 162176868Srink * resources when detaching. 163176868Srink * Return zero if successful, and ENOMEM if the resources 164176868Srink * could not be allocated. 165176868Srink */ 166176868Srinkint 167176868Srinkcmx_alloc_resources(device_t dev) 168176868Srink{ 169176868Srink struct cmx_softc *sc = device_get_softc(dev); 170176868Srink#ifdef CMX_INTR 171176868Srink int rv; 172176868Srink#endif 173176868Srink 174176868Srink sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 175176868Srink &sc->ioport_rid, RF_ACTIVE); 176176868Srink if (!sc->ioport) { 177176868Srink device_printf(dev, "failed to allocate io port\n"); 178176868Srink return ENOMEM; 179176868Srink } 180176868Srink sc->bst = rman_get_bustag(sc->ioport); 181176868Srink sc->bsh = rman_get_bushandle(sc->ioport); 182176868Srink 183176868Srink#ifdef CMX_INTR 184176868Srink sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 185176868Srink &sc->irq_rid, RF_ACTIVE); 186176868Srink if (!sc->irq) { 187176868Srink device_printf(dev, "failed to allocate irq\n"); 188176868Srink return ENOMEM; 189176868Srink } 190176868Srink if ((rv = bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, 191176868Srink cmx_intr, sc, &sc->ih)) != 0) { 192176868Srink device_printf(dev, "failed to set up irq\n"); 193176868Srink return ENOMEM; 194176868Srink } 195176868Srink#endif 196176868Srink 197176868Srink mtx_init(&sc->mtx, device_get_nameunit(dev), 198176868Srink "cmx softc lock", 199176868Srink MTX_DEF | MTX_RECURSE); 200176868Srink callout_init_mtx(&sc->ch, &sc->mtx, 0); 201176868Srink 202176868Srink return 0; 203176868Srink} 204176868Srink 205176868Srink/* 206176868Srink * Release the resources allocated by cmx_allocate_resources. 207176868Srink */ 208176868Srinkvoid 209176868Srinkcmx_release_resources(device_t dev) 210176868Srink{ 211176868Srink struct cmx_softc *sc = device_get_softc(dev); 212176868Srink 213176868Srink mtx_destroy(&sc->mtx); 214176868Srink 215176868Srink#ifdef CMX_INTR 216176868Srink if (sc->ih) { 217176868Srink bus_teardown_intr(dev, sc->irq, sc->ih); 218176868Srink sc->ih = NULL; 219176868Srink } 220176868Srink if (sc->irq) { 221176868Srink bus_release_resource(dev, SYS_RES_IRQ, 222176868Srink sc->irq_rid, sc->irq); 223176868Srink sc->irq = NULL; 224176868Srink } 225176868Srink#endif 226176868Srink 227176868Srink if (sc->ioport) { 228176868Srink bus_deactivate_resource(dev, SYS_RES_IOPORT, 229176868Srink sc->ioport_rid, sc->ioport); 230176868Srink bus_release_resource(dev, SYS_RES_IOPORT, 231176868Srink sc->ioport_rid, sc->ioport); 232176868Srink sc->ioport = NULL; 233176868Srink } 234176868Srink return; 235176868Srink} 236176868Srink 237176868Srink/* 238176868Srink * Bus independant device attachment routine. Creates the 239176868Srink * character device node. 240176868Srink */ 241176868Srinkint 242176868Srinkcmx_attach(device_t dev) 243176868Srink{ 244176868Srink struct cmx_softc *sc = device_get_softc(dev); 245176868Srink 246176868Srink if (!sc || sc->dying) 247176868Srink return ENXIO; 248176868Srink 249176868Srink sc->cdev = make_dev(&cmx_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 250176868Srink "cmx%d", device_get_unit(dev)); 251176868Srink if (!sc->cdev) { 252176868Srink device_printf(dev, "failed to create character device\n"); 253176868Srink return ENOMEM; 254176868Srink } 255176868Srink sc->cdev->si_drv1 = sc; 256176868Srink 257176868Srink return 0; 258176868Srink} 259176868Srink 260176868Srink/* 261176868Srink * Bus independant device detachment routine. Makes sure all 262176868Srink * allocated resources are freed, callouts disabled and waiting 263176868Srink * processes unblocked. 264176868Srink */ 265176868Srinkint 266176868Srinkcmx_detach(device_t dev) 267176868Srink{ 268176868Srink struct cmx_softc *sc = device_get_softc(dev); 269176868Srink 270176868Srink DEBUG_printf(dev, "called\n"); 271176868Srink 272176868Srink sc->dying = 1; 273176868Srink 274176868Srink CMX_LOCK(sc); 275176868Srink if (sc->polling) { 276176868Srink DEBUG_printf(sc->dev, "disabling polling\n"); 277176868Srink callout_stop(&sc->ch); 278176868Srink sc->polling = 0; 279176868Srink CMX_UNLOCK(sc); 280176868Srink callout_drain(&sc->ch); 281176868Srink selwakeuppri(&sc->sel, PZERO); 282176868Srink } else { 283176868Srink CMX_UNLOCK(sc); 284176868Srink } 285176868Srink 286176868Srink wakeup(sc); 287176868Srink destroy_dev(sc->cdev); 288176868Srink 289176868Srink DEBUG_printf(dev, "releasing resources\n"); 290176868Srink cmx_release_resources(dev); 291176868Srink return 0; 292176868Srink} 293176868Srink 294176868Srink/* 295176868Srink * Wait for buffer status register events. If test is non-zero, 296176868Srink * wait until flags are set, otherwise wait until flags are unset. 297176868Srink * Will spin SPIN_COUNT times, then sleep until timeout is reached. 298176868Srink * Returns zero if event happened, EIO if the timeout was reached, 299176868Srink * and ENXIO if the device was detached in the meantime. When that 300176868Srink * happens, the caller must quit immediately, since a detach is 301176868Srink * in progress. 302176868Srink */ 303176868Srinkstatic inline int 304176868Srinkcmx_wait_BSR(struct cmx_softc *sc, uint8_t flags, int test) 305176868Srink{ 306176868Srink int rv; 307176868Srink 308176868Srink for (int i = 0; i < SPIN_COUNT; i++) { 309176868Srink if (cmx_test_BSR(sc, flags, test)) 310176868Srink return 0; 311176868Srink } 312176868Srink 313176868Srink for (int i = 0; i * WAIT_TICKS < sc->timeout; i++) { 314176868Srink if (cmx_test_BSR(sc, flags, test)) 315176868Srink return 0; 316176868Srink rv = tsleep(sc, PWAIT|PCATCH, "cmx", WAIT_TICKS); 317176868Srink /* 318176868Srink * Currently, the only reason for waking up with 319176868Srink * rv == 0 is when we are detaching, in which 320176868Srink * case sc->dying is always 1. 321176868Srink */ 322176868Srink if (sc->dying) 323176868Srink return ENXIO; 324176868Srink if (rv != EAGAIN) 325176868Srink return rv; 326176868Srink } 327176868Srink 328176868Srink /* timeout */ 329176868Srink return EIO; 330176868Srink} 331176868Srink 332176868Srink/* 333176868Srink * Set the sync control register to val. Before and after writing 334176868Srink * to the SCR, we wait for the BSR to not signal BULK_OUT_FULL. 335176868Srink * Returns zero if successful, or whatever errors cmx_wait_BSR can 336176868Srink * return. ENXIO signals that the device has been detached in the 337176868Srink * meantime, and that we should leave the kernel immediately. 338176868Srink */ 339176868Srinkstatic inline int 340176868Srinkcmx_sync_write_SCR(struct cmx_softc *sc, uint8_t val) 341176868Srink{ 342176868Srink int rv = 0; 343176868Srink 344176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) { 345176868Srink return rv; 346176868Srink } 347176868Srink 348176868Srink cmx_write_SCR(sc, val); 349176868Srink 350176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) { 351176868Srink return rv; 352176868Srink } 353176868Srink 354176868Srink return 0; 355176868Srink} 356176868Srink 357176868Srink/* 358176868Srink * Returns a suitable timeout value based on the given command byte. 359176868Srink * Some commands appear to need longer timeout values than others. 360176868Srink */ 361176868Srinkstatic inline unsigned long 362176868Srinkcmx_timeout_by_cmd(uint8_t cmd) 363176868Srink{ 364176868Srink switch (cmd) { 365176868Srink case CMD_PC_TO_RDR_XFRBLOCK: 366176868Srink case CMD_PC_TO_RDR_SECURE: 367176868Srink case CMD_PC_TO_RDR_TEST_SECURE: 368176868Srink case CMD_PC_TO_RDR_OK_SECURE: 369176868Srink return CCID_DRIVER_BULK_DEFAULT_TIMEOUT; 370176868Srink 371176868Srink case CMD_PC_TO_RDR_ICCPOWERON: 372176868Srink return CCID_DRIVER_ASYNC_POWERUP_TIMEOUT; 373176868Srink 374176868Srink case CMD_PC_TO_RDR_GETSLOTSTATUS: 375176868Srink case CMD_PC_TO_RDR_ICCPOWEROFF: 376176868Srink case CMD_PC_TO_RDR_GETPARAMETERS: 377176868Srink case CMD_PC_TO_RDR_RESETPARAMETERS: 378176868Srink case CMD_PC_TO_RDR_SETPARAMETERS: 379176868Srink case CMD_PC_TO_RDR_ESCAPE: 380176868Srink case CMD_PC_TO_RDR_ICCCLOCK: 381176868Srink default: 382176868Srink return CCID_DRIVER_MINIMUM_TIMEOUT; 383176868Srink } 384176868Srink} 385176868Srink 386176868Srink/* 387176868Srink * Periodical callout routine, polling the reader for data 388176868Srink * availability. If the reader signals data ready for reading, 389176868Srink * wakes up the processes which are waiting in select()/poll(). 390176868Srink * Otherwise, reschedules itself with a delay of POLL_TICKS. 391176868Srink */ 392176868Srinkstatic void 393176868Srinkcmx_tick(void *xsc) 394176868Srink{ 395176868Srink struct cmx_softc *sc = xsc; 396176868Srink uint8_t bsr; 397176868Srink 398176868Srink CMX_LOCK(sc); 399176868Srink if (sc->polling && !sc->dying) { 400176868Srink bsr = cmx_read_BSR(sc); 401176868Srink DEBUG_printf(sc->dev, "BSR=%b\n", bsr, BSRBITS); 402176868Srink if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) { 403176868Srink sc->polling = 0; 404176868Srink selwakeuppri(&sc->sel, PZERO); 405176868Srink } else { 406176868Srink callout_reset(&sc->ch, POLL_TICKS, cmx_tick, sc); 407176868Srink } 408176868Srink } 409176868Srink CMX_UNLOCK(sc); 410176868Srink} 411176868Srink 412176868Srink/* 413176868Srink * Open the character device. Only a single process may open the 414176868Srink * device at a time. 415176868Srink */ 416176868Srinkstatic int 417176868Srinkcmx_open(struct cdev *cdev, int flags, int fmt, struct thread *td) 418176868Srink{ 419176868Srink struct cmx_softc *sc = cdev->si_drv1; 420176868Srink 421176868Srink if (sc == NULL || sc->dying) 422176868Srink return ENXIO; 423176868Srink 424176868Srink CMX_LOCK(sc); 425176868Srink if (sc->open) { 426176868Srink CMX_UNLOCK(sc); 427176868Srink return EBUSY; 428176868Srink } 429176868Srink sc->open = 1; 430176868Srink CMX_UNLOCK(sc); 431176868Srink 432176868Srink DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n", 433176868Srink flags, MODEBITS, td); 434176868Srink return 0; 435176868Srink} 436176868Srink 437176868Srink/* 438176868Srink * Close the character device. 439176868Srink */ 440176868Srinkstatic int 441176868Srinkcmx_close(struct cdev *cdev, int flags, int fmt, struct thread *td) 442176868Srink{ 443176868Srink struct cmx_softc *sc = cdev->si_drv1; 444176868Srink 445176868Srink if (sc == NULL || sc->dying) 446176868Srink return ENXIO; 447176868Srink 448176868Srink CMX_LOCK(sc); 449176868Srink if (!sc->open) { 450176868Srink CMX_UNLOCK(sc); 451176868Srink return EINVAL; 452176868Srink } 453176868Srink if (sc->polling) { 454176868Srink DEBUG_printf(sc->dev, "disabling polling\n"); 455176868Srink callout_stop(&sc->ch); 456176868Srink sc->polling = 0; 457176868Srink CMX_UNLOCK(sc); 458176868Srink callout_drain(&sc->ch); 459176868Srink selwakeuppri(&sc->sel, PZERO); 460176868Srink CMX_LOCK(sc); 461176868Srink } 462176868Srink sc->open = 0; 463176868Srink CMX_UNLOCK(sc); 464176868Srink 465176868Srink DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n", 466176868Srink flags, MODEBITS, td); 467176868Srink return 0; 468176868Srink} 469176868Srink 470176868Srink/* 471176868Srink * Read from the character device. 472176868Srink * Returns zero if successful, ENXIO if dying, EINVAL if an attempt 473176868Srink * was made to read less than CMX_MIN_RDLEN bytes or less than the 474176868Srink * device has available, or any of the errors that cmx_sync_write_SCR 475176868Srink * can return. Partial reads are not supported. 476176868Srink */ 477176868Srinkstatic int 478176868Srinkcmx_read(struct cdev *cdev, struct uio *uio, int flag) 479176868Srink{ 480176868Srink struct cmx_softc *sc = cdev->si_drv1; 481176868Srink unsigned long bytes_left; 482176868Srink uint8_t uc; 483176868Srink int rv, amnt, offset; 484176868Srink 485176868Srink if (sc == NULL || sc->dying) 486176868Srink return ENXIO; 487176868Srink 488176868Srink DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n", 489176868Srink uio->uio_resid, flag, MODEBITS); 490176868Srink 491176868Srink CMX_LOCK(sc); 492176868Srink if (sc->polling) { 493176868Srink DEBUG_printf(sc->dev, "disabling polling\n"); 494176868Srink callout_stop(&sc->ch); 495176868Srink sc->polling = 0; 496176868Srink CMX_UNLOCK(sc); 497176868Srink callout_drain(&sc->ch); 498176868Srink selwakeuppri(&sc->sel, PZERO); 499176868Srink } else { 500176868Srink CMX_UNLOCK(sc); 501176868Srink } 502176868Srink 503176868Srink if (uio->uio_resid == 0) { 504176868Srink return 0; 505176868Srink } 506176868Srink 507176868Srink if (uio->uio_resid < CMX_MIN_RDLEN) { 508176868Srink return EINVAL; 509176868Srink } 510176868Srink 511176868Srink if (flag & O_NONBLOCK) { 512176868Srink if (cmx_test_BSR(sc, BSR_BULK_IN_FULL, 0)) { 513176868Srink return EAGAIN; 514176868Srink } 515176868Srink } 516176868Srink 517176868Srink for (int i = 0; i < 5; i++) { 518176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) { 519176868Srink return rv; 520176868Srink } 521176868Srink sc->buf[i] = cmx_read_DTR(sc); 522176868Srink DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", i, sc->buf[i]); 523176868Srink } 524176868Srink 525176868Srink bytes_left = CMX_MIN_RDLEN + 526176868Srink (0x000000FF&((char)sc->buf[1])) + 527176868Srink (0x0000FF00&((char)sc->buf[2] << 8)) + 528176868Srink (0x00FF0000&((char)sc->buf[3] << 16)) + 529176868Srink (0xFF000000&((char)sc->buf[4] << 24)); 530176868Srink DEBUG_printf(sc->dev, "msgsz=%lu\n", bytes_left); 531176868Srink 532176868Srink if (uio->uio_resid < bytes_left) { 533176868Srink return EINVAL; 534176868Srink } 535176868Srink 536176868Srink offset = 5; /* prefetched header */ 537176868Srink while (bytes_left > 0) { 538176868Srink amnt = MIN(bytes_left, sizeof(sc->buf)); 539176868Srink 540176868Srink for (int i = offset; i < amnt; i++) { 541176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1))!=0) { 542176868Srink return rv; 543176868Srink } 544176868Srink sc->buf[i] = cmx_read_DTR(sc); 545176868Srink DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", 546176868Srink i, sc->buf[i]); 547176868Srink } 548176868Srink 549176868Srink if ((rv = uiomove(sc->buf, amnt, uio)) != 0) { 550176868Srink DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv); 551176868Srink return rv; 552176868Srink } 553176868Srink 554176868Srink if (offset) 555176868Srink offset = 0; 556176868Srink bytes_left -= amnt; 557176868Srink } 558176868Srink 559176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) { 560176868Srink return rv; 561176868Srink } 562176868Srink 563176868Srink if ((rv = cmx_sync_write_SCR(sc, SCR_READER_TO_HOST_DONE)) != 0) { 564176868Srink return rv; 565176868Srink } 566176868Srink 567176868Srink uc = cmx_read_DTR(sc); 568176868Srink DEBUG_printf(sc->dev, "success (DTR=%02x)\n", uc); 569176868Srink return 0; 570176868Srink} 571176868Srink 572176868Srink/* 573176868Srink * Write to the character device. 574176868Srink * Returns zero if successful, NXIO if dying, EINVAL if less data 575176868Srink * written than CMX_MIN_WRLEN, or any of the errors that cmx_sync_SCR 576176868Srink * can return. 577176868Srink */ 578176868Srinkstatic int 579176868Srinkcmx_write(struct cdev *cdev, struct uio *uio, int flag) 580176868Srink{ 581176868Srink struct cmx_softc *sc = cdev->si_drv1; 582176868Srink int rv, amnt; 583176868Srink 584176868Srink if (sc == NULL || sc->dying) 585176868Srink return ENXIO; 586176868Srink 587176868Srink DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n", 588176868Srink uio->uio_resid, flag, MODEBITS); 589176868Srink 590176868Srink if (uio->uio_resid == 0) { 591176868Srink return 0; 592176868Srink } 593176868Srink 594176868Srink if (uio->uio_resid < CMX_MIN_WRLEN) { 595176868Srink return EINVAL; 596176868Srink } 597176868Srink 598176868Srink if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_START)) != 0) { 599176868Srink return rv; 600176868Srink } 601176868Srink 602176868Srink sc->timeout = 0; 603176868Srink while (uio->uio_resid > 0) { 604176868Srink amnt = MIN(uio->uio_resid, sizeof(sc->buf)); 605176868Srink 606176868Srink if ((rv = uiomove(sc->buf, amnt, uio)) != 0) { 607176868Srink DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv); 608176868Srink /* wildly guessed attempt to notify device */ 609176868Srink sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; 610176868Srink cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE); 611176868Srink return rv; 612176868Srink } 613176868Srink 614176868Srink if (sc->timeout == 0) { 615176868Srink sc->timeout = cmx_timeout_by_cmd(sc->buf[0]); 616176868Srink DEBUG_printf(sc->dev, "cmd=%02x timeout=%lu\n", 617176868Srink sc->buf[0], sc->timeout); 618176868Srink } 619176868Srink 620176868Srink for (int i = 0; i < amnt; i++) { 621176868Srink if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0))!=0) { 622176868Srink return rv; 623176868Srink } 624176868Srink cmx_write_DTR(sc, sc->buf[i]); 625176868Srink DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", 626176868Srink i, sc->buf[i]); 627176868Srink } 628176868Srink } 629176868Srink 630176868Srink if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE)) != 0) { 631176868Srink return rv; 632176868Srink } 633176868Srink 634176868Srink DEBUG_printf(sc->dev, "success\n"); 635176868Srink return 0; 636176868Srink} 637176868Srink 638176868Srink/* 639176868Srink * Poll handler. Writing is always possible, reading is only possible 640176868Srink * if BSR_BULK_IN_FULL is set. Will start the cmx_tick callout and 641176868Srink * set sc->polling. 642176868Srink */ 643176868Srinkstatic int 644176868Srinkcmx_poll(struct cdev *cdev, int events, struct thread *td) 645176868Srink{ 646176868Srink struct cmx_softc *sc = cdev->si_drv1; 647176868Srink int revents = 0; 648176868Srink uint8_t bsr = 0; 649176868Srink 650176868Srink if (sc == NULL || sc->dying) 651176868Srink return ENXIO; 652176868Srink 653176868Srink bsr = cmx_read_BSR(sc); 654176868Srink DEBUG_printf(sc->dev, "called (events=%b BSR=%b)\n", 655176868Srink events, POLLBITS, bsr, BSRBITS); 656176868Srink 657176868Srink revents = events & (POLLOUT | POLLWRNORM); 658176868Srink if (events & (POLLIN | POLLRDNORM)) { 659176868Srink if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) { 660176868Srink revents |= events & (POLLIN | POLLRDNORM); 661176868Srink } else { 662176868Srink selrecord(td, &sc->sel); 663176868Srink CMX_LOCK(sc); 664176868Srink if (!sc->polling) { 665176868Srink DEBUG_printf(sc->dev, "enabling polling\n"); 666176868Srink sc->polling = 1; 667176868Srink callout_reset(&sc->ch, POLL_TICKS, 668176868Srink cmx_tick, sc); 669176868Srink } else { 670176868Srink DEBUG_printf(sc->dev, "already polling\n"); 671176868Srink } 672176868Srink CMX_UNLOCK(sc); 673176868Srink } 674176868Srink } 675176868Srink 676176868Srink DEBUG_printf(sc->dev, "success (revents=%b)\n", revents, POLLBITS); 677176868Srink 678176868Srink return revents; 679176868Srink} 680176868Srink 681176868Srink#ifdef CMX_INTR 682176868Srink/* 683176868Srink * Interrupt handler. Currently has no function except to 684176868Srink * print register status (if debugging is also enabled). 685176868Srink */ 686176868Srinkstatic void 687176868Srinkcmx_intr(void *arg) 688176868Srink{ 689176868Srink struct cmx_softc *sc = (struct cmx_softc *)arg; 690176868Srink 691176868Srink if (sc == NULL || sc->dying) 692176868Srink return; 693176868Srink 694176868Srink DEBUG_printf(sc->dev, "received interrupt (SCR=%b BSR=%b)\n", 695176868Srink cmx_read_SCR(sc), SCRBITS, 696176868Srink cmx_read_BSR(sc), BSRBITS); 697176868Srink 698176868Srink return; 699176868Srink} 700176868Srink#endif 701176868Srink 702