zoukankan      html  css  js  c++  java
  • LED驱动学习

    是一个char字符类型的驱动

    //配置模式为输出端口

    static unsigned int led_cfg_table [] = {

    S3C2410_GPB5_OUTP,

    S3C2410_GPB6_OUTP,

    S3C2410_GPB7_OUTP,

    S3C2410_GPB8_OUTP,

    };

    s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);

    s3c2410_gpio_cfgpin(37, 0x01 << 10);

    这个在\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中定义

    #define S3C2410_GPB5 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

    #define S3C2410_GPB5_INP (0x00 << 10)

    #define S3C2410_GPB5_OUTP (0x01 << 10)

    #define S3C2410_GPB5_nXBACK (0x02 << 10)

    S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

    #define S3C2410_GPIONO(bank,offset) ((bank) + (offset))

    #define S3C2410_GPIO_BANKA (32*0)

    #define S3C2410_GPIO_BANKB (32*1)

    static int __init dev_init(void)

    {

    int ret;

    int i;

    for (i = 0; i < 4; i++) {

    s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

    s3c2410_gpio_setpin(led_table[i], 0);

    }

    在驱动的初始化函数中经常看到,__init 前缀, 这个在下面文件中定义

    file:/include/linux/init.h

    · /* These macros are used to mark some functions or  

    ·  * initialized data (doesn't apply to uninitialized data)  

    ·  * as `initialization' functions. The kernel can take this

    ·  * as hint that the function is used only during the initialization  

    ·  * phase and free up used memory resources after  

    ·  *  

    ·  * Usage:  

    ·  * For functions:  

    ·  *  

    ·  * You should add __init immediately before the function name, like:  

    ·  *  

    ·  * static void __init initme(int x, int y)  

    ·  * {  

    ·  *    extern int z; z = x * y;  

    ·  * } 

    主要是将这个函数放在init段section中,这样可以在执行完成后,释放内存。

    void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

    {

    void __iomem *base = S3C24XX_GPIO_BASE(pin);

    unsigned long mask;

    unsigned long con;

    unsigned long flags;

    if (pin < S3C2410_GPIO_BANKB) {

    mask = 1 << S3C2410_GPIO_OFFSET(pin);

    } else {

    mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; //3<<(37*2)

    }

    switch (function) {

    case S3C2410_GPIO_LEAVE:

    mask = 0;

    function = 0;

    break;

    case S3C2410_GPIO_INPUT:

    case S3C2410_GPIO_OUTPUT:

    case S3C2410_GPIO_SFN2:

    case S3C2410_GPIO_SFN3:

    if (pin < S3C2410_GPIO_BANKB) {

    function -= 1;

    function &= 1;

    function <<= S3C2410_GPIO_OFFSET(pin);

    } else {

    function &= 3;

    function <<= S3C2410_GPIO_OFFSET(pin)*2;

    }

    }

    /* modify the specified register wwith IRQs off */

    local_irq_save(flags);

    con = __raw_readl(base + 0x00);

    con &= ~mask;

    con |= function;

    __raw_writel(con, base + 0x00);

    local_irq_restore(flags);

    }

    #define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)

    #define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

    S3C24XX_VA_GPIO这个在\arch\arm\plat-s3c24xx\include\plat\map.h中定义,这个是Memory Map的定义:

    #define S3C2410_PA_GPIO (0x56000000)

    #define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)

    #define S3C24XX_SZ_GPIO SZ_1M

    其中PA表示Physical Address,VA表示Virtual Address

    clip_image002

    由pdf中的GPIO的定义可以看出是一致的。

    /* UARTs */

    #define S3C24XX_VA_UART S3C_VA_UART

    #define S3C2410_PA_UART (0x50000000)

    #define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */

    #define S3C_ADDR(x) (S3C_ADDR_BASE + (x))

    #define S3C_ADDR_BASE (0xF4000000)

    __iomem是2.6.9中加入的特性。是用来个表示指会指向一个I/O的内存空间。主要是为了driver的通用性考虑。由于不同的CPU体系结构对 I/O空间的表示可能不同。当使用__iomem时,compiler会忽略对变量的检查(因为用的是void __iomem)。但sparse会对它进行检查,当__iomem的指针和正常的指针混用时,就会发出一些warnings

    有个地方讲不通:(这个地方应该是都不满足switch的条件,所以,function不改变)

    #define S3C2410_GPIO_LEAVE (0xFFFFFFFF)

    #define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */

    #define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)

    #define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */

    #define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */

    #define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */

    #define S3C2410_GPB5_OUTP (0x01 << 10)

    所以,

    s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);

    switch (function)

    根本对不上号?

    #define __raw_readl(p) (*(unsigned long *)(p))

    #define __raw_writel(v,p) (*(unsigned long *)(p) = (v))

    *******************************

    static struct miscdevice misc = {

    .minor = MISC_DYNAMIC_MINOR,

    .name = DEVICE_NAME,

    .fops = &dev_fops,

    };

    驱动注册时,如果次号指定MISC_DYNAMIC_MINOR则进行动态分配。

    #define DEVICE_NAME "leds"

    include\linux

    在这个头文件中主要是misc(混合)设备注册和注销:
    其它类型---不能严格划分的设备类型,也叫混合类型
    有:
    1.
    结构体:
    struct miscdevice {
        int minor;
        const char *name;
        const struct file_operations *fops;
        struct list_head list;
        struct device *parent;
        struct device *this_device;
    };
    2.
    misc设备注册:
    extern int misc_register(struct miscdevice * misc);
    misc设备注销:
    extern int misc_deregister(struct miscdevice * misc);
    说明:上面的结构体是注册混合设备所需要的参数。主要有:
    minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。利用次设备号来区分设备的。
    name:misc设备名。
    *fops:misc设备文件操作结构体。
    其它三个参数很少用。

    杂项设备(misc device)

    杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。

    也就是说,misc设备其实也就是特殊的字符设备,可自动生成设备节点。

    module_init(dev_init);

    module_exit(dev_exit);

    参考:http://blog.csdn.net/zhandoushi1982/archive/2009/12/02/4927579.aspx

  • 相关阅读:
    Window 服务安装
    SQL
    vb To c# or c# To vb
    CacheHelper-缓存
    让Linq的OrderBy支持动态字段
    哪些列上适合建立索引???
    如何查看Oracle数据库中无效的对象,约束,触发器和索引
    如何查看Oracle中被锁定的表
    ORACLE ASM
    WebLogic Server
  • 原文地址:https://www.cnblogs.com/yanhc/p/2175218.html
Copyright © 2011-2022 走看看