📄 9200-zlg7289a.c
字号:
/* * */#define __NO_VERSION__#include <linux/module.h>#include <linux/version.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/config.h>#include <linux/mm.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/hardware.h>#include <asm/uaccess.h>#undef DEBUG_ZLG7289//#define DEBUG_ZLG7289 1#ifdef DEBUG_ZLG7289#define DBG_ZLG7289(fmt, args...) printk(fmt,## args)#else#define DBG_ZLG7289(fmt, args...)#endifstatic int zlg7289_open(struct inode *, struct file *);static int zlg7289_close(struct inode *, struct file *);static int zlg7289_read(struct file *, char *, size_t, loff_t *);static int zlg7289_write(struct file *, const char *, size_t, loff_t *);static void zlg7289_interrupt(int, void *, struct pt_regs *);static void zlg7289_hardware_init(void);static unsigned char zlg7289_transform(unsigned char, unsigned char, int);static void uled_control(int, unsigned char);#define ZLG7289_MAJOR 252#define TRAN_CMD 1#define TRAN_CMD_DATA 2#define READ_CMD_DATA 3/* User CMD */#define ULED1_CONTROL 1#define ULED2_CONTROL 2#define ULED3_CONTROL 3#define ULED4_CONTROL 4#define ZLG_CMD 5#define ZLG_CMD_DATA 6/* PA0 --> DATA, PA2 --> CLK, PA3 --> CS#, PB29 --> KEY# *//* PC1, PC15, PC13, PC11 for User LED */#define ZLG_CS AT91C_PIO_PA24#define ZLG_CLK AT91C_PIO_PA28#define ZLG_DATA AT91C_PIO_PA29#define ZLG_KEY AT91C_PIO_PB29#define USER_LED1 AT91C_PIO_PC1#define USER_LED2 AT91C_PIO_PC15#define USER_LED3 AT91C_PIO_PC13#define USER_LED4 AT91C_PIO_PC11static struct file_operations zlg7289_fops = { open: zlg7289_open, read: zlg7289_read, write: zlg7289_write, release: zlg7289_close,};static int input_flag = 0;static unsigned char input_data = 0xff;static void zlg7289_hardware_init (void){ DBG_ZLG7289("zlg7289_hardware_init\n"); AT91_SYS->PIOA_PER |= ZLG_CS | ZLG_DATA | ZLG_CLK; AT91_SYS->PIOB_PER |= ZLG_KEY; AT91_SYS->PIOC_PER |= USER_LED1 | USER_LED2 | USER_LED3 | USER_LED4; AT91_SYS->PIOA_OER |= ZLG_CS | ZLG_DATA | ZLG_CLK; AT91_SYS->PIOA_SODR |= ZLG_CS; AT91_SYS->PIOB_ODR |= ZLG_KEY; AT91_SYS->PIOB_IER |= ZLG_KEY; AT91_SYS->PMC_PCER |= 0x0000001c; AT91_SYS->PIOC_OER |= USER_LED1 | USER_LED2 | USER_LED3 | USER_LED4; AT91_SYS->PIOC_SODR |= USER_LED1 | USER_LED2 | USER_LED3 | USER_LED4; }static void uled_control (int index, unsigned char on_off){ unsigned long led_pin; DBG_ZLG7289("uled_control index=%d, on_off=%d\n", index, on_off); switch (index){ case 1: led_pin = USER_LED1; break; case 2: led_pin = USER_LED2; break; case 3: led_pin = USER_LED3; break; case 4: led_pin = USER_LED4; break; default: return; } if(on_off == 1) AT91_SYS->PIOC_SODR |= led_pin; else AT91_SYS->PIOC_CODR |= led_pin; return;}static unsigned char zlg7289_transform (unsigned char cmd, unsigned char data, int type){ int i; unsigned char bit, read_data=0; DBG_ZLG7289("zlg7289_transform cmd=%x, data=%x, type=%x\n", cmd, data, type); /* CS# Low */ AT91_SYS->PIOA_CODR |= ZLG_CS; udelay(50); /* Transform CMD */ for(i=1; i<=8; i++){ /* CMD Output */ bit = ( cmd >> (8-i) ) & 0x01 ; //DBG_ZLG7289("zlg7289_transform bit %x\n", bit); if( bit ) AT91_SYS->PIOA_SODR |= ZLG_DATA; else AT91_SYS->PIOA_CODR |= ZLG_DATA; udelay(50); /* CLK High */ AT91_SYS->PIOA_SODR |= ZLG_CLK; udelay(50); /* CLK Low */ AT91_SYS->PIOA_CODR |= ZLG_CLK; udelay(50); } switch (type) { case TRAN_CMD: break; case TRAN_CMD_DATA: /* Transform DATA */ for(i=7; i>=0; i--){ /* DATA Output */ bit = ( data >> i ) & 0x01 ; if( bit ) AT91_SYS->PIOA_SODR |= ZLG_DATA; else AT91_SYS->PIOA_CODR |= ZLG_DATA; udelay(50); /* CLK High */ AT91_SYS->PIOA_SODR |= ZLG_CLK; udelay(50); /* CLK Low */ AT91_SYS->PIOA_CODR |= ZLG_CLK; udelay(50); } break; case READ_CMD_DATA: /* DATA Input */ AT91_SYS->PIOA_ODR |= ZLG_DATA; /* Read DATA */ for(i=7; i>=0; i--){ /* CLK High */ AT91_SYS->PIOA_SODR |= ZLG_CLK; udelay(25); /**/ if( (AT91_SYS->PIOA_PDSR & ZLG_DATA) != 0 ) read_data |= 1 << i; udelay(25); /* CLK Low */ AT91_SYS->PIOA_CODR |= ZLG_CLK; udelay(50); } /* DATA Output */ AT91_SYS->PIOA_OER |= ZLG_DATA; break; default: DBG_ZLG7289("zlg7289_transform error type %x\n", type); break; }//end switch /* CS# High */ AT91_SYS->PIOA_SODR |= ZLG_CS; udelay(50); DBG_ZLG7289("zlg7289_transform: read_data = %x\n", read_data); return read_data;}static int zlg7289_open (struct inode *inode, struct file *file){ DBG_ZLG7289("zlg7289_open\n"); MOD_INC_USE_COUNT; return 0;}static int zlg7289_close (struct inode *inode, struct file *file){ DBG_ZLG7289("zlg7289_close\n"); MOD_DEC_USE_COUNT; return 0;}static int zlg7289_read (struct file *file, char *buf, size_t count, loff_t *ppos){ unsigned char data; DBG_ZLG7289("zlg7289_read: input_flag %d\n", input_flag);/* if(!input_flag){ repeat: set_current_state(TASK_INTERRUPTIBLE); if (!input_flag && !signal_pending(current)) { schedule(); goto repeat; } current->state = TASK_RUNNING; }*/ put_user(input_data, buf);// input_flag = 0; input_data = 0xff; return count;}static int zlg7289_write (struct file *file, const char *buf, size_t count, loff_t *ppos){ unsigned char cmd_type, on_off, cmd, data; DBG_ZLG7289("zlg7289_write: %p\n", buf); get_user(cmd_type, buf++); switch (cmd_type) { case ULED1_CONTROL: get_user(on_off, buf); uled_control(1, on_off); break; case ULED2_CONTROL: get_user(on_off, buf); uled_control(2, on_off); break; case ULED3_CONTROL: get_user(on_off, buf); uled_control(3, on_off); break; case ULED4_CONTROL: get_user(on_off, buf); uled_control(4, on_off); break; case ZLG_CMD: get_user(cmd, buf); zlg7289_transform(cmd, 0, TRAN_CMD); break; case ZLG_CMD_DATA: get_user(cmd, buf++); get_user(data, buf); zlg7289_transform(cmd, data, TRAN_CMD_DATA); break; default: DBG_ZLG7289("zlg7289_write: cmd_type = %d error\n", cmd_type); break; }//end switch return count; }static void zlg7289_interrupt (int irq, void *dev_id, struct pt_regs *regs){ unsigned char data = 0; //DBG_ZLG7289("zlg7289_interrupt\n"); if(AT91_SYS->PIOB_ISR & ZLG_KEY){ data = zlg7289_transform(0x15, 0, READ_CMD_DATA); } printk("zlg7289_interrupt: key = %x\n", data); if( data != 0xff){ input_flag = 1; input_data = data; } return; }static void __init zlg7289_init (void){ int ret; zlg7289_hardware_init(); ret = request_irq(AT91C_ID_PIOB, zlg7289_interrupt, 0,"ZLG7289", NULL); if( ret !=0 ){ printk(KERN_ERR "Request Interrupt %d failed: error = %d\n", AT91C_ID_PIOB, ret); goto fail_request_irq; } if(register_chrdev(ZLG7289_MAJOR, "zlg7289", &zlg7289_fops)){ DBG_ZLG7289("register_chrdev for zlg7289 error\n"); goto fail_register_chrdev; } printk(KERN_INFO __FILE__ ": Keyboard for AT91RM9200, Using IRQ %d\n", AT91C_ID_PIOB); return; fail_register_chrdev: free_irq(AT91C_ID_PIOB, NULL);fail_request_irq: return;}static void __exit zlg7289_cleanup (void){ unregister_chrdev(ZLG7289_MAJOR, "zlg7289"); return; }module_init(zlg7289_init);module_exit(zlg7289_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -