linux驅動摸索 --驅動框架初始化(結合韋東山視頻教程)
阿新 • • 發佈:2017-09-20
boa kernel cde targe 一個 自動 comm argv ops
[cpp] view plain copy
[cpp] view plain copy
一.驅動框架
初始化:insmod 加載
1.確定主設備號:
分為靜態和動態分配,其中LED_GPIO_SIZE 表示支持的次設備號數目,一般默認為1. 相關實現代碼如下:
[cpp] view plain copy- 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;
- }
2.構造 file_operations 結構:結構成員對應相應的處理函數:
- static struct file_operations mini2440_leds_fops = {
- .owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創建的__this_module變量 */
- .open = mini2440_leds_open,
- .write = mini2440_leds_write,
- };
3.將相關操作告訴內核:
內核用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");
卸載驅動 rmmod 卸載 代碼實現如下:
- 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);
最後附上一個較為完整的驅動框架,其中創建了主設備號和次設備號,驅動代碼如下:
[cpp] view plain copy- #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 4
- static 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");
linux 測試代碼:
- #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;
- }
linux驅動摸索 --驅動框架初始化(結合韋東山視頻教程)