【驱动】第3课、分离分层驱动之学习笔记
开发环境
主 机:VMWare--Ubuntu-16.04.2-x64-100ask
开发板:Mini2440--256M NandFlash, 2M NorFlash, 64M SDRAM, LCD-TD35;
bootlorder:u-boot1.16, Kernel:2.6.22.6;
编译器:arm-linux-gcc-3.4.5
目录
1、问题1:关于驱动中device和driver的名字的问题
2、用platform_driver结构和platform_device结构分别注册驱动程序的操作部分和设备硬件部分
1、问题1:关于驱动中device和driver的名字的问题?
<1>第一种分配方法如下,即视频源程序:
led_drvtest.c: fd = open("/dev/led", O_RDWR);
led_dev.c: static struct platform_device led_dev = {.name = "myled", ...};
led_drv.c:
static int led_probe(struct platform_device *pdev)
{ major = register_chrdev(0, "myled", &led_fops);
cls = class_create(THIS_MODULE, "myled");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
static int led_remove(struct platform_device *pdev){... unregister_chrdev(major, "myled");...}
struct platform_driver led_drv = {.probe=led_probe, .remove=led_remove, .driver={.name= "myled",}};
<2>我自己的运行成功的程序:
led_drvtest.c: fd = open("/dev/myled_2", O_RDWR);
led_dev.c: static struct platform_device led_dev = {.name = "myled_2", ...};
led_drv.c:
static int led_probe(struct platform_device *pdev)
{ major = register_chrdev(0, "leds", &led_fops);
cls = class_create(THIS_MODULE, "leds");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "myled_2"); /* /dev/led */
return 0;
}
static int led_remove(struct platform_device *pdev){... unregister_chrdev(major, "leds");...}
struct platform_driver led_drv = {.probe=led_probe, .remove=led_remove, .driver={.name= "myled_2",}};
综上,platform_driver结构和platform_device结构中的 .name 名字和设备的结构体名字、设备节点的类名字及设备名字,没有
必须的联系,可以不一样!但是platform_driver结构和platform_device结构中的 .name 名字必须一样,方可配对!
2、用platform_driver结构和platform_device结构分别注册驱动程序的操作部分和设备硬件部分。
2.1、platform_driver部分(操作/较稳定的代码):static int led_drv_init(void){ platform_driver_register(&s3c2440_led_drv); return 0;}
注册platform_driver平台结构体,然后程序即会调用其.probe元素对应的函数.probe = led_drv_probe,在函数led_drv_probe内完成
以前课程学习的驱动的xx_init()中需要完成的任务,即注册设备结构/设备节点的类/设备、映射寄存器的虚拟地址到内存。
其中,映射寄存器的虚拟地址到内存,需要调用驱动xx_driver.c对应的xx_device.c程序中的platform_device结构设备对应的设备资
源resource,对应代码如下:
static int led_drv_probe(struct platform_device *dev){...
/* 映射寄存器地址到虚拟地址 */
struct resource *res = platform_get_resource(dev, IORESOURCE_MEM, 0);
gpio_con = ioremap(res->start, res->end - res->start + 1);
gpio_dat = gpio_con + 1;
res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
pin = res->start;
return 0;
}
2.2、platform_device部分(硬件):主要就是struct platform_device结构及其元素的定义。
led_drv3.c
1 /*
2 2018-12-10 3 File: led_drv3.c 4 功能: 配置/注册 platform_device 结构体; 5 说明: LED灯GPB5,6,7,8; 6 */ 7 #include <linux/module.h> 8 #include <linux/version.h> 9 10 #include <linux/init.h> 11 #include <linux/fs.h> 12 #include <linux/interrupt.h> 13 #include <linux/irq.h> 14 #include <linux/sched.h> 15 #include <linux/pm.h> 16 #include <linux/sysctl.h> 17 #include <linux/proc_fs.h> 18 #include <linux/delay.h> 19 #include <linux/platform_device.h> 20 #include <linux/input.h> 21 #include <linux/irq.h> 22 #include <linux/gpio_keys.h> 23 24 #include <asm/gpio.h> 25 #include <asm/uaccess.h> 26 #include <asm/irq.h> 27 #include <asm/io.h> 28 #include <asm/arch/regs-gpio.h> 29 #include <asm/hardware.h> 30 MODULE_LICENSE("GPL"); 31 32 static volatile int pin; /* pin = 5/6/7/8 */ 33 static volatile int major; 34 static struct class * cls; 35 36 static volatile unsigned long * gpio_con; 37 static volatile unsigned long * gpio_dat; 38 39 /* LED模块的打开函数 */ 40 static int s3c2440_leds_open(struct inode *inode, struct file *file) 41 { 42 *gpio_con &= ~(3<<(pin*2)); 43 *gpio_con |= (1<<(pin*2)); 44 45 return 0; 46 } 47 48 /* LED模块的写入操作函数 */ 49 static ssize_t s3c2440_leds_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 50 { 51 char val; 52 int ret; 53 54 ret = copy_from_user(&val, buf, count); 55 if(ret < 0) 56 { 57 printk("s3c2440_leds_write: Unable to copy_from_user !\n"); 58 return ret; 59 } 60 61 if(val == 0) 62 *gpio_dat &= ~(1<<pin); 63 if(val == 1) 64 *gpio_dat |= (1<<pin); 65 66 return 0; 67 } 68 69 static struct file_operations s3c2440_leds_fops = 70 { 71 .owner = THIS_MODULE, 72 .open = s3c2440_leds_open, 73 .write = s3c2440_leds_write, 74 }; 75 76 static int led_drv_probe(struct platform_device *dev) 77 { 78 struct resource * res; 79 /* 注册设备 */ 80 major = register_chrdev(0, "leds", &s3c2440_leds_fops); 81 cls = class_create(THIS_MODULE, "leds"); 82 class_device_create(cls, NULL, MKDEV(major, 0), NULL, "myled_3"); 83 /* 映射寄存器地址到虚拟地址 */ 84 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 85 gpio_con = ioremap(res->start, res->end - res->start + 1); 86 gpio_dat = gpio_con + 1; 87 88 res = platform_get_resource(dev, IORESOURCE_IRQ, 0); 89 pin = res->start; 90 91 return 0; 92 } 93 94 static int led_drv_remove(struct platform_device *dev) 95 { 96 /* 注销设备 */ 97 class_device_destroy(cls, MKDEV(major, 0)); 98 class_destroy(cls); 99 unregister_chrdev(major, "leds"); 100 /* 释放虚拟内存 */ 101 iounmap(gpio_con); 102 103 return 0; 104 } 105 106 struct platform_driver s3c2440_led_drv = { 107 .probe = led_drv_probe, 108 .remove = led_drv_remove, 109 .driver = { 110 .name = "myled_3", 111 } 112 }; 113 114 static int led_drv_init(void) 115 { 116 platform_driver_register(&s3c2440_led_drv); 117 return 0; 118 } 119 120 static void led_drv_exit(void) 121 { 122 platform_driver_unregister(&s3c2440_led_drv); 123 } 124 125 module_init(led_drv_init); 126 module_exit(led_drv_exit);
1 /* 2 2018-12-10 3 File: led_dev3.c 4 功能: 配置/注册 platform_device 结构体; 5 说明: LED灯GPB5,6,7,8; 6 GPBCON 0x56000010 7 */ 8 #include <linux/module.h> 9 #include <linux/version.h> 10 11 #include <linux/init.h> 12 #include <linux/fs.h> 13 #include <linux/interrupt.h> 14 #include <linux/irq.h> 15 #include <linux/sched.h> 16 #include <linux/pm.h> 17 #include <linux/sysctl.h> 18 #include <linux/proc_fs.h> 19 #include <linux/delay.h> 20 #include <linux/platform_device.h> 21 #include <linux/input.h> 22 #include <linux/irq.h> 23 #include <linux/gpio_keys.h> 24 25 #include <asm/gpio.h> 26 #include <asm/gpio.h> 27 #include <asm/uaccess.h> 28 #include <asm/irq.h> 29 #include <asm/io.h> 30 #include <asm/arch/regs-gpio.h> 31 #include <asm/hardware.h> 32 MODULE_LICENSE("GPL"); 33 34 /* 注册设备资源 */ 35 static struct resource led_dev_resource[] = { 36 { 37 .start = 0x56000010, 38 .end = 0x56000010 + 8 -1, 39 .flags = IORESOURCE_MEM 40 }, 41 { 42 .start = 6, 43 .end = 6, 44 .flags = IORESOURCE_IRQ 45 } 46 }; 47 48 static void led_dev_release(struct device * dev) 49 { 50 } 51 52 static struct platform_device s3c2440_led_dev = { 53 .name = "myled_3", 54 .id = -1, 55 .dev = { 56 .release = led_dev_release, 57 }, 58 .num_resources = ARRAY_SIZE(led_dev_resource), 59 .resource = led_dev_resource 60 }; 61 62 static int led_dev_init(void) 63 { 64 platform_device_register(&s3c2440_led_dev); 65 return 0; 66 } 67 68 static void led_dev_exit(void) 69 { 70 platform_device_unregister(&s3c2440_led_dev); 71 } 72 73 module_init(led_dev_init); 74 module_exit(led_dev_exit);
1 /* 2 2018-11-01 3 File: led_4_drvteest.c 4 功能: LED模块的测试文件; 5 */ 6 #include <stdio.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 12 void print_usage(char *file) 13 { 14 printf("Usage:\n"); 15 printf("%s, <on|off>\n", file); 16 printf("eg.\n"); 17 printf("%s, on\n", file); 18 printf("%s, off\n", file); 19 } 20 21 int main(int argc, char **argv) 22 { 23 int fd; 24 char val = 1; 25 26 if(argc != 2) 27 { 28 print_usage(argv[0]); 29 return 0; 30 } 31 32 fd = open("/dev/myled_3", O_RDWR); 33 if(fd < 0) 34 { 35 printf("Can't open /dev/myled_3!\n"); 36 return 0; 37 } 38 39 if(!strcmp(argv[1], "on")) 40 { 41 val = 0; 42 write(fd, &val, 1); 43 } 44 else if(!strcmp(argv[1], "off")) 45 { 46 val = 1; 47 write(fd, &val, 1); 48 } 49 else 50 { 51 print_usage(argv[0]); 52 return 0; 53 } 54 55 return 0; 56 }
1
1 ifneq ($(KERNELRELEASE),) 2 obj-m := led_drv3.o 3 obj-m += led_dev3.o 4 else 5 KERN_DIR ?= /home/book/workbook/mini2440/systems/linux-2.6.22.6 6 7 PWD = $(shell pwd) 8 all: 9 $(MAKE) -C $(KERN_DIR) M=$(PWD) modules 10 clean: 11 $(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean 12 rm -rf modules.order 13 14 endif
led_drv.c, led_dev.c, led_drvtest.c, Makefile