⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_se3208_1.c

📁 非阻塞方式的COM0的驱动
💻 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 + -