-
201221016Kim Haeram authored201221016Kim Haeram authored
dev.c 3.87 KiB
#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");