📄 serial_se3208_1.c
字号:
/*********************************************************************
filename: serial_se3208_1.c
describtion: the uart0 driver of uClinux by Jupiter MCU.
organization: Xi'an Swip Co., Ltd. of China
Copyright (C) by Raymond Ma<mayp@swip.com.cn> 10/23/03
*********************************************************************/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#define UART0_NAME "uart0"
#define UART0_MAJOR 206
#define UATR0_MINOR
#define SET_PLAY_MODE 1
#define SET_LOOP_BACK_MODE 2
#define SET_BAUD_RATE 9
#define USTAT_OVERRUN_ERROR_BIT 0x00000001
#define USTAT_PARITY_ERR0R_BIT 0x00000002
#define USTAT_FRAME_ERR0R_BIT 0x00000004
#define USTAT_BREAK_DETECT_BIT 0x00000008
#define USTAT_RX_EMPTY_BIT 0x00000010
#define USTAT_TX_HOLD_BIT 0x00000020
#define USTAT_TX_EMPTY_BIT 0x00000040
#define USTAT_RX_FIFO_BIT 0x00000F00
#define USTAT_TX_FIFO_BIT 0x0000F000
static DECLARE_WAIT_QUEUE_HEAD(rx_queue);
static DECLARE_WAIT_QUEUE_HEAD(tx_queue);
static devfs_handle_t devfs_handle, devfs_uart0_dir;
static char *dev_iduart0 = UART0_NAME;
#define BUFSIZE 4096
#define FIFOSIZE 16
#define TIMEOUT 20
unsigned char uart0_rx_buf[BUFSIZE]; //,uart0_rx_bufb[BUFSIZE];
static char uart0_tx_buf[BUFSIZE];
size_t rx_buf_head,rx_buf_ptr; //rx buffer pointer, next receive byte will be saved in the place of rx buffer
//size_t rx_buf_count;//a,rx_buf_countb; //rx buffer bytes counter
int rx_buf_ful;
size_t tx_buf_ptr; //tx buffer pointer, next send byte will be took from the place of tx buffer
size_t tx_buf_count; //tx buffer bytes counter
int timeout;
static ssize_t uart0_read(struct file *filp, char *buf, size_t count, loff_t *l)
{
int state=0;
int buf_ptr;
int buf_count_tmp;
buf_ptr=rx_buf_ptr;
if (rx_buf_head<buf_ptr){
buf_count_tmp=buf_ptr-rx_buf_head; //the number of received words form buf head to current buf pointer
if(count>=buf_count_tmp){
copy_to_user(buf, &uart0_rx_buf[rx_buf_head], buf_count_tmp);
state=buf_count_tmp;
rx_buf_head=buf_ptr;
}else if(count<buf_count_tmp){
copy_to_user(buf,&uart0_rx_buf[rx_buf_head], count);
state=count;
rx_buf_head+=count;
}
}else if(rx_buf_head>buf_ptr){
buf_count_tmp=BUFSIZE-rx_buf_head; //the number of received words form buf head to buf max address
if(count>=(buf_ptr+buf_count_tmp)){
copy_to_user(buf,&uart0_rx_buf[rx_buf_head], buf_count_tmp);
copy_to_user((buf+buf_count_tmp),&uart0_rx_buf[rx_buf_head], buf_ptr);
state=buf_ptr+buf_count_tmp;
rx_buf_head=buf_ptr;
}else if(count<(buf_ptr+buf_count_tmp)){
if(count<buf_count_tmp){
copy_to_user(buf,&uart0_rx_buf[rx_buf_head],count);
state=count;
rx_buf_head+=count;
}else if(count>buf_count_tmp){
copy_to_user(buf,&uart0_rx_buf[rx_buf_head],buf_count_tmp);
copy_to_user((buf+buf_count_tmp),&uart0_rx_buf,(count-buf_count_tmp));
state=count;
rx_buf_head=count-buf_count_tmp;
}else{
copy_to_user(buf,&uart0_rx_buf[rx_buf_head],count);
state=count;
rx_buf_head=0;
}
}
}else{
state=0;
}
return state;
}
static ssize_t uart0_write(struct file *filp, const char *buf, size_t count, loff_t *l)
{
int i;
char *user_buf=(char *)buf;
int state=0;
disable_irq(IRQ_UART0TX);
if(tx_buf_count==0){
if (count>BUFSIZE){
copy_from_user(&uart0_tx_buf, user_buf, BUFSIZE);
#if 0
printk("\n");
for(i=0;i<BUFSIZE;i++){
printk("%c",uart0_tx_buf[i]);
}
printk("......\n");
#endif
tx_buf_count=BUFSIZE;
tx_buf_ptr=0;
state=BUFSIZE;
}else if (count<=BUFSIZE){
copy_from_user(&uart0_tx_buf, user_buf, count);
#if 0
printk("\n");
for(i=0;i<count;i++){
printk("%c",uart0_tx_buf[i]);
}
printk("......\n");
#endif
tx_buf_count=count;
tx_buf_ptr=0;
state=count;
}
}
if((*USTAT0 & USTAT_TX_EMPTY_BIT)==0){
for(i=0;i<FIFOSIZE;i++){
if(tx_buf_count==0){
break;
}else{
*UTXB0=uart0_tx_buf[tx_buf_ptr];
tx_buf_ptr++;
tx_buf_count--;
}
}
}
enable_irq(IRQ_UART0TX);
return state;
}
unsigned int uart0_poll(struct file *filp, struct poll_table_struct *poll_talbe)
{
unsigned int mask=0;
if(rx_buf_ptr!=rx_buf_head) mask |=POLLIN | POLLRDNORM; /*can read*/
if(tx_buf_count==0) mask |=POLLOUT | POLLWRNORM; /*can write*/
return mask;
}
static void uart0_tx(int irq, void *dev_idledflash, struct pt_regs *regs)
{
int i;
disable_irq(IRQ_UART0TX);
wake_up_interruptible(&tx_queue);
for(i=0;i<FIFOSIZE;i++){
if(tx_buf_count==0){
break;
}else{
*UTXB0=uart0_tx_buf[tx_buf_ptr];
tx_buf_ptr++;
tx_buf_count--;
}
}
enable_irq(IRQ_UART0TX);
}
static void uart0_rx(int irq, void *dev_idledflash, struct pt_regs *regs)
{
disable_irq(IRQ_UART0RX);
while(*USTAT0 & USTAT_RX_FIFO_BIT){
uart0_rx_buf[rx_buf_ptr]=*URXB0;
rx_buf_ptr++;
if(rx_buf_ptr==rx_buf_head){
printk("uart0 rx buffer overflow\n");
}
}
enable_irq(IRQ_UART0RX);
}
static int uart0_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd){
case 1: *UCON0=0x0211; break;
case 2: *UCON0=0x0281; break;/*loopback*/
case 9:
switch(arg){
case 300: *UBDR0=0x017F;timeout=31;break; // 1843200/16/(383+1)=300
case 600: *UBDR0=0x00BF;timeout=16;break; // 1843200/16/(191+1)=600
case 1200: *UBDR0=0x005F;timeout=8;break; // 1843200/16/(95+1)=1200
case 2400: *UBDR0=0x002F;timeout=5;break; // 1843200/16/(47+1)=2400
case 4800: *UBDR0=0x0017;timeout=4;break; // 1843200/16/(23+1)=4800
case 9600: *UBDR0=0x000B;timeout=3;break; // 1843200/16/(11+1)=9600
case 19200: *UBDR0=0x0005;timeout=2;break; // 1843200/16/(5+1)=19200
case 38400: *UBDR0=0x0002;timeout=1;break; // 1843200/16/(2+1)=38400 //default baud rate
case 57600: *UBDR0=0x0001;timeout=1;break; // 1843200/16/(1+1)=57600
case 115200: *UBDR0=0x0000;timeout=1;break; // 1843200/16/(0+1)=115200
default: //printk("this baud rate is not exist\n");
}
break;
default: //printk("this command is not exist\n");
}
return 0;
}
static int uart0_open(struct inode *inode, struct file *filp)
{
int ret;
MOD_INC_USE_COUNT;
rx_buf_head=0;
rx_buf_ptr=0;
tx_buf_count=0;
tx_buf_ptr=0;
if ((ret = request_irq(IRQ_UART0RX, uart0_rx,
SA_INTERRUPT, "uart0_rx", dev_iduart0)))
{
printk("uart0_rx_init: failed to register IRQ_UART0RX\n");
free_irq(IRQ_UART0RX, dev_iduart0);
return ret;
}
if((ret=request_irq(IRQ_UART0TX,uart0_tx,
0,"uart0_tx", dev_iduart0)))
{
printk("uart0_tx_init: failed to register IRQ_UART0TX\n");
free_irq(IRQ_UART0TX, dev_iduart0);
return ret;
}
disable_irq(IRQ_UART0RX);
disable_irq(IRQ_UART0TX);
*UCON0=0x0211;
// *UCON0=0x0281; /*loopback*/
// *UBDR0=0x017F;timeout=31; // 1843200/16/(383+1)=300
// *UBDR0=0x00BF;timeout=16; // 1843200/16/(191+1)=600
// *UBDR0=0x005F;timeout=8; // 1843200/16/(95+1)=1200
// *UBDR0=0x002F;timeout=5; // 1843200/16/(47+1)=2400
// *UBDR0=0x0017;timeout=4; // 1843200/16/(23+1)=4800
// *UBDR0=0x000B;timeout=3; // 1843200/16/(11+1)=9600
// *UBDR0=0x0005;timeout=2; // 1843200/16/(5+1)=19200
*UBDR0=0x0002;timeout=1; // 1843200/16/(2+1)=38400 //default baud rate
// *UBDR0=0x0001;timeout=1; // 1843200/16/(1+1)=57600
// *UBDR0=0x0000;timeout=1; // 1843200/16/(0+1)=115200
init_waitqueue_head(&rx_queue);
init_waitqueue_head(&tx_queue);
enable_irq(IRQ_UART0RX);
enable_irq(IRQ_UART0TX);
return 0;
}
static int uart0_release(struct inode *inode, struct file *filp)
{
free_irq(IRQ_UART0RX, dev_iduart0);
while(tx_buf_count!=0){ //if tx buffer have some data, uart0 release will sleep on tx wait queue.
interruptible_sleep_on(&tx_queue);
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(timeout);
free_irq(IRQ_UART0TX, dev_iduart0);
*UCON0=0x0000;
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations uart0_fops = {
read: uart0_read,
write: uart0_write,
poll: uart0_poll,
ioctl: uart0_ioctl,
open: uart0_open,
release: uart0_release,
};
int __init uart0_init(void)
{
int ret;
if ((ret=devfs_register_chrdev(UART0_MAJOR, UART0_NAME, &uart0_fops))!=0)
{
printk("registering of " UART0_NAME " is failed\n");
return ret;
}
devfs_uart0_dir = devfs_mk_dir(NULL, "uart0", NULL);
devfs_handle = devfs_register(devfs_uart0_dir, "uart0",
DEVFS_FL_DEFAULT,
UART0_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&uart0_fops, NULL);
printk("uart0 initialized\n");
return 0;
}
void __exit uart0_cleanup(void)
{
devfs_unregister_chrdev(UART0_MAJOR, UART0_NAME);
printk("uart0 removed\n");
}
module_init(uart0_init);
module_exit(uart0_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -