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

📄 serial_se3208_2.c

📁 一个基于嵌入式linux的串口驱动程序和测试程序的源码
💻 C
字号:
#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 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 128
#define FIFOSIZE 16
#define TIMEOUT 10
unsigned char uart0_rx_buf[BUFSIZE];
static char uart0_tx_buf[BUFSIZE];
size_t rx_buf_count, rx_user_count;
size_t tx_buf_count, tx_user_count;

static ssize_t uart0_read(struct file *filp, char *buf, size_t count, loff_t *l)
{
	char *user_buf=buf;

	rx_buf_count=0;
	rx_user_count=count;
	
	while(rx_user_count>0){
		if (*USTAT0 & USTAT_RX_EMPTY_BIT){
			uart0_rx_buf[rx_buf_count]=*URXB0;
			rx_buf_count++;
		}else{
			interruptible_sleep_on_timeout(&rx_queue, TIMEOUT);
		}
	
		if (rx_user_count>BUFSIZE && rx_buf_count==BUFSIZE){
			copy_to_user(user_buf, &uart0_rx_buf, BUFSIZE);
			user_buf+=BUFSIZE;
			rx_buf_count=0;
			rx_user_count-=BUFSIZE;
		}else if (rx_user_count==rx_buf_count){
			copy_to_user(user_buf, &uart0_rx_buf, rx_user_count);
			rx_user_count=0;
			rx_buf_count=0;
		}
	}
	return count;
}

static ssize_t uart0_write(struct file *filp, const char *buf, size_t count, loff_t *l)
{
	char *user_buf=buf;
	int i,j=0;

	tx_buf_count=0;
	tx_user_count=count;


	while(tx_user_count>0){
		if (tx_user_count>BUFSIZE){
			copy_from_user(&uart0_tx_buf, user_buf, BUFSIZE);
			user_buf+=BUFSIZE;
			tx_buf_count=BUFSIZE;
			j=0;
			tx_user_count-=BUFSIZE;
		}else if (tx_user_count<=BUFSIZE){
			copy_from_user(&uart0_tx_buf, user_buf, tx_user_count);
			tx_buf_count=tx_user_count;
			j=0;
			tx_user_count=0;
		}

		while (tx_buf_count>0){
				if (tx_buf_count>FIFOSIZE){
					for(i=0;i<FIFOSIZE;i++){
						*UTXB0=uart0_tx_buf[j];
						j++;
					}
					tx_buf_count-=FIFOSIZE;
				}else if (tx_buf_count<=FIFOSIZE){
					for(i=0;i<tx_buf_count;i++){
						*UTXB0=uart0_tx_buf[j];
						j++;
					}
					tx_buf_count-=tx_buf_count;
				}				
			interruptible_sleep_on(&tx_queue);
		}
	}
	return count;
}

unsigned int uart0_poll(struct file *filp, struct poll_table_struct *poll_talbe)
{
	return 0;
}


static void uart0_tx(int irq, void *dev_idledflash, struct pt_regs *regs)
{
	wake_up_interruptible(&tx_queue);
}



static void uart0_rx(int irq, void *dev_idledflash, struct pt_regs *regs)
{
	wake_up_interruptible(&rx_queue);
}


static int uart0_open(struct inode *inode, struct file *filp)
{
	int ret;
	MOD_INC_USE_COUNT;

	if ((ret = request_irq(IRQ_UART0RX, uart0_rx,
				       0, "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;  //  1843200/16/(383+1)=300
//	*UBDR0=0x00BF;  //  1843200/16/(191+1)=600
//	*UBDR0=0x005F;  //  1843200/16/(95+1)=1200
//	*UBDR0=0x002F;  //  1843200/16/(47+1)=2400
//	*UBDR0=0x0017;  //  1843200/16/(23+1)=4800
//	*UBDR0=0x000B;  //  1843200/16/(11+1)=9600
//	*UBDR0=0x0005;  //  1843200/16/(5+1)=19200
	*UBDR0=0x0002;	// 1843200/16/(2+1)=38400
//	*UBDR0=0x0001;  // 1843200/16/(1+1)=57600
//	*UBDR0=0x0000;  // 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_UART0TX, dev_iduart0);
	free_irq(IRQ_UART0RX, 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:	NULL,
	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 + -