linux驱动程序开发-第三节:linux设备驱动程序设计流程


视频及资料链接地址:(上传中)

链接:https://pan.baidu.com/s/1avZjYyQGr2ljfPhEZjPumA 
提取码:qgox 

linux驱动程序开发-第三节:linux设备驱动程序设计流程_第1张图片


一、linux驱动的分类
1、字符设备驱动
1)设备:
LED、KEY、BEEP、声卡、显卡、摄像头、鼠标、键盘、触摸屏、手写板、USB、.....
[root@GEC6818 /]#ls /dev -l
crw-rw----    1 root     root       29,   0 Jan  1  1970 fb0
crw-rw----    1 root     root       14,   3 Jan  1  1970 dsp
crw-rw----    1 root     root       14,  19 Jan  1  1970 dsp1
crw-rw----    1 root     root      204,  64 Jan  1  1970 ttySAC0
crw-rw----    1 root     root      204,  65 Jan  1  1970 ttySAC1

2)特点:
设备类型是c。应用程序和驱动程序之间交互数据的时候,数据是以字节为单位,不同的设备类型,交互的数据格式不一样的。字符设备驱动数据是实时传递的,按照固定的格式传递。字符设备是没有缓存的,字符设备是没有文件系统的。

3)应用程序访问方法
linux系统IO函数:open()、read()、write()、ioctl()、close()、mmap()
触摸屏:
struct input_event ts_ev;
int fd=open("/dev/input/event0", O_RDONLY);
read(fd, &ts_ev, sizeof(struct input_event));
close(fd);

---------------------------------------------------------------------------------------------------------

2、块设备驱动
1)设备:
大容量的存储设备。如:eMMC(nand flash:8GB)、SD卡、U盘、移动硬盘、....
[root@GEC6818 /]#ls /dev -l
brw-rw----    1 root     root      179,   0 Jan  1  1970 mmcblk0
brw-rw----    1 root     root      179,  16 Jan  1  1970 mmcblk0boot1
brw-rw----    1 root     root      179,   1 Jan  1  1970 mmcblk0p1
brw-rw----    1 root     root      179,   8 Jan  1  1970 mmcblk0boot0
brw-rw----    1 root     root      179,   2 Jan  1  1970 mmcblk0p2
brw-rw----    1 root     root      179,   4 Jan  1  1970 mmcblk0p4
brw-rw----    1 root     root      179,   3 Jan  1  1970 mmcblk0p3
brw-rw----    1 root     root      179,   5 Jan  1  1970 mmcblk0p5
brw-rw----    1 root     root      179,   6 Jan  1  1970 mmcblk0p6
brw-rw----    1 root     root      179,   7 Jan  1  1970 mmcblk0p7

brw-rw-rw-    1 root     root        8,   0 Jan  1 00:06 sda
brw-rw-rw-    1 root     root        8,   1 Jan  1 00:06 sda1


2)特点:
块设备是带有缓存的,当缓存满了(刷新缓存)这些数据才会写到块设备上去。块设备是有文件系统的(根文件系统的格式是ext4)。数据是以块(block)为为单位的,1block=1024B。
3)应用程序访问方法
例:
    U盘中有一个文件test.txt,编写一个程序,读取test.txt文件中的内容,并将该内容通过串口2发送出去。
如何访问U盘?
挂载-----将块设备以某一种文件系统的格式挂载到根文件系统的某个目录上,在根据该目录访问块设备。
有些嵌入式平台可以自动挂载U盘(做了配置文件):
[root@GEC6818 /]#mount
sda1 on /mnt/udisk type vfat (rw,relatime,fmask=0000,dmask=0000,allow_utime=0022,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
U盘就自动挂载到/mnt/udisk/,文件系统的类型vfat。
[root@GEC6818 /]#ls /mnt/udisk/
1-STM32????                5-tiny210
2-??????                   System Volume Information
3-GEC6818                  ???????
4-GEC210

访问方法:
fd = open("/mnt/udisk/test.txt", O_RDONLY);
read()
close()

手动挂载:
[root@GEC6818 /]#mount -t vfat /dev/sda1 /data
[root@GEC6818 /]#ls /data

如何访问串口
fd = open("/dev/ttySAC2", O_RDWR);
初始化串口2
write(fd, buf, sizeof(buf));
close(fd);

-----------------------------------------------------------------------------------------------------
3、网络设备驱动
1)设备:网卡(有线网卡、无线网卡)
如何查看网络设备??
[root@GEC6818 /]#ifconfig -a
eth0      Link encap:Ethernet  HWaddr 0E:72:C9:E8:03:96  
          inet addr:192.168.22.180  Bcast:192.168.22.255  Mask:255.255.255.0
          inet6 addr: fe80::c72:c9ff:fee8:396/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:238 (238.0 B)
          Interrupt:80 

ip6tnl0   Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          NOARP  MTU:1452  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          LOOPBACK  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

sit0      Link encap:IPv6-in-IPv4  
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

2)特点:    
    网卡----物理层
    网络驱动-----数据链路层
    
3)应用程序访问网络设备
socket套接字:字节流---TCP;数据报---UDP;原始套接字---开发网络协议
              地址信息: IP地址和端口号
TCP的服务器
socket()/bind()/listen()/accept()/read()/recv()/write()/send()/close()
TCP的客户端
socket()/connect()//read()/recv()/write()/send()/close()

======================================================================================================
二、linux驱动模型
以字符设备驱动为例。

一、linux驱动的分类
1、字符设备驱动
1)设备:
LED、KEY、BEEP、声卡、显卡、摄像头、鼠标、键盘、触摸屏、手写板、USB、.....
[root@GEC6818 /]#ls /dev -l
crw-rw----    1 root     root       29,   0 Jan  1  1970 fb0
crw-rw----    1 root     root       14,   3 Jan  1  1970 dsp
crw-rw----    1 root     root       14,  19 Jan  1  1970 dsp1
crw-rw----    1 root     root      204,  64 Jan  1  1970 ttySAC0
crw-rw----    1 root     root      204,  65 Jan  1  1970 ttySAC1
crw-rw----    1 root     root      204,  66 Jan  1  1970 ttySAC2
crw-rw----    1 root     root      204,  67 Jan  1  1970 ttySAC3

2)特点:
设备类型是c。应用程序和驱动程序之间交互数据的时候,数据是以字节为单位,不同的设备类型,交互的数据格式不一样的。字符设备驱动数据是实时传递的,按照固定的格式传递。字符设备是没有缓存的,字符设备是没有文件系统的。

3)应用程序访问方法
linux系统IO函数:open()、read()、write()、ioctl()、close()、mmap()
触摸屏:
struct input_event ts_ev;
int fd=open("/dev/input/event0", O_RDONLY);
read(fd, &ts_ev, sizeof(struct input_event));
close(fd);

---------------------------------------------------------------------------------------------------------

2、块设备驱动
1)设备:
大容量的存储设备。如:eMMC(nand flash:8GB)、SD卡、U盘、移动硬盘、....
[root@GEC6818 /]#ls /dev -l
brw-rw----    1 root     root      179,   0 Jan  1  1970 mmcblk0
brw-rw----    1 root     root      179,  16 Jan  1  1970 mmcblk0boot1
brw-rw----    1 root     root      179,   1 Jan  1  1970 mmcblk0p1
brw-rw----    1 root     root      179,   8 Jan  1  1970 mmcblk0boot0
brw-rw----    1 root     root      179,   2 Jan  1  1970 mmcblk0p2
brw-rw----    1 root     root      179,   4 Jan  1  1970 mmcblk0p4
brw-rw----    1 root     root      179,   3 Jan  1  1970 mmcblk0p3
brw-rw----    1 root     root      179,   5 Jan  1  1970 mmcblk0p5
brw-rw----    1 root     root      179,   6 Jan  1  1970 mmcblk0p6
brw-rw----    1 root     root      179,   7 Jan  1  1970 mmcblk0p7

brw-rw-rw-    1 root     root        8,   0 Jan  1 00:06 sda
brw-rw-rw-    1 root     root        8,   1 Jan  1 00:06 sda1


2)特点:
块设备是带有缓存的,当缓存满了(刷新缓存)这些数据才会写到块设备上去。块设备是有文件系统的(根文件系统的格式是ext4)。数据是以块(block)为为单位的,1block=1024B。
3)应用程序访问方法
例:
    U盘中有一个文件test.txt,编写一个程序,读取test.txt文件中的内容,并将该内容通过串口2发送出去。
如何访问U盘?
挂载-----将块设备以某一种文件系统的格式挂载到根文件系统的某个目录上,在根据该目录访问块设备。
有些嵌入式平台可以自动挂载U盘(做了配置文件):
[root@GEC6818 /]#mount
sda1 on /mnt/udisk type vfat (rw,relatime,fmask=0000,dmask=0000,allow_utime=0022,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
U盘就自动挂载到/mnt/udisk/,文件系统的类型vfat。
[root@GEC6818 /]#ls /mnt/udisk/
1-STM32????                5-tiny210
2-??????                   System Volume Information
3-GEC6818                  ???????
4-GEC210

访问方法:
fd = open("/mnt/udisk/test.txt", O_RDONLY);
read()
close()

手动挂载:
[root@GEC6818 /]#mount -t vfat /dev/sda1 /data
[root@GEC6818 /]#ls /data

如何访问串口
fd = open("/dev/ttySAC2", O_RDWR);
初始化串口2
write(fd, buf, sizeof(buf));
close(fd);

-----------------------------------------------------------------------------------------------------
3、网络设备驱动
1)设备:网卡(有线网卡、无线网卡)
如何查看网络设备??
[root@GEC6818 /]#ifconfig -a
eth0      Link encap:Ethernet  HWaddr 0E:72:C9:E8:03:96  
          inet addr:192.168.22.180  Bcast:192.168.22.255  Mask:255.255.255.0
          inet6 addr: fe80::c72:c9ff:fee8:396/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:238 (238.0 B)
          Interrupt:80 

ip6tnl0   Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          NOARP  MTU:1452  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          LOOPBACK  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

sit0      Link encap:IPv6-in-IPv4  
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

2)特点:    
    网卡----物理层
    网络驱动-----数据链路层
    
3)应用程序访问网络设备
socket套接字:字节流---TCP;数据报---UDP;原始套接字---开发网络协议
              地址信息: IP地址和端口号
TCP的服务器
socket()/bind()/listen()/accept()/read()/recv()/write()/send()/close()
TCP的客户端
socket()/connect()//read()/recv()/write()/send()/close()

======================================================================================================
二、linux驱动模型
以字符设备驱动为例。

    
    

一、linux驱动的分类
1、字符设备驱动
1)设备:
LED、KEY、BEEP、声卡、显卡、摄像头、鼠标、键盘、触摸屏、手写板、USB、.....
[root@GEC6818 /]#ls /dev -l
crw-rw----    1 root     root       29,   0 Jan  1  1970 fb0
crw-rw----    1 root     root       14,   3 Jan  1  1970 dsp
crw-rw----    1 root     root       14,  19 Jan  1  1970 dsp1
crw-rw----    1 root     root      204,  64 Jan  1  1970 ttySAC0
crw-rw----    1 root     root      204,  65 Jan  1  1970 ttySAC1
crw-rw----    1 root     root      204,  66 Jan  1  1970 ttySAC2
crw-rw----    1 root     root      204,  67 Jan  1  1970 ttySAC3

2)特点:
设备类型是c。应用程序和驱动程序之间交互数据的时候,数据是以字节为单位,不同的设备类型,交互的数据格式不一样的。字符设备驱动数据是实时传递的,按照固定的格式传递。字符设备是没有缓存的,字符设备是没有文件系统的。

3)应用程序访问方法
linux系统IO函数:open()、read()、write()、ioctl()、close()、mmap()
触摸屏:
struct input_event ts_ev;
int fd=open("/dev/input/event0", O_RDONLY);
read(fd, &ts_ev, sizeof(struct input_event));
close(fd);

---------------------------------------------------------------------------------------------------------

2、块设备驱动
1)设备:
大容量的存储设备。如:eMMC(nand flash:8GB)、SD卡、U盘、移动硬盘、....
[root@GEC6818 /]#ls /dev -l
brw-rw----    1 root     root      179,   0 Jan  1  1970 mmcblk0
brw-rw----    1 root     root      179,  16 Jan  1  1970 mmcblk0boot1
brw-rw----    1 root     root      179,   1 Jan  1  1970 mmcblk0p1
brw-rw----    1 root     root      179,   8 Jan  1  1970 mmcblk0boot0
brw-rw----    1 root     root      179,   2 Jan  1  1970 mmcblk0p2
brw-rw----    1 root     root      179,   4 Jan  1  1970 mmcblk0p4
brw-rw----    1 root     root      179,   3 Jan  1  1970 mmcblk0p3
brw-rw----    1 root     root      179,   5 Jan  1  1970 mmcblk0p5
brw-rw----    1 root     root      179,   6 Jan  1  1970 mmcblk0p6
brw-rw----    1 root     root      179,   7 Jan  1  1970 mmcblk0p7

brw-rw-rw-    1 root     root        8,   0 Jan  1 00:06 sda
brw-rw-rw-    1 root     root        8,   1 Jan  1 00:06 sda1


2)特点:
块设备是带有缓存的,当缓存满了(刷新缓存)这些数据才会写到块设备上去。块设备是有文件系统的(根文件系统的格式是ext4)。数据是以块(block)为为单位的,1block=1024B。
3)应用程序访问方法
例:
    U盘中有一个文件test.txt,编写一个程序,读取test.txt文件中的内容,并将该内容通过串口2发送出去。
如何访问U盘?
挂载-----将块设备以某一种文件系统的格式挂载到根文件系统的某个目录上,在根据该目录访问块设备。
有些嵌入式平台可以自动挂载U盘(做了配置文件):
[root@GEC6818 /]#mount
sda1 on /mnt/udisk type vfat (rw,relatime,fmask=0000,dmask=0000,allow_utime=0022,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
U盘就自动挂载到/mnt/udisk/,文件系统的类型vfat。
[root@GEC6818 /]#ls /mnt/udisk/
1-STM32????                5-tiny210
2-??????                   System Volume Information
3-GEC6818                  ???????
4-GEC210

访问方法:
fd = open("/mnt/udisk/test.txt", O_RDONLY);
read()
close()

手动挂载:
[root@GEC6818 /]#mount -t vfat /dev/sda1 /data
[root@GEC6818 /]#ls /data

如何访问串口
fd = open("/dev/ttySAC2", O_RDWR);
初始化串口2
write(fd, buf, sizeof(buf));
close(fd);

-----------------------------------------------------------------------------------------------------
3、网络设备驱动
1)设备:网卡(有线网卡、无线网卡)
如何查看网络设备??
[root@GEC6818 /]#ifconfig -a
eth0      Link encap:Ethernet  HWaddr 0E:72:C9:E8:03:96  
          inet addr:192.168.22.180  Bcast:192.168.22.255  Mask:255.255.255.0
          inet6 addr: fe80::c72:c9ff:fee8:396/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:238 (238.0 B)
          Interrupt:80 

ip6tnl0   Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          NOARP  MTU:1452  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          LOOPBACK  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

sit0      Link encap:IPv6-in-IPv4  
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

2)特点:    
    网卡----物理层
    网络驱动-----数据链路层
    
3)应用程序访问网络设备
socket套接字:字节流---TCP;数据报---UDP;原始套接字---开发网络协议
              地址信息: IP地址和端口号
TCP的服务器
socket()/bind()/listen()/accept()/read()/recv()/write()/send()/close()
TCP的客户端
socket()/connect()//read()/recv()/write()/send()/close()

======================================================================================================
二、linux驱动模型
以字符设备驱动为例。

    linux驱动程序开发-第三节:linux设备驱动程序设计流程_第2张图片
    
    

 

====================================================================================================
一、移植设备驱动:
(1)总体思路:搭建编译设备驱动环境:即编译linux内核,需要注意内核版本的选择-------->建立设备驱动demo:两个文件(xx.c,Makefile);注意Makefile编写格式,驱动程序
也有框架------->下载到嵌入式设备安装,查询检测。

(2)详细步骤:如下。

======================================================================================================
二、linux内核模块是什么?
linux kernel module----linux内核模块

在linux内核中,每个驱动程序都是独立的module。每设计一个驱动程序,首先需要设计一个module。module相当于驱动程序的盒子。
module会编译成ko文件。module可以安装,可以卸载。


=======================================================================================================

三、编译驱动的内核源码
1.内核源码的版本要与目标平台上运行的linux内核的版本要一致
  GEC6818 :#uname -r
  内核源码:
    gec@ubuntu:~/6818GEC/kernel$ pwd
    /home/gec/6818GEC/kernel
    gec@ubuntu:~/6818GEC/kernel$ vi Makefile
   1 VERSION = 3                                                                
   2 PATCHLEVEL = 4
   3 SUBLEVEL = 39
   4 EXTRAVERSION =
   5 NAME = Saber-toothed Squirrel

2.内核源码要针对目标平台正确的配置过:
    gec@ubuntu:~/6818GEC/kernel$ make menuconfig

    System Type  --->
        ARM system type (SLsiAP S5P6818)  ---> 

3.内核源码要正确的编译过
gec@ubuntu:~/6818GEC$ ls
buildroot  GEC6818uboot  kernel  linux  mk  out  prebuilts  prototype  tools
gec@ubuntu:~/6818GEC$ ./mk -k
===============================================================================


四。设计一个最简单的module
查看linux内核源码,内核源码中有驱动程序设计的案例。
sourceinsight-----内核源码工程

例子:
/kernel/drivers/watchdog/nxp_wdt.c

#include
#include

static int __init gec6818_led_init(void)
{
    printk(KERN_WARNING "gec6818 led init\n");

    return 0;
}


static void __exit gec6818_led_exit(void)
{
    printk(KERN_WARNING "gec6818 led exit");
}

//驱动程序的入口和出口
module_init(gec6818_led_init);
module_exit(gec6818_led_exit);

//module的描述
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("GEC6818 LED Device Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");

=======================================================================================================
五、驱动程序的特点
1、驱动程序是运行在linux内核中的,而应用程序是运行在linux的用户空间的。
2、每个硬件都需要有一个驱动程序,驱动程序是独立的。在一个应用程序中可以访问多个驱动程序
    视频播放器 ---->显卡 + 声卡 + 鼠标
3、应用程序是有入口函数的,main()是入口。而应用程序是没有出口。
   驱动程序有入口、有出口。
   入口函数:module_init(gec6818_led_init);
   出口函数:module_exit(gec6818_led_exit);
   安装驱动:
        #insmod  led_drv.ko ---->自动调用入口函数module_init()---->gec6818_led_init()--->从内核申请资源、向内核注册驱动、建立驱动模型、....
   卸载驱动:
        #rmmod led_drv.ko
        ---->自动调用出口函数module_exit()---->gec6818_led_exit()--->释放申请的资源,注销驱动。

4、编写应用程序的时候,我们可以使用库函数和系统调用函数。
应用程序使用的头文件是哪里来的:
stdio.h  stdlib.h string.h   ------>
gcc : /usr/include/stdio.h
arm-linux-gcc : /usr/local/arm/5.4.0/usr/arm-none-linux-gnueabi/sysroot/usr/include/stdio.h
    编写驱动程序的时候,使用的头文件是哪里来的?
    linux/kernel.h  /linux/module.h   ------->
来自于linux内核源码:/kernel/linux/module.h

5、函数区别
应用程序:printf() 、malloc()、sleep()
驱动程序:printk()、kmalloc()、ssleep()
        
6、static 的作用?
应用程序:static修饰局部变量
驱动程序:static修饰全局变量和函数

7、__init和__exit关键字
__init用来修饰初始化函数,一般情况下初始化函数只运行一次,运行结束以后,就会将该函数占用的内存释放掉。

[    0.000000] Memory: 1024MB = 1024MB total
[    0.000000] Memory: 810820k/810820k available, 237756k reserved, 272384K highmem
..............................
[    0.000000]       .init : 0xc0a52000 - 0xc0a8f100   ( 245 kB)
[    0.000000]       .data : 0xc0a90000 - 0xc0b297d8   ( 614 kB)
..............................

[    4.218000] devtmpfs: mounted
[    4.221000] Freeing init memory: 244K


8、程序的编译
应用程序:
    #arm-linux-gcc -o test test.c
驱动程序:
    使用Makefile文件,并利用内核源码的Makefile和内核源码中的头文件来编译驱动程序。

gec@ubuntu:/mnt/hgfs/14嵌入式系统驱动/2module/demo1$ ls
led_drv.c  Makefile

gec@ubuntu:/mnt/hgfs/14嵌入式系统驱动/2module/demo1$ make
------------------------------------------------------------------------------------------
出错信息如果是:表明没有编译内核,请按照上面 “三、编译驱动的内核源码”编译内核即可,再次make
    make[1]: Entering directory '/home/wgh/6818GEC/kernel'

   ERROR: Kernel configuration is invalid.
         include/generated/autoconf.h or include/config/auto.conf are missing.
         Run 'make oldconfig && make prepare' on kernel src to fix it.


   WARNING: Symbol version dump /home/wgh/6818GEC/kernel/Module.symvers
           is missing; modules will have no dependencies and modversions.
-------------------------------------------------------------------------------------------

成功编译信息输出如下:
make ARCH=arm CROSS_COMPILE=/home/gec/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- -C /home/gec/6818GEC/kernel M=/mnt/hgfs/14嵌入式系统驱动/2module/demo1 modules
make[1]: Entering directory '/home/gec/6818GEC/kernel'
  CC [M]  /mnt/hgfs/14嵌入式系统驱动/2module/demo1/led_drv.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /mnt/hgfs/14嵌入式系统驱动/2module/demo1/led_drv.mod.o
  LD [M]  /mnt/hgfs/14嵌入式系统驱动/2module/demo1/led_drv.ko
make[1]: Leaving directory '/home/gec/6818GEC/kernel'

9、驱动程序安装好以后,驱动程序不是一直运行的;而是安装到内核中的一个程序,只有应用程序去调用驱动程序,这个驱动程序才开始工作。
=======================================================================================================
六、驱动的调试

1.查看ko的信息:modinfo 
gec@ubuntu:xxx/demo1$  modinfo led_drv.ko


2、查看ko的格式
gec@ubuntu:xxx/demo1$ file led_drv.ko

3、下载 led_drv.ko 到开发板上

4、安装驱动
[root@GEC6818 /test]#insmod led_drv.ko
[ 3488.195000] gec6818 led init

5、查看安装好的ko
[root@GEC6818 /test]#lsmod
led_drv 748 0 - Live 0xbf000000 (O)

6、卸载驱动
[root@GEC6818 /test]#rmmod led_drv.ko 
[ 3621.975000] gec6818 led exit

===============================================================================================================
七、编译驱动的Makefile
obj-m += led_drv.o
KERNELDIR:=/home/gec/6818GEC/kernel
CROSS_COMPILE:=/home/gec/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-

PWD:=$(shell pwd)

default:
    $(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules

clean:
    rm -rf *.o *.order .*.cmd *.ko *.mod.c *.symvers *.tmp_versions
    
1)obj-m += led_drv.o 
----m是module的意思,+= 追加赋值。?= 或 := 区别。led_drv.o---驱动远程序的目标文件。

2)KERNELDIR:=/home/gec/6818GEC/kernel 
----->内核源码的路径

3)CROSS_COMPILE:=/home/gec/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
-----交叉编译器的路径

4)PWD:=$(shell pwd)
-----当前路径,即编译驱动程序的Makefile文件所在的路径。

5)$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
去内核源码目录下,找到内核源码的Makefile文件,并将ARCH和CROSS_COMPILE变量传递给Makefile文件。利用内核源码的Makefile文件来编译当前路径下的驱动源文件,将驱动源文件编译成一个ko。

============================================================================================================


九、printk()


    
    
    
    

你可能感兴趣的:(嵌入式驱动开发,嵌入式驱动开发)