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

📄 directio1.c

📁 s3c2410的很多驱动实验
💻 C
字号:
/****************************************** *  这是一段含有基本功能的字符设备的驱动程序 *	$$$$  运行在内核空间 *	主要功能:对S3C2410的寄存器进行操作 * *****************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/ioport.h>	/* for verify_area */#include <linux/init.h>		/* for module_init */#include <asm/uaccess.h>  	/* for get_user and put_user */#include <asm-arm/arch-s3c2410/S3C2410.h>#include <linux/slab.h>#include <asm-arm/io.h>#include "directio.h"#define DEVICE_NAME "char_dev"static int 	Device_Open = 0;volatile unsigned long *led_addr1;	//ioremap()需要这样定义volatile unsigned long *led_addr2;	//ioremap()需要这样定义#define PCLK (50*1024*1024)int device_ioctl(struct inode *,struct file *,unsigned int, unsigned long);int request_port(unsigned int, int);int release_port(void);/**************************************   *	当一个过程要打开设备文件总是要调用这个函数 *	(对应于用户层的open()函数) * *************************************/static int device_open(struct inode *inode, struct file *file){	led_addr1 = ioremap(0x53000000,4);	//将看门狗WTCON物理地址映射到虚拟内存	led_addr2 = ioremap(0x53000008,4);	//将看门狗WTCNT物理地址映射到虚拟内存		*led_addr2 = 16896;	*led_addr1 = ((PCLK/1000000-1)<<8) | (3<<3) | (1) | (1 << 5);		if (Device_Open) return -EBUSY;		//不想同时与2个进程对话	Device_Open++;		return 0;}/**************************************   *	当一个过程要关闭设备文件就一定会调用本函数 *	该函数无返回值,因为它不能失败 *	(对应于用户层的close()函数) * *************************************/static int device_release(struct inode *inode, struct file *file){	Device_Open --;	// 准备下一次调用		return 0;}typedef struct port_stru{    unsigned int startaddr;    unsigned int endaddr;    struct port_stru * next;}port_stru;		//定义数据链表结构体struct port_stru *port_head = NULL;struct port_stru *port_tail = NULL;/*********************************************** * 端口申请 * 参数: *   port : port started *   nums : port nums(bytes) * 返回值: *   -1 : 参数错误 *   -2 : 端口忙 *    0 : OK *    1 : 端口已经被本模块请求 ***********************************************/int request_port(unsigned int port, int nums){	struct port_stru *temp = port_head;	if(nums <= 0)	{		printk("invalid ports\n");		return -1;	}	/* 在建好的链表中找出端口*/	while(temp)	{		if((port >= temp->startaddr && port <= temp->endaddr) && \		(port + nums - 1 >= temp->startaddr && port + nums -1 <= temp->endaddr))		{		//看看端口地址是否落在链表给出的地址范围内			return 1;	// 该端口已经在链表中already request by this module		}		temp = temp->next;	}	/*申请端口*/	if(check_region(port, nums))	{		printk("%x is used by another module\n", port);		return -2;	};	request_region(port, nums, DEVICE_NAME);	/* 把新端口添加到链表中 */	temp = (struct port_stru *)kmalloc(sizeof(struct port_stru), GFP_KERNEL);	temp->next = NULL;    	temp->startaddr = port;				//新端口的起始地址    temp->endaddr = port + nums -1;		//新端口的结束地址    	if(port_head == NULL)		//如果是头节点	{        port_tail = temp;		port_head = port_tail;	}    else		//如果不是头节点则要增加1个节点	{        port_tail->next = temp;		port_tail = port_tail->next;    }	return 0;}int release_port()	//释放链表{    struct port_stru *temp = port_head;    	while(port_head)    {		temp = port_head->next;		release_region(port_head->startaddr, 				port_head->endaddr - port_head->startaddr + 1);		kfree(port_head);		port_head = temp;	}	return 0;}/********************************************** *	当一个过程要对一个已经打开的设备文件进行I/o控制 *	就一定会调用本函数. *	 **********************************************/int device_ioctl(    struct inode *inode,    struct file *file,    unsigned int ioctl_num,		// ioctl的功能参数,在用户层指定    unsigned long ioctl_param)	// 用户传过来的数{	port_data temp;	port_data *data;		*led_addr2 = 16896;			/* 对应于ioctl()调用 */	switch (ioctl_num) 	{		case IOCTL_SET_MSG:	//接收到一个信息指针(在用户空间)用于对设备进行设置			printk("device_ioctl IOCTL_SET_MSG\n");						data = (struct port_data*) ioctl_param;	//获取用户传来的数据的首址			copy_from_user(&temp, data, sizeof(struct port_data));							// 该函数的功能:把用户空间的数据放到内核空间			if(temp.cmd == CMD_IRQ)			{				;			}			else			{				if(request_port(temp.startaddr, temp.nums) >= 0)				{		//写端口					switch(temp.opts)					{						case PORT_BYTE:		//向端口写1个字节							(*(unsigned char *)temp.startaddr) = temp.value;						break;						case PORT_HWORD:	//向端口写半个字(2字节)							(*(unsigned short *)temp.startaddr)= temp.value;						break;						case PORT_WORD:		//向端口写1个字(4字节)							//(*(unsigned int *)temp.startaddr)  = temp.value;							//outl(temp.value,temp.startaddr);						break;					}				}else				{					printk("\nrequest port error\n");					return -1;				}			}		break;		case IOCTL_GET_MSG:			data = (struct port_data*) ioctl_param;	//获取用户传来的数据的首址			copy_from_user(&temp, data, sizeof(struct port_data));									// 该函数的功能:把用户空间的数据放到内核空间			if(request_port(temp.startaddr, temp.nums) >= 0)			{			//读端口				switch(temp.opts)				{					case PORT_BYTE:						temp.value = (*(unsigned char *)temp.startaddr);					break;					case PORT_HWORD:						temp.value = (*(unsigned short *)temp.startaddr);					break;					case PORT_WORD:						temp.value = (*(unsigned int *)temp.startaddr);					break;				}			}else			{				printk("\nrequest port error\n");				return -1;			}			copy_to_user((struct port_data *) ioctl_param, &temp, sizeof(struct port_data));					// 该函数的功能:把内核空间的数据放到用户空间		break;	}	return 0;};/**************************************   *	模块声明:需要用到的函数的指针 *	 *************************************/struct file_operations Fops = {	.open 		= device_open,	.release 	= device_release,	.ioctl		= device_ioctl	};// 初始化模块: 注册字符设备static int __init directio_module_init( void ){	int ret_val;  	// 注册字符设备	ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);		// 若值为负则表示错误	if (ret_val < 0) {		printk ("%s failed with %d\n",			"Sorry, registering the character device ",			ret_val);		return ret_val;	}		printk ("Directio: let user program to access io port using outx & inx\n");	return 0;};// 卸载字符设备: rmmod命令将会调用本函数static void __exit directio_module_cleanup(void){	int ret;  	// 注销字符设备	ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);  	//  如果有错则报告	if (ret < 0)		printk("Error in module_unregister_chrdev: %d\n", ret);	else		printk("Close the char device OK!\n");		release_port();};module_init(directio_module_init);		//insmod命令调用module_exit(directio_module_cleanup);	//rmmod命令调用MODULE_LICENSE("GPL");MODULE_AUTHOR("Cvtech Co., Ltd <http://www.cvtech.com.cn>");MODULE_DESCRIPTION("directio char driver");

⌨️ 快捷键说明

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