Today I sorted out the character device driver template, separated by three files.
The initialization of the Main. c driver.
Loadmod. C provides functions for installing and detaching drivers.
Fileops. c file operation function.
Makefile
#KERNELDIR = /home/fontlose/board/tx2416/kernelsom2416KERNELDIR = /usr/src/kernels/2.6.35.13-92.fc14.i686/PWD := $(shell pwd)#CC = arm-linux-gccmoddev-objs=main.o fileops.o loadmod.oobj-m+=moddev.o modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions.PHONY: modules clean
Main. c
#include <linux/module.h>#include <linux/kernel.h>#include <linux/device.h>#include <linux/init.h>#include "loadmod.h"#include "fileops.h"MODULE_AUTHOR("my name");MODULE_LICENSE("Dual BSD/GPL");#define MAJORNUM 0#define MINJORNUM 60 struct file_operations ops={ .owner=THIS_MODULE, .open=fileops_open, .write=fileops_write, .read=fileops_read, .release=fileops_release};static int template_init(void){ if ( install_chardev(MAJORNUM,MINJORNUM,4,"moduledev","modclass",&ops)) return -1; if(fileops_init()) { uninstall_chardev(); return -1; } return 0;}static void template_exit(void){ uninstall_chardev(); fileops_destroy(); printk(KERN_ALERT "goodbye\n");}module_init(template_init);module_exit(template_exit);
Loadmod. h
#ifndef __LOADMOD_H__#define __LOADMOD_H__#include <linux/fs.h> extern unsigned char install_chardev(int major_i,int minor_i,unsigned char count,char*devname,char*classname,struct file_operations *ops); extern int uninstall_chardev(void);#endif
Loadmod. c
# Include <Linux/module. h> # include <Linux/errno. h> # include <Linux/kernel. h> # include <Linux/device. h >#include <Linux/kdev_t.h> # include <Linux/err. h> # include <Linux/cdev. h> # include <Linux/init. h> # include <Linux/Fs. h> # include <Linux/string. h> static struct cdev cdev_install; // static struct class * class_install; // static int major_install, minor_install; // static unsigned char count_install; // *** INS Tall_chardev character device registration function * @ major_ I master device Number * @ minor_ I sub-device Number * @ count number of devices * @ devname device name + registered device name automatically generates devname + times under/dev file of the device Number * @ classname device class name * @ ops file operation data structure */unsigned char install_chardev (INT major_ I, int minor_ I, unsigned char count, char * devname, char * classname, struct file_operations * OPS) {// Step 1: register the device number int I; dev_t dev; if (major_ I = 0) // dynamically apply for a master device number {int res = alloc_chrdev_region (& Dev, minor_ I, Count, devnam E); If (RES) {printk (kern_alert "alloc chrdev region fail! \ N "); Return-1;} major_ I = major (Dev);} else {int res; Dev = mkdev (major_ I, minor_ I); Res = register_chrdev_region (Dev, count, devname); If (RES) {printk (kern_alert "register chrdev region fail! \ N "); Return-1 ;}} major_install = major_ I; minor_install = minor_ I; count_install = count; // Step 2: register the device cdev_install.count = 0; If (Ops! = 0) {cdev_init (& cdev_install, OPS); cdev_install.owner = this_module; cdev_install.ops = OPS; If (cdev_add (& cdev_install, Dev, count_install) {Dev, count_install ); printk (kern_alert "cdev add Fail! \ N "); Return-1 ;}// Step 3: create a device node. Note that class_device_create and class_device_destroy are used in Linux 2.6 // earlier versions, later versions use device_create and device_destroy class_install = class_create (this_module, classname); If (is_err (class_install) {If (cdev_install.count> 0) cdev_del (& cdev_install); Dev, count_install); printk (kern_alert "class creat fail! \ N "); Return-1 ;}for (I = 0; I <count; I ++) {device_create (class_install, null, mkdev (major_install, minor_install + I ), null, "% S % d", devname, minor_install + I);} printk (kern_alert "device initial success Major: % d Minor: % d! \ N ", major_install, minor_install); Return 0;}/*** uninstall_chardev uninstall character device */INT uninstall_chardev (void) {int I; If (cdev_install.count> 0) cdev_del (& cdev_install); unregister_chrdev_region (mkdev (major_install, minor_install), count_install); for (I = 0; I <count_install; I ++) {device_destroy (class_install, mkdev (major_install, minor_install + I);} class_destroy (class_install); Return 0 ;}
Fileops. h
#ifndef __FILEOPS_H__#define __FILEOPS_H__#include <linux/fs.h>extern int fileops_init(void);extern void fileops_destroy(void);extern int fileops_open(struct inode *inode, struct file *filp);extern int fileops_release(struct inode *inode,struct file *filp);extern ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp);extern ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);extern int fileops_ioctl(struct inode *, struct file *, unsigned int, unsigned long);#endif
Fileops. c
# Include <Linux/init. h> # include <Linux/kernel. h >#include <Linux/kdev_t.h> # include <Linux/err. h> # include <Linux/cdev. h> # include <Linux/Fs. h> # include "fileops. H "# include <ASM/uaccess. h>/*** called during initialization */INT fileops_init (void) {return 0 ;} /*** the release function calls the */void fileops_destroy (void) {}/ *** file opening driver during module uninstallation to prepare for subsequent operations, if you do not enable the default function, * initialize the device. If necessary, initialize the index node of the filp-> private_data ** @ inode file to store the basic information of the file and directory, determine the specific device * @ filp */INT fileops_open (struct inode * inode, struct file * filp) based on the number of times in the inode structure) {printk (kern_alert "fileops_open \ n"); Return 0 ;}/ *** disable the memory used to release the open application to close the device */INT fileops_release (struct inode * inode, struct file * filp) {printk (kern_alert "fileops_release \ n"); Return 0 ;} /*** read the device * @ filp. Generally, private_data data is operated. * @ Buff: the cache of the user space, used to store the read data * @ count the size of the data the user wants to read * @ OFFP the location of the file the user is accessing * the actual read size negative number is returned, indicating an error */ssize_t fileops_read (struct file * filp, char _ User * buff, size_t count, loff_t * OFFP) {/* update OFFP */printk (kern_alert "fileops_read \ n"); Return 0 ;} /*** write the device * @ filp to perform private_data operations * @ buff user space cache, used to store the data to be written * @ count the data size the user wants to write * @ OFFP the file location the user is accessing * return the actual write size negative number indicating an error */ssize_t fileops_write (struct file * filp, const char _ User * buff, size_t count, loff_t * OFFP) {/* The system call will always write until the write count is sufficient. If the return value is less than count, this method will be called again until an error is returned or count */printk (kern_alert "fileops_write \ n"); Return count;} is written ;} /*** fileops_ioctl IOCTL System Call provides a method for issuing device-specific commands * @ inode * @ filp * @ cmd * @ Arg */INT fileops_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long Arg) {printk (kern_alert "fileops_ioctl \ n"); Return 0 ;}
Test Results
[root@localhost module]# makemake -C /usr/src/kernels/2.6.35.13-92.fc14.i686/ M=/home/fontlose/board/tx2416/rootfs/usr/ldds/module modulesmake[1]: Entering directory `/usr/src/kernels/2.6.35.13-92.fc14.i686' CC [M] /home/fontlose/board/tx2416/rootfs/usr/ldds/module/main.o CC [M] /home/fontlose/board/tx2416/rootfs/usr/ldds/module/fileops.o CC [M] /home/fontlose/board/tx2416/rootfs/usr/ldds/module/loadmod.o LD [M] /home/fontlose/board/tx2416/rootfs/usr/ldds/module/moddev.o Building modules, stage 2. MODPOST 1 modules CC /home/fontlose/board/tx2416/rootfs/usr/ldds/module/moddev.mod.o LD [M] /home/fontlose/board/tx2416/rootfs/usr/ldds/module/moddev.komake[1]: Leaving directory `/usr/src/kernels/2.6.35.13-92.fc14.i686'[root@localhost module]# dmesg|tail -2[31864.045477] device initial success major:247 minor:60![31872.877461] goodbye[root@localhost module]# ls /dev/moduledev6*/dev/moduledev60 /dev/moduledev61 /dev/moduledev62 /dev/moduledev63[root@localhost module]# ls /sys/class/modclass/moduledev60 moduledev61 moduledev62 moduledev63[root@localhost module]# echo 1234 > /dev/moduledev60 [root@localhost module]# dmesg|tail -3[32022.480159] fileops_open[32022.480171] fileops_write[32022.480174] fileops_release