第三方驱动移植 —— 黑盒移植

黑盒移植,即在不用理解驱动程序的细节基础上进行移植

驱动移植的主要流程如下:

一、黑盒移植

1、将驱动编译进内核

  如果内核中已经有了已经支持的驱动,那直接在menu上选配即可。若没有,则需要第三方的驱动或者自己写一个驱动,移植进内核。

  1)将第三方驱动放到linux源码的driver目录中

  拷贝LED驱动程序至drivers目录
  LED属于字符设备,所以放在drivers/char/目录下

  2)修改Makefile让驱动编译进内核(对应目录下的Makefile)

  make uImage编译内核

  3)测试·驱动

烧写镜像到开发板

在ubuntu上编译驱动程序测试代码, 并拷贝到根文件系统

 1 #include <stdio.h>
 2 #include <fcntl.h>
 3 #include <unistd.h>
 4 #include <stdlib.h>
 5 #include <sys/ioctl.h>
 6
 7 #define LED_MAGIC ‘L‘
 8 #define LED_ON  _IOW(LED_MAGIC, 1, int)
 9 #define LED_OFF _IOW(LED_MAGIC, 2, int)
10
11 int main(int argc, char **argv)
12 {
13     int fd;
14
15     fd = open("/dev/led", O_RDWR);
16     if (fd < 0) {
17         perror("open");
18         exit(1);
19     }
20
21     printf("open led ok\n");
22
23     //实现LED灯闪烁
24     while(1)
25     {
26       ioctl(fd, LED_ON); //点亮灯
27       usleep(100000);
28       ioctl(fd, LED_OFF); //灭灯
29       usleep(100000);
30     }
31
32     return 0;
33 }

fs4412_app.c

在板子上运行app.c,测试驱动

报错,看到app.c

得知,需要创建设备文件

  4)创建设备文件

在fs4412_led_drv.c中,获取设备号

501为主设备号,0为次设备号

在板子上创建设备文件

mknod  /dev/led c 501 0

再次执行,可以发现LED灯闪烁并相应输出打印信息

二、通过配置Kconfig来添加驱动

  如果在实际开发中都像以上方法一样,手动添加驱动到文件夹,修改Makefile,不想加载驱动的时候又从相应文件中删除,那么当驱动数量很多时,会十分的繁杂。所以可以通过在配置Kconfig在图形界面中,添减驱动。

  1)在Kconfig中添加一个led设备驱动

  进入对于子目录下的Kconfig

  

  make menuconfig

  

  打开帮助信息

  

  可以看到相关驱动已经在图形界面里了

  2)修改Makefile

  将原来的信息注释,添加配置项

  

  3)在图形界面选择不编译进内核,测试一下

  

 4)编译测试

  make menuconfig

  在编译界面没有看到fs4412_led_drv.o编译进来,再到板子上看看

  

  led驱动确实没有编译进内核。

 3、编译驱动为独立模块

   在前面使用了两者方法来加载驱动,但是这两种方法都是通过在内核目录里添加文件,在对应目录下修改Makefile和Kconfig。这样对于新增的驱动并不好管理。因此我们可以单独创建一个目录,目录可以在任意位置,内核外,把要载入的驱动独立出来。如何实现?

 1)配置为模块方法

  在内核外单独编译驱动模块

  创建目录,

  

  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 #include <linux/fs.h>
  4 #include <linux/cdev.h>
  5 #include <asm/io.h>
  6
  7
  8 #define LED_MAGIC ‘L‘
  9 #define LED_ON  _IOW(LED_MAGIC, 1, int)
 10 #define LED_OFF _IOW(LED_MAGIC, 2, int)
 11
 12 #define LED_MA   501
 13 #define LED_MI    0
 14 #define LED_NUM   1
 15
 16 #define LED_CON 0x11000C20
 17 #define LED_DAT 0x11000C24
 18
 19
 20 struct cdev cdev;
 21
 22 unsigned int *ledcon;
 23 unsigned int *leddat;
 24
 25 int led_open (struct inode *inode, struct file *file)
 26 {
 27     printk("led_open\n");
 28
 29
 30     ledcon = ioremap(LED_CON, 4);
 31     if(ledcon == NULL) {
 32         printk("ioremap LED_CON error\n");
 33         return -1;
 34     }
 35     writel(0x01, ledcon);  //设置LED3 GPX1_0 为输出模式
 36
 37
 38     leddat = ioremap(LED_DAT, 4);
 39     if(leddat == NULL) {
 40         printk("ioremap LED_DAT error\n");
 41         return -1;
 42     }
 43     writel(1, leddat);    //设置LED3 GPX1_0 输出高电平
 44
 45     return 0;
 46 }
 47
 48 int led_release(struct inode *inode, struct file *file)
 49 {
 50     printk("led_close\n");
 51     return 0;
 52 }
 53
 54 long led_ioctl(struct file *file, unsigned int cmd, unsigned long args)
 55 {
 56     switch(cmd)
 57     {
 58     case  LED_ON:
 59         printk("led on ..\n");
 60         writel(1, leddat);    //设置LED3 GPX1_0 输出高电平
 61         break;
 62     case  LED_OFF:
 63         printk("led off ..\n");
 64         writel(0, leddat);    //设置LED3 GPX1_0 输出高电平
 65         break;
 66     default:
 67         printk("no command\n");
 68         break;
 69     }
 70     return 0;
 71 }
 72
 73
 74 struct file_operations led_fops = { //文件操作
 75     .owner = THIS_MODULE,
 76     .open = led_open,
 77     .release =led_release,
 78     .unlocked_ioctl = led_ioctl,
 79 };
 80
 81 static led_init(void)
 82 {
 83     int ret;
 84     dev_t devno = MKDEV(LED_MA, LED_MI);
 85     ret= register_chrdev_region(devno, LED_NUM, "newled");  //注册设备号
 86     if(ret) {
 87         printk("register_chrdev_region error\n");
 88         return -1;
 89     }
 90
 91     cdev_init(&cdev, &led_fops);           //初始化字符设备
 92     ret = cdev_add(&cdev, devno, LED_NUM); //添加字符设备到系统中
 93     if (ret < 0) {
 94         printk("cdev_add error\n");
 95         return -1;
 96     }
 97
 98     printk("Led init  5    \n");
 99     return 0;
100 }
101
102 static void led_exit(void)
103 {
104     dev_t devno = MKDEV(LED_MA, LED_MI);
105     cdev_del(&cdev);
106     unregister_chrdev_region(devno, LED_NUM);  //取消注册
107     printk("Led exit\n");
108 }
109
110 module_init(led_init);
111 module_exit(led_exit);
112 MODULE_LICENSE("Dual BSD/GPL");

fs4412_led_drv.c

 1 ifeq ($(KERNELRELEASE),)
 2 KERNELDIR ?= /home/linux/kernel/linux-3.14-fs4412
 3 PWD := $(shell pwd)
 4
 5 all:
 6     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
 7
 8 clean:
 9     $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
10     rm -rf a.out
11
12 else
13     obj-m := fs4412_led_drv.o
14 endif

Makefile

  2)make 编译出ko模块

make之后(Makefile里面将module附加到了make命令后,所以直接make就好了),会自动跳到内核里面,借用内核的Makefile把当前驱动程序编译成ko文件,拷贝到根文件系统

  在内核中的Kconfig,配置驱动为模块方式编译进内核

将配置项改为tristate后可以选择编译为模块

 4)编译所有模块 make modules

  编译模块不需要重新编译内核,make module即可。

 

会生成以上两个文件,这个ko文件和之前单独在led目录里面make出来的ko是相同的,只是编译的环境不一样而已。选择一个拷贝到nfs即可。

  5)插入模块

  转到ko文件所在目录下

  insmod fs4412_led_drv.ko

  创建设备节点(应用访问驱动的入口)

  mknod   /dev/led c 501 0

  6)运行测试驱动的应用程序

  ./a.out

参考博客:

https://blog.csdn.net/m0_37542524/article/details/86476109

原文地址:https://www.cnblogs.com/y4247464/p/12359830.html

时间: 2024-10-10 07:49:38

第三方驱动移植 —— 黑盒移植的相关文章

Android安卓书籍推荐《Android驱动开发与移植实战详解》下载

百度云下载地址:点我 Android凭借其开源性.优异的用户体验和极为方便的开发方式,赢得了广大用户和开发者的青睐,目前已经发展成为市场占有率很高的智能手机操作系统. <Android驱动开发与移植实战详解>分为18章,依次讲解了Android系统的基本知识, Linux内核的基本知识,分析了Android系统的源码,深入分析HAL层的基本知识,GoldFish下的驱动.MSM内核和驱动.OMAP内核和驱动.显示系统驱动.输入系统驱动.振动器系统驱动.音频系统驱动和视频输出系统驱动,多媒体框架

U-Boot移植_DDR3移植

疯雨-版权所有,转载请注明[http://blog.csdn.net/u010346967] U-Boot移植_DDR3移植:首先在这里感谢网友fengtian的整理,没有你就没有这篇文章 在系统上电后,CPU并不知道外部的RAM是什么类型的存储器,因此U-Boot需要对CPU进行RAM初始化设置,然后将程序拷贝到RAM中运行. 本系统采用的RAM是DDR3类型存储芯片,容量是4GB,频率是1066KHz:系统从eMMC中启动.采用的是U-Boot-2009版,linux3.0.35系统内核,U

设备驱动调试和移植的一般方法

做linux底层软件工作也有两年了,算上研究生时期对底层软件的研究,加起来也快四年了.慢慢地发现有必要总结一些一般性的方法了.因为一般性的方法有宏观上的指导意义,以后调试和移植驱动时,经常性地回味这些一般性的方法可以防止自己犯同样的错误,进而少走弯路,以最高的效率完成工作. 当谈到底层软件,我们一般都会想到bootloader.BSP.device driver.linux kernel等等.这篇文章将会着重介绍linux device driver调试的一般性方法.另外,关于设备驱动移植的方法

linux 内核移植(八)——移植三星移植过的内核

8.21 1:做好移植前的准备工作 获取三星移植过的kernel,创建SI工程,添加到虚拟机中,修改Makefile的ARCH和CROSS_COMPILE修改结果如下 ARCH = arm CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- 然后试着去配置,(在arch/configs/下找一个最接近自己开发板的,这里选择的是smdkv210_android_defconfig)得到.config文件,然后m

mini6410移植--uboot移植(1)

u-boot移植 (1)移植环境 u-boot版本:u-boot-2011-03Linux平台:XP下虚拟机Ubuntu12.04交叉编译工具:arm-linux-gcc-4.5.1arm开发板:mini6410        CPU:S3C6410        DDR:256M        Nand Flash:256M        网卡:DM9000EP (2)移植目标 支持Nand启动支持Nand读写支持yaffs写入支持tftp下载 下载UBoot把它解压,然后得到u-boot-2

mini6410移植--uboot移植(2)

串口中打印出来的信息大多数来自board.c文件 print_cpuinfo函数在/*arch/arm/cpu/arm1176/s3c64xx/speed.c*/实现更改相应的信息即可. checkboard函数在/*board/samsung/th6410/th6410.c*/实现,更改相应的信息即可. 串口初始化在lowlevel_init.S中实现,其代码如下,这是经过修改后的代码,因为工作量问题我们不再具体讲述.

向tiny6410中移植中移植linux-4.5.1内核(最新)

下载linux-4.5.1.tar.gz 解压在任意目录下.我解压在/home/tiny6410/ # tar xvzf linux-4.5.1.tar.gz # cd linux-4.5.1/ 修改Makefile文件 在第251和252行上  改成自己的交叉编译器 251 ARCH ?= arm 252 CROSS_COMPILE ?= arm-linux- 在linux源码文件中有一个三星Demo板的默认配置 这里我们的配置文件就先用这个  arch/arm/configs/s3c6400

飞凌OK6410开发板SDIO无线8189WIFI模块驱动移植

为什么要移植?开发板不是已经提供了无线驱动吗? 貌似是这样的..本来是好用的.加入自己第三方驱动后发现WIFI用不了...最后发现飞凌提供的内核里面没有8189芯片的代码...问售后他们说那边是好的.这么到我这里就不行了呢?妈蛋...郁闷了...智能自己动手,把驱动移植进去... 1  找8189es芯片的原厂驱动代码:这里我找了N久,传到网盘里... http://pan.baidu.com/s/1bn7Gz6n 2 解压拷贝 tar jxvf rtl8288EUS_rtl8189ES_lin

linux enc28j60网卡驱动移植(硬件spi和模拟spi)

本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因...刚好手上有一个enc28j60的网卡模块,于是就着手移植enc28j60的驱动. 其实移植enc28j60的驱动也十分简单,网上有现成的,只需要分配一些硬件资源即可. 由于我的内核版本老到掉牙,没有自带enc28j60的驱动,只能在网上找一个: enc28j60.c http://git.ti.com/ti-linux-kernel/ti-li