Interface of the Linux kernel character device

  

Character devices are the most hardware devices, such as common touchscreen, lcd, etc.

It is generally believed that data needs to be accessed sequentially, and the network card can also be considered as a character device. The difference is that the network needs a lot of processing related to the protocol stack. The feature of the block device is that the read and write data is performed in blocks, but more importantly, it can be accessed immediately.

The 2.6 kernel is more complicated than the 2.4 kernel operation, but it can avoid some unnecessary problems and enhance the scientificity from the structure and principle. The following is a recent example of the driver, I hope to explain this one or two.

Driver development takes the form of modules, because the final need to drive services to our upper-level software applications requires that the driver be run in kernel space. Operating system
At runtime, we need to use A fixed way to add our driver to the kernel, the module provides us with such a method. The general module requires three important parts: MODULE_LICENSE("GPL");module_init(dvr_tdm_init);module_exit(dvr_tdm_exit);

tdm_init and tdm_exit are function names that need to be implemented in the module, as follows:

static struct file_operations dvr_tdm_fops ={read: dvr_tdm_read,write: dvr_tdm_write,open: dvr_tdm_open,release: dvr_tdm_release,}; #if 0 This structure includes many function pointers, adding implementations of these functions can implement many advanced functions. Such as: 1, to achieve blocking of the device non-blocking (mainly using DECLARE_WAIT_QUEUE_HEAD (name); init_waitqueue_head (wait_queue_head_t *name); wait_event_interruptible (queue, condition) void wake_up_interruptible (wait_queue_head_t *queue); See: Concurrency and competition 2, concurrent with Competition 3, to achieve support for the select function. 4, to achieve mmap of the kernel space. 5, io control of the hardware, etc.

#e ndif

static struct cdev * dvr_tdm_cdev; static dev_t tdm_dev_t;

static int __init dvr_tdm_init (void) {ret = alloc_chrdev_region (& tdm_dev_t, 0, DVR_TDM_COUNT, DRV_NAME); if (ret! = 0) {printk (KERN_ERR " alloc_chrdev_regin failed \\ n "); goto out;} dvr_tdm_cdev = cdev_alloc (); dvr_tdm_cdev- & gt; ops = & dvr_tdm_fops; dvr_tdm_cdev- & gt; owner = THIS_MODULE; //init driver interfacescdev_init ( dvr_tdm_cdev, & dvr_tdm_fops); debug (" dvr_tdm_init:! chr device initialized \\ n ");

ret = cdev_add (dvr_tdm_cdev, tdm_dev_t, DVR_TDM_COUNT); if (ret) {printk (" dvr_tdm_init: Chr device added\ ");}else{printk("dvr_tdm_init: cannot add chr device\ ");}out:return ret;}

static void __exit dvr_tdm_exit(void){unregister_chrdev_region(tdm_dev_t , DVR_TDM_COUNT); cdev_del(dvr_tdm_cdev);} __init and __exit before the function name are: __exit declares the code to be put into the kernel startup init area, the code in the area is only run once, after the end of the run, the code is throw away. Code marked as __exit is discarded directly. Both of these statements are prepared for the module to be added to the kernel. If it is only run as a standalone module, the above statement has no meaning. The following is the basic implementation of the driver's read write open release function. static int dvr_tdm_open (struct inode * inode, struct file * filp) {if //If the module has been inserted into the kernel, the module increments the reference count (try_module_get (THIS_MODULE)!); if the module has not been inserted into the kernel, it returns 0 represents An error occurred. Printk("try_module_get error\ "); debug("dvr_tdm_open: driver run ok\ ");

return 0;}

static ssize_t dvr_tdm_write (struct file *file, const char __user * buf, size_t count, loff_t * offset) {short signed int pcm_buffer [TDM_FRAME_LENGTH]; int ret; ret = copy_from_user (pcm_buffer, buf, count); if (ret) printk (" dvr_tdm_write: there are% x bytes can not read from user \\ n ", ret); //...... return 0;}

static int dvr_tdm_release (struct inode * inode, struct file * filp) {module_put (THIS_MODULE ); debug (" dvr_tdm_release: driver release ok \\ n ");

return 0;}

static ssize_t dvr_tdm_read (struct file * file, char __user * buf, size_t count, loff_t *pos){short signed int pcm_buffer[TDM_FRAME_LENGTH];int ret;//....get data ret=copy_to_user(buf, pcm_buffer, TDM_FRAME_LENGTH); if(ret)printk("dvr_tdm_read: there are %x bytes can 't read for user \\ n ", ret); return 0;}

Makefile: ifneq ($ (KERNELREASE),) obj-m += mpc8315_tdm.oelseKERNELDIR ?= /home/wilson/ltib/rpm/BUILD/linux/buildobj-m += dvr_tdm.odvr_tdm-objs := tdm_driver.oPWD := $(shell pwd)ALL:$(MAKE) ARCH= Powerpc CROSS_COMPILE=powerpc-e300c3-linux-gnu- O=build -C $(KERNELDIR) M=$(PWD) modulesclean:rm *.o *.koendif

Device Node Creation: #! /bin /sh

module = " dvr_tdm " device = " dvr_tdm " mode = 664error = " Error: Can not find dvr tdm device "

insmod ./$module.ko $ * | |  Exit 1major=`cat /proc/devices |  Grep $device |  awk '{print $ 1}' `if [-z $ major] then echo $ error; exit 1fi

rm -f /dev /$ {device}

Copyright © Windows knowledge All Rights Reserved