一、驱动模块的加载
1. 静态 编译进内核
2. 动态 编译成模块 如下:
解决方法
结果
led电灯例子
- 创建一个led.c
- 修改Makefile、Kconfig
- make modules
- cp drivers/char/led.ko /home/linux/nfs/rootfs
- 开发板 insmod led.ko
- 去 /home/linux/nfs/rootfs 上 写程序.c
- arm-linux-gcc 程序.c
- 开发板 创建节点 mknod /dev/led c 253 0
- 开发板 运行程序
~/linux-2.6.32.2/drivers/char/ led.c 内核(操作系统)代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#define MAJOR_NUM 253
#define MINOR_NUM 0
#define DEV_NAME "led"
#define DEV_NUM 1
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;
static void init_led(void)
{
// 配置GPB5引脚功能为输出
*gpbcon &= ~(3 << 10);
*gpbcon |= (1 << 10);
// 将GPB5引脚电平置高
*gpbdat |= (1 << 5);
}
static void led_on(void)
{
// 将GPB5引脚电平置低
*gpbdat &= ~(1 << 5);
}
static void led_off(void)
{
// 将GPB5引脚电平置高
*gpbdat |= (1 << 5);
}
static int open (struct inode * inode, struct file * file)
{
init_led();
printk("led open ...\n");
return 0;
}
static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
printk("led read ...\n");
return 0;
}
static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
int ret = strlen(buf);
if(!strcmp(buf, "ledon"))
led_on();
else if(!strcmp(buf, "ledoff"))
led_off();
else
ret = -1;
printk("led write ...\n");
return ret;
}
static int close (struct inode * inode, struct file * file)
{
printk("led close ...\n");
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = open,
.read = read,
.write = write,
.release = close
};
static struct cdev cdev;
static dev_t dev;
static int __init led_init(void)
{
int ret = 0;
dev = MKDEV(MAJOR_NUM, MINOR_NUM);
cdev_init(&cdev, &fops);
ret = cdev_add(&cdev, dev, DEV_NUM);
if(ret < 0)
goto err_cdev_add;
ret = register_chrdev_region(dev, DEV_NUM, DEV_NAME);
if(ret < 0)
goto err_register_chrdev_region;
gpbcon = ioremap(GPBCON, sizeof(*gpbcon));
gpbdat = ioremap(GPBDAT, sizeof(*gpbdat));
printk("led_init ...\n");
return ret;
err_cdev_add:
cdev_del(&cdev);
printk("led cdev_add failed\n");
return ret;
err_register_chrdev_region:
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led register_chrdev_region\n");
return ret;
}
static void __exit led_exit(void)
{
iounmap(gpbcon);
iounmap(gpbdat);
unregister_chrdev_region(dev, DEV_NUM);
cdev_del(&cdev);
printk("led_exit ###############################\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
~/nfs/rootfs led_app.c 应用层(栈)代码
1 #include <fcntl.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6
7 int main(int argc, const char *argv[])
8 {
9 int fd = open("/dev/led",O_RDWR);
10 if (fd < 0)
11 {
12 perror("open led fail");
13 return -1;
14 }
15
16 unsigned char buf[48] = {0};
17
18 while(1)
19 {
20 write(fd,"ledon",strlen("ledon"));
21 sleep(2);
22 write(fd,"ledoff",strlen("ledoff"));
23 sleep(2);
24 }
25 close(fd);
26 return 0;
27 }
拷贝数据函数
不要直接从内核操作应用层代码,也不要直接从应用层操作内核代码
可以间接操作,通过函数copy_from_user()、copy_to_user()