第一章 linux之Ubuntu入门
Ubuntu的终端操作指令与shell命令
Ubuntu压缩与解压缩
Ubuntu用户和用户组
Ubuntu文件权限管理
vim编辑器
make工具和Makefile的引入
shell脚本入门
第二章linux之ARM(MX6U)裸机篇
MX6U的特点在于是少数几个官方提供了可移植SDK的linux单片机
所以可以进行裸机开发
否则实际中的linux裸机开发都是用汇编语言对寄存器进行操作。
编写好汇编语言以后使用imxdownload交叉编译,然后存入SD卡中
为了方便,就开始使用make 和 Makefile
再进一步,使用imx6ul.lds连接文件一次性编译多个.c文件
第三章linux系统移植
可移植的系统分三种
uboot厂商提供
半导体厂商提供
正点原子厂商提供
主要涉及移植以后一些宏定义的修改 和打包以后使用MfgTool工具烧写
第四章linux驱动开发篇
一、主要是根据linux下的各种驱动框架进行开发
linux驱动分为三大类:
1、宇符设备驱动,最多的。
2、块设备驱动,存储
3、网络设备驱动,
一个设备不说是一定只属于某一个类型。比如USB WIFI,.SDIO WIFI,属于网络设备驱动,因为他又有USB和SDIO,因此也属于字符设备驱动。
二、linux下应用程序和驱动是完全分开的,驱动获取传感器数据,上传给应用程序进行数据处理。而不像STM32是杂糅在一起的。
用户空间(应用程序)与内核空间(linux操作系统内核和驱动程序)
应用程序想要访问内核资源,三种方法:系统调用、异常(中断)和陷入
应用程序不会直接调用系统调用,而是通过API函数来间接的调用系统调用,比如POSX、
API和C库等。uniⅸ类操作系统中最常用的编程接口就是POSIX.
每个系统调用都有一个系统调用号。“
系统调用处于内核空间,应用程序无法直接访问,因此需要陷入“到内核,方法就是软
中断。陷入内核以后还要指定系统调用号。
一、字符设备驱动框架
字符设备驱动的编写主要就是驱动对应的 open、 close、 read。。。其实就是file_operations结构体成员变量的实现
1主要写两个部分(驱动+应用)
驱动
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : chrdevbase.c
作者 : 左忠凯
版本 : V1.0
描述 : chrdevbase驱动文件。
其他 : 无
论坛 : www.openedv.com
日志 : 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/
#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
static char readbuf[100]; /* 读缓冲区 */
static char writebuf[100]; /* 写缓冲区 */
static char kerneldata[] = {"kernel data!"}; //要读写的字符串数组数据
/*
* @description : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 要打开的设备文件,file结构体有个叫做private_data的成员变量
* 一般在open的时候将private_data指向设备结构体。
* @return : 0 成功;其他 失败
*/
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
//printk("chrdevbase open!\r\n");
return 0;
}
/*
* @description : 从设备读取数据
* @param - filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - cnt : 要读取的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 向用户空间(应用层)发送数据 memcpy 、 copy_to_user*/
memcpy(readbuf, kerneldata, sizeof(kerneldata));
retvalue = copy_to_user(buf, readbuf, cnt);
if(retvalue == 0){
printk("kernel senddata ok!\r\n");
}else{
printk("kernel senddata failed!\r\n");
}
//printk("chrdevbase read!\r\n");
return 0;
}
/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 接收用户空间传递给内核的数据并且打印出来 copy_from_user */
retvalue = copy_from_user(writebuf, buf, cnt);
if(retvalue == 0){
printk("kernel recevdata:%s\r\n", writebuf);
}else{
printk("kernel recevdata failed!\r\n");
}
//printk("chrdevbase write!\r\n");
return 0;
}
/*
* @description : 关闭/释放设备
* @param - filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int chrdevbase_release(struct inode *inode, struct file *filp)
{
//printk("chrdevbase release!\r\n");
return 0;
}
/*
* 设备操作函数结构体 linux应用程序就是实现file_operations结构体内的各种方法
*/
static struct file_operations chrdevbase_fops = {
.owner = THIS_MODULE,
.open = chrdevbase_open, //打开设备
.read = chrdevbase_read, //从设备读取数据
.write = chrdevbase_write, //向设备写数据
.release = chrdevbase_release, //关闭/释放设备
};
/*
* @description : 驱动入口函数
* @param : 无
* @return : 0 成功;其他 失败
*/
static int __init chrdevbase_init(void)
{
int retvalue = 0;
/* 注册字符设备驱动
主设备号
设备名
指针指向实现的file_operations结构体 */
retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);
if(retvalue < 0){
printk("chrdevbase driver register failed\r\n");
}
printk("chrdevbase init!\r\n");
return 0;
}
/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit chrdevbase_exit(void)
{
/* 注销字符设备驱动 释放主设备号*/
unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
printk("chrdevbase exit!\r\n");
}
/*
* 将上面两个函数指定为驱动的入口和出口函数
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
/*
* LICENSE和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");
应用
/*
* @Author: “wuhaozhen” 908342915@qq.com
* @Date: 2022-05-03 13:54:37
* @LastEditors: “wuhaozhen” 908342915@qq.com
* @LastEditTime: 2022-05-09 12:35:22
* @FilePath: \01_chrdevbase\chrdevbaseApp.c
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : chrdevbaseApp.c
作者 : 左忠凯
版本 : V1.0
描述 : chrdevbase驱测试APP。
其他 : 使用方法:./chrdevbase /dev/chrdevbase <1>|<2>
argv[2] 1:读文件
argv[2] 2:写文件
论坛 : www.openedv.com
日志 : 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/
static char usrdata[] = {"usr data!"};
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[]) //字符设备驱动框架:类似于STM32的 SD卡 文件读写流操作
{
int fd, retvalue;//fd 文件描述符
char *filename;
char readbuf[100], writebuf[100];
if(argc != 3){//传参个数不为3,说明主设备号等缺少,因此不能执行应用
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
/* 打开驱动文件 open API
通过传参 判断要使用哪个驱动文件 以及命令是什么
./chrdevbaseAPP /dev/chrdevbase 1 */
fd = open(filename, O_RDWR);
if(fd < 0){
printf("Can't open file %s\r\n", filename);
return -1;
}
if(atoi(argv[2]) == 1){
/* 从驱动文件读取数据 */
retvalue = read(fd, readbuf, 50);
if(retvalue < 0){
printf("read file %s failed!\r\n", filename);
}else{
/* 读取成功,打印出读取成功的数据 */
printf("read data:%s\r\n",readbuf);
}
}
if(atoi(argv[2]) == 2){
/* 向设备驱动写数据 */
memcpy(writebuf, usrdata, sizeof(usrdata));
retvalue = write(fd, writebuf, 50);
if(retvalue < 0){
printf("write file %s failed!\r\n", filename);
}
}
/* 关闭设备 */
retvalue = close(fd);
if(retvalue < 0){
printf("Can't close file %s\r\n", filename);
return -1;
}
return 0;
}
2将驱动和应用交叉编译 ,获得 .ko文件
arm-linux-gnueabihf-gcc chrdevbaseAPP.c chrdevbaseAPP
3 通过tftp挂载至linux,
1)cd lib/modules/4.1.15/
2)挂载驱动 modprobe chrdevbase.ko
3)查看设备号是否存在 cat /proc/devices
4)创建设备节点 mknod /dev/chrdevbase c 200 0
5) 运行应用 ./chrdevbaseAPP /dev/chrdevbase 1
./chrdevbaseAPP /dev/chrdevbase 2
6)卸载驱动 rmmod chrdevbase
内存映射(led点灯实验,寄存器操作)
当ip冲突需要修改IP时,linux中的bootargs和bootcmd和serverip都需要修改
Linux新字符设备驱动实验
goto对于错误的处理方法(类似堆栈处理,倒序)