我如何学习为 Linux 编写字符设备驱动程序?

发布于 2024-08-02 16:19:36 字数 24 浏览 9 评论 0原文

Linux下如何编写字符设备驱动?

How to write char device drivers in Linux?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

后知后觉 2024-08-09 16:19:36

一个很好的例子是 Linux“softdog”,或者软件看门狗定时器。加载后,它将监视特殊设备的写入情况,并根据这些写入的频率采取行动。

它还向您展示了如何实现基本的 ioctl 接口,这非常有用。

要查看的文件是 drivers/watchdog/softdog.c

如果您通过示例学习,那么这是一个非常好的开始。其他人建议的基本字符设备(空、随机等)也很好,但没有充分演示您需要如何实现 ioctl() 接口。

附带说明一下,我相信驱动程序是由 Alan Cox 编写的。如果您要从示例中学习,那么研究顶级维护人员的工作绝不是一个坏主意。您可以非常确定该驱动程序也说明了遵守正确的 Linux 标准。

就驱动程序而言(在 Linux 中),字符驱动程序是最容易编写的,也是最有价值的,因为您可以看到代码运行得非常快。祝你好运,黑客快乐。

A very good example is the Linux "softdog", or software watchdog timer. When loaded, it will watch a special device for writes and take action depending on the frequency of those writes.

It also shows you how to implement a rudamentary ioctl interface, which is very useful.

The file to look at is drivers/watchdog/softdog.c

If you learn by example, that is a very good one to start with. The basic character devices (null, random, etc) as others suggest are also good, but do not adequately demonstrate how you need to implement an ioctl() interface.

A side note, I believe the driver was written by Alan Cox. If your going to learn from example, its never a bad idea to study the work of a top level maintainer. You can be pretty sure that the driver also illustrates adhering to proper Linux standards.

As far as drivers go (in Linux), character drivers are the easiest to write and also the most rewarding, as you can see your code working very quickly. Good luck and happy hacking.

韵柒 2024-08-09 16:19:36

阅读这本书:O'Reilly 出版的Linux 设备驱动程序

对我帮助很大。

Read this book: Linux Device Drivers published by O'Reilly.

Helped me a lot.

心头的小情儿 2024-08-09 16:19:36

到目前为止,我最喜欢的学习内核工作原理的书(我已经阅读了其中的大部分)是:

Linux内核开发(第2版)

这本书相当短,先读它,然后再看O'Reilly关于驱动程序的书。

My favorite book for learning how the kernel works, BY FAR (and I've read most of them) is:

Linux Kernel Development (2nd Edition)

This book is fairly short, read it first, then read the O'Reilly book on drivers.

べ映画 2024-08-09 16:19:36

阅读 Linux 设备驱动程序第三版。好的事情是开始编码。我只是粘贴一个简单的字符驱动程序,以便您可以开始编码。

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h> /*this is the file structure, file open read close */
#include<linux/cdev.h> /* this is for character device, makes cdev avilable*/
#include<linux/semaphore.h> /* this is for the semaphore*/
#include<linux/uaccess.h> /*this is for copy_user vice vers*/

int chardev_init(void);
void chardev_exit(void);
static int device_open(struct inode *, struct file *);
static int device_close(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static loff_t device_lseek(struct file *file, loff_t offset, int orig);

/*new code*/
#define BUFFER_SIZE 1024
static char device_buffer[BUFFER_SIZE];
struct semaphore sem;
struct cdev *mcdev; /*this is the name of my char driver that i will be registering*/
int major_number; /* will store the major number extracted by dev_t*/
int ret; /*used to return values*/
dev_t dev_num; /*will hold the major number that the kernel gives*/

#define DEVICENAME "megharajchard"

/*inode reffers to the actual file on disk*/
static int device_open(struct inode *inode, struct file *filp) {
    if(down_interruptible(&sem) != 0) {
        printk(KERN_ALERT "megharajchard : the device has been opened by some other device, unable to open lock\n");
        return -1;
    }
    //buff_rptr = buff_wptr = device_buffer;
    printk(KERN_INFO "megharajchard : device opened succesfully\n");
    return 0;
}

static ssize_t device_read(struct file *fp, char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_read; /* gives the number of bytes to read*/
    int bytes_read;/*number of bytes actually read*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_read = length;
    else
        bytes_to_read = maxbytes;
    if(bytes_to_read == 0)
        printk(KERN_INFO "megharajchard : Reached the end of the device\n");
    bytes_read = bytes_to_read - copy_to_user(buff, device_buffer + *ppos, bytes_to_read);
    printk(KERN_INFO "megharajchard : device has been read %d\n",bytes_read);
    *ppos += bytes_read;
    printk(KERN_INFO "megharajchard : device has been read\n");
    return bytes_read;
}

static ssize_t device_write(struct file *fp, const char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_write; /* gives the number of bytes to write*/
    int bytes_writen;/*number of bytes actually writen*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_write = length;
    else
        bytes_to_write = maxbytes;
    bytes_writen = bytes_to_write - copy_from_user(device_buffer + *ppos, buff, bytes_to_write);
    printk(KERN_INFO "megharajchard : device has been written %d\n",bytes_writen);
    *ppos += bytes_writen;
    printk(KERN_INFO "megharajchard : device has been written\n");
    return bytes_writen;
}

static loff_t device_lseek(struct file *file, loff_t offset, int orig) {
    loff_t new_pos = 0;
    printk(KERN_INFO "megharajchard : lseek function in work\n");
    switch(orig) {
        case 0 : /*seek set*/
            new_pos = offset;
            break;
        case 1 : /*seek cur*/
            new_pos = file->f_pos + offset;
            break;
        case 2 : /*seek end*/
            new_pos = BUFFER_SIZE - offset;
            break;
    }
    if(new_pos > BUFFER_SIZE)
        new_pos = BUFFER_SIZE;
    if(new_pos < 0)
        new_pos = 0;
    file->f_pos = new_pos;
    return new_pos;
}

static int device_close(struct inode *inode, struct file *filp) {
    up(&sem);
    printk(KERN_INFO "megharajchard : device has been closed\n");
    return ret;
}

struct file_operations fops = { /* these are the file operations provided by our driver */
    .owner = THIS_MODULE, /*prevents unloading when operations are in use*/
    .open = device_open,  /*to open the device*/
    .write = device_write, /*to write to the device*/
    .read = device_read, /*to read the device*/
    .release = device_close, /*to close the device*/
    .llseek = device_lseek
};


int chardev_init(void) 
{
    /* we will get the major number dynamically this is recommended please read ldd3*/
    ret = alloc_chrdev_region(&dev_num,0,1,DEVICENAME);
    if(ret < 0) {
        printk(KERN_ALERT " megharajchard : failed to allocate major number\n");
        return ret;
    }
    else
        printk(KERN_INFO " megharajchard : mjor number allocated succesful\n");
    major_number = MAJOR(dev_num);
    printk(KERN_INFO "megharajchard : major number of our device is %d\n",major_number);
    printk(KERN_INFO "megharajchard : to use mknod /dev/%s c %d 0\n",DEVICENAME,major_number);

    mcdev = cdev_alloc(); /*create, allocate and initialize our cdev structure*/
    mcdev->ops = &fops;   /*fops stand for our file operations*/
    mcdev->owner = THIS_MODULE;

    /*we have created and initialized our cdev structure now we need to add it to the kernel*/
    ret = cdev_add(mcdev,dev_num,1);
    if(ret < 0) {
        printk(KERN_ALERT "megharajchard : device adding to the kerknel failed\n");
        return ret;
    }
    else
        printk(KERN_INFO "megharajchard : device additin to the kernel succesful\n");
    sema_init(&sem,1);  /* initial value to one*/

    return 0;
}

void chardev_exit(void)
{
    cdev_del(mcdev); /*removing the structure that we added previously*/
    printk(KERN_INFO " megharajchard : removed the mcdev from kernel\n");

    unregister_chrdev_region(dev_num,1);
    printk(KERN_INFO "megharajchard : unregistered the device numbers\n");
    printk(KERN_ALERT " megharajchard : character driver is exiting\n");
}

MODULE_AUTHOR("A G MEGHARAJ([email protected])");
MODULE_DESCRIPTION("A BASIC CHAR DRIVER");
//MODULE_LICENCE("GPL");    

module_init(chardev_init);
module_exit(chardev_exit);

这是 make 文件。

obj-m   := megharajchard.o

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD)

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

加载脚本。确保主编号为 251,否则进行相应更改。

#!/bin/sh

sudo insmod megharajchard.ko
sudo mknod /dev/megharajchard c 251 0
sudo chmod 777 /dev/megharajchard

卸载脚本,

#!/bin/sh

sudo rmmod megharajchard
sudo rm /dev/megharajchard

也是一个测试设备运行情况的程序

#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<malloc.h>

#define DEVICE "/dev/megharajchard"
//#define DEVICE "megharaj.txt"
int debug = 1, fd = 0;

int write_device() {
    int write_length = 0;
    ssize_t ret;
        char *data = (char *)malloc(1024 * sizeof(char));
    printf("please enter the data to write into device\n");
    scanf(" %[^\n]",data); /* a space added after"so that it reads white space, %[^\n] is addeed so that it takes input until new line*/
    write_length = strlen(data);
    if(debug)printf("the length of dat written = %d\n",write_length);
    ret = write(fd, data, write_length);
    if(ret == -1)
        printf("writting failed\n");
    else
        printf("writting success\n");
    if(debug)fflush(stdout);/*not to miss any log*/
    free(data);
return 0;
}

int read_device() {
    int read_length = 0;
    ssize_t ret;
        char *data = (char *)malloc(1024 * sizeof(char));
    printf("enter the length of the buffer to read\n");
    scanf("%d",&read_length);
    if(debug)printf("the read length selected is %d\n",read_length);
    memset(data,0,sizeof(data));
    data[0] = '0\';
    ret = read(fd,data,read_length);
    printf("DEVICE_READ : %s\n",data);
    if(ret == -1)
        printf("reading failed\n");
    else
        printf("reading success\n");
    if(debug)fflush(stdout);/*not to miss any log*/
    free(data);
return 0;
}

int lseek_device() {
    int lseek_offset = 0,seek_value = 0;
    int counter = 0; /* to check if function called multiple times or loop*/
    counter++;
    printf("counter value = %d\n",counter);
    printf("enter the seek offset\n");
    scanf("%d",&lseek_offset);
    if(debug) printf("seek_offset selected is %d\n",lseek_offset);
    printf("1 for SEEK_SET, 2 for SEEK_CUR and 3 for SEEK_END\n");
    scanf("%d", &seek_value);
    printf("seek value = %d\n", seek_value);
    switch(seek_value) {
        case 1: lseek(fd,lseek_offset,SEEK_SET);
            return 0;
            break;  
        case 2: lseek(fd,lseek_offset,SEEK_CUR);
            return 0;
            break;          
        case 3: lseek(fd,lseek_offset,SEEK_END);
            return 0;
            break;  
        default : printf("unknown  option selected, please enter right one\n");
            break;  
    }
    /*if(seek_value == 1) {
        printf("seek value = %d\n", seek_value);
        lseek(fd,lseek_offset,SEEK_SET);
        return 0;
    }
    if(seek_value == 2) {
        lseek(fd,lseek_offset,SEEK_CUR);
        return 0;
    }
    if(seek_value == 3) {
        lseek(fd,lseek_offset,SEEK_END);
        return 0;
    }*/
    if(debug)fflush(stdout);/*not to miss any log*/
return 0;
}

int lseek_write() {
    lseek_device();
    write_device();
return 0;
}

int lseek_read() {
    lseek_device();
    read_device();
return 0;
}

int main()
{
    int value = 0;
    if(access(DEVICE, F_OK) == -1) {
        printf("module %s not loaded\n",DEVICE);
        return 0;
    }
    else
        printf("module %s loaded, will be used\n",DEVICE);

    while(1) {
    printf("\t\tplease enter 1 to write\n \
                     2 to read\n \
                     3 to lseek and write\
                 4 to lseek and read\n");
        scanf("%d",&value);
        switch(value) {
            case 1 :printf("write option selected\n");
            fd = open(DEVICE, O_RDWR);
            write_device();
            close(fd); /*closing the device*/
            break;
            case 2 :printf("read option selected\n"); 
            /* dont know why but i am suppoesed to open it for writing and close it, i cant keep  open and read.
            its not working, need to sort out why is that so */
            fd = open(DEVICE, O_RDWR);
            read_device();
            close(fd); /*closing the device*/
            break;
            case 3 :printf("lseek  option selected\n");
            fd = open(DEVICE, O_RDWR);
            lseek_write();
            close(fd); /*closing the device*/
            break;  
            case 4 :printf("lseek  option selected\n");
            fd = open(DEVICE, O_RDWR);
            lseek_read();   
            close(fd); /*closing the device*/
            break;
            default : printf("unknown  option selected, please enter right one\n");
            break;
        }
    }
    return 0;
}

Read linux device driver 3rd edition. And the good thing is start coding. I am just pasting a simple char driver so that you can start coding.

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h> /*this is the file structure, file open read close */
#include<linux/cdev.h> /* this is for character device, makes cdev avilable*/
#include<linux/semaphore.h> /* this is for the semaphore*/
#include<linux/uaccess.h> /*this is for copy_user vice vers*/

int chardev_init(void);
void chardev_exit(void);
static int device_open(struct inode *, struct file *);
static int device_close(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static loff_t device_lseek(struct file *file, loff_t offset, int orig);

/*new code*/
#define BUFFER_SIZE 1024
static char device_buffer[BUFFER_SIZE];
struct semaphore sem;
struct cdev *mcdev; /*this is the name of my char driver that i will be registering*/
int major_number; /* will store the major number extracted by dev_t*/
int ret; /*used to return values*/
dev_t dev_num; /*will hold the major number that the kernel gives*/

#define DEVICENAME "megharajchard"

/*inode reffers to the actual file on disk*/
static int device_open(struct inode *inode, struct file *filp) {
    if(down_interruptible(&sem) != 0) {
        printk(KERN_ALERT "megharajchard : the device has been opened by some other device, unable to open lock\n");
        return -1;
    }
    //buff_rptr = buff_wptr = device_buffer;
    printk(KERN_INFO "megharajchard : device opened succesfully\n");
    return 0;
}

static ssize_t device_read(struct file *fp, char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_read; /* gives the number of bytes to read*/
    int bytes_read;/*number of bytes actually read*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_read = length;
    else
        bytes_to_read = maxbytes;
    if(bytes_to_read == 0)
        printk(KERN_INFO "megharajchard : Reached the end of the device\n");
    bytes_read = bytes_to_read - copy_to_user(buff, device_buffer + *ppos, bytes_to_read);
    printk(KERN_INFO "megharajchard : device has been read %d\n",bytes_read);
    *ppos += bytes_read;
    printk(KERN_INFO "megharajchard : device has been read\n");
    return bytes_read;
}

static ssize_t device_write(struct file *fp, const char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_write; /* gives the number of bytes to write*/
    int bytes_writen;/*number of bytes actually writen*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_write = length;
    else
        bytes_to_write = maxbytes;
    bytes_writen = bytes_to_write - copy_from_user(device_buffer + *ppos, buff, bytes_to_write);
    printk(KERN_INFO "megharajchard : device has been written %d\n",bytes_writen);
    *ppos += bytes_writen;
    printk(KERN_INFO "megharajchard : device has been written\n");
    return bytes_writen;
}

static loff_t device_lseek(struct file *file, loff_t offset, int orig) {
    loff_t new_pos = 0;
    printk(KERN_INFO "megharajchard : lseek function in work\n");
    switch(orig) {
        case 0 : /*seek set*/
            new_pos = offset;
            break;
        case 1 : /*seek cur*/
            new_pos = file->f_pos + offset;
            break;
        case 2 : /*seek end*/
            new_pos = BUFFER_SIZE - offset;
            break;
    }
    if(new_pos > BUFFER_SIZE)
        new_pos = BUFFER_SIZE;
    if(new_pos < 0)
        new_pos = 0;
    file->f_pos = new_pos;
    return new_pos;
}

static int device_close(struct inode *inode, struct file *filp) {
    up(&sem);
    printk(KERN_INFO "megharajchard : device has been closed\n");
    return ret;
}

struct file_operations fops = { /* these are the file operations provided by our driver */
    .owner = THIS_MODULE, /*prevents unloading when operations are in use*/
    .open = device_open,  /*to open the device*/
    .write = device_write, /*to write to the device*/
    .read = device_read, /*to read the device*/
    .release = device_close, /*to close the device*/
    .llseek = device_lseek
};


int chardev_init(void) 
{
    /* we will get the major number dynamically this is recommended please read ldd3*/
    ret = alloc_chrdev_region(&dev_num,0,1,DEVICENAME);
    if(ret < 0) {
        printk(KERN_ALERT " megharajchard : failed to allocate major number\n");
        return ret;
    }
    else
        printk(KERN_INFO " megharajchard : mjor number allocated succesful\n");
    major_number = MAJOR(dev_num);
    printk(KERN_INFO "megharajchard : major number of our device is %d\n",major_number);
    printk(KERN_INFO "megharajchard : to use mknod /dev/%s c %d 0\n",DEVICENAME,major_number);

    mcdev = cdev_alloc(); /*create, allocate and initialize our cdev structure*/
    mcdev->ops = &fops;   /*fops stand for our file operations*/
    mcdev->owner = THIS_MODULE;

    /*we have created and initialized our cdev structure now we need to add it to the kernel*/
    ret = cdev_add(mcdev,dev_num,1);
    if(ret < 0) {
        printk(KERN_ALERT "megharajchard : device adding to the kerknel failed\n");
        return ret;
    }
    else
        printk(KERN_INFO "megharajchard : device additin to the kernel succesful\n");
    sema_init(&sem,1);  /* initial value to one*/

    return 0;
}

void chardev_exit(void)
{
    cdev_del(mcdev); /*removing the structure that we added previously*/
    printk(KERN_INFO " megharajchard : removed the mcdev from kernel\n");

    unregister_chrdev_region(dev_num,1);
    printk(KERN_INFO "megharajchard : unregistered the device numbers\n");
    printk(KERN_ALERT " megharajchard : character driver is exiting\n");
}

MODULE_AUTHOR("A G MEGHARAJ([email protected])");
MODULE_DESCRIPTION("A BASIC CHAR DRIVER");
//MODULE_LICENCE("GPL");    

module_init(chardev_init);
module_exit(chardev_exit);

and this is the make file.

obj-m   := megharajchard.o

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD)

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

load script. make sure the major number is 251 or else change it accordingly.

#!/bin/sh

sudo insmod megharajchard.ko
sudo mknod /dev/megharajchard c 251 0
sudo chmod 777 /dev/megharajchard

unload script,

#!/bin/sh

sudo rmmod megharajchard
sudo rm /dev/megharajchard

also a c program to test the operation of your device

#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<malloc.h>

#define DEVICE "/dev/megharajchard"
//#define DEVICE "megharaj.txt"
int debug = 1, fd = 0;

int write_device() {
    int write_length = 0;
    ssize_t ret;
        char *data = (char *)malloc(1024 * sizeof(char));
    printf("please enter the data to write into device\n");
    scanf(" %[^\n]",data); /* a space added after"so that it reads white space, %[^\n] is addeed so that it takes input until new line*/
    write_length = strlen(data);
    if(debug)printf("the length of dat written = %d\n",write_length);
    ret = write(fd, data, write_length);
    if(ret == -1)
        printf("writting failed\n");
    else
        printf("writting success\n");
    if(debug)fflush(stdout);/*not to miss any log*/
    free(data);
return 0;
}

int read_device() {
    int read_length = 0;
    ssize_t ret;
        char *data = (char *)malloc(1024 * sizeof(char));
    printf("enter the length of the buffer to read\n");
    scanf("%d",&read_length);
    if(debug)printf("the read length selected is %d\n",read_length);
    memset(data,0,sizeof(data));
    data[0] = '0\';
    ret = read(fd,data,read_length);
    printf("DEVICE_READ : %s\n",data);
    if(ret == -1)
        printf("reading failed\n");
    else
        printf("reading success\n");
    if(debug)fflush(stdout);/*not to miss any log*/
    free(data);
return 0;
}

int lseek_device() {
    int lseek_offset = 0,seek_value = 0;
    int counter = 0; /* to check if function called multiple times or loop*/
    counter++;
    printf("counter value = %d\n",counter);
    printf("enter the seek offset\n");
    scanf("%d",&lseek_offset);
    if(debug) printf("seek_offset selected is %d\n",lseek_offset);
    printf("1 for SEEK_SET, 2 for SEEK_CUR and 3 for SEEK_END\n");
    scanf("%d", &seek_value);
    printf("seek value = %d\n", seek_value);
    switch(seek_value) {
        case 1: lseek(fd,lseek_offset,SEEK_SET);
            return 0;
            break;  
        case 2: lseek(fd,lseek_offset,SEEK_CUR);
            return 0;
            break;          
        case 3: lseek(fd,lseek_offset,SEEK_END);
            return 0;
            break;  
        default : printf("unknown  option selected, please enter right one\n");
            break;  
    }
    /*if(seek_value == 1) {
        printf("seek value = %d\n", seek_value);
        lseek(fd,lseek_offset,SEEK_SET);
        return 0;
    }
    if(seek_value == 2) {
        lseek(fd,lseek_offset,SEEK_CUR);
        return 0;
    }
    if(seek_value == 3) {
        lseek(fd,lseek_offset,SEEK_END);
        return 0;
    }*/
    if(debug)fflush(stdout);/*not to miss any log*/
return 0;
}

int lseek_write() {
    lseek_device();
    write_device();
return 0;
}

int lseek_read() {
    lseek_device();
    read_device();
return 0;
}

int main()
{
    int value = 0;
    if(access(DEVICE, F_OK) == -1) {
        printf("module %s not loaded\n",DEVICE);
        return 0;
    }
    else
        printf("module %s loaded, will be used\n",DEVICE);

    while(1) {
    printf("\t\tplease enter 1 to write\n \
                     2 to read\n \
                     3 to lseek and write\
                 4 to lseek and read\n");
        scanf("%d",&value);
        switch(value) {
            case 1 :printf("write option selected\n");
            fd = open(DEVICE, O_RDWR);
            write_device();
            close(fd); /*closing the device*/
            break;
            case 2 :printf("read option selected\n"); 
            /* dont know why but i am suppoesed to open it for writing and close it, i cant keep  open and read.
            its not working, need to sort out why is that so */
            fd = open(DEVICE, O_RDWR);
            read_device();
            close(fd); /*closing the device*/
            break;
            case 3 :printf("lseek  option selected\n");
            fd = open(DEVICE, O_RDWR);
            lseek_write();
            close(fd); /*closing the device*/
            break;  
            case 4 :printf("lseek  option selected\n");
            fd = open(DEVICE, O_RDWR);
            lseek_read();   
            close(fd); /*closing the device*/
            break;
            default : printf("unknown  option selected, please enter right one\n");
            break;
        }
    }
    return 0;
}
百善笑为先 2024-08-09 16:19:36

看看标准内核中一些非常简单的标准 - “null”、“zero”、“mem”、“random”等。他们展示了简单的实现。

显然,如果您正在驱动真正的硬件,那就更复杂了 - 您需要了解如何与硬件以及设备的子系统 API(PCI、USB 等)进行交互。您可能还需要了解如何使用中断、内核定时器等。

Have a look at some of the really simple standard ones - "null", "zero", "mem", "random", etc, in the standard kernel. They show the simple implementation.

Obviously if you're driving real hardware it's more complicated- you need to understand how to interface with the hardware as well as the subsystem APIs (PCI, USB etc) for your device. You might need to understand how to use interrupts, kernel timers etc as well.

羞稚 2024-08-09 16:19:36

完成此操作后,开始阅读基本的“tty”驱动程序。

首先重点关注驱动程序注册架构,这意味着:-

  1. 查看要填充哪些结构- 例如:- struct file_operations f_ops = ....
  2. 哪些函数负责向 core 注册特定结构。例如:- _register_driver。
    完成上述操作后,看看您想要驱动程序实现什么功能(策略),然后想办法实现该策略(称为机制)——策略和机制允许您区分驱动程序的各个方面。
  3. 编写编译 makefile(如果您有多个文件,这很困难 - 但并不难)。
  4. 尝试解决错误和警告,
    你会成功的。

在编写机制时,永远不要忘记它为用户空间中的应用程序提供了什么。

  • Just check the character driver skeleton from here http://www.linuxforu.com/2011/02/linux-character-drivers/....Go ahead and read all the topics here, understand thoroughly.(this is kinda a tutorial-so play along as said).

  • See how "copy_to_user" and "copy_from_user" functions work, which you can use in read/write part of the driver function callbacks.

Once you are done with this, start reading a basic "tty" driver.

Focus, more on the driver registration architecture first, which means:-

  1. See what structures are to be filled- ex:- struct file_operations f_ops = ....
  2. Which are the function responsible to register a particular structure with core . ex:- _register_driver.
    Once you are done with the above, see what functionality you want with the driver(policy), then think of way to implement that policy(called mechanism)- the policy and mechanism allows you to distinguish between various aspects of the driver.
  3. write compilation makefiles(its hard if you have multiple files- but not tht hard).
  4. Try to resolve the errors and warnings,
    and you will be through.

When writing mechanism, never forget what it offers to the applications in user space.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文