配置交叉编译环境
arm-linux-gcc -v交叉编译
1、将版本配置为4.4.3
2、内核一部分
外设(时钟配置、GPIO、串口)
3、配置环境(将板载设置为2440)
ubuntu下查看函数原码
ctag -R 路径
设置完成后进主
函数将光标停在函数名字处按Ctrl + }可跳转至函数 Ctrl + t回到原位置
配置内核
出现异常
sudo apt-get install u-boot-tools
用下面这个命令下载一个u-boot-tools
完成之后重新将uImage下载至板子上
每次配置完(make menuconfig)后要编译+拷贝到tftpboot下
字符设备驱动程序
1、框架格式
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
int _init first_dirver_init(void)
{
printk("first_dirver_init OK\n");
}
void _exit first_dirver_exit(void)
{
printk("first_dirver_exit OK\n");
}
module_init(first_dirver_init);
module_exit(first_dirver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("QuJunjie");
2、第一种编译流程(使用Makefile编译)
若需要添加文件,只需在Makefile中添加一个目标文件即可
3、加入驱动
4、将模块加载到板子上验证程序
第二种编译流程
函数接口
int register_chardev( unsigned int major, const char *name, const struct file_operations *fops)
设备号:设备编号(在内核中区分设备的一个数)
主设备号(driver):驱动程序本身
子设备号(device):使用了驱动程序的设备
注:同一个主设备号可能有多个子设备号,不允许有多个同名的主设备号,同一个主设备号不能有多个相同的设备
参数:
major:主设备号
name:设备名字
fops:结构体(file_operations)指针
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#define DEVICE_MAJOR 200
#define DEVICE_NAME "first_driver"
int first_driver_open(struct inode *node, struct file *fp)
{
printk("first_driver_open OK\n");
return 0;
}
ssize_t first_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset)
{
printk("first_driver_read OK\n");
return 0;
}
ssize_t first_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{
printk("first_driver_write OK\n");
return 0;
}
int first_driver_release(struct inode *node, struct file *fp)
{
printk("first_driver_release OK\n");
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = first_driver_open,
.read = first_driver_read,
.write = first_driver_write,
.release = first_driver_release
};
int __init first_dirver_init(void)
{
register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &fops);
printk("first_dirver_init OK\n");
return 0;
}
void __exit first_dirver_exit(void)
{
unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME);
printk("first_dirver_exit OK\n");
}
module_init(first_dirver_init);
module_exit(first_dirver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("QuJunjie");
注册字符设备
创建nod,地址 名字 类型 主设备号 子设备号
运行流程:
但凡要访问到CPU的外设寄存器,都要用到映射函数
映射函数
ioremap
参数:物理地址;要映射几个字节;
解除映射函数: