首页 > 代码库 > Android 从硬件到应用:一步一步向上爬 1 -- 从零编写底层硬件驱动程序

Android 从硬件到应用:一步一步向上爬 1 -- 从零编写底层硬件驱动程序

硬件平台:TI AM335X Starter Kit

开发源码:TI-Android-ICS-4.0.3-DevKit-EVM-SK-3.0.1.bin

主机系统:Ubuntu 10.04

       这次写《Android 从硬件到应用》是想尝试从底层的最简单的GPIO硬件驱动开始,一步一步的向上走,经过硬件抽象层HAL、JNI方法等,最终编写出APP,达到硬件调用的目的,期间会增加一些Android下C程序测试底层驱动的细节。既然是从零编写驱动,那就要脱离源码包里已有的一些api函数,从硬件电路开始。找到EVM板GPIO处原理图:

       我要控制LED D1的状态,如上图所示,D1接了Q4,也就是BSS138,N沟道的MOS器件,AM335X_GPIO_LED4为高电平时,Q4的栅极漏极导通,D1为亮,反之,灭。首先设置GPIO时钟:

一、CM_PER_GPIO1_CLKCTRL:地址0x44E000AC 要装载的值为 0x00040002

接着设置GPIO1输出使能:

二、GPIO_OE:地址0x4804C134 要装载的值为 0x0

然后设置输出GPIO1的输出:

三、GPIO_DATAOUT:地址0x4804C13C 要装载的值为 0x00000010或者是0x00000000,让AM335X_GPIO_LED4引脚为高或低,这样D1就可以亮灭

编写驱动程序 android_gpio.c:移到drivers/char目录下

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/uaccess.h> /* copy_to_user,copy_from_user */  
#include <linux/miscdevice.h>  
#include <linux/device.h>  
#include <asm/io.h>  
  
static struct class  *gpio_class;  
  
volatile unsigned long *DIR;  
volatile unsigned long *DAT; 
volatile unsigned long *CLK; 
  
int gpio_open (struct inode *inode,struct file *filp)  
  
{  
    *CLK = 0x00040002; //Enable
    *DIR = (*DIR)&0xffffffef;  //output  
    return 0;  
}  
  
ssize_t gpio_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)  
{  
    return 0;  
}  
  
ssize_t gpio_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)  
{  
    char val_buf[2];  
    int ret;  
    ret = copy_from_user(val_buf,buf,count);  
          
    switch(val_buf[0])  
    {  
        case 0x31 :  
            *DAT = (*DAT)|0x00000010;  
            break;  
        case 0x30 :  
            *DAT = (*DAT)&0xffffffef;         
            break;  
        default :  
            break;  
    }  
    return count;  
}  
  
struct file_operations gpio_fops =  
{  
    .owner   = THIS_MODULE,  
    .open    = gpio_open,  
    .read    = gpio_read,  
    .write   = gpio_write,  
} ;  
  
int major;  
int gpio_init (void)  
{     
      
    major = register_chrdev(0,"Android_gpio",&gpio_fops);  
    gpio_class = class_create(THIS_MODULE, "Android_gpio");  
    device_create(gpio_class,NULL,MKDEV(major,0),NULL,"AdrIO");  
  
    DIR = (volatile unsigned long *)ioremap(0x4804C134,4);  
    DAT = (volatile unsigned long *)ioremap(0x4804C13C,4);  
    CLK = (volatile unsigned long *)ioremap(0x44E000AC,4);

    printk ("gpio is ready\n");  
    return 0;  
}  
  
void gpio_exit (void)  
{  
    unregister_chrdev(major,"Android_gpio");  
    device_destroy(gpio_class,MKDEV(major,0));  
    class_destroy(gpio_class);  
  
    iounmap(DIR);  
    iounmap(DAT);  
    iounmap(CLK);
  
    printk ("module exit\n");  
    return ;  
}  
  
MODULE_LICENSE("GPL");  
module_init(gpio_init);  
module_exit(gpio_exit); 
打开drivers/char目录下的Makefile,增加:

obj-$(CONFIG_ANDROID_GPIO)	+= android_gpio.o
打开drivers/char目录下的Kconfig,增加:

config ANDROID_GPIO
       tristate "android gpio enable"
       default y
源码目录下执行:

make ARCH=arm CROSS_COMPILE=arm-eabi- uImage

生成uImage,重新启动新系统,ls /dev 查看设备:

# ls /dev                                                      
AdrIO                                                                         
alarm                                                                          
android_adb                                                                
ashmem                                                                      
binder                                                                         
block                                                                           
bus 

发现AdrIO设备,第一步完成,注意在操作物理地址时一定要对位进行操作,不然

GPIO1会影响到AM335X Starter Kit的LCD显示,下一步就要执行C程序测试该驱动。

Android 从硬件到应用:一步一步向上爬 1 -- 从零编写底层硬件驱动程序