KDD 문자 장치 기본 개념

12894 단어
데이터 구조 와 관 계 는 다음 과 같다.
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 와 관련 된 함 수 는 cdevinit:
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.
"; 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
", 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
", 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!
", 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
", 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.
"; 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
", 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
", 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
"); return 0; } int hello_release(struct inode* node, struct file* file){ printk(KERN_ALERT "hello_release 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){ int i; dev_t devno; printk(KERN_INFO "hello, %s!
", 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
", 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.
"; 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
", 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
", 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!
", 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
", 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

좋은 웹페이지 즐겨찾기