diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rfid_reader_spidev.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/src/rfid_reader_spidev.c b/src/rfid_reader_spidev.c new file mode 100644 index 0000000..e546380 --- /dev/null +++ b/src/rfid_reader_spidev.c @@ -0,0 +1,389 @@ +/* Direct spi for RC632 transport layer + * (based on openpcd reader) + * + * (C) 2007 by Frederic RODO <f.rodo@til-technologies.fr> + * + * This reader use the Linux's spidev interface, so it need a least + * kernel 2.6.22 + */ + +/* + * 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 <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/types.h> +#include <linux/spi/spidev.h> + +#include <librfid/rfid.h> +#include <librfid/rfid_reader.h> +#include <librfid/rfid_asic.h> +#include <librfid/rfid_asic_rc632.h> +#include <librfid/rfid_reader_spidev.h> +#include <librfid/rfid_layer2.h> +#include <librfid/rfid_protocol.h> + +/* FIXME */ +#include "rc632.h" +static int spidev_fd; + +struct spi_ioc_transfer xfer[1]; + +/* 256bytes max FSD/FSC, plus 1 bytes header, plus 10 bytes reserve */ +#define SENDBUF_LEN (256+1+10) +#define RECVBUF_LEN SENDBUF_LEN +static char snd_buf[SENDBUF_LEN]; +static char rcv_buf[RECVBUF_LEN]; + +static int spidev_read(unsigned char reg, unsigned char len, + unsigned char *buf) +{ + int ret; + + if (!len) + return -EINVAL; + + snd_buf[0] = (reg<<1) | 0x80; + if (len > 1) + memset(&snd_buf[1], reg<<1 , len-1); + snd_buf[len] = 0; + + /* prepare spi buffer */ + xfer[0].tx_buf = (__u64) snd_buf; + xfer[0].rx_buf = (__u64) rcv_buf; + xfer[0].len = len + 1; + + ret = ioctl(spidev_fd, SPI_IOC_MESSAGE(1), xfer); + if (ret < 0) { + DEBUGPC("ERROR sending command\n"); + return ret; + } else if (ret != (len + 1)) { + DEBUGPC("ERROR sending command bad length\n"); + return -EINVAL; + } + + memcpy(buf, &rcv_buf[1], len); + + return len; +} + +static int spidev_write(unsigned char reg, unsigned char len, + const unsigned char *buf) +{ + int ret; + + if (!len) + return -EINVAL; + + snd_buf[0] = (reg << 1) & 0x7E; + memcpy(&snd_buf[1], buf, len); + + /* prepare spi buffer */ + xfer[0].tx_buf = (__u64) snd_buf; + xfer[0].rx_buf = (__u64) NULL; + xfer[0].len = len + 1; + + ret = ioctl(spidev_fd, SPI_IOC_MESSAGE(1), xfer); + if (ret < 0) { + DEBUGPC("ERROR sending command\n"); + return ret; + } + else if (ret != len+1) + return -EINVAL; + + return len; +} + +static int spidev_reg_read(struct rfid_asic_transport_handle *rath, + unsigned char reg, unsigned char *value) +{ + int ret; + + ret = spidev_read(reg, 1, value); + if (ret < 0) + return ret; + DEBUGP("%s reg = 0x%02x, val = 0x%02x\n", __FUNCTION__, reg, *value); + + return 1; +} + +static int spidev_reg_write(struct rfid_asic_transport_handle *rath, + unsigned char reg, unsigned char value) +{ + int ret; + + ret = spidev_write(reg, 1, &value); + if (ret < 0) + return ret; + + DEBUGP("%s reg = 0x%02x, val = 0x%02x\n", __FUNCTION__, reg, value); + + return 1; +} + +static int spidev_fifo_read(struct rfid_asic_transport_handle *rath, + unsigned char len, unsigned char *buf) +{ + int ret; + + ret = spidev_read(2, len, buf); + if (ret < 0) + return ret; + + DEBUGP("%s len=%u, val=%s\n", __FUNCTION__, len, + rfid_hexdump(buf, len)); + + return len; +} + +static int spidev_fifo_write(struct rfid_asic_transport_handle *rath, + unsigned char len, const unsigned char *buf, + unsigned char flags) +{ + int ret; + + ret = spidev_write(2, len, buf); + if (ret < 0) + return ret; + + DEBUGP("%s len=%u, data=%s\n", __FUNCTION__, len, + rfid_hexdump(buf, len)); + + return len; +} + +struct rfid_asic_transport spidev_spi = { + .name = "spidev", + .priv.rc632 = { + .fn = { + .reg_write = &spidev_reg_write, + .reg_read = &spidev_reg_read, + .fifo_write = &spidev_fifo_write, + .fifo_read = &spidev_fifo_read, + }, + }, +}; + +static int spidev_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 spidev_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 +spidev_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 spidev_14443a_init(struct rfid_reader_handle *rh) +{ + int ret; + ret = rh->ah->asic->priv.rc632.fn.iso14443a.init(rh->ah); + return ret; +} + +static int +spidev_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 spidev_14443b_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso14443b.init(rh->ah); +} + +static int spidev_15693_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso15693.init(rh->ah); +} + +static int +spidev_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 +spidev_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); +} + +static struct rfid_reader_handle *spidev_open(void *data) +{ + struct rfid_reader_handle *rh; + struct rfid_asic_transport_handle *rath; + __u32 tmp; + + /* open spi device */ + if (!data) { + DEBUGP("No device name\n"); + return NULL; + } + if ((spidev_fd = open(data, O_RDWR)) < 0) { + DEBUGP("Unable to open:\n"); + return NULL; + } + + rh = malloc(sizeof(*rh)); + if (!rh) + goto out_close_spi; + + memset(rh, 0, sizeof(*rh)); + + rath = malloc(sizeof(*rath)); + if (!rath) + goto out_rh; + memset(rath, 0, sizeof(*rath)); + + rath->rat = &spidev_spi; + rh->reader = &rfid_reader_spidev; + + /* Configure spi device, MODE 0 */ + tmp = SPI_MODE_0; + if (ioctl(spidev_fd, SPI_IOC_WR_MODE, &tmp) < 0) + goto out_rath; + + /* MSB First */ + tmp = 0; + if (ioctl(spidev_fd, SPI_IOC_WR_LSB_FIRST, &tmp) < 0) + goto out_rath; + + /* 8 bits per word */ + tmp = 8; + if (ioctl(spidev_fd, SPI_IOC_WR_BITS_PER_WORD, &tmp) < 0) + goto out_rath; + + /* 1 MHz */ + tmp = 1e6; + if (ioctl(spidev_fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp) < 0) + goto out_rath; + + /* turn on rc632 */ + rh->ah = rc632_open(rath); + if (!rh->ah) + goto out_rath; + + /* everything is ok, returning reader handler */ + return rh; +out_rath: + free(rath); +out_rh: + free(rh); +out_close_spi: + close(spidev_fd); + return NULL; +} + +static void spidev_close(struct rfid_reader_handle *rh) +{ + struct rfid_asic_transport_handle *rath = rh->ah->rath; + + if (rh->ah) + rc632_close(rh->ah); + + if (spidev_fd > 0) + close(spidev_fd); + + if (rath) + free(rath); + + if (rh) + free(rh); +} + +struct rfid_reader rfid_reader_spidev = { + .name = "spidev reader", + .id = RFID_READER_SPIDEV, + .open = &spidev_open, + .close = &spidev_close, + .transceive = &spidev_transceive, + .l2_supported = (1 << RFID_LAYER2_ISO14443A) | + (1 << RFID_LAYER2_ISO14443B) | + (1 << RFID_LAYER2_ISO15693), + .proto_supported = (1 << RFID_PROTOCOL_TCL) | + (1 << RFID_PROTOCOL_MIFARE_UL) | + (1 << RFID_PROTOCOL_MIFARE_CLASSIC), + .iso14443a = { + .init = &spidev_14443a_init, + .transceive_sf = &spidev_transceive_sf, + .transceive_acf = &spidev_transceive_acf, + .speed = RFID_14443A_SPEED_106K + | RFID_14443A_SPEED_212K | RFID_14443A_SPEED_424K, + .set_speed = &spidev_14443a_set_speed, + }, + .iso14443b = { + .init = &spidev_14443b_init, + }, + .mifare_classic = { + .setkey = &spidev_mifare_setkey, + .auth = &spidev_mifare_auth, + }, +}; + |