喜羊羊系列【设备 - 驱动器 编译进内核】
博客:http://blog.csdn.net/muyang_ren
这篇和设备-驱动动态载入进内核做对照
*针对不同的平台。可能放进的不是以下的文件内,仅仅做參考
1、头文件
放进:linux-3.0.8\arch\arm\plat-samsung\include\plat
led.h
#ifndef _HEAD_H #define _HEAD_H #define MAGIC 'h' #define LED_ON _IOW(MAGIC,1,int) #define LED_OFF _IOW(MAGIC,0,int) struct led_device{ dev_t devno; unsigned int led_major; struct cdev *led_cdev; struct class *led_class; struct device *led_device; }; #endif
====================================================================================================================================
2、设备文件
方法一:将设备资源直接加进/linux-3.0.8/arch/arm/mach-s5pv210下的mach-smdkv210.c
① struct platform_device s5pv210_led_device_lhy = { .name = "s5pv210_led_lhy", .id = 1, }; static struct platform_device *smdkv210_devices[] __initdata = { 。。。。。
。
。。。
。。。
。
。。
。。
。。。
。。。
。。。。 }
②将设备信息加入总线 <span style="white-space:pre"> </span>改动arch/arm/mach-s5pv210/mach-smdkv210.c文件 static struct platform_device *smdkv210_devices[] __initdata = { ... ... /*加入例如以下代码*/ &s5pv210_led_device_lhy, //新加入的 }方法二:
①将设备文件dev-led.c 放进 linux-3.0.8/arch/arm/plat-samsung
led_dev.c
#include <linux/platform_device.h> #include <plat/led.h> #include <plat/devs.h> #include <plat/cpu.h> struct platform_device s5pv210_led_device_lhy = { .name = "s5pv210_led_lhy", .id = 1, };②向arch/arm/mach-s5pv210/mach-smdkv210.c(跟平台架构相关文件)加入
static struct platform_device *smdkv210_devices[] __initdata = { .... &s5pv210_led_device_lhy, //新加入 };③向linux-3.0.8/arch/arm/plat-samsung/Makefile加入
obj-$(CONFIG_S3C_DEV_LED) += led_dev.o④向linux-3.0.8/arch/arm/plat-samsung/Kconfig加入
config S3C_DEV_LED bool "S5PV210 LED driver support" help s5pv210 led device support
⑤加入外部声明arch/arm/plat-samsung/include/plat/devs.h
extern struct platform_device s5pv210_led_device_lhy;
====================================================================================================================================
3、平台驱动
①将led_drv.c 放进linux-3.0.8/drivers/my_led
led_drv.c
#include<linux/fs.h> //register_chrled #include<linux/device.h> //class_create/ledice_create #include<linux/slab.h> //kmalloc #include<asm/uaccess.h> //copy_to_user/copy_from_user #include<asm/io.h> //ioremap #include<linux/gpio.h> //gpio_request #include <plat/gpio-cfg.h> //s3c_gpio_cfgpin #include <linux/cdev.h> //cdev_alloc #include <linux/platform_device.h> //下面是移植时须要添加的 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <plat/cpu.h> #include <plat/led.h> #include <plat/devs.h> static struct led_device *led_drv; static int led_open(struct inode *inode, struct file *file) { printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); s3c_gpio_cfgpin(S5PV210_GPC0(3),S3C_GPIO_OUTPUT); s3c_gpio_cfgpin(S5PV210_GPC0(4),S3C_GPIO_OUTPUT); return 0; } static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); return count; } ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); return 0; } static long led_ioctl(struct file *file, unsigned int cmd, unsigned long val) { printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); printk(KERN_INFO"cmd=%d arg=%ld\n", cmd, val); switch(cmd) { case LED_ON: gpio_set_value(S5PV210_GPC0(val),1); break; case LED_OFF: gpio_set_value(S5PV210_GPC0(val),0); break; default: break; } return 0; } //硬件操作方法 static struct file_operations led_fops={ .owner = THIS_MODULE, .open = led_open, .write = led_write, .read = led_read, .unlocked_ioctl = led_ioctl, }; static int s5pv210_led_probe(struct platform_device *pdrv){ int ret; led_drv = kmalloc(sizeof(struct led_device),GFP_KERNEL); if(led_drv==NULL){ printk(KERN_ERR"no memory malloc for fs210_led\n"); return -ENOMEM; } /*1. 动态注冊/申请主设备*/ ret=alloc_chrdev_region(&led_drv->devno,0,1,"dev_module"); if (ret < 0) { printk(KERN_ERR "unable to get major\n"); return -EFAULT; goto out_err_1; } //从设备号中分离出主设备号 led_drv->led_major = MAJOR(led_drv->devno); /*为cdev分配空间*/ led_drv->led_cdev = cdev_alloc(); /*注冊硬件操作方法/初始化cdev*/ cdev_init(led_drv->led_cdev,&led_fops); /*注冊字符设备*/ cdev_add(led_drv->led_cdev,led_drv->devno,1); /*2. 创建设备类*/ led_drv->led_class=class_create(THIS_MODULE,"led_class"); if (IS_ERR(led_drv->led_class)) { printk(KERN_ERR "class_create() failed for led_class\n"); ret = -ENODATA; goto out_err_2; } /*3. 创建设备文件*/ led_drv->led_device=device_create(led_drv->led_class,NULL,MKDEV(led_drv->led_major,0),NULL,"led"); // /led/xxx if (IS_ERR(led_drv->led_device)) { printk(KERN_ERR "device_create failed for led_device\n"); ret = -ENODEV; goto out_err_3; } /*申请GPC0_3,4引脚资源*/ gpio_request(S5PV210_GPC0(3),"LED1"); gpio_request(S5PV210_GPC0(4),"LED2"); return 0; out_err_3: class_destroy(led_drv->led_class); out_err_2: unregister_chrdev(led_drv->led_major,"led_module"); out_err_1: kfree(led_drv); return ret; } static int s5pv210_led_remove(struct platform_device *pdrv){ unregister_chrdev(led_drv->led_major,"led_module"); device_destroy(led_drv->led_class,MKDEV(led_drv->led_major,0)); class_destroy(led_drv->led_class); gpio_free(S5PV210_GPC0(3)); gpio_free(S5PV210_GPC0(4)); kfree(led_drv); return 0; } struct platform_device_id led_ids[]={ [0]={ .name = "s5pv210_led_lhy", .driver_data = 0, }, }; static struct platform_driver s5pv210_led_driver = { .probe = s5pv210_led_probe, .remove = s5pv210_led_remove, .driver = { .name = "s5pv210_led_lhy", .owner = THIS_MODULE, }, .id_table = led_ids, }; static int __devinit s5pv210_led_init(void) { return platform_driver_register(&s5pv210_led_driver); } static void __devexit s5pv210_led_exit(void) { platform_driver_unregister(&s5pv210_led_driver); } module_init(s5pv210_led_init); module_exit(s5pv210_led_exit); MODULE_DESCRIPTION("LED driver for Marvell PM860x"); MODULE_AUTHOR("kiron"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s5pv210-led");②在当前文件夹的Kconfig后加入,没有就新建
config S5PV210_LED_DRV tristate "led_dev for fs210 device" help led driver is for s5pv210, choose y/m/n③在当前文件夹的Makefile后加入,没有就新建
<span style="white-space:pre"> </span>obj-$(CONFIG_S5PV210_LED_DRV) = led_drv.o
④改动上级文件夹的Makefile和Kconfig
将linux-3.0.8/drivers/Kconfig 加入
source "drivers/my_led/Kconfig"将linux-3.0.8/drivers/Makefile 加入
<span style="white-space:pre"> </span>obj-y += mydriver/
最后就是自己make menuconfig里配置选项了。
====================================================================================================================================
4、測试程序
编译測试要使用交叉工具连<span style="white-space:pre"> </span>arm-none-linux-gnueabi-gcc led_test.c -o led_test
附:
将可运行文件增加到开机启动,改动根文件系统filesystem
vi filesystem/etc/init.d/rcS ./star_app/led_test
測试程序
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/ioctl.h> #include <unistd.h> #define MAGIC 'h' #define LED_ON _IOW(MAGIC,1,int) #define LED_OFF _IOW(MAGIC,0,int) static void my_sleep(int n){ int j; for(j=0; j<10000000*n; j++); } int main(void) { printf("-------------------------------\n" <span style="white-space:pre"> </span>"|| start:一闪一闪亮晶晶 ||\n" "-------------------------------\n"); my_sleep(1); int fd; unsigned int cmd=0; unsigned long val=0; fd=open("/dev/led", O_RDWR); if(fd<0){ perror("open failed!\n"); exit(1); } int i; for(i=0; i<10; i++){ if(i%2==0) cmd=LED_OFF; else cmd=LED_ON; val=3; //亮 led3 if(ioctl(fd,cmd,val)<0){ perror("ioctl failed!\n"); exit(1); } val=4; //亮 led4 if(ioctl(fd,cmd,val)<0){ perror("ioctl failed!\n"); exit(1); } my_sleep(1); } close(fd); return 0; }
版权声明:本文博客原创文章,博客,未经同意,不得转载。