KDD字符设备基本概念
2013-10-02 16:46
169 查看
数据结构及关系如下:
struct cdev表示字符设备,ops为文件操作函数,dev为设备号:
关联cdev和ops的函数是cdev_init:
关联cdev和dev的函数是cdev_add,即添加字符设备:
添加字符设备后,就可以用mknod创建文件,可以读写。
创建设备号时,需要指定设备名,即函数alloc_chrdev_region。
mknod需要知道设备名和设备号,安装驱动后,可以在/proc/devices中依据设备名查到设备号:
创建文件后,就可以读写这个文件/dev/winlin了:
最后,删除设备和驱动:
完整源码如下:
Makefile如下:
一个驱动可以创建多个设备,即minor不一样,major一样。代码如下:
这两个设备都是共享一个cdev和data,可以让每个设备有不同的表示,即根据count来开辟一个结构体,这个结构体包含了cdev和data。
代码如下:
Makefile修改为:
安装脚本:
include/linux/cdev.h 12 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.h 518 /* 519 * Keep mostly read-only and often accessed (especially for 520 * the RCU path lookup and 'stat' data) fields at the beginning 521 * 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.h 765 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.h struct 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";
/**
make
insmod hello.ko \ && major_device_number=`awk '$2=="winlin" {print $1}' /proc/devices` \ && mknod /dev/winlin c $major_device_number 0
cat /dev/winlin \ && echo "linux is a great operating system for server." > /dev/winlin \ && cat /dev/winlin
rm -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.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.mod.* *.ko *.order *.symvers *.o endif
一个驱动可以创建多个设备,即minor不一样,major一样。代码如下:
// hello.c #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("GPL"); int major = 0; int count = 1; char* name = "winlin"; /** make insmod 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 1 cat /dev/winlin0 \ && echo "[dev0] linux is a great operating system for server." > /dev/winlin0 \ && cat /dev/winlin0 cat /dev/winlin1 \ && echo "[dev1] linux is a great operating system for server." > /dev/winlin1 \ && cat /dev/winlin1 rm -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"; /** make insmod 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 1 cat /dev/winlin0 \ && echo "[dev0] linux is a great operating system for server." > /dev/winlin0 \ && cat /dev/winlin0 cat /dev/winlin1 \ && echo "[dev1] linux is a great operating system for server." > /dev/winlin1 \ && cat /dev/winlin1 rm -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.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.mod.* *.ko *.order *.symvers *.o install: bash install.sh uninstall: rm -f /dev/winlin* rmmod hello endif
安装脚本:
#!/bin/bash #install.sh insmod hello.ko count=2 major_device_number=`cat /proc/devices|grep winlin|awk '{print $1}'` mknod /dev/winlin0 c ${major_device_number} 0 mknod /dev/winlin1 c ${major_device_number} 1
相关文章推荐
- Linux 设备驱动基本概念
- Linux设备模型(1)_基本概念
- linux驱动基础开发1——linux 设备驱动基本概念
- 字符设备驱动基本框架
- Linux设备模型(1)_基本概念
- USB设备的基本概念
- Linux字符设备驱动编写基本流程
- Linux设备模型(1)_基本概念
- Samsung_tiny4412(驱动笔记03)----字符设备驱动基本操作及调用流程
- 字符设备驱动(一)——基本架构
- 基本概念学习---设备上下文HDC(MFC中设备上下文句柄)
- Linux设备模型(1)_基本概念
- 2.linux驱动基础开发1——linux 设备驱动基本概念
- 基本概念学习之GDI(图形设备接口Graphics Device Interface)
- 字符,字符集,字节和编码等一些基本概念的澄清
- Linux字符设备驱动程序编写基本流程
- Linux 设备驱动之 UIO 机制(基本概念)
- 深入浅出linux之设备基本概念
- Linux设备模型(1)_基本概念
- zigbee基本概念--网络设备类型和PANID