喜羊羊系列之【设备 - 驱动 编入内核】

来源:互联网 发布:淘宝店铺更改所在地 编辑:程序博客网 时间:2024/06/06 03:26

博客: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/xxxif (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;elsecmd=LED_ON;val=3;            //亮 led3if(ioctl(fd,cmd,val)<0){perror("ioctl failed!\n");exit(1);}val=4;            //亮 led4if(ioctl(fd,cmd,val)<0){perror("ioctl failed!\n");exit(1);}my_sleep(1);}close(fd);return 0;}







0 0
原创粉丝点击