ARM-Linux驱动内核(S3C2440)

Linux启动流程

驱动(程序) : 驱使设备行动的程序

1. 启动bootloader---引导操作系统启动的(裸机)程序,为操作系统启动准备环境,并引导操作系统启动

2. 启动kernel---操作系统核心 (俗称的操作系统)

3. 加载根文件系统---一堆文件的集合(根目录下的文件)

存储分类
RAM(随机存储) SRAM 静态 DRAM 动态 SDRAM 同步动态 SDR(DDR2\3\4\5)
ROM(只读存储) PROM 可编程 EPROM 可擦除 EEPROM 电子可擦除

Flash : 是RAM和ROM的结合体。具有速度快,掉电不丢失的特点
Norflash : 可线性访问 (和内存访问方式相同)
Nandflash :不可线性访问 (需要专门的软件访问)
地址相关代码:运行地址(加载地址)和链接地址必须保持一致
地址无关代码:运行地址(加载地址)和链接地址可以不同
长跳转(绝对跳转): 目标函数的跳转地址是固定的(绝对位置)
短跳转(相对跳转): 目标函数的跳转地址是可变的(相对位置)

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|------------------------------------------------------------|
| Bootloader :一个裸机程序 | Kernel :一个复杂的程序 | 根文件系统:一堆文件的集合 |
| uboot ------ booloader 初始 CPU( 工作模式 ) 初始化异常向量表 初始化栈 初始化时钟 初始化内存 关看门狗 关闭 Cache 初始相关外设 集成相关的协议 搬移 kernel 到内存 向内核传参 ( 根文件系统类型 / 位 置 /init 进程 / 内核启动阶段使用 ip/ 调试串口 ) 引导 kernel 启动 ( 设置 PC ) --- (bootloader 从此不再控制 cpu cpu 的控制权彻底移交 kernel) | 内存管理 文件管理 进程管理 网络管理 设备管理 启动到最后阶段时加载 ( 挂载的 形式 ) 根文件系统 先启动 init 进程 - > shell -> app | 配置文件 系统命令 ( 程序 ) 库文件 ( 动 / 静态库 ) 用户程序 普通文件 ( 文本 /mp3/ 图片 ) |

Tftp:简单文件传输协议 将uImage拷贝到tftp服务目录下
Nfs:网络文件系统 将rootfs.tar.gz拷贝到nfs服务目录下,并加sudo解压
程序编译的过程:
预处理 编译 汇编 链接
main.c main.i main.s main.o mainapp
fun.c fun.o
gcc main.c fun.o -o mainapp
库:xxx.o的集合---归并
静态库 :会被编译进可执行程序 , 程序执行时不需要库文件
动态库 :不会被编译进可执行程序 , 程序执行时需要库文件 (编译和运行都需要库文件的存在)
动态库生成: gcc -fPIC -shared fun.c -o libfun.so
静态库生成: gcc -c fun.c -o fun.o
ar -rcv libfun.a fun.o
Uboot启动:
Norflash:NORFLASH被接在0地址处,系统上电后PC默认指向0地址,直接运行norflash中的uboot
Nandflash: 系统上电后自动搬移 uboot 的前 4KB 的程序到 IRAM 中 (IRAM 的起始地址 0x40000000 ,大小 4KB) ,此时 PC(0 地址 ) 被映射到0x40000000 地址处, uboot 必须在前 4KB 程序中完成内存的初始化,并将自己剩余的部分搬移到内存继续执行。
Kernel:
Nandflash : uboot 直接搬移 nandflash 中的 uImage 到内存的 0x30008000 地址处,启动内核
远程主机(ubuntu): uboot通过tftp将ubuntu中的uImage下载到内存的0x30008000地址处,启动内核
Rootfs:
Nandflash : 内核启动到最后阶段时直接挂载到 nandflash 上
远程主机(ubuntu): 通过nfs挂载到ubuntu中的nfs目录下

内核编译:

选择模块进行编译------条件编译
Kconfig 定义 make menuconfig 中的配置选项
make menuconfig 可视化界面配置.config中的宏(内核活地图)
.config 保存内核的配置(保存的是选择条件的值)
Makefile:根据 .config 文件中的宏的值进行编译
同层目录下 Kconfig 和 makefile 总是成对出现
动态加载驱动模块:
编译内核模块:

  1. 配置 make menuconfig 模块编译选项为M (Kconfig 中类型定义为 tristate)

  2. make uImage (如果原来该模块为 y,则需要重新编译出不包含该模块的内核)------非必要

  3. make modules 编译内核模块 在源文件同层目录下生成同名的内核模块 xxx.ko

  4. 将编译生成的 xxx.ko 拷贝到目标平台
    动态加载:

  5. insmod led.ko 动态加载内核模块(类似于windows下安装一个新的驱动)

  6. lsmod 查看动态加载的驱动模块

  7. rmmod led 卸载动态加载的驱动模块
    ADC模块驱动编译

    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/kdev_t.h>
    #include <linux/fs.h>
    #include <linux/module.h>
    #include <linux/cdev.h>
    #include <asm/string.h>
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/irqreturn.h>
    #include <linux/wait.h>
    #include <linux/sched.h>

    #define MAJOR_NUM 251
    #define MINOR_NUM 0
    #define DEV_NAME "adc"
    #define ADCCON 0x58000000
    #define ADCDAT0 0x5800000C
    #define CLKCON 0x4C00000C
    static volatile unsigned long * adccon;
    static volatile unsigned long * adcdat0;
    static volatile unsigned long * clkcon;
    static wait_queue_head_t wq;
    static unsigned int condition = 0;

    static irqreturn_t irq_handler(int num, void * arg)
    {
    printk("irq_handler num = %d\n", num);
    condition = 1;
    wake_up_interruptible(&wq);
    return IRQ_HANDLED;
    }

    static int init_adc(void)
    {
    *adccon = (1 << 14) | (49 << 6);
    return 0;
    }

    static int adc_start(void)
    {
    *adccon |= (1 << 0);
    return 0;
    }

    static unsigned short adc_read(void)
    {
    unsigned short adc_value = *adcdat0 & 0x3ff;
    return adc_value;
    }

    static int open(struct inode * node, struct file * file)
    {
    init_adc();
    printk("adc open ...\n");
    return 0;
    }

    static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * loff)
    {
    unsigned short data = 0;
    printk("adc read start ...\n");
    condition = 0;
    adc_start();
    wait_event_interruptible(wq, condition);

     data = adc_read();
     copy_to_user(buf, &data, sizeof(data));
    
     printk("adc read end ...\n");
     return sizeof(data);
    

    }

    static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * loff)
    {
    return 0;
    }

    static int close(struct inode * node, struct file * file)
    {
    printk("adc close ...\n");
    return 0;
    }

    static struct file_operations fops =
    {
    .owner = THIS_MODULE,
    .open = open,
    .read = read,
    .write = write,
    .release = close
    };

    static struct miscdevice misc_dev =
    {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEV_NAME,
    .fops = &fops
    };

    static int __init adc_init(void)
    {
    int ret = 0;
    ret = misc_register(&misc_dev);
    if(ret < 0)
    goto err;

     ret = request_irq(IRQ_ADC, irq_handler, IRQF_DISABLED, "irq_adc", NULL);
     if(ret < 0)
     	goto err_irq;
    
     init_waitqueue_head(&wq);
    
     adccon = ioremap(ADCCON, sizeof(adccon));
     adcdat0 = ioremap(ADCDAT0, sizeof(adcdat0));
     clkcon = ioremap(CLKCON, sizeof(clkcon));
     *clkcon |= (1 << 15);
     printk("CLKCON = %lx\n", *clkcon);
    
     printk("adc_init   ###############################\n");
     return 0;
    

    err:
    misc_deregister(&misc_dev);
    printk("adc cdev_add failed ret = %d\n", ret);
    return ret;

    err_irq:
    disable_irq(IRQ_ADC);
    free_irq(IRQ_ADC, NULL);
    misc_deregister(&misc_dev);
    printk("adc cdev_add failed ret = %d\n", ret);
    return ret;
    }

    static void __exit adc_exit(void)
    {
    iounmap(clkcon);
    iounmap(adcdat0);
    iounmap(adccon);
    disable_irq(IRQ_ADC);
    free_irq(IRQ_ADC, NULL);
    misc_deregister(&misc_dev);
    printk("adc_exit ###############################\n");
    }

    module_init(adc_init);
    module_exit(adc_exit);
    MODULE_LICENSE("GPL");

相关推荐
醉颜凉3 分钟前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
QMCY_jason26 分钟前
Ubuntu 安装RUST
linux·ubuntu·rust
慕雪华年30 分钟前
【WSL】wsl中ubuntu无法通过useradd添加用户
linux·ubuntu·elasticsearch
苦逼IT运维1 小时前
YUM 源与 APT 源的详解及使用指南
linux·运维·ubuntu·centos·devops
仍有未知等待探索1 小时前
Linux 传输层UDP
linux·运维·udp
zeruns8021 小时前
如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程
linux·运维·服务器·docker·网站
卑微求AC1 小时前
(C语言贪吃蛇)16.贪吃蛇食物位置随机(完结撒花)
linux·c语言·开发语言·嵌入式·c语言贪吃蛇
北城青1 小时前
WebRTC Connection Negotiate解决
运维·服务器·webrtc
Hugo_McQueen2 小时前
pWnos1.0 靶机渗透 (Perl CGI 的反弹 shell 利用)
linux·服务器·网络安全
海滩游侠2 小时前
ARM assembly: Lesson 10
arm开发