经过一段时间的,翻过了好几本书,大致上理解了linux驱动的基本步骤。从驱动LED入手实践操作,一路碰钉不少。经过一番挣扎,还是成功地让LED在开发板上闪起来!下面将粗略分享下过程。
将scrosstools3.4.1,解压后放到指定目录。再对 /etc/profile 文件修改相关信息。再执行命令
source /etc/profile
可将该交叉编译器成为当前默认编译器。
执行命令
arm-linux-gcc –v
可以检测该编译器安装是否成功。
Linux的外设可以分为3类:字符设备 (character device) 、块设备(block device)和网络接口(network interface)。
这里LED以字符设备类型驱动。LED驱动程序文件名为 s3c24xx_leds.c ,将它放置内核代码中的 /kerner/drivers/char ,用于往后的编译工作。
先来看看s3c24xx_leds.c 文件中主要有那些函数:
(以下为《嵌入式linux开发完全手册》中的程序)
/* 应用程序对设备文件/dev/leds执行open(...)时,
* 就会调用s3c24xx_leds_open函数
*/
static int s3c24xx_leds_open(struct inode *inode, struct file *file)
/* 应用程序对设备文件/dev/leds执行ioclt(...)时,
* 就会调用s3c24xx_leds_ioctl函数
*/
static int s3c24xx_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
/* 这个结构是字符设备驱动程序的核心
* 当应用程序操作设备文件时所调用的open、read、write等函数,
* 最终会调用这个结构中指定的对应函数
*/
static struct file_operations s3c24xx_leds_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = s3c24xx_leds_open,
.ioctl = s3c24xx_leds_ioctl,
};
/*
* 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数
*/
static int __init s3c24xx_leds_init(void)
{
/* 注册字符设备驱动程序
* 参数为主设备号、设备名字、file_operations结构;
* 这样,主设备号就和具体的file_operations结构联系起来了,
* 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数
* LED_MAJOR可以设为0,表示由内核自动分配主设备号
*/
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
.
.
.
}
/*
* 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数
*/
static void __exit s3c24xx_leds_exit(void)
要加LED到内核里面,首先要为LED设备获得一个注册号,即主、次设备号。可以自定义主设备号,但是要确保该号不能被其它设备使用,也可以让主设备好为0,让系统自动分配。这里我定义主设备号为222。
理解驱动程序中函数的功能后,现在可以进行编译。执行命令
make modules SUBDIRS=drivers/char
编译字符设备驱动,编译成功后,可以在该文件夹下找到s3c24xx_leds.ko 文件。将它放到开发板的文件夹中(如/mydevices),执行命令加载驱动设备
insmod s3c24xx_leds.ko
没有返回错误提示,则加载成功。执行命令
lsmod
可以看见该该驱动设备的信息。
Module Size Used by Not tainted
s3c24xx_leds 2048 0
驱动加载成功后,还需要应用程序对设备的控制。
int main(void)
{
int fd = -1;
fd = open("/dev/led", 0); // 打开设备
if (fd < 0) { //打开设备失败
printf("Can't open /dev/led/n");
return -1;
}
else {printf("led is running");//打开设备成功
printf("by:jammy-lee");}
ioctl(fd, IOCTL_LED_ON, 0);
ioctl(fd, IOCTL_LED_OFF, 1);
ioctl(fd, IOCTL_LED_OFF, 2);
ioctl(fd, IOCTL_LED_ON, 3);
}
上面的程序中fd = open("/dev/led", 0); 可以看到,/dev/led 为设备文件,所以还需要执行命令建立设备文件
mknod /dev/led c 222 0
其中,c代表字符设备,222为主设备号,0为次设备号。那么应用程序通过读写led设备文件,从而连接到s3c24xx_leds.ko 中的函数操作。
执行命令编译应用程序
arm-linux-gcc –o led_test led_test.c %编译程序
arm-linux-strip led_test %去掉led_test调试部分,生成的程序小很多
一开始运行应用程序的时候,发现不能运行"-sh: ./led_test: Permission denied"。以为是编译出了问题,反复安装交叉编译以及编译程序还是不能解决。后来请教一下高人,才知道是权限问题,导致不能运行。执行指令
chmod 777 led_test
程序真的能动起来!激动啊!!!!
作者:jammy_lee