您的位置:首页 > 其它

喜羊羊系列【设备 - 驱动器 编译进内核】

2015-08-19 19:57 411 查看
博客: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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: