/* //insmod hello //rmmod hello //mknod /dev/ir c 250 0 // /proc/devices */ #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #include #include #include #include #include #include #include "hw.h" #ifndef _IR_ #define _IR_ //#define EXPORT_NO_SYMBOLS /* IOCTL functions */ #define IR_GET_BAUD_RATE 0 #define IR_SET_BAUD_RATE 1 #define IR_GET_STATUS_0 2 #define IR_GET_STATUS_1 3 /* Control Registers */ //#define UTCR0 0x80030000 //#define UTCR1 0x80030004 //#define UTCR2 0x80030008 //#define UTCR3 0x8003000C //#define UTCR4 0x80030010 #define UTCR0 __REG(0x80030000) #define UTCR1 __REG(0x80030004) #define UTCR2 __REG(0x80030008) #define UTCR3 __REG(0x8003000C) #define UTCR4 __REG(0x80030010) /* Data Register */ //#define UTDR 0x80030014 #define UTDR __REG(0x80030014) /* Status Registers */ //#define UTSR0 0x8003001C //#define UTSR1 0x80030029 #define UTSR0 __REG(0x8003001C) #define UTSR1 __REG(0x80030029) /* HSSP Register */ //#define HSCR0 0x80040060 #define HSCR0 __REG(0x80040060) /* Clear byte for status registers */ #define CLEAR 0xFF /* UTCR0 */ #define PE_OFF 0x00 /* Disables parity */ #define PE_ON 0x01 /* Enables parity */ #define OES_OFF 0x00 /* Odd parity */ #define OES_ON 0x02 /* Even parity */ #define SBS_OFF 0x00 /* One stop bit */ #define SBS_ON 0x04 /* Two stop bits */ #define DSS_OFF 0x00 /* 7-bit data */ #define DSS_ON 0x08 /* 8-bit data */ #define SCE_OFF 0x00 /* On-chip baud rate generator */ #define SCE_ON 0x10 /* Clock input via GPIO pin 20 */ #define RCE_OFF 0x00 /* Rising edge of clock input for receive if SCE_ON */ #define RCE_ON 0x20 /* Falling edge of clock input for receive if SCE_ON */ #define TCE_OFF 0x00 /* Rising edge of clock input for transmit if SCE_ON */ #define TCE_ON 0x40 /* Falling edge of clock input for transmit if SCE_ON */ /* UTCR1 and UTCR2 */ #define BRD 0x18 /* Baud Rate Generator for 9600 bps (default) */ /* UTCR3 */ #define RXE_OFF 0x01 /* Disable UART receive operation */ #define RXE_ON 0x00 /* Enable UART receive operation */ #define TXE_OFF 0x02 /* Disable UART transmit operation */ #define TXE_ON 0x00 /* Enable UART transmit operation */ #define BRK_OFF 0x04 /* UART in normal operation */ #define BRK_ON 0x00 /* Force TXD3 low to generate a break */ #define RIE_OFF 0x00 /* Disable receive FIFO interrupt */ #define RIE_ON 0x08 /* Enable receive FIFO interrupt */ #define TIE_OFF 0x00 /* Disable transmit FIFO interrupt */ #define TIE_ON 0x10 /* Enable transmit FIFO interrupt */ #define LBM_OFF 0x00 /* Disable Loopback mode */ #define LBM_ON 0x20 /* Enable Loopback mode */ /* UTCR4 */ #define HSE_ON 0x01 /* HP-SIR modulation enabled if ITR=0 */ #define HSE_OFF 0x00 /* HP-SIR modulation disabled if ITR=0 */ /* HSCR0 */ #define ITR_ON 0x01 /* IrDA transmission rate -> 4 Mbps */ #define ITR_OFF 0x00 /* IrDA transmission rate -> 115.2 Kbps */ /* Flow Control */ #define XOFF 0x00 #define XON 0x01 #define ERROR 0x00 #define OK 0x01 #endif int ir_major = 250; int ir_busy = 0; MODULE_PARM(ir_major,"i"); /*typedef struct IR_Dev { void **data; struct IR_Dev *next; int quantum; int qset; unsigned long size; devfs_handle_t handle; unsigned int access_key; struct semaphore sem; } IR_Dev; */ int init_module(void); void cleanup_module(void); int ir_open(struct inode *inode,struct file *filp); int ir_close(struct inode *inode, struct file *filp); ssize_t ir_read(struct file *filp,char* buf,size_t count,loff_t *f_pos); ssize_t ir_write(struct file *filp, char* buf, size_t count, loff_t *f_pos); int ir_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg); static struct file_operations ir_fops = { NULL, /* module */ NULL, /* lseek */ (void *)ir_read, /* read */ (void *)ir_write, /* write */ NULL, /* readdir */ NULL, /* select */ (void *)ir_ioctl, /* ioctl */ NULL, /* mmap */ (void *)ir_open, /* open */ (void *)ir_close, /* close */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* lock */ NULL, /* readv */ }; int ir_open(struct inode *inode,struct file *filp) { if(ir_busy) return -EBUSY; ir_busy = 1; return 0; } int ir_close(struct inode *inode, struct file *filp) { ir_busy = 0; return 0; } ssize_t ir_read(struct file *filp,char* buf,size_t count,loff_t *f_pos) { unsigned char byte; volatile unsigned char *p; p = (volatile unsigned char *)(UTDR); byte = *p; copy_to_user(buf,&byte,1); count = 1; return 1; } ssize_t ir_write(struct file *filp, char* buf, size_t count, loff_t *f_pos) { unsigned char byte; volatile unsigned char *p; copy_from_user((char *)&byte, (char *)buf, 1); p = (volatile unsigned char *)(UTDR); *p = byte; return count; } int ir_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg) { unsigned int brd, r; unsigned char b; volatile unsigned char *p; switch(cmd) { case IR_GET_BAUD_RATE: p = (volatile unsigned char *)(UTCR1); b = *p; brd = ((unsigned int)b)&0x000F; brd <<= 8; brd &= 0x0F00; p = (volatile unsigned char *)(UTCR2); b = *p; brd |= ((unsigned int)b)&0x00FF; r = (3686400/(16*(brd+1))); copy_to_user((unsigned int *)arg,&r,1); break; case IR_SET_BAUD_RATE: copy_from_user(&r, (unsigned int *)arg, 1); brd = ((3686400/(16*r)-1)); b = ((unsigned char)(brd>>8))&0x0F; p = (volatile unsigned char *)(UTCR1); *p = b; b = ((unsigned char)brd)&0xFF; p = (volatile unsigned char *)(UTCR2); *p = b; break; case IR_GET_STATUS_0: p = (volatile unsigned char *)(UTSR0); b = *p; copy_to_user((unsigned char *)arg,&b,1); break; case IR_GET_STATUS_1: p = (volatile unsigned char *)(UTSR1); b = *p; copy_to_user((unsigned char *)arg,&b,1); break; default: return -EINVAL; } return 0; } int init_module(void) { int err; unsigned int brd; unsigned char b; volatile unsigned char *p; err = register_chrdev(ir_major,"ir",&ir_fops); if(err<0) printk("<0>register_chrdev error\n"); /* Clear all writable or "sticky" status bits, writing a 1 to each bit */ p = (volatile unsigned char *)(UTSR0); *p = CLEAR; p = (volatile unsigned char *)(UTSR1); *p = CLEAR; /* Program the desired operation mode in the control registers */ b = (PE_OFF | OES_OFF | SBS_OFF | DSS_ON | SCE_OFF | RCE_OFF | TCE_OFF); p = (volatile unsigned char *)(UTCR0); *p = b; brd = BRD; b = ((unsigned char)(brd>>8))&0x0F; p = (volatile unsigned char *)(UTCR1); *p = b; b = ((unsigned char)brd)&0xFF; p = (volatile unsigned char *)(UTCR2); *p = b; /* ACGHP: setting RIE_ON and TIE_ON to enable interrupts setting LBM_ON to enable loopback mode */ b = (RXE_ON | TXE_ON | BRK_OFF | RIE_OFF | TIE_OFF | LBM_ON); p = (volatile unsigned char *)(UTCR3); *p = b; /* Tell the HSSP control register that we're going SIR */ b = ITR_OFF; p = (volatile unsigned char *)(HSCR0); *p = b; /* Now we can enable the HP-SIR modulation in the UART register */ b = HSE_ON; p = (volatile unsigned char *)(UTCR4); *p = b; printk("<0>module OK\n"); return 0; } void cleanup_module(void) { int i=0; while(unregister_chrdev(ir_major+i,"ir")==-EINVAL) { i++; printk("-"); if(i==512) return; } printk("<0>module OK\n"); } /*module_init(init_module); module_exit(cleanup_module);*/