1. 程式人生 > >【驅動】第3課、分離分層驅動之學習筆記

【驅動】第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結構分別註冊驅動程式的操作部分和裝置硬體部分

3、原始碼


 

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結構及其元素的定義。

3、原始碼

 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