📄 rc531.c
字号:
/* rc531.c: Mifare RC531 Driver */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/uaccess.h>#define RC531_MINOR 21#define RC531_CMD 0#define RC531_REGR 1#define RC531_REGW 2struct rc531_cmd{ int cmd; char *sendbuf; char *recvbuf; int bytesent; int byterecv; int bitsrecv; int timeout; int status;};struct rc531_regw{ int addr; int data;};static wait_queue_head_t waitq;static struct rc531_cmd rcmd;static int rc531_use;static int sendptr, recvptr;static char sendbuf[1024];static char recvbuf[1024];static int r531(int reg){ *(unsigned char*)0x0a000000 = ((reg>>3)&0x07)|0x80; return *(unsigned char*)((reg&0x07)+0x0a000000);}static void w531(int reg, int data){ *(unsigned char*)0x0a000000 = ((reg>>3)&0x07)|0x80; *(unsigned char*)((reg&0x07)+0x0a000000) = data;}static void rc531_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int i, irqrq, irqmask, nbytes; while(r531(0x03)&0x08){ irqmask = r531(0x06); irqrq = r531(0x07)&irqmask; if(irqrq&0x01){ //low alert nbytes = 56-r531(0x04); while(nbytes>0 && sendptr!=rcmd.bytesent){ w531(0x02, sendbuf[sendptr]); nbytes--; sendptr++; } if(sendptr==rcmd.bytesent){ w531(0x06, 0x01); //disable low alert } w531(0x07, 0x01); //clear low alert } if(irqrq&0x10){ //tx irq w531(0x07, 0x10); //clear tx irq if(rcmd.cmd==0x01){ //write e2 command w531(0x06, 0x7f); //disable all irq w531(0x07, 0x7f); //clear all irq rcmd.status = 0; wake_up_interruptible(&waitq); } } if(irqrq&0x0e){ //high alert, rx irq, idle irq nbytes = r531(0x04); for(i=0; i<nbytes; i++){ recvbuf[recvptr] = r531(0x02); recvptr++; rcmd.byterecv++; } w531(0x07, 0x0a); } if(irqrq&0x04){ //idle irq w531(0x06, 0x7f); //disable all irq w531(0x07, 0x7f); //clear all irq rcmd.status = 0; wake_up_interruptible(&waitq); } if(irqrq&0x20){ //timeout irq w531(0x06, 0x7f); //disable all irq w531(0x07, 0x7f); //clear all irq rcmd.status = 0x80; wake_up_interruptible(&waitq); } }}static int rc531_open(struct inode *inode, struct file *file){ if(rc531_use == 0){ MOD_INC_USE_COUNT; rc531_use ++; return 0; }else{ return -EBUSY; }}static int rc531_release(struct inode *inode, struct file *file){ if(rc531_use){ MOD_DEC_USE_COUNT; rc531_use --; return 0; }else{ return -ENODEV; }}static int rc531_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int retv, data; struct rc531_regw wcmd; retv = 0; switch(cmd){ case RC531_CMD: copy_from_user(&rcmd, (struct rc531_cmd*)arg, sizeof(rcmd)); copy_from_user(sendbuf, rcmd.sendbuf, rcmd.bytesent); rcmd.byterecv = 0; rcmd.bitsrecv = 0; rcmd.status = -1; sendptr = 0; recvptr = 0; w531(0x01, 0x00); //Enter idle mode w531(0x06, 0x00); //disable all irq w531(0x07, 0x7f); //clear all irq data = r531(0x09); //flush fifo data |= 0x01; w531(0x09, data); w531(0x2c, rcmd.timeout); //set timeout w531(0x01, rcmd.cmd); w531(0x06, 0xbf); while(rcmd.status==-1){ interruptible_sleep_on(&waitq); } w531(0x06, 0x00); //disable all irq w531(0x07, 0x7f); //clear all irq data = r531(0x09); //stop timer data |= 0x04; w531(0x09, data); w531(0x01, 0x00); //Enter idle mode rcmd.status |= r531(0x0a); if(rcmd.cmd!=0x19 && rcmd.cmd!=0x0b) rcmd.status &= ~0x40; //clear key error copy_to_user(rcmd.recvbuf, recvbuf, rcmd.byterecv); copy_to_user((struct rc531_cmd*)arg, &rcmd, sizeof(rcmd)); break; case RC531_REGR: retv = r531(arg); break; case RC531_REGW: copy_from_user(&wcmd, (struct rc531_regw*)arg, sizeof(wcmd)); w531(wcmd.addr, wcmd.data); break; default: } return retv;}static struct file_operations rc531_fops = { owner: THIS_MODULE, ioctl: rc531_ioctl, open: rc531_open, release: rc531_release,};static struct miscdevice rc531_miscdev = { RC531_MINOR, "rc531", &rc531_fops};static int __init rc531_init(void){ int retv; rc531_use = 0; retv = misc_register(&rc531_miscdev); printk("rc531 driver!\n"); init_waitqueue_head(&waitq); retv = request_irq(INT_EINT1, rc531_interrupt, 0, "rc531", NULL); return retv;}static void __exit rc531_exit(void){ misc_deregister(&rc531_miscdev); free_irq(INT_EINT1, NULL); return;}module_init(rc531_init);module_exit(rc531_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -