Linux character device driver development detailed

Source: Internet
Author: User
Tags goto volatile

First, the classification and characteristics of equipment

1. Character devices

A character device is a data-oriented device that does not have a request buffer, and access to the device can only be accessed sequentially by byte, not randomly.
Most of the devices under Linux are character devices. An application accesses a character device through a character device node. It is usually necessary to implement system calls such as open, close, read, and write at least.
Device nodes are typically created in the/dev directory by the Mknod command, including the type of device, primary/secondary device number, and access control for the device, such as: CRW-RW----1 root root 4, 23:34/DEV/TTYS0
The common character device has mouse, keyboard, serial port, console and so on. Of course, there are also character devices that can be accessed randomly, such as tape drives, but the time required to access random data is largely dependent on the location of the data within the device.

2, Block equipment

Storage devices generally belong to the block device, the block device has a request buffer, and support random access without having to access the data in sequence, such as you can first access the data behind, and then access the previous data, which is not possible for the character device.
Although there is a block device node under Linux, the application generally accesses the block device through the file system and its cache, rather than reading and writing data on the block device directly through the device node.
Each block device has a corresponding device file in the/dev/directory, the device node, which contains the type of device, the primary/secondary device number, and the access control of the device, such as BRW-RW----1 root root 3, 1 Jul 5 2000/dev/hda1
A block device can be used as a normal bare device to hold arbitrary data, or a block device can be formatted as a file system type, and then read the data on the block device in the format of the file system type. Common block devices have various hard disks, flash disks, RAM disks, and so on.

3. Network Equipment

Unlike character devices and block devices, it is message-oriented rather than stream-oriented, and it does not support random access or request buffers.
In Linux, a network device can also be called a network interface, it does not have the same device number as the character device and the block device, only a unique name such as eth0, eth1, etc., the name does not need to correspond to the device file node, the application through the socket rather than the device node to access network equipment , there is no network device node in the system at all.

Ii. General steps for character device driver development

1. Determine the main device number and the slave number. The main device number is the identity of the kernel to identify a class of devices, from the device number for the kernel to determine a specific device. The main device number and the slave number are represented by a 32-bit integer variable, the main device number is 12 bits, ranging from 0 to 4095, usually 1 to 255, from the device number to 20 bits, from 0 to 1048575, and usually 0 to 255.

2, realize file_operations structure.

3, call the relevant function to initialize and register the character device.

4, call destroy function, release the character device.

5. Create a device file node.


Third, the main data structure

The main structure in the character device driver is these two. A character device corresponds to a cdev that is called to the corresponding function in the file operation structure when the application calls open (), write (), read (), and so on.


1, equipment structure body

struct CDEV
{
struct Kobject kobj; /* Embedded Kobject Object */
struct module *owner; /* Owning module */
struct File_operations *ops; /* File operation structure */
struct List_head list;
dev_t Dev; /* Device number */
unsigned int count;
};

2. File operation structure

struct File_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct KIOCB *, const struct IOVEC *, unsigned long, loff_t);
ssize_t (*aio_write) (struct KIOCB *, const struct IOVEC *, unsigned long, loff_t);
Int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
Long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
Long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
Int (*mmap) (struct file *, struct vm_area_struct *);
Int (*open) (struct inode *, struct file *);
Int (*flush) (struct file *, fl_owner_t ID);
Int (*release) (struct inode *, struct file *);
Int (*fsync) (struct file *, int datasync);
Int (*aio_fsync) (struct KIOCB *, int datasync);
Int (*fasync) (int, struct file *, int);
Int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area) (struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
Int (*check_flags) (int);
Int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write) (struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read) (struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
Int (*setlease) (struct file *, long, struct file_lock * *);
};

Iv. Description of functions

1, int register_chrdev_region (dev_t first, unsigned int count, char *name);

function: Static allocation of the main device number, find a kernel is not used by the main device number to use.

Parameter description: Parameter one, the starting value of the device number range to be assigned, the secondary device number is usually 0, parameter two, the number of consecutive device numbers requested, parameter three, the name of the device.

2, int alloc_chrdev_region (dev_t *dev,unsigned int firstminor,unsigned int Count,char *name);

Function: Dynamically assigns a master device number.

Parameter description: Parameter one, return the device number, parameter two, the first secondary device number, parameter three, the number of consecutive device numbers requested, parameter four, device name.

3, void Unregister_chrdev_region (dev_t first, unsigned int count);

Function: Used to release the device number, usually called in the module clear function. There are applications to be released, to correspond.

4, void Cdev_init (struct Cdev *, Struc t file_operations *);

Functions: Used to initialize the individual members of the Cdev and establish a connection between Cdev and File_operations.

5, int cdev_add (struct Cdev *, dev_t, unsigned);

Function: Bind the requested device number to the device, then I add a cdev to the system to complete the registration of the character device.

6, void Cdev_del (struct cdev *);

Function: Complete logoff of character device


Note: Before calling the Cdv_add () function to register a character device with the system, you should first call the Register_chrdev_region () function or the Alloc_chrdev_region function to request a device number from the system. Conversely, after calling the Cdev_del () function to unregister the character device from the system, the Unregister_chrdev_region function should be called to release the device number that was originally requested.


How far simple example (key-driven)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <asm/gpio.h>

#define BUTTON_NAME "Poll_button"
#define OMAP_BUTTON_GPIO 29

static int button_major = 0;
static int button_minor = 0;
static struct Cdev Button_cdev;
static struct Class *p_button_class = NULL;
static struct Device *p_button_device = NULL;

static struct timer_list button_timer1;
static struct timer_list button_timer2;
static volatile int ev_press_poll = 0;
static volatile char down_times[] = {0};
static volatile int BUTTON_IRQ = 0;
static int flag_interrupt = 1;

Static Declare_wait_queue_head (Button_waitq_poll);


static irqreturn_t buttons_interrupt (int irq, void *dev_id)
{
if (flag_interrupt)
{
Flag_interrupt = 0;
Mod_timer (&button_timer2,jiffies + hz/100);
}
Return Irq_retval (irq_handled);
}

static void Button_timer_handle1 (unsigned long arg)
{
int key_value;

down_times[0]++;
Key_value = Gpio_get_value (Omap_button_gpio);

if (Key_value! = 0)
{
Ev_press_poll= 1;
Wake_up_interruptible (&button_waitq_poll);
}
Else
{
Mod_timer (&button_timer1,jiffies + HZ);
}
}

static void Button_timer_handle2 (unsigned long arg)
{
int key_value;

Flag_interrupt = 1;
Key_value = Gpio_get_value (Omap_button_gpio);
if (key_value==0)
{
Mod_timer (&button_timer1,jiffies + HZ);
}
}


static int Button_open (struct inode *inode,struct file *file)
{
int err;

Init_timer (&button_timer1);
Init_timer (&AMP;BUTTON_TIMER2);
Button_timer1.function = &button_timer_handle1;
Button_timer2.function = &button_timer_handle2;

BUTTON_IRQ = OMAP_GPIO_IRQ (Omap_button_gpio);
Err = REQUEST_IRQ (BUTTON_IRQ, Buttons_interrupt, irq_type_edge_falling, "Button_irq", NULL);
if (ERR)
{
PRINTK ("fail to erquest IRQ:%d err =%d\n", button_irq,err);

DISABLE_IRQ (BUTTON_IRQ);
FREE_IRQ (BUTTON_IRQ, NULL);
Return-ebusy;
}

Ev_press_poll = 0;

return 0;
}

static int button_close (struct inode *inode, struct file *file)
{
FREE_IRQ (BUTTON_IRQ, NULL);
return 0;
}


static int button_read (struct file *filp, char __user *buff, size_t count, loff_t *OFFP)
{
unsigned long err;

Err = Copy_to_user (buff, (const void *) Down_times, min (sizeof (down_times), count));
Down_times[0] = 0;

return err? -efault:min (sizeof (down_times), count);
}


static unsigned int button_poll (struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = 0;

걒 (poll_table)
Poll_wait (file, &button_waitq_poll, wait);

if (Ev_press_poll)
{
±ê
Ev_press_poll = 0;
Mask |= Pollin | Pollrdnorm;
}

return mask;
}


static const struct File_operations Button_fops = {
. Owner = This_module,
. open = Button_open,
. Release = Button_close,
. Read = Button_read,
. Poll = Button_poll,
. write = Button_write,
. IOCTL = Button_ioctl
};


static int Button_setup_cdev (struct Cdev *cdev, dev_t devno)
{
int ret = 0;

Cdev_init (Cdev, &button_fops);
Cdev->owner = This_module;
ret = Cdev_add (Cdev, Devno, 1);

return ret;
}

static int __init button_init (void)
{
int ret;
dev_t Devno;

PRINTK ("button_init\n");

if (button_major)
{
Devno = MKDEV (Button_major, Button_minor);
ret = Register_chrdev_region (Devno, 1, button_name);
}
Else
{
ret = Alloc_chrdev_region (&devno, Button_minor, 1, button_name);
Button_major = Major (Devno);

}

if (Ret < 0)
{
PRINTK ("Get button_major fail\n");
return ret;
}

ret = Button_setup_cdev (&button_cdev, Devno);
if (ret)
{
PRINTK ("Button_setup_cdev fail =%d\n", ret);
Goto Cdev_add_fail;
}

P_button_class = Class_create (This_module, button_name);
ret = Is_err (P_button_class);
if (ret)
{
PRINTK (kern_warning "button class_create fail\n");
Goto Class_create_fail;
}
P_button_device = device_create (P_button_class, NULL, DEVNO, NULL, button_name);
ret = Is_err (p_button_device);
if (ret)
{
PRINTK (kern_warning "button device_create fail, error code%LD", Ptr_err (P_button_device));
Goto Device_create_fail;
}

return 0;

Device_create_fail:
Class_destroy (P_button_class);
Class_create_fail:
Cdev_del (&button_cdev);
Cdev_add_fail:
Unregister_chrdev_region (Devno, 1);
return ret;

}

static void __exit button_exit (void)
{
dev_t Devno;

PRINTK ("button_exit\n");

Devno = MKDEV (Button_major, Button_minor);
Del_timer_sync (&button_timer1);
Del_timer_sync (&AMP;BUTTON_TIMER2);
Device_destroy (P_button_class, Devno);
Class_destroy (P_button_class);
Cdev_del (&button_cdev);
Unregister_chrdev_region (Devno, 1);
}

Module_init (Button_init);
Module_exit (Button_exit);

Module_author ("Jimmy");
Module_description ("button Driver");
Module_license ("GPL");


Vi. how the application uses drivers

The above driver invokes the Class_create () function and the device_create () function, so that Udev creates a device node named Poll_button in/dev under the system startup. After the application opens the device node using the Open function, it can call the read (), write () function to read and write.

If the application does not call these two functions, create the device node manually, such as Mknod/dev/poll_button C 250 0.

Vii. attached makefile file

Ifneq ($ (kernelrelease),)
Obj-m: = BUTTON.O
Else
Kerneldir? =/home/share/linux-2.6.32-devkit8500
#KERNELDIR? =/lib/modules/$ (Shell uname-r)/build
PWD: = $ (shell pwd)

Default
$ (make)-C $ (Kerneldir) m=$ (PWD) modules

endif

Install
$ (make)-C $ (Kerneldir) m=$ (PWD) Modules_install

Clean
RM-RF *.o *~ core depend. *.cmd *.ko *.mod.c. Tmp_versions *.symvers *.order

This article is from the "s wind continue to blow S" blog, please be sure to keep this source http://9171414.blog.51cto.com/9161414/1675327

Linux character device driver development detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.