Original URL: http://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html
first, the Linux system divides the device into 3 categories: Character device, block device, network device. Using drivers:
1, character device : Refers to a byte can only one byte read and write devices, can not randomly read the device memory of a certain data, read data need to follow the data. The character device is a stream-oriented device, and the common character devices are mouse, keyboard, serial port, console and led device.
2, block device : Refers to the device can be read from any location of a certain length of data equipment. Block devices include hard disks, disks, USB sticks, and SD cards.
Each character device or block device corresponds to a device file in the/dev directory. The Linux User program uses the driver to manipulate character devices and block devices through device files (or device nodes).
Second, the character device driver base:
1, the main device number and the secondary device number (both for the device number):
A character device or a block device has a master device number and a secondary device number. The main device number identifies the driver that is connected to the device file and is used to reflect the device type. The secondary device number is used by the driver to identify which device is operating and to distinguish between devices of the same type.
In the Linux kernel, the device number is described by dev_t, as defined in 2.6.28:
typedef u_long DEV_T;
In a 32-bit machine is 4 bytes, the high 12 bits represent the main device number, and the lower 12 bits represent the secondary device number.
You can use the following macros to obtain primary and secondary device numbers from dev_t: You can also use the following macros to generate dev_t from the primary and secondary device numbers:
MAJOR (dev_t Dev); MKDEV (int major,int minor);
MINOR (dev_t Dev);
View Code
2, the allocation of equipment number (two methods):
(1) Static application:
int Register_chrdev_region (dev_t from, unsigned count, const char *name);
View Code
(2) Dynamic distribution:
int alloc_chrdev_region (dev_t *dev, unsigned baseminor, unsigned count, const char *name);
View Code
Logoff device number :
void Unregister_chrdev_region (dev_t from, unsigned count);
To create a device file :
Use Cat/proc/devices to view the device name, device number, to which you are applying.
(1) manually created with Mknod: Mknod filename type Major minor
(2) automatic creation;
Using Udev (Mdev) to automate the creation of device files, first ensure that Udev (Mdev) is supported and configured by BusyBox. In the driver initialization code, call Class_create to create a class for the device, and then call device_create for each device to create the corresponding device.
3, character device driver important data structure :
(1) struct file: Represents an open file descriptor, each open file in the system has an associated struct file in the kernel. It is created by the kernel at open and passed to any function that operates on the file until it is finally closed. When all instances of the file are closed, the kernel releases the data structure.
View Code
(2) struct inode: used to log the physical information of a file. It is different from the file structure that represents open. A file can correspond to multiple file structures, but only one inode structure. The inode is generally passed as a parameter to the function in the file_operations structure.
The inode is translated into Chinese as an index node. Partition of each storage device or storage device (storage device is hard disk, floppy disk, USB stick ...) After being formatted as a filesystem, there should be two parts, one for the inode, and the other for the Block,block to store the data. The inode is the information that is used to store this data, including file size, owner, attribution user group, read-write permission, and so on. The Inode indexes the information for each file, so there is a value for the inode. According to the instructions, the operating system can find the corresponding file by the Inode value.
View Code
(3) struct file_operations
This section is from: http://blog.chinaunix.net/space.php?uid=20729583&do=blog&id=1884550, thanks to Chinahhucai for sharing.
View Code
Three, character device driver program design :
1. Device Registration :
In the linux2.6 kernel, character devices are described using struct cdev;
struct CDEV
{
struct Kobject kobj;//embedded Kobject Object
struct Module *owner;//owned modules
struct file_operations *ops;//file operation structure Body
struct List_head list;
dev_t dev;//device number, length 32 bits, of which 12 is the main device number, low 20 bits for this device number
unsigned int count;
};
The registration of a character device is divided into three steps:
(1) Distribution cdev:struct Cdev *cdev_alloc (void);
(2) Initialize cdev:void cdev_init (struct cdev *cdev, const struct file_operations *fops);
(3) Add Cdev:int cdev_add (struct Cdev *p, dev_t Dev, unsigned count)
View Code
2. device Operation Implementation : the implementation of the File_operations function set (to clarify when a function is called?) What do you use it for? )
Special note: Data exchange for driver applications:
The data exchange between the driver and the application is very important. The read () and write () functions in file_operations are used to exchange data between the driver and the application. With data exchange, drivers and applications can understand each other's situation. However, drivers and applications belong to different address spaces. The driver does not have direct access to the application's address space, nor does the application directly access the driver's address space, which destroys data in each other's space, causing system crashes or data corruption. The secure approach is to use the specialized functions provided by the kernel to exchange data between the application space and the driver space. These functions strictly inspect and convert the pointers passed by the user program to ensure the security of the data exchanged between the user program and the driver. These functions are:
Get_user (Local,user);
3. device logoff : void Cdev_del (struct cdev *p);
Four, character device driver summary:
The character device is a simple type of device in the 3 class device (character device, block device, network device), the main work of the driver is to initialize, add and delete the CDEV structure, request and release the device number, and fill the operation function in the file_operation structure, and implement File_ Operations important functions such as read (), write (), IOCTL () in the structure. A driver-driven relationship for Cdev struct, file_operations, and user-space calls.
Five: Character device driver analysis:
(1)memdev.h
View Code
(2) memdev.c
static mem_major = Memdev_major;
Module_param (mem_major, int, s_irugo);
struct Mem_dev *mem_devp; /* Device Structural body pointer */
struct Cdev Cdev;
/* File Open function */
int Mem_open (struct inode *inode, struct file *filp)
{
struct Mem_dev *dev;
/* Get the secondary device number */
int num = MINOR (Inode->i_rdev);
if (num >= memdev_nr_devs)
Return-enodev;
dev = &mem_devp[num];
/* Assign the device description structure pointer to the file private data pointer */
Filp->private_data = Dev;
return 0;
}
/* File deallocation function */
int mem_release (struct inode *inode, struct file *filp)
{
return 0;
}
/* Read function */
Static ssize_t mem_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos; /* Record file pointer offset position */
unsigned int count = size; /* Record the number of bytes to read */
int ret = 0; /* return value */
struct Mem_dev *dev = filp->private_data; /* Get the device structure pointer */
/* Determine if the read position is valid */
if (P >= memdev_size)/* The offset to read is greater than the memory space of the device */
return 0;
if (Count > Memdev_size-p)/* The bytes to read are larger than the memory space of the device */
Count = memdev_size-p;
/* Read data to user space: Kernel space-User space Exchange data */
if (Copy_to_user (buf, (void*) (Dev->data + P), count))
{
ret =-Efault;
}
Else
{
*ppos + = count;
ret = count;
PRINTK (kern_info "read%d bytes (s) from%d\n", Count, p);
}
return ret;
}
/* Write function */
Static ssize_t mem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct Mem_dev *dev = filp->private_data; /* Get the device structure pointer */
/* Parse and get a valid write length */
if (P >= memdev_size)
return 0;
if (Count > Memdev_size-p)/* The bytes to be written are larger than the memory space of the device */
Count = memdev_size-p;
/* Write data from user space */
if (Copy_from_user (Dev->data + p, buf, Count))
ret =-Efault;
Else
{
*ppos + = count; /* Increase offset position */
ret = count; /* Returns the actual number of bytes written */
PRINTK (kern_info "written%d bytes (s) from%d\n", Count, p);
}
return ret;
}
/* Seek file Locator function */
Static loff_t mem_llseek (struct file *filp, loff_t offset, int whence)
{
loff_t Newpos;
Switch (whence) {
Case 0:/* seek_set */* relative to File start offset */
Newpos = offset; /* Update file pointer location */
Break
Case 1:/* seek_cur */
Newpos = Filp->f_pos + offset;
Break
Case 2:/* seek_end */
Newpos = memdev_size-1 + offset;
Break
Default:/* can ' t happen */
Return-einval;
}
if ((newpos<0) | | | (newpos>memdev_size))
Return-einval;
Filp->f_pos = Newpos;
return newpos;
}
/* File operation structure */
static const struct File_operations Mem_fops =
{
. Owner = This_module,
. Llseek = Mem_llseek,
. Read = Mem_read,
. write = Mem_write,
. open = Mem_open,
. Release = Mem_release,
};
/* Device driver module load function */
static int memdev_init (void)
{
int result;
int i;
dev_t Devno = MKDEV (mem_major, 0);
/* Apply for device number, when Xxx_major is not 0 o'clock, indicates static designation; When 0 o'clock, indicates dynamic request */
/* Static application device number */
if (mem_major)
result = Register_chrdev_region (Devno, 2, "Memdev");
else/* Dynamically assign device number */
{
result = Alloc_chrdev_region (&devno, 0, 2, "Memdev");
Mem_major = Major (Devno); /* The main device number to get the request */
}
if (Result < 0)
return result;
/* Initialize the CDEV structure and pass the FILE_OPERATIONS structure pointer */
Cdev_init (&cdev, &mem_fops);
Cdev.owner = This_module; /* Specify the owning module */
Cdev.ops = &mem_fops;
/* Register character device */
Cdev_add (&cdev, MKDEV (mem_major, 0), Memdev_nr_devs);
/* Allocate memory for device description structure */
MEM_DEVP = Kmalloc (Memdev_nr_devs * sizeof (struct mem_dev), gfp_kernel);
if (!MEM_DEVP)/* Request failed */
{
result =-Enomem;
Goto Fail_malloc;
}
memset (MEM_DEVP, 0, sizeof (struct mem_dev));
/* Allocate memory for device */
for (i=0; i < Memdev_nr_devs; i++)
{
Mem_devp[i].size = memdev_size;
Mem_devp[i].data = Kmalloc (memdev_size, Gfp_kernel);
memset (mem_devp[i].data, 0, memdev_size);
}
return 0;
Fail_malloc:
Unregister_chrdev_region (Devno, 1);
return result;
}
/* Module Unload function */
static void Memdev_exit (void)
{
Cdev_del (&cdev); /* Unregister the device */
Kfree (MEM_DEVP); /* release device structure in vivo */
Unregister_chrdev_region (MKDEV (mem_major, 0), 2); /* Release the device number */
}
Module_author ("David Xie");
Module_license ("GPL");
Module_init (Memdev_init);
Module_exit (Memdev_exit);
(3) Application (test file):app-mem.c
#include <stdio.h>
int main ()
{
FILE *fp0 = NULL;
Char buf[4096];
/* Initialize buf*/
strcpy (Buf, "Mem is char dev!");
printf ("BUF:%s\n", BUF);
/* Open the device file */
Fp0 = fopen ("/dev/memdev0", "r+");
if (fp0 = = NULL)
{
printf ("Open Memdev0 error!\n");
return-1;
}
/* Write to Device */
Fwrite (Buf, sizeof (BUF), 1, fp0);
/* Relocate the file location (think about the consequences of not having the Directive) */
Fseek (Fp0,0,seek_set);
/* Clear buf*/
strcpy (Buf, "Buf is null!");
printf ("BUF:%s\n", BUF);
/* read out the device */
Fread (Buf, sizeof (BUF), 1, fp0);
/* Test Results */
printf ("BUF:%s\n", BUF);
return 0;
}
Test steps:
1) cat/proc/devices See what number has been used, we choose a non-use of XXX.
2) Insmod Memdev.ko
3) Create a "/dev/memdev0" Device node with the "Mknod/dev/memdev0 C XXX 0" command.
4) Cross-compile the app-mem.c file, download and execute:
#./app-mem, showing:
Mem is char dev!
"Go" Linux device driver simple character device driver