KDD字符设备基本概念
来源:互联网 发布:喝咖啡会难怀孕吗 知乎 编辑:程序博客网 时间:2024/05/17 23:39
数据结构及关系如下:
include/linux/cdev.h12 struct cdev {13 struct kobject kobj;14 struct module *owner;15 const struct file_operations *ops;16 struct list_head list;17 dev_t dev;18 unsigned int count;19 };include/linux/fs.h518 /*519 * Keep mostly read-only and often accessed (especially for520 * the RCU path lookup and 'stat' data) fields at the beginning521 * of the 'struct inode'522 */523 struct inode {595 union {596 struct pipe_inode_info *i_pipe;597 struct block_device *i_bdev;598 struct cdev *i_cdev;599 };612 };include/linux/fs.h765 struct file {777 struct inode *f_inode; /* cached value */800 /* needed for tty driver, and maybe others */801 void *private_data;812 };
struct cdev表示字符设备,ops为文件操作函数,dev为设备号:
// include/linux/cdev.hstruct cdev { struct module *owner; const struct file_operations *ops; dev_t dev; // ......};
关联cdev和ops的函数是cdev_init:
void cdev_init(struct cdev *, const struct file_operations *);
关联cdev和dev的函数是cdev_add,即添加字符设备:
int cdev_add(struct cdev *, dev_t, unsigned);
添加字符设备后,就可以用mknod创建文件,可以读写。
创建设备号时,需要指定设备名,即函数alloc_chrdev_region。
mknod需要知道设备名和设备号,安装驱动后,可以在/proc/devices中依据设备名查到设备号:
insmod hello.ko \&& major_device_number=`awk '$2=="winlin" {print $1}' /proc/devices` \&& mknod /dev/winlin c $major_device_number 0
创建文件后,就可以读写这个文件/dev/winlin了:
cat /dev/winlin \&& echo "linux is a great operating system for server." > /dev/winlin \&& cat /dev/winlin
最后,删除设备和驱动:
rm -f /dev/winlin \&& rmmod hello
完整源码如下:
// hello.c#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("GPL");dev_t devno;int count = 1;char* name = "winlin";/**makeinsmod hello.ko \&& major_device_number=`awk '$2=="winlin" {print $1}' /proc/devices` \&& mknod /dev/winlin c $major_device_number 0cat /dev/winlin \&& echo "linux is a great operating system for server." > /dev/winlin \&& cat /dev/winlinrm -f /dev/winlin \&& rmmod hello*//*module_param(count, int, S_IRUGO|S_IWUSR);*/module_param(name, charp, S_IRUGO|S_IWUSR);#include <linux/fs.h>#include <linux/uaccess.h>char _data[1024] = "KDD char device buffer.\n";ssize_t hello_read(struct file* file, char __user* data, size_t size, loff_t* offset){ int len = strlen(_data); if(*offset >= len){ return 0; } printk(KERN_ALERT "hello_read, len=%d, size=%d, offset=%d\n", len, (int)size, (int)*offset); if(copy_to_user(data, _data, (len < size)? len:size) != 0){ return -1; } *offset += len; return len;}ssize_t hello_write(struct file* file, const char __user* data, size_t size, loff_t* offset){ int size_to_write = (sizeof(_data) - 1 < size)? sizeof(_data) - 1:size; printk(KERN_ALERT "hello_write, len=%d, size=%d, offset=%d\n", size_to_write, (int)size, (int)*offset); if(copy_from_user(_data, data, size_to_write) != 0){ return -1; } _data[size_to_write] = 0; return size_to_write;}int hello_open(struct inode* node, struct file* file){ return 0;}int hello_release(struct inode* node, struct file* file){ return 0;}struct file_operations fops = { .owner = THIS_MODULE, .read = hello_read, .write = hello_write, .open = hello_open, .release = hello_release,};#include <linux/cdev.h>struct cdev dev;int hello_init(void){ printk(KERN_INFO "hello, %s!\n", name); if(alloc_chrdev_region(&devno, 0, count, name) != 0){ return -1; } cdev_init(&dev, &fops); dev.owner = THIS_MODULE; //dev.ops = &fops; if(cdev_add(&dev, devno, 1) != 0){ return -1; } return 0;}void hello_exit(void){ printk(KERN_ALERT "goodbye, %s\n", name); unregister_chrdev_region(devno, count);}module_init(hello_init);module_exit(hello_exit);
Makefile如下:
ifneq ($(KERNELRELEASE),) obj-m := hello.oelse KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean:rm -f *.mod.* *.ko *.order *.symvers *.oendif
一个驱动可以创建多个设备,即minor不一样,major一样。代码如下:
// hello.c#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("GPL");int major = 0;int count = 1;char* name = "winlin";/**makeinsmod hello.ko count=2\&& major_device_number=`awk '$2=="winlin" {print $1}' /proc/devices` \&& mknod /dev/winlin0 c $major_device_number 0 \&& mknod /dev/winlin1 c $major_device_number 1cat /dev/winlin0 \&& echo "[dev0] linux is a great operating system for server." > /dev/winlin0 \&& cat /dev/winlin0cat /dev/winlin1 \&& echo "[dev1] linux is a great operating system for server." > /dev/winlin1 \&& cat /dev/winlin1rm -f /dev/winlin* \&& rmmod hello*/module_param(count, int, S_IRUGO|S_IWUSR);module_param(name, charp, S_IRUGO|S_IWUSR);#include <linux/fs.h>#include <linux/uaccess.h>char _data[1024] = "KDD char device buffer.\n";ssize_t hello_read(struct file* file, char __user* data, size_t size, loff_t* offset){ int len = strlen(_data); if(*offset >= len){ return 0; } printk(KERN_ALERT "hello_read, len=%d, size=%d, offset=%d\n", len, (int)size, (int)*offset); if(copy_to_user(data, _data, (len < size)? len:size) != 0){ return -1; } *offset += len; return len;}ssize_t hello_write(struct file* file, const char __user* data, size_t size, loff_t* offset){ int size_to_write = (sizeof(_data) - 1 < size)? sizeof(_data) - 1:size; printk(KERN_ALERT "hello_write, len=%d, size=%d, offset=%d\n", size_to_write, (int)size, (int)*offset); if(copy_from_user(_data, data, size_to_write) != 0){ return -1; } _data[size_to_write] = 0; return size_to_write;}int hello_open(struct inode* node, struct file* file){ printk(KERN_ALERT "hello_open file\n"); return 0;}int hello_release(struct inode* node, struct file* file){ printk(KERN_ALERT "hello_release file\n"); return 0;}struct file_operations fops = { .owner = THIS_MODULE, .read = hello_read, .write = hello_write, .open = hello_open, .release = hello_release,};#include <linux/cdev.h>struct cdev dev;int hello_init(void){ int i; dev_t devno; printk(KERN_INFO "hello, %s!\n", name); if(alloc_chrdev_region(&devno, 0, count, name) != 0){ return -1; } major = MAJOR(devno); cdev_init(&dev, &fops); dev.owner = THIS_MODULE; //dev.ops = &fops; for(i = 0; i < count; i++){ if(cdev_add(&dev, MKDEV(major, i), 1) != 0){ return -1; } } return 0;}void hello_exit(void){ printk(KERN_ALERT "goodbye, %s\n", name); cdev_del(&dev); unregister_chrdev_region(MKDEV(major, 0), count);}module_init(hello_init);module_exit(hello_exit);
这两个设备都是共享一个cdev和data,可以让每个设备有不同的表示,即根据count来开辟一个结构体,这个结构体包含了cdev和data。
代码如下:
// hello.c#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("GPL");int major = 0;int count = 1;char* name = "winlin";/**makeinsmod hello.ko count=2\&& major_device_number=`awk '$2=="winlin" {print $1}' /proc/devices` \&& mknod /dev/winlin0 c $major_device_number 0 \&& mknod /dev/winlin1 c $major_device_number 1cat /dev/winlin0 \&& echo "[dev0] linux is a great operating system for server." > /dev/winlin0 \&& cat /dev/winlin0cat /dev/winlin1 \&& echo "[dev1] linux is a great operating system for server." > /dev/winlin1 \&& cat /dev/winlin1rm -f /dev/winlin* \&& rmmod hello*/module_param(count, int, S_IRUGO|S_IWUSR);module_param(name, charp, S_IRUGO|S_IWUSR);#include <linux/fs.h>#include <linux/uaccess.h>#include <linux/cdev.h>struct winlin_dev{ dev_t devno; char data[1024]; struct cdev cdev;};const char* msg = "KDD char device buffer.\n";struct winlin_dev* devs;ssize_t hello_read(struct file* file, char __user* data, size_t size, loff_t* offset){ struct winlin_dev* dev = file->private_data; int len = strlen(dev->data); if(*offset >= len){ return 0; } printk(KERN_ALERT "hello_read, len=%d, size=%d, offset=%d\n", len, (int)size, (int)*offset); if(copy_to_user(data, dev->data, (len < size)? len:size) != 0){ return -1; } *offset += len; return len;}ssize_t hello_write(struct file* file, const char __user* data, size_t size, loff_t* offset){ struct winlin_dev* dev = file->private_data; int size_to_write = (sizeof(dev->data) - 1 < size)? sizeof(dev->data) - 1:size; printk(KERN_ALERT "hello_write, len=%d, size=%d, offset=%d\n", size_to_write, (int)size, (int)*offset); if(copy_from_user(dev->data, data, size_to_write) != 0){ return -1; } dev->data[size_to_write] = 0; return size_to_write;}int hello_open(struct inode* node, struct file* file){ struct winlin_dev* dev = container_of(node->i_cdev, struct winlin_dev, cdev); file->private_data = dev; return 0;}int hello_release(struct inode* node, struct file* file){ return 0;}struct file_operations fops = { .owner = THIS_MODULE, .read = hello_read, .write = hello_write, .open = hello_open, .release = hello_release,};int hello_init(void){ int i; dev_t devno; printk(KERN_INFO "hello, %s!\n", name); if(alloc_chrdev_region(&devno, 0, count, name) != 0){ return -1; } major = MAJOR(devno); devs = kmalloc(count * sizeof(struct winlin_dev), GFP_KERNEL); if(!devs){ return -1; } memset(devs, 0, count * sizeof(struct winlin_dev)); for(i = 0; i < count; i++){ cdev_init(&devs[i].cdev, &fops); devs[i].cdev.owner = THIS_MODULE; //devs[i].cdev.ops = &fops; devs[i].devno = MKDEV(major, i); if(cdev_add(&devs[i].cdev, devs[i].devno, 1) != 0){ return -1; } memcpy(devs[i].data, msg, strlen(msg)); } return 0;}void hello_exit(void){ int i; printk(KERN_ALERT "goodbye, %s\n", name); for(i = 0; i < count; i++){ cdev_del(&devs[i].cdev); } kfree(devs); unregister_chrdev_region(MKDEV(major, 0), count);}module_init(hello_init);module_exit(hello_exit);
Makefile修改为:
ifneq ($(KERNELRELEASE),) obj-m := hello.oelse KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean:rm -f *.mod.* *.ko *.order *.symvers *.oinstall:bash install.shuninstall:rm -f /dev/winlin*rmmod helloendif
安装脚本:
#!/bin/bash#install.shinsmod hello.ko count=2major_device_number=`cat /proc/devices|grep winlin|awk '{print $1}'`mknod /dev/winlin0 c ${major_device_number} 0mknod /dev/winlin1 c ${major_device_number} 1
- KDD字符设备基本概念
- KDD
- USB设备的基本概念
- 设备模型一(基本概念)
- Linux设备驱动基本概念
- Linux 设备驱动基本概念
- 字符设备
- 字符设备
- 字符设备
- 字符设备
- 字符设备
- 字符设备
- 字符设备
- 块设备 字符设备
- 字符设备 块设备
- 块设备、字符设备
- KDD Cup2011
- KDD:HelloWorld
- 啊哈!算法:三个算法问题(左旋转,大数据,变位词集)
- C语言递归练习
- 推荐本人关于Android的一些学习资料
- hdu1541 树状数组
- oracle之存储过程
- KDD字符设备基本概念
- ffmpeg参数说明(转载)
- Unity3D Update() 和 FixedUpdate()区别--unity3Dday02
- Oracle DB启动
- php拓展开发之模块全局变量
- Java基础加强<二>_内省、注解、泛型
- stack of flapjacks uva 120
- CUDA常见问题之无法在c文件中调用cu文件中定义的函数
- 简单贪心-hdu-3697-Selecting courses