From 91f920e0d37910c789528f3422dc904615f1a53c Mon Sep 17 00:00:00 2001 From: laforge Date: Sun, 23 Jul 2006 18:38:25 +0000 Subject: [PATCH] add support for new OpenPCD design git-svn-id: https://svn.gnumonks.org/trunk/librfid@1851 e0336214-984f-0b4b-a45f-81c69e1f0ede --- include/librfid/rfid_reader.h | 1 + include/librfid/rfid_reader_openpcd.h | 42 +++ src/Makefile.am | 2 +- src/rfid.c | 2 + src/rfid_reader_openpcd.c | 385 ++++++++++++++++++++++++++ 5 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 include/librfid/rfid_reader_openpcd.h create mode 100644 src/rfid_reader_openpcd.c diff --git a/include/librfid/rfid_reader.h b/include/librfid/rfid_reader.h index 695221d..f604852 100644 --- a/include/librfid/rfid_reader.h +++ b/include/librfid/rfid_reader.h @@ -48,6 +48,7 @@ struct rfid_reader { enum rfid_reader_id { RFID_READER_CM5121, RFID_READER_PEGODA, + RFID_READER_OPENPCD, }; struct rfid_reader_handle { diff --git a/include/librfid/rfid_reader_openpcd.h b/include/librfid/rfid_reader_openpcd.h new file mode 100644 index 0000000..3f8a071 --- /dev/null +++ b/include/librfid/rfid_reader_openpcd.h @@ -0,0 +1,42 @@ +#ifndef _OPENPCD_PROTO_H +#define _OPENPCD_PROTO_H + +/* This header file describes the USB protocol of the OpenPCD RFID reader */ + +#include + +struct openpcd_hdr { + u_int8_t cmd; /* command */ + u_int8_t flags; + u_int8_t reg; /* register */ + u_int8_t val; /* value (in case of write *) */ + u_int16_t len; + u_int16_t res; + u_int8_t data[0]; +} __attribute__((packed)); + +#define OPENPCD_REG_MAX 0x3f + +#define OPENPCD_CMD_WRITE_REG 0x01 +#define OPENPCD_CMD_WRITE_FIFO 0x02 +#define OPENPCD_CMD_WRITE_VFIFO 0x03 +#define OPENPCD_CMD_REG_BITS_CLEAR 0x04 +#define OPENPCD_CMD_REG_BITS_SET 0x05 + +#define OPENPCD_CMD_READ_REG 0x11 +#define OPENPCD_CMD_READ_FIFO 0x12 +#define OPENPCD_CMD_READ_VFIFO 0x13 + +#define OPENPCD_CMD_SET_LED 0x21 + +#define OPENPCD_CMD_IRQ 0x40 /* IRQ reported by RC632 */ + +#define OPENPCD_VENDOR_ID 0x2342 +#define OPENPCD_PRODUCT_ID 0x0001 +#define OPENPCD_OUT_EP 0x01 +#define OPENPCD_IN_EP 0x82 +#define OPENPCD_IRQ_EP 0x83 + +extern struct rfid_reader rfid_reader_openpcd; + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index ef44e7d..48cb4a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = librfid.la CORE=rfid.c rfid_layer2.c rfid_protocol.c rfid_reader.c L2=rfid_layer2_iso14443a.c rfid_layer2_iso14443b.c rfid_layer2_iso15693.c rfid_iso14443_common.c PROTO=rfid_proto_tcl.c rfid_proto_mifare_ul.c rfid_proto_mifare_classic.c -READER=rfid_reader_cm5121.c rfid_asic_rc632.c +READER=rfid_reader_cm5121.c rfid_asic_rc632.c rfid_reader_openpcd.c if MY_CCID READER_LOW=ccid/rfid_reader_cm5121_ccid_direct.c ccid/ccid-driver.c diff --git a/src/rfid.c b/src/rfid.c index 6fba46a..ea6c0aa 100644 --- a/src/rfid.c +++ b/src/rfid.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -41,6 +42,7 @@ rfid_hexdump(const void *data, unsigned int len) int rfid_init() { rfid_reader_register(&rfid_reader_cm5121); + rfid_reader_register(&rfid_reader_openpcd); rfid_layer2_register(&rfid_layer2_iso14443a); rfid_layer2_register(&rfid_layer2_iso14443b); rfid_protocol_register(&rfid_protocol_tcl); diff --git a/src/rfid_reader_openpcd.c b/src/rfid_reader_openpcd.c new file mode 100644 index 0000000..500428d --- /dev/null +++ b/src/rfid_reader_openpcd.c @@ -0,0 +1,385 @@ +/* OpenPC specific RC632 transport layer + * + * (C) 2006 by Harald Welte + * + * The OpenPCD is an Atmel AT91SAM7Sxx based USB RFID reader. + * It's CL RC632 is connected via SPI. + * + * TODO: + * - put hdl from static variable into asic transport or reader handle + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* FIXME */ +#include "rc632.h" + + +#define SENDBUF_LEN (256+7+10) /* 256bytes max FSD/FSC, plus 7 bytes header, + plus 10 bytes reserve */ +#define RECVBUF_LEN SENDBUF_LEN + +static char snd_buf[SENDBUF_LEN]; +static char rcv_buf[RECVBUF_LEN]; +static struct openpcd_hdr *snd_hdr; +static struct openpcd_hdr *rcv_hdr; + + +static struct usb_device *dev; +static struct usb_dev_handle *hdl; + +static int openpcd_send_command(u_int8_t cmd, u_int8_t reg, u_int8_t val, + u_int16_t len, const unsigned char *data) +{ + int ret; + u_int16_t cur; + + snd_hdr->cmd = cmd; + snd_hdr->reg = reg; + snd_hdr->val = val; + snd_hdr->len = len; + if (data && len) + memcpy(snd_hdr->data, data, len); + + cur = sizeof(*snd_hdr) + len; + + return usb_bulk_write(hdl, OPENPCD_OUT_EP, snd_hdr, cur, 0); +} + +static int openpcd_recv_reply(void) +{ + int ret; + + ret = usb_bulk_read(hdl, OPENPCD_IN_EP, rcv_buf, sizeof(rcv_buf), 1000); + + return ret; +} + +static struct usb_device *find_opcd_device(void) +{ + struct usb_bus *bus; + + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *dev; + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == OPENPCD_VENDOR_ID + && dev->descriptor.idProduct == OPENPCD_PRODUCT_ID + && dev->descriptor.iManufacturer == 0 + && dev->descriptor.iProduct == 0 + && dev->descriptor.bNumConfigurations == 1 + && dev->config->bNumInterfaces == 1 + && dev->config->iConfiguration == 0) + return dev; + } + } + return NULL; +} + +static int openpcd_reg_write(struct rfid_asic_transport_handle *rath, + unsigned char reg, unsigned char value) +{ + int ret; + + DEBUGP("reg=0x%02x, val=%02x: ", reg, value); + + ret = openpcd_send_command(OPENPCD_CMD_WRITE_REG, reg, value, 0, NULL); + if (ret < 0) + DEBUGPC("ERROR\n"); + else + DEBUGPC("OK\n"); + + ret = openpcd_recv_reply(); + if (ret < 0) + DEBUGPC("ERROR\n"); + else + DEBUGPC("OK\n"); + + return ret; +} + +static int openpcd_reg_read(struct rfid_asic_transport_handle *rath, + unsigned char reg, + unsigned char *value) +{ + int ret; + + DEBUGP("reg=0x%02x, ", reg); + + ret = openpcd_send_command(OPENPCD_CMD_READ_REG, reg, 0, 0, NULL); + if (ret < 0) { + DEBUGPC("ERROR\n"); + return ret; + } + + ret = openpcd_recv_reply(); + if (ret < 0) { + DEBUGPC("ERROR\n"); + return ret; + } + + *value = rcv_hdr->val; + DEBUGPC("val=%02x: OK\n", *value); + + return ret; +} + +static int openpcd_fifo_read(struct rfid_asic_transport_handle *rath, + unsigned char num_bytes, + unsigned char *buf) +{ + int ret; + + DEBUGP(" "); + + ret = openpcd_send_command(OPENPCD_CMD_READ_FIFO, 0x00, num_bytes, 0, NULL); + if (ret < 0) { + DEBUGPC("ERROR\n"); + return ret; + } + + ret = openpcd_recv_reply(); + if (ret < 0) { + DEBUGPC("ERROR\n"); + return ret; + } + + memcpy(buf, rcv_hdr->data, rcv_hdr->len); + + return ret; +} + +static int openpcd_fifo_write(struct rfid_asic_transport_handle *rath, + unsigned char len, + const unsigned char *bytes, + unsigned char flags) +{ + int ret; + + ret = openpcd_send_command(OPENPCD_CMD_WRITE_FIFO, 0, 0, len, bytes); + + return ret; +} + +static int openpcd_transceive(struct rfid_reader_handle *rh, + enum rfid_frametype frametype, + const unsigned char *tx_data, unsigned int tx_len, + unsigned char *rx_data, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + return rh->ah->asic->priv.rc632.fn.transceive(rh->ah, frametype, + tx_data, tx_len, rx_data, + rx_len, timeout, flags); +} + +static int openpcd_transceive_sf(struct rfid_reader_handle *rh, + unsigned char cmd, struct iso14443a_atqa *atqa) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.transceive_sf(rh->ah, + cmd, + atqa); +} + +static int +openpcd_transceive_acf(struct rfid_reader_handle *rh, + struct iso14443a_anticol_cmd *cmd, + unsigned int *bit_of_col) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.transceive_acf(rh->ah, + cmd, bit_of_col); +} + +static int +openpcd_14443a_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.init(rh->ah); +} + +static int +openpcd_14443a_set_speed(struct rfid_reader_handle *rh, + unsigned int tx, + unsigned int speed) +{ + u_int8_t rate; + + DEBUGP("setting rate: "); + switch (speed) { + case RFID_14443A_SPEED_106K: + rate = 0x00; + DEBUGPC("106K\n"); + break; + case RFID_14443A_SPEED_212K: + rate = 0x01; + DEBUGPC("212K\n"); + break; + case RFID_14443A_SPEED_424K: + rate = 0x02; + DEBUGPC("424K\n"); + break; + case RFID_14443A_SPEED_848K: + rate = 0x03; + DEBUGPC("848K\n"); + break; + default: + return -EINVAL; + break; + } + return rh->ah->asic->priv.rc632.fn.iso14443a.set_speed(rh->ah, + tx, rate); +} + +static int +openpcd_14443b_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso14443b.init(rh->ah); +} + +static int +openpcd_15693_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso15693.init(rh->ah); +} + +static int +openpcd_mifare_setkey(struct rfid_reader_handle *rh, const u_int8_t *key) +{ + return rh->ah->asic->priv.rc632.fn.mifare_classic.setkey(rh->ah, key); +} + +static int +openpcd_mifare_auth(struct rfid_reader_handle *rh, u_int8_t cmd, + u_int32_t serno, u_int8_t block) +{ + return rh->ah->asic->priv.rc632.fn.mifare_classic.auth(rh->ah, + cmd, serno, block); +} + +struct rfid_asic_transport openpcd_ccid = { + .name = "OpenPCD Dumb USB Protocol", + .priv.rc632 = { + .fn = { + .reg_write = &openpcd_reg_write, + .reg_read = &openpcd_reg_read, + .fifo_write = &openpcd_fifo_write, + .fifo_read = &openpcd_fifo_read, + }, + }, +}; + +static struct rfid_reader_handle * +openpcd_open(void *data) +{ + struct rfid_reader_handle *rh; + struct rfid_asic_transport_handle *rath; + + snd_hdr = (struct openpcd_hdr *)snd_buf; + rcv_hdr = (struct openpcd_hdr *)rcv_buf; + + usb_init(); + if (!usb_find_busses()) + return NULL; + if (!usb_find_devices()) + return NULL; + + dev = find_opcd_device(); + if (!dev) + return NULL; + + hdl = usb_open(dev); + if (!hdl) + return NULL; + + if (usb_claim_interface(hdl, 0) < 0) { + usb_close(hdl); + return NULL; + } + + rh = malloc(sizeof(*rh)); + if (!rh) + return NULL; + memset(rh, 0, sizeof(*rh)); + + rath = malloc(sizeof(*rath)); + if (!rath) + goto out_rh; + memset(rath, 0, sizeof(*rath)); + + rath->rat = &openpcd_ccid; + rh->reader = &rfid_reader_openpcd; + + rh->ah = rc632_open(rath); + if (!rh->ah) + goto out_rath; + + DEBUGP("returning %p\n", rh); + return rh; + +out_rath: + free(rath); +out_rh: + free(rh); + + return NULL; +} + +static void +openpcd_close(struct rfid_reader_handle *rh) +{ + struct rfid_asic_transport_handle *rath = rh->ah->rath; + + usb_close(hdl); + + rc632_close(rh->ah); + free(rath); + free(rh); +} + +struct rfid_reader rfid_reader_openpcd = { + .name = "OpenPCD RFID Reader", + .id = RFID_READER_OPENPCD, + .open = &openpcd_open, + .close = &openpcd_close, + .transceive = &openpcd_transceive, + .iso14443a = { + .init = &openpcd_14443a_init, + .transceive_sf = &openpcd_transceive_sf, + .transceive_acf = &openpcd_transceive_acf, + .speed = RFID_14443A_SPEED_106K | RFID_14443A_SPEED_212K | + RFID_14443A_SPEED_424K, //| RFID_14443A_SPEED_848K, + .set_speed = &openpcd_14443a_set_speed, + }, + .iso14443b = { + .init = &openpcd_14443b_init, + }, + .mifare_classic = { + .setkey = &openpcd_mifare_setkey, + .auth = &openpcd_mifare_auth, + }, +}; + + -- 2.20.1