一.驱动框架
初始化:insmod 加载
1.确定主设备号:
分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:
int result; dev_t dev; /*分配主设备号*/ if (scull_major) /*静态分配一个主设备号*/ { dev = MKDEV(scull_major,0); result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME); } else /*动态分配一个主设备号*/ { result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME); scull_major = MAJOR(dev); } if(result <0) { printk("LED:can not get major:%d/n",scull_major); return result; }
static struct file_operations mini2440_leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = mini2440_leds_open, .write = mini2440_leds_write, };
内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,
led_class = class_create(THIS_MODULE,DEVICE_NAME); cdev_init(&led_gpio_cdev, &mini2440_leds_fops); result = cdev_add(&led_gpio_cdev, dev, 1); if(result <0) { printk("LED:cdev_add error/n"); return result; } device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");
dev_t dev_id = MKDEV(scull_major, 0); /*卸载主设备号*/ unregister_chrdev_region(dev_id, LED_GPIO_SIZE); device_destroy(led_class,MKDEV(scull_major, 0)); cdev_del(&led_gpio_cdev); class_destroy(led_class);
最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <mach/io.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/device.h>#include <linux/cdev.h>#define DEVICE_NAME "led_1"#define LED_GPIO_SIZE 4static int scull_major = 0;static struct class *led_class;static struct cdev led_gpio_cdev[LED_GPIO_SIZE];static int mini2440_leds_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev); printk("/dev/led%d has opened/n",minor); return 0;}static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos){ char val; int minor = MINOR(filp->f_dentry->d_inode->i_rdev); copy_from_user(&val, buf, 1); printk("/dev/led%d write the val = %d/n",minor,val); return 0;}static struct file_operations mini2440_leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = mini2440_leds_open, .write = mini2440_leds_write, };/* * 执行insmod命令时就会调用这个函数 */static int mini2440_leds_init(void){ int result,i; dev_t dev; /*分配主设备号*/ if (scull_major) /*静态分配一个主设备号*/ { dev = MKDEV(scull_major,0); result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME); } else /*动态分配一个主设备号*/ { result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME); scull_major = MAJOR(dev); } if(result <0) { printk("LED:can not get major:%d/n",scull_major); return result; } led_class = class_create(THIS_MODULE,DEVICE_NAME); if (IS_ERR(led_class)) { return PTR_ERR(led_class); } for (i=0; i<LED_GPIO_SIZE;i++) { cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops); result = cdev_add(&led_gpio_cdev[i], (dev+i), 1); if(result <0) { printk("LED:cdev_add error/n"); return result; } device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i); } return 0;}/* * 执行rmmod命令时就会调用这个函数 */static void mini2440_leds_exit(void){ int i; dev_t dev_id = MKDEV(scull_major, 0); /*卸载主设备号*/ unregister_chrdev_region(dev_id, LED_GPIO_SIZE); for(i=0;i<LED_GPIO_SIZE;i++) { device_destroy(led_class,MKDEV(scull_major, i)); cdev_del(&led_gpio_cdev[i]); } class_destroy(led_class);}/* 这两行指定驱动程序的初始化函数和卸载函数 */module_init(mini2440_leds_init);module_exit(mini2440_leds_exit);/* 描述驱动程序的一些信息,不是必须的 */MODULE_LICENSE("GPL");
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>/* * ledtest <dev> <on|off> */void print_usage(char *file){ printf("Usage:/n"); printf("%s <dev> <on|off>/n",file); printf("eg. /n"); printf("%s /dev/led0 a/n", file); printf("%s /dev/led1 b/n", file); printf("%s /dev/led2 c/n", file); printf("%s /dev/led3 d/n", file);}int main(int argc, char **argv){ int fd; char* filename; char val; if (argc != 3) { print_usage(argv[0]); return 0; } filename = argv[1]; fd = open(filename, O_RDWR); if (fd < 0) { printf("error, can't open %s/n", filename); return 0; } if (!strcmp("a", argv[2])) { val = 10; write(fd, &val, 1); } else if (!strcmp("b", argv[2])) { val = 11; write(fd, &val, 1); } else if (!strcmp("c", argv[2])) { val = 12; write(fd, &val, 1); } else if (!strcmp("d", argv[2])) { val = 13; write(fd, &val, 1); } return 0;}