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

📄 lucas_com.c

📁 Linux下面的串口驱动程序
💻 C
字号:
/****//**pre-processing directives for version control*/#define DEBUG#define PRE_2_6/**pre-processing directives for functionality*/#define easy_printk(x) printk(KERN_INFO	x)#define easy_printk2(x,y) printk(KERN_INFO x,y)#define easy_printk3(x,y,z) printk(KERN_INFO x,y,z)#define myprintk(x) easy_printk2("lucas%05d-->\t",se_mypr_num++);	easy_printk(x)#define myprintk2(x,y) easy_printk2("lucas%05d-->\t",se_mypr_num++);	easy_printk2(x,y)#define myprintk3(x,y,z) easy_printk2("lucas%05d-->\t",se_mypr_num++);	easy_printk3(x,y,z)#ifdef DEBUG#define dbgprintk(x) easy_printk2("lucas debug%05d-->\t",se_dbgpr_num++);	easy_printk(x)#define dbgprintk2(x,y) easy_printk2("lucas debug%05d-->\t",se_dbgpr_num++);	easy_printk2(x,y)#define dbgprintk3(x,y,z) easy_printk2("lucas debug%05d-->\t",se_dbgpr_num++);	easy_printk3(x,y,z)#else #define dbgprintk(x)#define dbgprintk2(x,y)#define dbgprintk3(x,y,z)#endif/**file inclusion*/#include<linux/init.h>#include<linux/module.h>#include<linux/cdev.h>#include<linux/types.h>#include<linux/fs.h>#include<asm/io.h>#include<linux/interrupt.h>#include<asm/uaccess.h>MODULE_LICENSE("Dual BSD/GPL");/**function declaration*/void wait(long _micro_sec);int	com_open(struct inode* _pinode, struct file* _pfile);int	com_release(struct inode* _pinode, struct file* _pfile);ssize_t	com_lq_read(struct file* _pfile, char __user* _puser, size_t _size, loff_t* _poff);ssize_t	com_irq_read(struct file* _pfile, char __user* _puser, size_t _size, loff_t* _poff);ssize_t	com_lq_write(struct file* _pfile, const char __user* _puser, size_t _size, loff_t* _poff);ssize_t	com_irq_write(struct file* _pfile, const char __user* _puser, size_t _size, loff_t* _poff);int	com_ioctl(struct inode* _pinode, struct file* _pfile, unsigned int _arg1, unsigned long _arg2); static irqreturn_t com_handler(int _irq, void* _dev_id, struct pt_regs* _regs);/**user-defined types*///The se_fops must be an external valuestruct file_operations se_fops={        .owner=THIS_MODULE,        .open=com_open,        .release=com_release,        .ioctl=com_ioctl,        .read=com_irq_read,	        .write=com_lq_write,	};struct dev_id{	int maj_no;	int min_no;	//char* dev_name;};/**extern variables*/static int se_mypr_num=1;static int se_dbgpr_num=1;static int se_open_times=0;struct dev_id se_com_dev_id;static int se_rd_bytes=0;static char se_rd_buf[3];static int se_rd_index=0;static char se_wr_buf[3];static int se_wr_index=0;/**const variables*/static const int MAJ_NUM=100;static const char *NAME="lucas_com";static const int PORT_DATA1=0x3f8;static const int PORT_DATA2=0x3f9;static const int PORT_LINE_CTL=0x3fb;static const int PORT_LINE_STS=0x3fd;static const int PORT_IRQ_CTL=0x3f9;static const int PORT_MODEM_CTL=0x3fc;static const int BAUD_RATE=9600;static const int FREQ=1843200/16;static const int IRQ_COM=4;static const int ENABLED_IRQ=0x01;	//enabled IRQ bit  static const long QUERY_TIME_OUT=10^6;	//time out for query/**function definition*/static int com_init(void){	#ifdef PRE_2_6	int reg_rslt;	int low_byte,upp_byte;	myprintk2("Driver %s initializing\n",NAME);	reg_rslt=register_chrdev(MAJ_NUM,NAME,&se_fops);	//manipulate the I/O ports	low_byte=(FREQ/BAUD_RATE)&0xff;	upp_byte=((FREQ/BAUD_RATE)>>8)&0xff;	//set the baud rate	outb_p(0x80,PORT_LINE_CTL);	outb_p(low_byte,PORT_DATA1);	outb_p(upp_byte,PORT_DATA2);	//set the data format	outb_p(0x03,PORT_LINE_CTL);	return 0;	#else	#endif	}static void com_exit(void){	#ifdef PRE_2_6	int ureg_rslt;			myprintk2("%s is removed\n",NAME);	ureg_rslt=unregister_chrdev(MAJ_NUM,NAME);	#else	#endif}int	com_open(struct inode* _pinode, struct file* _pfile){	int result;	int one_byte;	se_open_times++;	dbgprintk2("opening driver %s\n",NAME);	dbgprintk2("Device is openned %d times\n",se_open_times);	//firstly check device-specific errors	//request IRQ for the first open	if(1==se_open_times)		{		result=request_irq(IRQ_COM,com_handler,0,NAME,&se_com_dev_id);		if(0==result)		{			myprintk3("Success requesting IRQ %d for driver %s\n",IRQ_COM,NAME);			//if the IRQ is allocated successfully, then enable the			//hardware IRQ, note the order here does matter.				//firstly disable the modem IRQ to refresh			/**			one_byte=inb_p(PORT_MODEM_CTL);			outb_p(one_byte&(~0x0b),PORT_MODEM_CTL);//may have bug here			dbgprintk2("MODEM_CTL is 0x%x after disabled\n",inb_p(PORT_MODEM_CTL));			**/			//then enable the modem IRQ			one_byte=inb_p(PORT_MODEM_CTL);			outb_p(one_byte|0x0b,PORT_MODEM_CTL);//may have bug here			dbgprintk2("MODEM_CTL is 0x%x after enabled\n",inb_p(PORT_MODEM_CTL));									//firstly disable according bits in the  IRQ register to refresh			/**			one_byte=inb_p(PORT_IRQ_CTL);			outb_p(one_byte&(~ENABLED_IRQ),PORT_IRQ_CTL);			dbgprintk2("IRQ_CTL is 0x%x after disabled\n",inb_p(PORT_IRQ_CTL));			**/			//then enable according bits in the  IRQ register			outb_p(one_byte|ENABLED_IRQ,PORT_IRQ_CTL);					dbgprintk2("IRQ_CTL is 0x%x after enabled\n",inb_p(PORT_IRQ_CTL));					}		else		{			printk(KERN_ALERT "Error requesting IRQ for driver %s\n",NAME);		}		}	return 0;}int	com_release(struct inode* _pinode, struct file* _pfile){	int one_byte;	se_open_times--;	myprintk2("releasing driver %s\n",NAME);		dbgprintk2("Device is openned %d times\n",se_open_times);	if(0==se_open_times)	{		//releasing the requested IRQ as well				free_irq(IRQ_COM,&se_com_dev_id);				//disable the hardware as well			one_byte=inb_p(PORT_MODEM_CTL);		//firstly disable modem IRQ		outb_p(one_byte&(~0x0b),PORT_MODEM_CTL);//may have bug here		dbgprintk2("MODEM_CTL is 0x%x after disabled\n",inb_p(PORT_MODEM_CTL));		//then disable according bits in the  IRQ register		one_byte=inb_p(PORT_IRQ_CTL);		outb_p(one_byte&(~ENABLED_IRQ),PORT_IRQ_CTL);				dbgprintk2("IRQ_CTL is 0x%x after disabled\n",inb_p(PORT_IRQ_CTL));				myprintk3("driver %s freed the IRQ%d\n",NAME,IRQ_COM);	}	return 0;}/**reading from the COM using the loop-query mode**/ssize_t	com_lq_read(struct file* _pfile, char __user* _puser, size_t _size, loff_t* _poff){		int one_bit=0,one_byte=0;	int read_bytes=0;	char buf[_size];	int i=0;	dbgprintk2("user buffer address:%llu\n",_puser);	dbgprintk2("reading from driver %s\n",NAME);	//to do	copy_to_user(_puser,se_rd_buf,sizeof(se_rd_buf));		return 0;	//query for the status of line register	//and check bit D0 for whether the data is ready	//for receiving			one_byte=inb_p(PORT_LINE_STS);			dbgprintk2("The line status in hex:0x%x\n",one_byte);	dbgprintk2("The line status after previous query:0x%x\n",inb_p(PORT_LINE_STS));	one_bit=one_byte&0x01;		while(0)	{		//firstly wait for some time until time is out		wait(QUERY_TIME_OUT); 		if(1==one_bit)		{				one_byte=inb_p(PORT_DATA1);							dbgprintk2("One char %c is received\n",one_byte);			if(i<_size)			{								buf[i]=one_byte;				i++;				read_bytes++;			}			else	//specified size is read			{					copy_to_user(_puser,buf,_size);				return read_bytes;					}									//The commented code is not needed as the hardware will do the job automatically			//one_byte=one_byte&0xfe;			//outb_p(one_byte,PORT_LINE_STS);									}		else	//time is out		{		}		}}		/**reading from the COM using the interrupt mode**/ssize_t	com_irq_read(struct file* _pfile, char __user* _puser, size_t _size, loff_t* _poff){		unsigned long copied_bytes=0;	dbgprintk2("reading from %s using IRQ\n",NAME);	dbgprintk2("user buffer address:%ull\n",_puser);	copied_bytes=sizeof(se_rd_buf)-copy_to_user(_puser,se_rd_buf,sizeof(se_rd_buf));	dbgprintk2("copied_bytes by com_irq_read %u\n",copied_bytes);	return copied_bytes;			}/**writing to the COM using loop-query mode**/ssize_t	com_lq_write(struct file* _pfile, const char __user* _puser, size_t _size, loff_t* _poff){	int one_bit=0,one_byte=0;	unsigned long written_bytes=0;	dbgprintk2("writing to driver %s\n",NAME);		copy_from_user(se_wr_buf,_puser,sizeof(se_wr_buf));	for(se_wr_index=0;se_wr_index<sizeof(se_wr_buf);se_wr_index++)	{		//check bit D5 for whether 		//the send register is empty			one_bit=0;		while(0==one_bit)		{			one_byte=inb_p(PORT_LINE_STS);			dbgprintk2("The line status in hex:0x%x\n",one_byte);			dbgprintk2("The line status after previous query:0x%x\n",inb_p(PORT_LINE_STS));			one_bit=(one_byte>>5)&0x01;		}		//to be modified 		if(1==one_bit)		{							outb_p(se_wr_buf[se_wr_index],PORT_DATA1);			written_bytes++;						/**The commented code is not needed as the hardware will do the job automatically			one_byte=one_byte|0x60;			outb_p(one_byte,PORT_LINE_STS);				*/		}	}	return written_bytes;}int	com_ioctl(struct inode* _pinode, struct file* _pfile, unsigned int _arg1, unsigned long  _arg2){	dbgprintk2("Controlling %s\n",NAME);	return 0;} static irqreturn_t com_handler(int _irq, void* _dev_id, struct pt_regs* _regs){	int copied_bytes=0;	int one_byte;		//firstly CLI of interface card if needed		if(1)	//if(MAJ_NUM==((struct dev_id *)_dev_id)->maj_no)	{		dbgprintk("Entering com_handler\n");		one_byte=inb_p(PORT_DATA1);				dbgprintk2("A char %c was read\n",one_byte);		//dbgprintk3("A char '\%c\'=0x%x was read\n",one_byte,one_byte);		se_rd_buf[se_rd_index]=one_byte;		se_rd_index=(se_rd_index+1)%sizeof(se_rd_buf);									}	else	{		return IRQ_NONE;	}	return IRQ_HANDLED;		}//waiting for specified secondsvoid wait(long _micro_sec){	long long loop=(long long)3*10^9*_micro_sec/10^6;	while(loop--)	{		//do nothing;	}}module_init(com_init);module_exit(com_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -