Ubuntu环境驱动编写


基本上分为两部分:

  1. Linux内核下载、编译、加载、新内核Ubuntu启动;
  2. 测试驱动编写(包括:driver.c、测试.c、Makefile)、编译、加载、测试、卸载;

Linux内核下载、编译、加载、新内核Ubuntu启动

有许多坑!

内核下载

内核source下载,有两类:

sudo apt-cache search linux-source //查看版本号
sudo apt install linux-source-xxxx版本号 //一般下载到、usr/src/ 目录下
tar -jxvf … -C /解压目录 //.tar.bz2文件解压

内核编译、加载、重启

进入解压source目录:

  • 编译内核(一),安装工具:

sudo apt-get install libncurses5-dev libssl-dev
sudo apt-get install build-essential openssl
sudo apt-get install zlibc minizip
sudo apt-get install libidn11-dev libidn11

  • 编译内核(二),预处理:1

sudo make mrproper
sudo make clean
sudo make menuconfig

  • 编译内核(三),加载、重启

sudo make –j8 //-j8指编译机器有8个核,-j4指4个核,可加快编译速度,不加为1个核
sudo make bzImage //在source的目录./arch/x86/boot/下生产bzImage文件,也有文档不使用此命令
sudo make modules
sudo make modules_install //安装内核模块
sudo make install //安装内核,此步可生产启动选项中的内核选项,如下条描述
sudo reboot //

  1. /usr/src目录下有“linux-header-xxxx版本号”的目录,对应Linux启动时,advanced(按shift键可进入)里的内核启动选项;
  2. 系统重启后,需要判断运行内核版本:

uname -r //后续驱动开发中,Makefile中定义KERNELDIR要指明内核source文件所在目录,有就是和编译的驱动和内核版本挂钩,如何版本不对,内核不能完成insmod;

驱动编写等

  1. 用户目录下,编写:Makefile、chardev.c、main.c(驱动测试程序)

make //依靠Makefile的内容,生成启动文件.ko;
gcc -o test main.c //生成可执行测试程序

  1. 驱动加载等

sudo insmod chardev.ko //加载,如果chardev.c中有printk打印信息,需要使用命令查看
sudo lsmod //查看模块是否加载
sudo rmmod //卸载模块

  1. 驱动模块添加到/dev/目录下:[link]

gedit /proc/devices //查看 chardev 驱动模块的主设备号
mknod /dev/chardev c 250 0 //在/dev/目录下,创建设备 chardev,其中,c代码字符驱动,250是驱动主设备号,0是次设备号。次设备号一般都为0
rm -rf /dev/chardev //删除 /dev/目录下的 chardev 设备

  1. kernel打印信息查看

cat /var/log/syslog //查看打印信息;
dmesg //-c 清除;
cat /proc/kmsg & //这时候能动态显示调试信息;

参考代码 [link]

  1. Makefile
#//
#Makefile
#make -C $(KDIR) M=$(SRCPWD) modules此语句前必须要一个Tab键
#rm -rf chardev.o此语句前必须要一个Tab键
#//

obj-m:=chardev.o 
KDIR:=/lib/modules/$(shell uname -r)/build 
#Kernel_Dir
SRCPWD:=$(shell pwd) 
all: 
	make -C $(KDIR) M=$(SRCPWD) modules 
clean: 
	rm -rf chardev.o
#//
  1. chardev.c
//
#include <linux/kernel.h> 
#include <linux/fs.h>                  
#include <linux/module.h> 
#include <asm/uaccess.h>               
#include <linux/cdev.h>                
//
static int char_read(struct file *filp,char __user *buffer,size_t,loff_t *);        
static int char_open(struct inode *,struct file *);                                      
static int char_write(struct file *filp,const char __user *buffer,size_t ,loff_t*); 
static int char_release(struct inode *,struct file *);                                  
//
//static int device_open_count;                     
static int major;
//
static const struct file_operations file_ops = { 
.read = char_read, 
.write = char_write, 
.open = char_open, 
.release = char_release, 
};

static int __init char_init(void) 
{  
int value; 
major = 0; 
value = register_chrdev(major, "chardev", &file_ops); 
if (value < 0) { 
printk("register dev failed!\n"); 
return value; 
} 
if (major == 0)  
major = value;
return 0; 
}

static int char_open(struct inode *inode,struct file *file) 
{ 
//  if(device_open_count == 0) 
//    device_open_count++; 
//  else{ 
//     printk("设备已经被打开\n"); 
//     return -1; 
//  } 
try_module_get(THIS_MODULE);

return 0; 
}

static int char_release(struct inode *inode,struct file *file) 
{ 
//    device_open_count--; 
module_put(THIS_MODULE); 
return 0; 
}

static int char_read(struct file *filp,char __user *buffer,size_t length,loff_t *offset) 
{  
if(length < 0) 
return -1; 
else if(length > 12) 
length = 12;

if(0 == copy_to_user(buffer,"Hello Linux!",length)) 
return length; 
return -1;
}

static int char_write(struct file *filp,const char __user  *buffer,size_t length,loff_t *offset) 
{ 
return 0; 
}

static void __exit module_close(void) 
{ 
unregister_chrdev(major, "chardev");
}

//

module_init(char_init); 
module_exit(module_close);

//
  1. main.c
///

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <string.h>

///

int main(void) 
{ 
char ch = 0;
int testdev; 
int i,rf=0; 
char buf[15];

memset(buf, 0, sizeof(buf)); 
testdev = open("/dev/chardev",O_RDWR); 
if ( testdev == -1 ) 
{ 
perror("open error!\n"); 
exit(0); 
}

while ('q' != ch)
{
rf=read(testdev,buf,11); 
if(rf<0)
{ 
printf("read error[%d]!\n",rf); 
}
else
{
printf("R:%s\n",buf); 
}
scanf("%c",&ch);
}
close(testdev);

return 0; 
}

///

  1. mrproper为清除编译过程中产生的所有中间文件,clean为清除上一次产生的编译中间文件,在menuconfig中出现选择的图形化界面后,直接按右方向键选择到exit退出,退出提示中选择保存(生产.config文件),实现内核的默认配置。 ↩︎

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值