标签:
1、字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。
2、块设备:是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。
每一个字符设备或块设备都在/dev目录下对应一个设备文件。linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备。
二、字符设备驱动程序基础:
1、主设备号和次设备号(二者一起为设备号)
主设备号:反应设备类型。 次设备号:区分同类型设备。
typedef u_long dev_t; 在32位机中是4个字节,高12位表示主设备号,低12位表示次设备号
从dev_t中获得主次设备号: 通过主次设备号生成dev_t:
MAJOR(dev_t dev); MKDEV(int major,int minor);
MINOR(dev_t dev);
2、分配设备号(两种方法):
(1)静态申请:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
(2)动态分配:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
注销设备号:
void unregister_chrdev_region(dev_t from, unsigned count);
创建设备文件:
利用cat /proc/devices查看申请到的设备名,设备号。
(1)使用mknod手工创建:mknod filename type major minor
(2)自动创建;
利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。在驱动初始化代码里调用class_create为该设备创建一个class,再为每个设备调用device_create创建对应的设备。
3、字符设备驱动程序重要的数据结构:
(1)struct file:代表一个打开的文件描述符,系统中每一个打开的文件在内核中都有一个关联的struct file。它由内核在open时创建,并传递给在文件上操作的任何函数,直到最后关闭。当文件的所有实例都关闭之后,内核释放这个数据结构。
(2)struct inode:用来记录文件的物理信息。它和代表打开的file结构是不同的。一个文件可以对应多个file结构,但只有一个inode结构。inode一般作为file_operations结构中函数的参数传递过来。
inode译成中文就是索引节点。每个存储设备或存储设备的分区(存储设备是硬盘、软盘、U盘 ... ... )被格式化为文件系统后,应该有两部份,一部份是inode,另一部份是Block,Block是用来存储数据用的。而inode呢,就是用来存储这些数据的信息,这些信息包括文件大小、属主、归属的用户组、读写权限等。inode为每个文件进行信息索引,所以就有了inode的数值。操作系统根据指令,能通过inode值最快的找到相对应的文件
(3)struct file_operations
三、字符设备驱动程序设计:
1.设备注册:
在linux2.6内核中,字符设备使用struct cdev来描述
- struct cdev
- {
- struct kobject kobj;
- struct module *owner;
- struct file_operations *ops;
- struct list_head list;
- dev_t dev;
- unsigned int count;
- };
字符设备的注册分为三个步骤:
(1)分配cdev: struct cdev *cdev_alloc(void);
(2)初始化cdev: void cdev_init(struct cdev *cdev, const struct file_operations *fops);
(3)添加cdev: int cdev_add(struct cdev *p, dev_t dev, unsigned count)
2.设备操作的实现:file_operations函数集的实现(要明确某个函数什么时候被调用?调用来做什么操作?)
特别注意:驱动程序与应用程序的数据交换:
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);
put_user(local,user);
get_user(local,user);
3.设备注销:void cdev_del(struct cdev *p);
五:字符设备驱动程序分析:
(1)memdev.h
- #ifndef _MEMDEV_H_
- #define _MEMDEV_H_
-
- #ifndef MEMDEV_MAJOR
- #define MEMDEV_MAJOR 251 /*预设的mem的主设备号*/
- #endif
-
- #ifndef MEMDEV_NR_DEVS
- #define MEMDEV_NR_DEVS 2 /*设备数*/
- #endif
-
- #ifndef MEMDEV_SIZE
- #define MEMDEV_SIZE 4096
- #endif
-
-
- struct mem_dev
- {
- char *data;
- unsigned long size;
- };
-
- #endif /* _MEMDEV_H_ *
(2)memdev.c
- static mem_major = MEMDEV_MAJOR;
- module_param(mem_major, int, S_IRUGO);
- struct mem_dev *mem_devp;
- struct cdev cdev;
-
-
- int mem_open(struct inode *inode, struct file *filp)
- {
- struct mem_dev *dev;
-
-
- int num = MINOR(inode->i_rdev);
-
- if (num >= MEMDEV_NR_DEVS)
- return -ENODEV;
- dev = &mem_devp[num];
-
-
- filp->private_data = dev;
-
- return 0;
- }
-
- int mem_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
-
- static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
- {
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
- struct mem_dev *dev = filp->private_data;
-
-
- if (p >= MEMDEV_SIZE)
- return 0;
- if (count > MEMDEV_SIZE - p)
- count = MEMDEV_SIZE - p;
-
-
- if (copy_to_user(buf, (void*)(dev->data + p), count))
- {
- ret = - EFAULT;
- }
- else
- {
- *ppos += count;
- ret = count;
- printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
- }
- return ret;
- }
-
- static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
- {
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
- struct mem_dev *dev = filp->private_data;
-
-
- if (p >= MEMDEV_SIZE)
- return 0;
- if (count > MEMDEV_SIZE - p)
- count = MEMDEV_SIZE - p;
-
-
- if (copy_from_user(dev->data + p, buf, count))
- ret = - EFAULT;
- else
- {
- *ppos += count;
- ret = count;
-
- printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
- }
- return ret;
- }
-
- static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
- {
- loff_t newpos;
-
- switch(whence) {
- case 0:
- newpos = offset;
- break;
- case 1:
- newpos = filp->f_pos + offset;
- break;
- case 2:
- newpos = MEMDEV_SIZE -1 + offset;
- break;
- default:
- return -EINVAL;
- }
- if ((newpos<0) || (newpos>MEMDEV_SIZE))
- return -EINVAL;
-
- filp->f_pos = newpos;
- return newpos;
- }
-
-
- static const struct file_operations mem_fops =
- {
- .owner = THIS_MODULE,
- .llseek = mem_llseek,
- .read = mem_read,
- .write = mem_write,
- .open = mem_open,
- .release = mem_release,
- };
-
-
-
- static int memdev_init(void)
- {
- int result;
- int i;
-
-
- dev_t devno = MKDEV(mem_major, 0);
-
-
-
-
- if (mem_major)
- result = register_chrdev_region(devno, 2, "memdev");
- else
- {
- result = alloc_chrdev_region(&devno, 0, 2, "memdev");
- mem_major = MAJOR(devno);
- }
-
- if (result < 0)
- return result;
-
-
- cdev_init(&cdev, &mem_fops);
- cdev.owner = THIS_MODULE;
- cdev.ops = &mem_fops;
-
-
- cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
-
-
- mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
- if (!mem_devp)
- {
- result = - ENOMEM;
- goto fail_malloc;
- }
- memset(mem_devp, 0, sizeof(struct mem_dev));
-
-
- for (i=0; i < MEMDEV_NR_DEVS; i++)
- {
- mem_devp[i].size = MEMDEV_SIZE;
- mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
- memset(mem_devp[i].data, 0, MEMDEV_SIZE);
- }
-
- return 0;
-
- fail_malloc:
- unregister_chrdev_region(devno, 1);
-
- return result;
- }
-
-
- static void memdev_exit(void)
- {
- cdev_del(&cdev);
- kfree(mem_devp);
- unregister_chrdev_region(MKDEV(mem_major, 0), 2);
- }
-
- MODULE_AUTHOR("David Xie");
- MODULE_LICENSE("GPL");
-
- module_init(memdev_init);
- module_exit(memdev_exit);
(3)应用程序(测试文件):app-mem.c
- #include <stdio.h>
-
-
- int main()
- {
- FILE *fp0 = NULL;
- char Buf[4096];
-
-
- strcpy(Buf,"Mem is char dev!");
- printf("BUF: %s\n",Buf);
-
-
- fp0 = fopen("/dev/memdev0","r+");
- if (fp0 == NULL)
- {
- printf("Open Memdev0 Error!\n");
- return -1;
- }
-
-
- fwrite(Buf, sizeof(Buf), 1, fp0);
-
-
- fseek(fp0,0,SEEK_SET);
-
-
- strcpy(Buf,"Buf is NULL!");
- printf("BUF: %s\n",Buf);
-
-
-
- fread(Buf, sizeof(Buf), 1, fp0);
-
-
- printf("BUF: %s\n",Buf);
-
- return 0;
-
-
- }
字符设备驱动
标签:
原文地址:http://www.cnblogs.com/liuchengchuxiao/p/4209465.html