#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/delay.h> #include <asm/mach/map.h> #include <asm/io.h> #include <asm/uaccess.h> #define UART_MAJOR_NUMBER 504 #define UART_DEV_NAME "uart_ioctl" #define GPIO_BASE_ADDR 0x3F200000 #define GPFSEL1 0x04 #define USRT_BASE_ADDR 0x3F201000 #define UART_DR 0x00 #define UART_FR 0x18 #define UART_CR 0x30 #define UART_LCRH 0X2C #define IOCTL_MAGIC_NUMBER 'l' #define IOCTL_CMD_DIRECTION _IOWR(IOCTL_MAGIC_NUMBER, 0, int) #define IOCTL_CMD_RECEIVE _IOWR(IOCTL_MAGIC_NUMBER, 1, int) #define IOCTL_CMD_TRANSMIT _IOWR(IOCTL_MAGIC_NUMBER, 2, int) static void __iomem *gpio_base; static void __iomem *usrt_base; volatile unsigned int *gpsel1; volatile unsigned int *uart_dr; volatile unsigned int *uart_fr; volatile unsigned int *uart_cr; volatile unsigned int *uart_lcrh; int uart_open(struct inode *inode, struct file *filp){ printk(KERN_ALERT "UART driver open!!\n"); gpio_base = ioremap(GPIO_BASE_ADDR, 0x60); usrt_base = ioremap(USRT_BASE_ADDR, 0x60); gpsel1 = (volatile unsigned int *)(gpio_base + GPFSEL1); uart_dr = (volatile unsigned int *)(usrt_base + UART_DR); uart_fr = (volatile unsigned int *)(usrt_base + UART_FR); uart_cr = (volatile unsigned int *)(usrt_base + UART_CR); // 185PAGE uart_lcrh = (volatile unsigned int *)(usrt_base + UART_LCRH); return 0; } int uart_release(struct inode *inode, struct file *filp){ printk(KERN_ALERT "UART driver closed!!\n"); iounmap((void *)gpio_base); return 0; } long uart_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int txff, rxfe; int kbuf=-1; int i=0; char cbuf[1024]; int writelen = 0; int singlechar = '\0'; switch (cmd){ case IOCTL_CMD_DIRECTION: copy_from_user(&kbuf,(const void*)arg, 4); *gpsel1 |= (1<<14); // gpio14 takes alt0 TXD0 *gpsel1 |= (1<<17); // gpio15 takes alt0 RXD0 if(kbuf==0){ // input *uart_cr &= ~(1<<0); // disable uart. *uart_lcrh &= ~(1<<4); // FEN <- 0. *uart_cr &= ~(1<<8); // TXE <- 0 *uart_cr |= (1<<9); // RXE <- 1 *uart_lcrh |= (1<<4); // FEN <- 1. *uart_cr |= (1<<0); // enable uart. } else if(kbuf==1){ // output *uart_cr &= ~(1<<0); // disable uart. *uart_lcrh &= ~(1<<4); // FEN <- 0. *uart_cr &= ~(1<<9); // RXE <- 0 *uart_cr |= (1<<8); // TXE <- 1 *uart_lcrh |= (1<<4); // FEN <- 1. *uart_cr |= (1<<0); // enable uart. } else{ // error. printk(KERN_ALERT "ERR in DIRECTION: invalid operand\n"); } break; case IOCTL_CMD_RECEIVE: printk(KERN_ALERT "receive called\n"); /* rxfe = 0; while(!rxfe){ rxfe = (*uart_fr>>4); // read RXFE } // now rx is not empty */ singlechar = (*uart_dr); // read DATA copy_to_user((void*)arg, (const void*)&singlechar, 4); break; case IOCTL_CMD_TRANSMIT: printk(KERN_ALERT "transmit called\n"); copy_from_user(&cbuf,(const void*)arg, 1024); writelen = strlen(cbuf); for(i=0; i<writelen; i++){ singlechar = cbuf[i]; /* txff = 1; while(txff){ txff = (*uart_fr>>5); // read TXFF } // now tx fifo is not full * */ *uart_dr |= (int) singlechar; // write DATA } break; } return 0; } static struct file_operations uart_fops = { .owner = THIS_MODULE, .open = uart_open, .release = uart_release, .unlocked_ioctl = uart_ioctl }; int __init uart_init(void){ if(register_chrdev(UART_MAJOR_NUMBER, UART_DEV_NAME, &uart_fops) < 0 ) printk(KERN_ALERT "UART driver initialization failed\n"); else printk(KERN_ALERT "UART driver initialization successful\n"); return 0; } void __exit uart_exit(void){ unregister_chrdev(UART_MAJOR_NUMBER, UART_DEV_NAME); printk(KERN_ALERT "UART driver exit done\n"); } module_init(uart_init); module_exit(uart_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Haeram"); MODULE_DESCRIPTION("des");