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

博客: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;
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-10-26 20:38:36

喜羊羊系列【设备 - 驱动器 编译进内核】的相关文章

【转】Linux驱动模块编译进内核中

原文网址:http://blog.chinaunix.net/uid-29287950-id-4573481.html BQ27501驱动编译进内核 一.       驱动程序编译进内核的步骤 在 linux 内核中增加程序需要完成以下三项工作: 1. 将编写的源代码复制到 Linux 内核源代码的相应目录: 2. 在目录的 Kconfig 文件中增加新源代码对应项目的编译配置选项: 3. 在目录的 Makefile 文件中增加对新源代码的编译条目. bq27501驱动编译到内核中具体步骤如下:

11.把helloworld字符驱动模块编译进内核

首先是hello.c 文件: Hello.c: 接着是修改driver/char/Kconfig: 添加: 修改字符设备驱动里的Makefile: 打开Makefile: obj-$(CONFIG_HELLO_WORLD) += hello.o 进入配置界面: 选择Device driver:进入: 选择Character devices: 进入: 找到我们的helloworld,并选中: 一直保存退出: 编译: 编译完成: Tftp烧写: 启动看到我们驱动代码打印出来的: 说明我们的内核模块成

详解将驱动程序编译进linux内核

1.进入目录linux-kernel-samsung-dev\drivers\char 2.新建目标目录01.led,将驱动相关文件复制到此目录 注:需确保复制的驱动文件是能正常运行的驱动 3.在目录01.led里编写Kconfig文件 menu "xxx" config XXX_LED tristate "xxx_ggg210_led" default n help The led water made by xxx which was used by platf

【转】6.4.6 将驱动编译进Linux内核进行测试

原文网址:http://www.apkbus.com/android-98520-1-1.html 前面几节都是将Linux驱动编译成模块,然后动态装载进行测试.动态装载驱动模块不会随着Android系统的启动而自动装载,因此Android系统每次启动都必须使用insmod或modprobe命令装载Linux驱动模块. 对于嵌入式系统(包括嵌入式Android.嵌入式Linux等)一般都采用将Linux驱动编译进内核的方式.这样做虽然没有动态装载灵活,但Linux驱动会随着Android的启动而

学习重新编译Linux内核

一.实验目的学习重新编译Linux内核,理解.掌握Linux内核和发行版本的区别. 二.实验内容在Linux操作系统环境下重新编译内核.实验主要内容:A. 查找并且下载一份内核源代码,本实验使用最新的Linux内核2.6.36.B. 配置内核.C. 编译内核和模块.D. 配置启动文件.本次实验环境是Linux2.6.35内核的环境下,下载并重新编译内核源代码(2.6.36):然后,配置GNU的启动引导工具grub,成功运行编译成功的内核. 三.主要仪器设备(必填)Linux环境:utuntu10

自定义配置编译linux内核

1 编译linux内核原因一般情况下,我们是不需要重新去编译linux内核的,但如果你发现你需要修改内核的某个部分或者说你需要的某个模块并没有编译进内核,那里你可以通过重新编译内核来满足你的需求,比如当我们需要用bcache时,但默认bcache是没有编译进内核的,我们可以通过修改编译配置文件,将bcache编译进内核,以下的编译操作均是在Centos7.3平台上进行的演示. 2 编译前准备工作2.1 编译用户身份选择官方是强调编译linux内核是强烈不建议以root身份来进行编译的,因为这样有

将MPLS编译进linux内核中

系统环境:linux kernel 2.6.35.(此环境是上一篇文章中将ubuntu内核替换后的环境) 编译过程如下: 1)首先需要下载patch文件:linux-kernel-v2.6.35-mpls1.980.patch.下载链接: http://ftp.jaist.ac.jp/pub/sourceforge/m/project/mp/mpls-linux/mpls-linux/Patches/linux-kernel-v2.6.35.13-mpls1.980.patch 或者: http

静态编译进Linux内核

一.准备好可以正常引导开发板的源码 二.在内核源码kernel文件夹的driver目录下,创建led_arm文件夹 mkdir drivers/led_arm 三.将"LED驱动实验"的驱动程序拷贝到led_arm目录下(详情见上一次LED驱动博客) 将led.c拷贝在该文件夹下面 Kconfig就是对应着内核的配置菜单.假如要想添加新的驱动到内核的源码中,可以通过修改Kconfig来增加对我们驱动的配置菜单,这样就有途径选择我们的驱动. 每个config菜单项都要有类型定义,bool

实例:编译Linux内核3.18.25概要

前提: 将CentOS 7上3.10.0-229.el7.x86_64重新编译一个3.18.25内核 自编译安装,按照自己的硬件平台架构编译,能最适合硬件主机的性能 且按照需要编译模块,可以选择自己需要的包编译 [[email protected] tmp]# uname  -a 一.编译前准备工作 1.宿主机系统 本次编译宿主机:VMware Workstation Pro12 上的CentOS 7.0操作系统 2.开发环境(开发工具,开发库),头文件 [[email protected] y