Understand the character device driver development process from Linux kernel LED driver

Contents

  • Blog description
  • Development environment
  • 1. Linux character device driver composition
    • 1.1 Character device driver module loading and unloading functions
    • 1.2 Character device driver in the file_operations structure Member function
  • 2. Character device driver-device number registration and uninstallation
    • 2.1 Device number registration
    • 2.2 Device number cancellation< /li>
  • 3. Character device driver-file operation
  • Reference material
  • Sample code

< /div>

@(Understand the development process of character device driver from the Linux kernel LED driver)

blog description

Date of writing 2018.12.08
Date of completion 2019.10.06
Recently maintained none
author of this article multimicro
Contact information [email protected]
GitHub https://github.com/wifialan
The address of this article https://blog.csdn.net/multimicro/article/details/84898135

Development environment

< td>kernel version
Environment description Detailed information Remarks
Operating system Ubunut 18.04.3 LTS
Development board S3C2440(JZ2440-V3)
linux-3.4.2 Official website address
busybox version busybox-1.22.1 Official website address
Compiler arm-li nux-gcc-4.4.3 Download URL
Compiler path /opt/FriendlyARM/toolschain/4.4.3/bin absolute path

1. Linux character device driver composition

Quoted from Song Baohua “Linux Device Driver Development Detailed Explanation–Based on the Latest Linux 4.0 Kernel” P138 content:


In Linux, the character device driver is composed of the following parts.
1. Character device driver module loading and unloading functions
2. Member functions in the file_operations structure of the character device driver


Let’s first introduce the development process of the character device: the character device driver is connected to the host computer program through the device number. The upper computer program controls the driver through file operations, that is, read, write, ioctl and so on.

  • ps. (For Linux systems, everything is a file. After the driver is loaded successfully, the driver node number information will be added in /proc/devices) li>

So a character device driver should contain 1. Device number registration, uninstallation and 2. File operation two functions, registered device The number is used to provide an interface, and the file operation is used to operate the drive.

The structure of the character device driver is shown in the figure below:
Insert picture description herevoid cdev_init(struct cdev *cdev, const struct file_operations *fops){ memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); kobject_init(&cdev- >kobj, &ktype_cdev_default); cdev->ops = fops;}

It can be seen that the last statement cdev->ops = fops; completes the < code>file_operations binding
Let’s get a perceptual understanding of the registration and uninstallation function prototypes of the device number, and the file operation function prototypes from the perspective of the programming language.

1.1 Character device driver module loading and unloading functions

//Loading function static int __init xxx_init(void){ ... ...}//Unloading function static int __exit xxx_exit(void){ ... ...}

1.2 member functions in the file_operations structure of the character device driver

static const struct file_operations xxx_fileops = {.owner = THIS_MODULE, .write = xxx_write, .read = xxx_read , .open = xxx_open, .unlocked_ioctl = xxx_ioctl, ... ...};static int xxx_open( struct inode *inodes, struct file *filp ){ ... ...}static long xxx_ioctl( struct file *file, unsigned int cmd, unsigned long arg ){ ... ...}static ssize_t xxx_write( struct file *filp, const char __user *buffer, size_t size, loff_t *f_pos ){ ... ...}static ssize_t xxx_read( struct file *filp, const char __user *buffer, size_t size, loff_t *f_pos ){ ... ...}

2. Character device driver— —Device number registration and uninstallation

Take the character device driver source code I wrote as an example, the path is linux-3.4.2\drivers\char\s3c2440_leds.c, the article is attached There is a complete code
The registration of the device number is completed by static int __init s3c2440_leds_init(void)
The uninstallation of the device number is completed by static int __init s3c2440_leds_exit(void)
First analyze the registration of the device number, and then analyze the uninstallation

2.1 Device number registration

The device number is divided into a major device number and a minor device number. If the major device number is defined in the source code (the minor device number is generally 0), then the registration of the device number can be completed directly, and the process is
insert picture description here
After successful registration, you can access cat /proc/devicesCommand to view the device number
Insert picture description here

2.2 Device number cancellation

Compared with device number registration, the cancellation process is very simple:
insert picture description here

3. Character device driver-file operation

When the host computer program After the corresponding driver is opened (on the link) by calling the open function, the open function will return a == file descriptor == temporarily recorded as fd, and then read, write, ioctl and other operations of the driver can be completed by using fd. Simple character device drivers mostly use the ioctl function to control the driver, and this ioctl function itself is not difficult, its implementation is:

static long s3c2440_leds_ioctl( struct file *file, unsigned int cmd, unsigned long arg )

The first parameter in the function
: indicates the file descriptor to be operated on
The second parameter: indicates the command word passed
The third parameter: indicates the variable word passed
The meaning of the second parameter and the third parameter has no hard and fast rules, and the passed parameters comply with the corresponding The keyword can limit the type.

The example reference is given below

static long s3c2440_leds_ioctl( struct file *file, unsigned int cmd, unsigned long arg ){ printk(DRV_NAME "\tRecv cmd: %u\n", cmd); printk(DRV_NAME "\tRecv arg: %lu\n", arg); //IO operations function. if(arg> 4) {return -EINVAL ;} switch (cmd) {case IOCTL_LED_ON: //#define IOCTL_LED_ON 1 s3c2410_gpio_setpin(S3C2410_GPF(arg+3), 0);//Set pin printk("Open LED %lu ",arg); return 0; case IOCTL_LED_OFF: //#define IOCTL_LED_OFF 0 s3c2410_gpio_setpin(S3C2410_GPF(arg+3), 1); printk("Close LED %lu ",arg); return 0; default : return -EINVAL; }}

Reference Materials

1. Song Baohua "Linux Device Driver Development Detailed Explanation-Based on the Latest Linux 4.0 Kernel"< /strong> Chapter 6 Character Device Driver

Sample Code

/* * Driver for S3C2440 base board. * * Copyright (C ) 2019 Alan NWPU <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * MULTIBEANS, NP U Youyi West Ave, Beilin District, Xi'an, China. */#include  /* Every Linux kernel module must include this head */#include  /* Every Linux kernel module must include this head */#include  /* printk() */#include  /* struct fops */#include  /* error codes */#include  /* cdev_alloc() */#include  /* request_mem_region() */#include #include #include #include #include #include #include # include #include #include #include #include #include #include #define DRV_NAME "s3c2440_leds"#define DRV_AUTHOR "Alan Tian <[email protected]>"#define DRV_DESC "S3C2440 LED Pin Driver"#define S3C2440_LED_SIZE 0x1000#define S3C2440_LED_MAJOR 230#define S3C2440_LED_MI NOR 0 static int major = S3C2440_LED_MAJOR; static int minor = S3C2440_LED_MINOR; /* The second parameter when the application executes ioctl(fd, cmd, arg)*/#define IOCTL_LED_ON 0#define IOCTL_LED_OFF 1static int s_opendes s3c2440, struct struct file *filp );static long s3c2440_leds_ioctl( struct file *file, unsigned int cmd, unsigned long arg );static ssize_t s3c2440_leds_write( struct file *filp, const char __user *buffer, size_t size, loff_t static_t *3creadsize_t *3creadsize_t ); (struct file *filp, const char __user *buffer, size_t size, loff_t *f_pos );struct s3c2440_leds_dev_t{ struct cdev cdev; unsigned char mem[S3C2440_LED_SIZE];} *s3c2440_LED_SIZE];) *s3c2440_LED_SIZE];) *s3c2440_LED_SIZE = {.owner = THIS_MODULE, .write = s3c2440_leds_write, .read = s3c2440_leds_read, .open = s3c2440_leds_open, .unlocked_ioctl = s3c2440_leds_ioctl,};static int s3c2 440_leds_open( struct inode *inodes, struct file *filp ){ //int ret; filp->private_data = s3c2440_leds_dev; printk(DRV_NAME"\tS3C2440 open function...\n"); return 0;}static long s3c2440_leds_ioctl( struct file *file, unsigned int cmd, unsigned long arg ){ printk(DRV_NAME "\tRecv cmd: %u\n", cmd); printk(DRV_NAME "\tRecv arg: %lu\n", arg); //IO operations function. if(arg> 4) {return -EINVAL;} switch (cmd) {case IOCTL_LED_ON: s3c2410_gpio_setpin(S3C2410_GPF(arg+3), 0);//Set pin printk("Open LED %lu ",arg) ; return 0; case IOCTL_LED_OFF: s3c2410_gpio_setpin(S3C2410_GPF(arg+3), 1); printk("Close LED %lu ",arg); return 0; default: return -EINVAL; })static ssize_t s3c2440_leds_write( struct file *filp , const char __user *buffer, size_t size, loff_t *f_pos ){ unsigned long p = *f_pos; unsigned int count = size; int ret = 0; struct s3c2440_leds_dev_t *dev = filp->private_data; if(p >= S3C2440_LED_SIZE) return 0; if(count> S3C2440_LED_SIZE-p) count = S3C2440_LED_SIZE-p; memset(dev->mem), 0, S3ZE2440_LED if(copy_from_user(dev->mem + p, buffer, count)) {ret = -EFAULT;} else {*f_pos += count; ret = count; printk(KERN_INFO "writter %u bytes(s) from %lu\ n", count, p);} return ret; }static ssize_t s3c2440_leds_read( struct file *filp, const char __user *buffer, size_t size, loff_t *f_pos ){ unsigned long p = *f_pos; unsigned int count = size; int ret = 0; struct s3c2440_leds_dev_t *dev = filp->private_data; if(p >= S3C2440_LED_SIZE) return 0; if(count> S3C2440_LED_SIZE-p) count = S3C2440_LED_SIZE-p; if(copy_to_user(mem +, p dev-> , count)) {ret = -EFAULT;} else {*f_pos += count; ret = count; printk(KERN_ INFO "read %u bytes(s) from %lu\n", count, p);} return ret;}static int __init s3c2440_leds_init(void){ int ret,err; dev_t devid; if(major) {devid = MKDEV (major, 0); ret = register_chrdev_region(devid, 1, DRV_NAME); printk("Origin Creat node %d\n",major);} else {ret = alloc_chrdev_region(&devid, 0, 1, DRV_NAME); major = MAJOR(devid); printk("Arrage1 Creat node %d\n",major);} if(ret <0) {printk(DRV_NAME "\ts3c2440 new device failed\n"); //goto fail_malloc; return ret; } s3c2440_leds_dev = kzalloc(sizeof(struct s3c2440_leds_dev_t), GFP_KERNEL); if(!s3c2440_leds_dev) {ret = -ENOMEM; goto fail_malloc;} printk("success init leds\nc_40";s_dev24leds-dev_sop_dev); err = cdev_add(&s3c2440_leds_dev->cdev, devid, 1); if(err) printk(KERN_NOTICE "Error %d adding s2c2440_leds %d",err, 1); return 0; fail_malloc: unr egister_chrdev_region(devid, 1); return ret;}static void __exit s3c2440_leds_exit(void){ printk("Starting delet node %d\n",major); cdev_del(&s3c2440_leds_dev->cdev); kfree(s3c2440_leds_dev); unregister (major, minor), 1); printk("Delete node %d\n",major);}module_init(s3c2440_leds_init);module_exit(s3c2440_leds_exit);MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPLICTION(DRV_DES_C");MODULE_DESCRIPLICTION(DRV_DES_C"); ;

Contents

  • Blog description
  • < li>Development environment

  • 1. Composition of Linux character device driver
    • 1.1 Load and unload functions of character device driver module
    • 1.2 In the file_operations structure of character device driver Member functions of
  • 2. Character device driver-device number registration and uninstallation
    • 2.1 Device number registration
    • 2.2 Device number cancellation
  • 3. Character device driver-file operation
  • Reference material
  • Sample code

  • Blog description
  • Development environment
  • 1. Linux character device driver composition
    • 1.1 Character device driver module loading and unloading functions
    • 1.2 Member functions in the file_operations structure of the character device driver
  • 2 . Character device driver-device number registration and uninstallation
    • 2.1 Device number registration
    • 2.2 Device number cancellation
  • 3. Character device Drive-file operation
  • Reference material
  • Sample code

Leave a Comment

Your email address will not be published.