Commit cmx(4), a driver for Omnikey CardMan 4040 PCMCIA smartcard readers.
PR: kern/114582 Submitted by: Daniel Roethlisberger <daniel@roe.ch> Reviewed by: imp, myself Tested by: johans, myself MFC after: 2 weeks
This commit is contained in:
parent
de37e39122
commit
603d67ae36
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=176868
@ -49,6 +49,7 @@ MAN= aac.4 \
|
||||
ch.4 \
|
||||
ciss.4 \
|
||||
cm.4 \
|
||||
cmx.4 \
|
||||
cnw.4 \
|
||||
coda.4 \
|
||||
${_coretemp.4} \
|
||||
|
95
share/man/man4/cmx.4
Normal file
95
share/man/man4/cmx.4
Normal file
@ -0,0 +1,95 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 7, 2007
|
||||
.Dt CMX 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm cmx
|
||||
.Nd Omnikey CardMan 4040 smartcard reader device driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd device cmx
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for the PCCARD based
|
||||
.Em Omnikey CardMan 4040
|
||||
smartcard reader.
|
||||
The driver provides a character device special file based
|
||||
.Em Chip/Smart Card Interface Devices (CCID)
|
||||
interface. The driver implements what the vendor calls the
|
||||
.Em Synchronious API
|
||||
onto the smartcard reader device.
|
||||
.Pp
|
||||
Reading and writing is synchronious, meaning that a call to
|
||||
.Xr write 2
|
||||
directly corresponds to a complete CCID command sent to the
|
||||
device, while the following
|
||||
.Xr read 2
|
||||
will return the complete answer from the reader. There is no
|
||||
support for partial reads or writes. There is no upper limit on
|
||||
CCID request or response sizes, but the complete CCID request
|
||||
must be sent to the driver in
|
||||
.Xr write 2
|
||||
and the complete CCID response must fit into the buffer
|
||||
supplied to
|
||||
.Xr read 2 .
|
||||
.Pp
|
||||
Non-blocking I/O,
|
||||
.Xr select 2
|
||||
and
|
||||
.Xr poll 2
|
||||
are supported and work as expected. An open file descriptor
|
||||
will always be ready for writing, but only ready for reading
|
||||
if the device indicates that it has data available.
|
||||
.Sh COMPATIBILITY
|
||||
Userland smartcard code written for the vendor's Linux drivers
|
||||
should work with the
|
||||
.Nm
|
||||
driver without modification.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/ports/security/openct -compact
|
||||
.It Pa /dev/cmx\fBn\fP
|
||||
Character device special file.
|
||||
.It Pa /usr/ports/security/openct
|
||||
OpenCT, a userspace smartcard daemon containing a
|
||||
.Em CCID
|
||||
driver which directly supports
|
||||
.Nm
|
||||
devices.
|
||||
.\".It Pa /usr/ports/devel/pcsc-lite
|
||||
.\"PC/SC-Lite, a userspace smartcard daemon.
|
||||
.\".It Pa /usr/ports/devel/libccid
|
||||
.\"libccid, a generic
|
||||
.\".Em CCID
|
||||
.\"driver for use by PC/SC-Lite to interface to
|
||||
.\".Nm
|
||||
.\"devices.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr pccard 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm cmx
|
||||
driver first appeared in
|
||||
.Fx 7.1 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
driver was written by
|
||||
.An Daniel Roethlisberger Aq daniel@roe.ch ,
|
||||
originally based on the Linux driver v1.1.0 by
|
||||
.An Omnikey GmbH Aq www.omnikey.com .
|
||||
Early testing and bug fixes by
|
||||
.An Marcin Cieslak Aq saper@system.pl .
|
||||
.Sh BUGS
|
||||
.An -nosplit
|
||||
The way the
|
||||
.Nm
|
||||
driver talks to the CardMan 4040 is a bit rough. Due to the
|
||||
complete lack of hardware documentation other than vendor drivers
|
||||
for other operating systems, the gory details of the device's
|
||||
I/O registers are not understood very well. There may be error
|
||||
conditions which can only be solved by physically reinserting the
|
||||
reader.
|
@ -2115,6 +2115,7 @@ device tnt4882
|
||||
# rc: RISCom/8 multiport card
|
||||
# rp: Comtrol Rocketport(ISA/PCI) - single card
|
||||
# si: Specialix SI/XIO 4-32 port terminal multiplexor
|
||||
# cmx: OmniKey CardMan 4040 pccard smartcard reader
|
||||
|
||||
# Notes on the Comtrol Rocketport driver:
|
||||
#
|
||||
@ -2170,6 +2171,7 @@ options SI_DEBUG
|
||||
hint.si.0.at="isa"
|
||||
hint.si.0.maddr="0xd0000"
|
||||
hint.si.0.irq="12"
|
||||
device cmx
|
||||
|
||||
#
|
||||
# The 'bktr' device is a PCI video capture device using the Brooktree
|
||||
|
@ -508,6 +508,8 @@ dev/cardbus/cardbus_cis.c optional cardbus
|
||||
dev/cardbus/cardbus_device.c optional cardbus
|
||||
dev/ciss/ciss.c optional ciss
|
||||
dev/cm/smc90cx6.c optional cm
|
||||
dev/cmx/cmx.c optional cmx
|
||||
dev/cmx/cmx_pccard.c optional cmx pccard
|
||||
dev/cnw/if_cnw.c optional cnw pccard
|
||||
dev/cpufreq/ichss.c optional cpufreq
|
||||
dev/cs/if_cs.c optional cs
|
||||
|
701
sys/dev/cmx/cmx.c
Normal file
701
sys/dev/cmx/cmx.c
Normal file
@ -0,0 +1,701 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
|
||||
* Copyright (c) 2000-2004 OMNIKEY GmbH (www.omnikey.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* OMNIKEY CardMan 4040 a.k.a. CardMan eXtended (cmx) driver.
|
||||
* This is a PCMCIA based smartcard reader which seems to work
|
||||
* like an I/O port mapped USB CCID smartcard device.
|
||||
*
|
||||
* I/O originally based on Linux driver version 1.1.0 by OMNIKEY.
|
||||
* Dual GPL/BSD. Almost all of the code has been rewritten.
|
||||
* $Omnikey: cm4040_cs.c,v 1.7 2004/10/04 09:08:50 jp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/selinfo.h>
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/cmx/cmxvar.h>
|
||||
#include <dev/cmx/cmxreg.h>
|
||||
|
||||
#ifdef CMX_DEBUG
|
||||
#define DEBUG_printf(dev, fmt, args...) \
|
||||
device_printf(dev, "%s: " fmt, __FUNCTION__, ##args)
|
||||
#else
|
||||
#define DEBUG_printf(dev, fmt, args...)
|
||||
#endif
|
||||
|
||||
#define SPIN_COUNT 1000
|
||||
#define WAIT_TICKS (hz/100)
|
||||
#define POLL_TICKS (hz/10)
|
||||
|
||||
/* possibly bogus */
|
||||
#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*hz)
|
||||
#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*hz)
|
||||
#define CCID_DRIVER_MINIMUM_TIMEOUT (3*hz)
|
||||
|
||||
#ifdef CMX_DEBUG
|
||||
static char BSRBITS[] = "\020"
|
||||
"\01BULK_OUT_FULL" /* 0x01 */
|
||||
"\02BULK_IN_FULL" /* 0x02 */
|
||||
"\03(0x04)"; /* 0x04 */
|
||||
#ifdef CMX_INTR
|
||||
static char SCRBITS[] = "\020"
|
||||
"\01POWER_DOWN" /* 0x01 */
|
||||
"\02PULSE_INTERRUPT" /* 0x02 */
|
||||
"\03HOST_TO_READER_DONE" /* 0x04 */
|
||||
"\04READER_TO_HOST_DONE" /* 0x08 */
|
||||
"\05ACK_NOTIFY" /* 0x10 */
|
||||
"\06EN_NOTIFY" /* 0x20 */
|
||||
"\07ABORT" /* 0x40 */
|
||||
"\10HOST_TO_READER_START"; /* 0x80 */
|
||||
#endif /* CMX_INTR */
|
||||
static char POLLBITS[] = "\020"
|
||||
"\01POLLIN" /* 0x0001 */
|
||||
"\02POLLPRI" /* 0x0002 */
|
||||
"\03POLLOUT" /* 0x0004 */
|
||||
"\04POLLERR" /* 0x0008 */
|
||||
"\05POLLHUP" /* 0x0010 */
|
||||
"\06POLLINVAL" /* 0x0020 */
|
||||
"\07POLLRDNORM" /* 0x0040 */
|
||||
"\10POLLRDBAND" /* 0x0080 */
|
||||
"\11POLLWRBAND"; /* 0x0100 */
|
||||
static char MODEBITS[] = "\020"
|
||||
"\01READ" /* 0x0001 */
|
||||
"\02WRITE" /* 0x0002 */
|
||||
"\03NONBLOCK" /* 0x0004 */
|
||||
"\04APPEND" /* 0x0008 */
|
||||
"\05SHLOCK" /* 0x0010 */
|
||||
"\06EXLOCK" /* 0x0020 */
|
||||
"\07ASYNC" /* 0x0040 */
|
||||
"\10FSYNC" /* 0x0080 */
|
||||
"\11NOFOLLOW" /* 0x0100 */
|
||||
"\12CREAT" /* 0x0200 */
|
||||
"\13TRUNK" /* 0x0400 */
|
||||
"\14EXCL" /* 0x0800 */
|
||||
"\15(0x1000)" /* 0x1000 */
|
||||
"\16(0x2000)" /* 0x2000 */
|
||||
"\17HASLOCK" /* 0x4000 */
|
||||
"\20NOCTTY" /* 0x8000 */
|
||||
"\21DIRECT"; /* 0x00010000 */
|
||||
#endif /* CMX_DEBUG */
|
||||
|
||||
devclass_t cmx_devclass;
|
||||
|
||||
static d_open_t cmx_open;
|
||||
static d_close_t cmx_close;
|
||||
static d_read_t cmx_read;
|
||||
static d_write_t cmx_write;
|
||||
static d_poll_t cmx_poll;
|
||||
#ifdef CMX_INTR
|
||||
static void cmx_intr(void *arg);
|
||||
#endif
|
||||
|
||||
static struct cdevsw cmx_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = cmx_open,
|
||||
.d_close = cmx_close,
|
||||
.d_read = cmx_read,
|
||||
.d_write = cmx_write,
|
||||
.d_poll = cmx_poll,
|
||||
.d_name = "cmx",
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the softc structure. Must be called from
|
||||
* the bus specific device allocation routine.
|
||||
*/
|
||||
void
|
||||
cmx_init_softc(device_t dev)
|
||||
{
|
||||
struct cmx_softc *sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate driver resources. Must be called from the
|
||||
* bus specific device allocation routine. Caller must
|
||||
* ensure to call cmx_release_resources to free the
|
||||
* resources when detaching.
|
||||
* Return zero if successful, and ENOMEM if the resources
|
||||
* could not be allocated.
|
||||
*/
|
||||
int
|
||||
cmx_alloc_resources(device_t dev)
|
||||
{
|
||||
struct cmx_softc *sc = device_get_softc(dev);
|
||||
#ifdef CMX_INTR
|
||||
int rv;
|
||||
#endif
|
||||
|
||||
sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
|
||||
&sc->ioport_rid, RF_ACTIVE);
|
||||
if (!sc->ioport) {
|
||||
device_printf(dev, "failed to allocate io port\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
sc->bst = rman_get_bustag(sc->ioport);
|
||||
sc->bsh = rman_get_bushandle(sc->ioport);
|
||||
|
||||
#ifdef CMX_INTR
|
||||
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
&sc->irq_rid, RF_ACTIVE);
|
||||
if (!sc->irq) {
|
||||
device_printf(dev, "failed to allocate irq\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
if ((rv = bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY,
|
||||
cmx_intr, sc, &sc->ih)) != 0) {
|
||||
device_printf(dev, "failed to set up irq\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev),
|
||||
"cmx softc lock",
|
||||
MTX_DEF | MTX_RECURSE);
|
||||
callout_init_mtx(&sc->ch, &sc->mtx, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the resources allocated by cmx_allocate_resources.
|
||||
*/
|
||||
void
|
||||
cmx_release_resources(device_t dev)
|
||||
{
|
||||
struct cmx_softc *sc = device_get_softc(dev);
|
||||
|
||||
mtx_destroy(&sc->mtx);
|
||||
|
||||
#ifdef CMX_INTR
|
||||
if (sc->ih) {
|
||||
bus_teardown_intr(dev, sc->irq, sc->ih);
|
||||
sc->ih = NULL;
|
||||
}
|
||||
if (sc->irq) {
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->irq_rid, sc->irq);
|
||||
sc->irq = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sc->ioport) {
|
||||
bus_deactivate_resource(dev, SYS_RES_IOPORT,
|
||||
sc->ioport_rid, sc->ioport);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT,
|
||||
sc->ioport_rid, sc->ioport);
|
||||
sc->ioport = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bus independant device attachment routine. Creates the
|
||||
* character device node.
|
||||
*/
|
||||
int
|
||||
cmx_attach(device_t dev)
|
||||
{
|
||||
struct cmx_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!sc || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
sc->cdev = make_dev(&cmx_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
|
||||
"cmx%d", device_get_unit(dev));
|
||||
if (!sc->cdev) {
|
||||
device_printf(dev, "failed to create character device\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
sc->cdev->si_drv1 = sc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bus independant device detachment routine. Makes sure all
|
||||
* allocated resources are freed, callouts disabled and waiting
|
||||
* processes unblocked.
|
||||
*/
|
||||
int
|
||||
cmx_detach(device_t dev)
|
||||
{
|
||||
struct cmx_softc *sc = device_get_softc(dev);
|
||||
|
||||
DEBUG_printf(dev, "called\n");
|
||||
|
||||
sc->dying = 1;
|
||||
|
||||
CMX_LOCK(sc);
|
||||
if (sc->polling) {
|
||||
DEBUG_printf(sc->dev, "disabling polling\n");
|
||||
callout_stop(&sc->ch);
|
||||
sc->polling = 0;
|
||||
CMX_UNLOCK(sc);
|
||||
callout_drain(&sc->ch);
|
||||
selwakeuppri(&sc->sel, PZERO);
|
||||
} else {
|
||||
CMX_UNLOCK(sc);
|
||||
}
|
||||
|
||||
wakeup(sc);
|
||||
destroy_dev(sc->cdev);
|
||||
|
||||
DEBUG_printf(dev, "releasing resources\n");
|
||||
cmx_release_resources(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for buffer status register events. If test is non-zero,
|
||||
* wait until flags are set, otherwise wait until flags are unset.
|
||||
* Will spin SPIN_COUNT times, then sleep until timeout is reached.
|
||||
* Returns zero if event happened, EIO if the timeout was reached,
|
||||
* and ENXIO if the device was detached in the meantime. When that
|
||||
* happens, the caller must quit immediately, since a detach is
|
||||
* in progress.
|
||||
*/
|
||||
static inline int
|
||||
cmx_wait_BSR(struct cmx_softc *sc, uint8_t flags, int test)
|
||||
{
|
||||
int rv;
|
||||
|
||||
for (int i = 0; i < SPIN_COUNT; i++) {
|
||||
if (cmx_test_BSR(sc, flags, test))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i * WAIT_TICKS < sc->timeout; i++) {
|
||||
if (cmx_test_BSR(sc, flags, test))
|
||||
return 0;
|
||||
rv = tsleep(sc, PWAIT|PCATCH, "cmx", WAIT_TICKS);
|
||||
/*
|
||||
* Currently, the only reason for waking up with
|
||||
* rv == 0 is when we are detaching, in which
|
||||
* case sc->dying is always 1.
|
||||
*/
|
||||
if (sc->dying)
|
||||
return ENXIO;
|
||||
if (rv != EAGAIN)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* timeout */
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the sync control register to val. Before and after writing
|
||||
* to the SCR, we wait for the BSR to not signal BULK_OUT_FULL.
|
||||
* Returns zero if successful, or whatever errors cmx_wait_BSR can
|
||||
* return. ENXIO signals that the device has been detached in the
|
||||
* meantime, and that we should leave the kernel immediately.
|
||||
*/
|
||||
static inline int
|
||||
cmx_sync_write_SCR(struct cmx_softc *sc, uint8_t val)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
cmx_write_SCR(sc, val);
|
||||
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a suitable timeout value based on the given command byte.
|
||||
* Some commands appear to need longer timeout values than others.
|
||||
*/
|
||||
static inline unsigned long
|
||||
cmx_timeout_by_cmd(uint8_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CMD_PC_TO_RDR_XFRBLOCK:
|
||||
case CMD_PC_TO_RDR_SECURE:
|
||||
case CMD_PC_TO_RDR_TEST_SECURE:
|
||||
case CMD_PC_TO_RDR_OK_SECURE:
|
||||
return CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
|
||||
|
||||
case CMD_PC_TO_RDR_ICCPOWERON:
|
||||
return CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
|
||||
|
||||
case CMD_PC_TO_RDR_GETSLOTSTATUS:
|
||||
case CMD_PC_TO_RDR_ICCPOWEROFF:
|
||||
case CMD_PC_TO_RDR_GETPARAMETERS:
|
||||
case CMD_PC_TO_RDR_RESETPARAMETERS:
|
||||
case CMD_PC_TO_RDR_SETPARAMETERS:
|
||||
case CMD_PC_TO_RDR_ESCAPE:
|
||||
case CMD_PC_TO_RDR_ICCCLOCK:
|
||||
default:
|
||||
return CCID_DRIVER_MINIMUM_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Periodical callout routine, polling the reader for data
|
||||
* availability. If the reader signals data ready for reading,
|
||||
* wakes up the processes which are waiting in select()/poll().
|
||||
* Otherwise, reschedules itself with a delay of POLL_TICKS.
|
||||
*/
|
||||
static void
|
||||
cmx_tick(void *xsc)
|
||||
{
|
||||
struct cmx_softc *sc = xsc;
|
||||
uint8_t bsr;
|
||||
|
||||
CMX_LOCK(sc);
|
||||
if (sc->polling && !sc->dying) {
|
||||
bsr = cmx_read_BSR(sc);
|
||||
DEBUG_printf(sc->dev, "BSR=%b\n", bsr, BSRBITS);
|
||||
if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
|
||||
sc->polling = 0;
|
||||
selwakeuppri(&sc->sel, PZERO);
|
||||
} else {
|
||||
callout_reset(&sc->ch, POLL_TICKS, cmx_tick, sc);
|
||||
}
|
||||
}
|
||||
CMX_UNLOCK(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the character device. Only a single process may open the
|
||||
* device at a time.
|
||||
*/
|
||||
static int
|
||||
cmx_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct cmx_softc *sc = cdev->si_drv1;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
CMX_LOCK(sc);
|
||||
if (sc->open) {
|
||||
CMX_UNLOCK(sc);
|
||||
return EBUSY;
|
||||
}
|
||||
sc->open = 1;
|
||||
CMX_UNLOCK(sc);
|
||||
|
||||
DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n",
|
||||
flags, MODEBITS, td);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the character device.
|
||||
*/
|
||||
static int
|
||||
cmx_close(struct cdev *cdev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct cmx_softc *sc = cdev->si_drv1;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
CMX_LOCK(sc);
|
||||
if (!sc->open) {
|
||||
CMX_UNLOCK(sc);
|
||||
return EINVAL;
|
||||
}
|
||||
if (sc->polling) {
|
||||
DEBUG_printf(sc->dev, "disabling polling\n");
|
||||
callout_stop(&sc->ch);
|
||||
sc->polling = 0;
|
||||
CMX_UNLOCK(sc);
|
||||
callout_drain(&sc->ch);
|
||||
selwakeuppri(&sc->sel, PZERO);
|
||||
CMX_LOCK(sc);
|
||||
}
|
||||
sc->open = 0;
|
||||
CMX_UNLOCK(sc);
|
||||
|
||||
DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n",
|
||||
flags, MODEBITS, td);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the character device.
|
||||
* Returns zero if successful, ENXIO if dying, EINVAL if an attempt
|
||||
* was made to read less than CMX_MIN_RDLEN bytes or less than the
|
||||
* device has available, or any of the errors that cmx_sync_write_SCR
|
||||
* can return. Partial reads are not supported.
|
||||
*/
|
||||
static int
|
||||
cmx_read(struct cdev *cdev, struct uio *uio, int flag)
|
||||
{
|
||||
struct cmx_softc *sc = cdev->si_drv1;
|
||||
unsigned long bytes_left;
|
||||
uint8_t uc;
|
||||
int rv, amnt, offset;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
|
||||
uio->uio_resid, flag, MODEBITS);
|
||||
|
||||
CMX_LOCK(sc);
|
||||
if (sc->polling) {
|
||||
DEBUG_printf(sc->dev, "disabling polling\n");
|
||||
callout_stop(&sc->ch);
|
||||
sc->polling = 0;
|
||||
CMX_UNLOCK(sc);
|
||||
callout_drain(&sc->ch);
|
||||
selwakeuppri(&sc->sel, PZERO);
|
||||
} else {
|
||||
CMX_UNLOCK(sc);
|
||||
}
|
||||
|
||||
if (uio->uio_resid == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uio->uio_resid < CMX_MIN_RDLEN) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (flag & O_NONBLOCK) {
|
||||
if (cmx_test_BSR(sc, BSR_BULK_IN_FULL, 0)) {
|
||||
return EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
sc->buf[i] = cmx_read_DTR(sc);
|
||||
DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", i, sc->buf[i]);
|
||||
}
|
||||
|
||||
bytes_left = CMX_MIN_RDLEN +
|
||||
(0x000000FF&((char)sc->buf[1])) +
|
||||
(0x0000FF00&((char)sc->buf[2] << 8)) +
|
||||
(0x00FF0000&((char)sc->buf[3] << 16)) +
|
||||
(0xFF000000&((char)sc->buf[4] << 24));
|
||||
DEBUG_printf(sc->dev, "msgsz=%lu\n", bytes_left);
|
||||
|
||||
if (uio->uio_resid < bytes_left) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
offset = 5; /* prefetched header */
|
||||
while (bytes_left > 0) {
|
||||
amnt = MIN(bytes_left, sizeof(sc->buf));
|
||||
|
||||
for (int i = offset; i < amnt; i++) {
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1))!=0) {
|
||||
return rv;
|
||||
}
|
||||
sc->buf[i] = cmx_read_DTR(sc);
|
||||
DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
|
||||
i, sc->buf[i]);
|
||||
}
|
||||
|
||||
if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
|
||||
DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (offset)
|
||||
offset = 0;
|
||||
bytes_left -= amnt;
|
||||
}
|
||||
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if ((rv = cmx_sync_write_SCR(sc, SCR_READER_TO_HOST_DONE)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uc = cmx_read_DTR(sc);
|
||||
DEBUG_printf(sc->dev, "success (DTR=%02x)\n", uc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the character device.
|
||||
* Returns zero if successful, NXIO if dying, EINVAL if less data
|
||||
* written than CMX_MIN_WRLEN, or any of the errors that cmx_sync_SCR
|
||||
* can return.
|
||||
*/
|
||||
static int
|
||||
cmx_write(struct cdev *cdev, struct uio *uio, int flag)
|
||||
{
|
||||
struct cmx_softc *sc = cdev->si_drv1;
|
||||
int rv, amnt;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
|
||||
uio->uio_resid, flag, MODEBITS);
|
||||
|
||||
if (uio->uio_resid == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uio->uio_resid < CMX_MIN_WRLEN) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_START)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
sc->timeout = 0;
|
||||
while (uio->uio_resid > 0) {
|
||||
amnt = MIN(uio->uio_resid, sizeof(sc->buf));
|
||||
|
||||
if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
|
||||
DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
|
||||
/* wildly guessed attempt to notify device */
|
||||
sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
|
||||
cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (sc->timeout == 0) {
|
||||
sc->timeout = cmx_timeout_by_cmd(sc->buf[0]);
|
||||
DEBUG_printf(sc->dev, "cmd=%02x timeout=%lu\n",
|
||||
sc->buf[0], sc->timeout);
|
||||
}
|
||||
|
||||
for (int i = 0; i < amnt; i++) {
|
||||
if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0))!=0) {
|
||||
return rv;
|
||||
}
|
||||
cmx_write_DTR(sc, sc->buf[i]);
|
||||
DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
|
||||
i, sc->buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE)) != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DEBUG_printf(sc->dev, "success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll handler. Writing is always possible, reading is only possible
|
||||
* if BSR_BULK_IN_FULL is set. Will start the cmx_tick callout and
|
||||
* set sc->polling.
|
||||
*/
|
||||
static int
|
||||
cmx_poll(struct cdev *cdev, int events, struct thread *td)
|
||||
{
|
||||
struct cmx_softc *sc = cdev->si_drv1;
|
||||
int revents = 0;
|
||||
uint8_t bsr = 0;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return ENXIO;
|
||||
|
||||
bsr = cmx_read_BSR(sc);
|
||||
DEBUG_printf(sc->dev, "called (events=%b BSR=%b)\n",
|
||||
events, POLLBITS, bsr, BSRBITS);
|
||||
|
||||
revents = events & (POLLOUT | POLLWRNORM);
|
||||
if (events & (POLLIN | POLLRDNORM)) {
|
||||
if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
} else {
|
||||
selrecord(td, &sc->sel);
|
||||
CMX_LOCK(sc);
|
||||
if (!sc->polling) {
|
||||
DEBUG_printf(sc->dev, "enabling polling\n");
|
||||
sc->polling = 1;
|
||||
callout_reset(&sc->ch, POLL_TICKS,
|
||||
cmx_tick, sc);
|
||||
} else {
|
||||
DEBUG_printf(sc->dev, "already polling\n");
|
||||
}
|
||||
CMX_UNLOCK(sc);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_printf(sc->dev, "success (revents=%b)\n", revents, POLLBITS);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
#ifdef CMX_INTR
|
||||
/*
|
||||
* Interrupt handler. Currently has no function except to
|
||||
* print register status (if debugging is also enabled).
|
||||
*/
|
||||
static void
|
||||
cmx_intr(void *arg)
|
||||
{
|
||||
struct cmx_softc *sc = (struct cmx_softc *)arg;
|
||||
|
||||
if (sc == NULL || sc->dying)
|
||||
return;
|
||||
|
||||
DEBUG_printf(sc->dev, "received interrupt (SCR=%b BSR=%b)\n",
|
||||
cmx_read_SCR(sc), SCRBITS,
|
||||
cmx_read_BSR(sc), BSRBITS);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
115
sys/dev/cmx/cmx_pccard.c
Normal file
115
sys/dev/cmx/cmx_pccard.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/cmx/cmxvar.h>
|
||||
|
||||
#include <dev/pccard/pccardvar.h>
|
||||
#include <dev/pccard/pccard_cis.h>
|
||||
|
||||
#include "pccarddevs.h"
|
||||
|
||||
static const struct pccard_product cmx_pccard_products[] = {
|
||||
PCMCIA_CARD(OMNIKEY, CM4040),
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Probe for the card.
|
||||
*/
|
||||
static int
|
||||
cmx_pccard_probe(device_t dev)
|
||||
{
|
||||
const struct pccard_product *pp;
|
||||
if ((pp = pccard_product_lookup(dev, cmx_pccard_products,
|
||||
sizeof(cmx_pccard_products[0]), NULL)) != NULL) {
|
||||
if (pp->pp_name != NULL)
|
||||
device_set_desc(dev, pp->pp_name);
|
||||
return 0;
|
||||
}
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach to the pccard, and call bus independant attach and
|
||||
* resource allocation routines.
|
||||
*/
|
||||
static int
|
||||
cmx_pccard_attach(device_t dev)
|
||||
{
|
||||
int rv = 0;
|
||||
cmx_init_softc(dev);
|
||||
|
||||
if ((rv = cmx_alloc_resources(dev)) != 0) {
|
||||
device_printf(dev, "cmx_alloc_resources() failed!\n");
|
||||
cmx_release_resources(dev);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if ((rv = cmx_attach(dev)) != 0) {
|
||||
device_printf(dev, "cmx_attach() failed!\n");
|
||||
cmx_release_resources(dev);
|
||||
return rv;
|
||||
}
|
||||
|
||||
device_printf(dev, "attached\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static device_method_t cmx_pccard_methods[] = {
|
||||
DEVMETHOD(device_probe, cmx_pccard_probe),
|
||||
DEVMETHOD(device_attach, cmx_pccard_attach),
|
||||
DEVMETHOD(device_detach, cmx_detach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t cmx_pccard_driver = {
|
||||
"cmx",
|
||||
cmx_pccard_methods,
|
||||
sizeof(struct cmx_softc),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(cmx, pccard, cmx_pccard_driver, cmx_devclass, 0, 0);
|
||||
|
66
sys/dev/cmx/cmxreg.h
Normal file
66
sys/dev/cmx/cmxreg.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
|
||||
* Copyright (c) 2000-2004 OMNIKEY GmbH (www.omnikey.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* I/O port registers */
|
||||
#define REG_OFFSET_DTR 0 /* data transfer register */
|
||||
#define REG_OFFSET_BSR 1 /* buffer status register */
|
||||
#define REG_OFFSET_SCR 2 /* sync control register */
|
||||
|
||||
/* buffer status register flags */
|
||||
#define BSR_BULK_OUT_FULL 0x01
|
||||
#define BSR_BULK_IN_FULL 0x02
|
||||
|
||||
/* sync control register flags */
|
||||
#define SCR_POWER_DOWN 0x01
|
||||
#define SCR_PULSE_INTERRUPT 0x02
|
||||
#define SCR_HOST_TO_READER_DONE 0x04
|
||||
#define SCR_READER_TO_HOST_DONE 0x08
|
||||
#define SCR_ACK_NOTIFY 0x10
|
||||
#define SCR_EN_NOTIFY 0x20
|
||||
#define SCR_ABORT 0x40
|
||||
#define SCR_HOST_TO_READER_START 0x80
|
||||
|
||||
/* CCID commands */
|
||||
#define CMD_PC_TO_RDR_SETPARAMETERS 0x61
|
||||
#define CMD_PC_TO_RDR_ICCPOWERON 0x62
|
||||
#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63
|
||||
#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65
|
||||
#define CMD_PC_TO_RDR_SECURE 0x69
|
||||
#define CMD_PC_TO_RDR_ESCAPE 0x6B
|
||||
#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C
|
||||
#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D
|
||||
#define CMD_PC_TO_RDR_ICCCLOCK 0x6E
|
||||
#define CMD_PC_TO_RDR_XFRBLOCK 0x6F
|
||||
#define CMD_PC_TO_RDR_TEST_SECURE 0x74
|
||||
#define CMD_PC_TO_RDR_OK_SECURE 0x89
|
||||
#define CMD_RDR_TO_PC_DATABLOCK 0x80
|
||||
#define CMD_RDR_TO_PC_SLOTSTATUS 0x81
|
||||
#define CMD_RDR_TO_PC_PARAMETERS 0x82
|
||||
#define CMD_RDR_TO_PC_ESCAPE 0x83
|
||||
#define CMD_RDR_TO_PC_OK_SECURE 0x89
|
99
sys/dev/cmx/cmxvar.h
Normal file
99
sys/dev/cmx/cmxvar.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*#define CMX_DEBUG*/
|
||||
/*#define CMX_INTR*/
|
||||
|
||||
#define CMX_MIN_RDLEN 10 /* min read length */
|
||||
#define CMX_MIN_WRLEN 5 /* min write length */
|
||||
#define CMX_BUFSZ 512 /* I/O block size */
|
||||
|
||||
struct cmx_softc {
|
||||
device_t dev; /* pccard device */
|
||||
struct cdev *cdev; /* character device */
|
||||
|
||||
struct resource *ioport; /* io port resource descriptor */
|
||||
int ioport_rid; /* io port resource identification */
|
||||
|
||||
bus_space_tag_t bst; /* bus space tag */
|
||||
bus_space_handle_t bsh; /* bus space handle */
|
||||
|
||||
#ifdef CMX_INTR
|
||||
struct resource* irq; /* irq resource descriptor */
|
||||
int irq_rid; /* irq resource identification */
|
||||
void *ih; /* intr handle */
|
||||
#endif
|
||||
|
||||
struct mtx mtx; /* per-unit lock */
|
||||
struct callout ch; /* callout handle */
|
||||
struct selinfo sel; /* select/poll queue handle */
|
||||
|
||||
int open; /* is chardev open? */
|
||||
int polling; /* are we polling? */
|
||||
int dying; /* are we detaching? */
|
||||
|
||||
unsigned long timeout; /* response timeout */
|
||||
|
||||
uint8_t buf[CMX_BUFSZ]; /* read/write buffer */
|
||||
};
|
||||
|
||||
extern devclass_t cmx_devclass;
|
||||
|
||||
void cmx_init_softc(device_t);
|
||||
int cmx_alloc_resources(device_t);
|
||||
void cmx_release_resources(device_t);
|
||||
int cmx_attach(device_t);
|
||||
int cmx_detach(device_t);
|
||||
|
||||
#define CMX_READ_1(sc, off) \
|
||||
(bus_space_read_1((sc)->bst, (sc)->bsh, off))
|
||||
#define CMX_WRITE_1(sc, off, val) \
|
||||
(bus_space_write_1((sc)->bst, (sc)->bsh, off, val))
|
||||
|
||||
#define cmx_read_BSR(sc) \
|
||||
CMX_READ_1(sc, REG_OFFSET_BSR)
|
||||
#define cmx_write_BSR(sc, val) \
|
||||
CMX_WRITE_1(sc, REG_OFFSET_BSR, val)
|
||||
#define cmx_read_SCR(sc) \
|
||||
CMX_READ_1(sc, REG_OFFSET_SCR)
|
||||
#define cmx_write_SCR(sc, val) \
|
||||
CMX_WRITE_1(sc, REG_OFFSET_SCR, val)
|
||||
#define cmx_read_DTR(sc) \
|
||||
CMX_READ_1(sc, REG_OFFSET_DTR)
|
||||
#define cmx_write_DTR(sc, val) \
|
||||
CMX_WRITE_1(sc, REG_OFFSET_DTR, val)
|
||||
|
||||
#define cmx_test(byte, flags, test) \
|
||||
(((byte) & (flags)) == ((test) ? (flags) : 0))
|
||||
|
||||
#define cmx_test_BSR(sc, flags, test) \
|
||||
cmx_test(cmx_read_BSR(sc), flags, test)
|
||||
|
||||
#define CMX_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||
#define CMX_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
|
||||
#define CMX_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, (what))
|
@ -143,6 +143,7 @@ vendor BAY 0x01eb Bay Networks
|
||||
vendor FARALLON 0x0200 Farallon Communications
|
||||
vendor RELIA 0x0215 RELIA Technologies Corporation
|
||||
vendor TELECOMDEVICE 0x021b Telecom Device
|
||||
vendor OMNIKEY 0x0223 OMNIKEY GmbH
|
||||
vendor NOKIA 0x023d Nokia Communications
|
||||
vendor SAMSUNG 0x0250 Samsung
|
||||
vendor HWN 0x0261 Home Wireless Networks
|
||||
@ -471,6 +472,9 @@ product OLICOM OC3231 0x3132 GoCard Token Ring 16/4/Modem 288
|
||||
product OLICOM OC2232 0x3222 GoCard Combo Eth/Modem 336
|
||||
product OLICOM OC3232 0x3232 GoCard Token Ring 16/4/Modem 336
|
||||
|
||||
/* OMNIKEY Products */
|
||||
product OMNIKEY CM4040 0x0200 OMNIKEY CardMan 4040
|
||||
|
||||
/* Ositech Products */
|
||||
product OSITECH JACK_144 0x0001 Jack of Diamonds Ethernet/Modem 14.4
|
||||
product OSITECH JACK_288 0x0002 Jack of Diamonds Ethernet/Modem 28.8
|
||||
|
@ -52,6 +52,7 @@ SUBDIR= ${_3dfx} \
|
||||
${_ce} \
|
||||
${_ciss} \
|
||||
${_cm} \
|
||||
${_cmx} \
|
||||
coda \
|
||||
coda5 \
|
||||
${_coff} \
|
||||
@ -446,6 +447,7 @@ _asr= asr
|
||||
_bios= bios
|
||||
_ciss= ciss
|
||||
_cm= cm
|
||||
_cmx= cmx
|
||||
_coretemp= coretemp
|
||||
_ctau= ctau
|
||||
_cx= cx
|
||||
@ -503,6 +505,7 @@ _ath_rate_onoe= ath_rate_onoe
|
||||
_ath_rate_sample=ath_rate_sample
|
||||
_cardbus= cardbus
|
||||
_cbb= cbb
|
||||
_cmx= cmx
|
||||
_ciss= ciss
|
||||
_coretemp= coretemp
|
||||
_cpufreq= cpufreq
|
||||
@ -568,6 +571,7 @@ _cardbus= cardbus
|
||||
_cbb= cbb
|
||||
_ciss= ciss
|
||||
_cm= cm
|
||||
_cmx= cmx
|
||||
_coff= coff
|
||||
_cpufreq= cpufreq
|
||||
_em= em
|
||||
|
12
sys/modules/cmx/Makefile
Normal file
12
sys/modules/cmx/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
MAINTAINER= daniel@roe.ch
|
||||
|
||||
.PATH: ${.CURDIR}/../../dev/cmx
|
||||
|
||||
KMOD= cmx
|
||||
SRCS= cmx.c cmxvar.h cmxreg.h \
|
||||
cmx_pccard.c \
|
||||
pccarddevs.h device_if.h bus_if.h card_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user