rfid4-写成platform驱动
适应时代发展,将misc驱动封装到platfrom总线里面去,
platform平台总线模型,把设备和驱动分开,即一个东东要分成两个部分去写和去insmod,是不是有点麻烦。--对于固定于一个cpu平台的用户确实感觉比较麻烦,但是linux的目标是兼容所有的cpu平台,在换cpu平台时就会发现这种设计的优点。
先看一个platform的简单例子
先把Makefile列出
驱动代码my_exit()函数里面还需要释放资源-------2011-11-18
release_resource(my_mem);
kfree(my_mem) ;
platform平台总线模型,把设备和驱动分开,即一个东东要分成两个部分去写和去insmod,是不是有点麻烦。--对于固定于一个cpu平台的用户确实感觉比较麻烦,但是linux的目标是兼容所有的cpu平台,在换cpu平台时就会发现这种设计的优点。
先看一个platform的简单例子
先把Makefile列出
ifneq ($(KERNELRELEASE),) obj-m := platform_dev.o platform_drv.o else KDIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2 #KDIR := /lib/modules/`uname -r`/build all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers endif以下是设备
/******************platfrom_dev.c***************************/ #include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/string.h> #include <linux/init.h> #include <linux/kernel.h> #define DEVICE_NAME "song_rfid" static struct resource my_resource[] = { [0] = { .start = 0x56000050, .end = 0x56000050 + 0x10 - 1, .flags = IORESOURCE_MEM, }, /* 设备内存资源 GPFCON 0X56000050 GPFDAT 0X56000054 GPFUP 0X56000058 */ /* [1] = { .start = 25, .end = 25, .flags = IORESOURCE_IRQ, }*/ }; static struct platform_device my_device = { .name = DEVICE_NAME,//此处指定的名字要和驱动中的名字匹配,song_rfid .id = -1, .num_resources = ARRAY_SIZE(my_resource), .resource = my_resource, }; static int __init my_init(void) { int ret=0; ret = platform_device_register(&my_device); /*注册设备,即想虚拟总线上添加此设备 也可以用platform_device_alloc分配一个现成的设备和用platform_device_add添加到总线上 */ if (ret == 0) { printk("Register %s\n",DEVICE_NAME); } else { printk("Register error.\n"); } return ret; } static void __exit my_exit(void) { platform_device_unregister(&my_device); printk("Unregister %s\n",DEVICE_NAME); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); MODULE_VERSION("1.5");以下是驱动
/******************platfrom_drv.c***************************/ #include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/string.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/io.h> #define DRIVER_NAME "song_rfid" static void __iomem *my_kv_base;//内核虚拟地址 static struct resource *my_mem; static int my_probe(struct platform_device *pdev) { struct resource *res; int size; printk("driver find device : %s which can handle\n",DRIVER_NAME); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); /*获取内存资源 如果先insmod设备内核就会把设备挂到平台总线上,之后在insmod驱动时,平台核心会遍历整个平台总线上的设备名字,找到和该驱动名字匹配的设备, 然后调用驱动的probe函数同时把该设备的struct platform_device当做参数pdev传递给probe函数, 这样驱动就可以使用platform_get_resource(pdev,,)获取设备的各个资源 如果先insmod驱动,情况与上类似如果找到总线上某个设备可以和该驱动匹配,会成功调用驱动的probe */ if (res == NULL) { printk("no memory resource specified\n"); return -ENOENT; } size = (res->end - res->start) + 1; my_mem = request_mem_region(res->start, size, pdev->name);//向内核申请内存资源 if (my_mem == NULL) { printk("failed to get memory region\n"); return -ENOENT; } my_kv_base = ioremap(res->start, size);//得到虚拟地址,之后再去操作... return 0; } static int my_remove(struct platform_device *pdev) { printk("driver found device : %s unpluged\n",DRIVER_NAME); return 0; } static struct platform_driver my_driver = { .probe = my_probe, .remove = my_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME,//此处指定的名字要和设备中的名字匹配,song_rfid }, }; static int __init my_init(void) { printk("Register my_driver.\n"); return platform_driver_register(&my_driver); /*注册驱动 即向平台总线上添加一个驱动*/ } static void __exit my_exit(void) { printk("Unregister my_driver.\n"); platform_driver_unregister(&my_driver); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
驱动代码my_exit()函数里面还需要释放资源-------2011-11-18
release_resource(my_mem);
kfree(my_mem) ;
[root@FriendlyARM plg]# insmod platform_dev.ko //插入设备 Register song_rfid [root@FriendlyARM plg]# cat /proc/iomem //insmo设备后就会在iomem有了登记 .... 56000050-5600005f : song_rfid 56000050-5600005f : song_rfid ... [root@FriendlyARM plg]# insmod platform_drv.ko //插入驱动 Register my_driver. driver find device : song_rfid which can handle [root@FriendlyARM plg]# ls /sys/bus/platform/devices/ dm9000 s3c2410-rtc s3c2440-sdi s3c24xx_uda134x.0 regulatory.0 s3c2410-spi.0 s3c2440-uart.0 soc-audio s3c2410-iis s3c2410-wdt s3c2440-uart.1 song_rfid s3c2410-lcd s3c2440-i2c s3c2440-uart.2 s3c2410-ohci s3c2440-nand s3c2440-usbgadget [root@FriendlyARM plg]# ls /sys/bus/platform/drivers dm9000 s3c2410-ohci s3c2440-uart song_rfid s3c-i2c s3c2410-rtc s3c24xx-nand s3c-sdi s3c2410-spi s3c24xx_uda134x s3c2410-lcd s3c2412-lcd soc-audio
/* 另外,已经有许多按照平台模式写的驱动设备被编译进内核,在march-mini2440.c中 static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_spi0, &s3c_device_iis, &mini2440_device_eth, &s3c24xx_uda134x, &s3c_device_nand, &s3c_device_sdi, &s3c_device_usbgadget, }; 这些都是设备,大部分定义在arch/arm/plat-s3c24xx/Devs.c中 比如 Watchdog static struct resource s3c_wdt_resource[] = { [0] = { .start = S3C24XX_PA_WATCHDOG, .end = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_WDT, .end = IRQ_WDT, .flags = IORESOURCE_IRQ, } }; struct platform_device s3c_device_wdt = { .name = "s3c2410-wdt", .id = -1, .num_resources = ARRAY_SIZE(s3c_wdt_resource), .resource = s3c_wdt_resource, }; 内核启动时会执行这个函数,在mach-mini2440.c中,将这些设备挂到平台总线上。 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); 至于这些平台设备对应的驱动,则分散在drivers目录下各个文件中(如果有的话,但大部分都有)。如果有,则可以在make memuconfig时配置,或者编译进内核或者 编译成模块;如果没有则要自己写了。 */