Led驱动程序及应用程序编写

本来打算写一下NAND驱动和网卡驱动及USB驱动的,突然发现好长时间不写驱动,写驱动的套路都忘的差不多了,而且以前写的驱动程序都不够模块化,想复用的话还需要做些修改,所以,还是先写一下LED驱动,熟悉一下套路,顺便把程序模块化了,留着以后备用。

1.先看一下LED的硬件原理图


Led驱动程序及应用程序编写_第1张图片


Led驱动程序及应用程序编写_第2张图片

根据以上两张图片内容,可以列出如下表格:

LED-number LED-net GPIO
LED1 nLED_1 GPB5
LED2 nLED_2 GPB6
LED3 nLED_3 GPB7
LED4 nLED_4 GPB8

根据电路的基本知识,IO口低电平时,LED亮,IO口高电平时,LED灭.

CMD STATE GPIO-LEVEL
ON 0
OFF 1

用下列宏可以获得主设备号和次设备号

MAJOR(dev_t dev)
MANOR(dev_t dev)

用下列宏则可以通过主设备号和次设备号生成dev_t;

MKDEV(int major,int minor)

/**
Allocates a range of char device numbers.The major number will be chosen
dynamically ,and retured(along with the first minor number)in @dev.Returns zero or negative error code.
*/
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name);
/*
This function will unregisters a range of @count device numbers,starting with @from,The
caller should normally be the one who allocated those numbers in the first place...
*/
void unregister_chrdev_region(dev_t from,unsigned count);

以上两个函数是动态分配设备号和注销设备号的函数,为了使函数可移植,使用上面两个函数处理设备号。

建立一个表格,列出成对出现的函数

Tables Are Cool
ioremap iounmap xxx

这里写图片描述
Led驱动程序及应用程序编写_第3张图片

led驱动程序-手动创建设备节点版本

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static struct cdev led_cdev;
#define NAME "LED_GPIO_TEST"

#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP  0x56000018

#define LED1 (1<<0) /*GPB5*/
#define LED2 (1<<1) /*GPB6*/
#define LED3 (1<<2) /*GPB7*/
#define LED4 (1<<3) /*GPB8*/

dev_t dev_id;
unsigned int *gpbcon;
unsigned int *gpbdat;
unsigned int *gpbup;

static int led_open(struct inode *inode,struct file *file)
{
        return 0;
}

static int led_write(struct file *filp,const char __user *buff,size_t count,loff_t *offp)
{
        unsigned char kernel_buf;
        unsigned int data;
        copy_from_user(&kernel_buf,buff,sizeof(unsigned char));
        /*off*/
        if ((kernel_buf & (1<<7)) == 0) {
                switch (kernel_buf) {
                        case LED1:
                                data = readl(gpbdat);
                                data |= (1<<5);
                                writel(data,gpbdat);
                                break;
                        case LED2:
                                data = readl(gpbdat);
                                data |= (1<<6);
                                writel(data,gpbdat);
                                break;
                        case LED3:
                                data = readl(gpbdat);
                                data |= (1<<7);
                                writel(data,gpbdat);
                                break;
                        case LED4:
                                data = readl(gpbdat);
                                data |= (1<<8);
                                writel(data,gpbdat);
                                break;
                        default:
                                printk("led_write parameter is wrong!!!\n");
                                break;
                }
        } else {        /*on*/
                kernel_buf &=(unsigned char)(~(1<<7));
                switch (kernel_buf) {
                        case LED1:
                                data = readl(gpbdat);
                                data &= ~(1<<5);
                                writel(data,gpbdat);
                                break;
                        case LED2:
                                data = readl(gpbdat);
                                data &= ~(1<<6);
                                writel(data,gpbdat);
                                break;
                        case LED3:
                                data = readl(gpbdat);
                                data &= ~(1<<7);
                                writel(data,gpbdat);
                                break;
                        case LED4:
                                data = readl(gpbdat);
                                data &= ~(1<<8);
                                writel(data,gpbdat);
                                break;
                        default:
                                printk("on led_write parameter is wrong!!!\n");
                                break;
                }
        }
        return 0;
}

static const struct file_operations led_fops = 
{
        .owner = THIS_MODULE,
        .write = led_write,
        .open = led_open
};
/**
 * gpio level
 * 0 - ON
 * 1 - OFF
 * */
static void led_gpio_init(void)
{
        unsigned int data;
        /*将IO地址空间映射到内核的虚拟地址空间上去,便于访问*/
        gpbcon =(unsigned int *) ioremap(GPBCON,4);
        gpbdat =(unsigned int *) ioremap(GPBDAT,4);
        gpbup  =(unsigned int *) ioremap(GPBUP,4);
        /*
         *GPB8 [17:16]  00 = Input 01 = Output 
         *GPB7 [15:14]  00 = Input 01 = Output 
         *GPB6 [13:12]  00 = Input 01 = Output 
         *GPB5 [11:10]  00 = Input 01 = Output 
         */
        data = readl(gpbcon);
        data &= ~(0x3 << 10 | 0x3 << 12 | 0x3 << 14|0x3 << 16);
        data |= (1 << 10 | 1 << 12 | 1 << 14 | 1 << 16);
        writel(data,gpbcon);

        data = readl(gpbdat);
        data &= ~((1<<5)| (1<<6)| (1<<7)| (1<<8)); 
        data |= (1<<5)|(1<<6)|(1<<7)|(1<<8);
        writel(data,gpbdat);
}
static int __init led_init(void)
{
        int rc;
        int error;
        rc = alloc_chrdev_region(&dev_id,0,1,NAME);
        if(rc < 0) {
                printk("alloc_chrdev_region failed\n");
                goto fail_alloc;
        }
        cdev_init(&led_cdev,&led_fops);
        led_cdev.owner = THIS_MODULE;

        error = cdev_add(&led_cdev,dev_id,1);
        if (error) {
                printk("Could not add cdev\n");
                goto fail_with_cdev;
        }
        led_gpio_init();
        return 0;
fail_with_cdev:
        unregister_chrdev_region(dev_id,1);
fail_alloc:
        return -1;
}

static void __exit led_exit(void)
{
        cdev_del(&led_cdev);
        unregister_chrdev_region(dev_id,1);
}

MODULE_LICENSE("GPL");
module_init(led_init);
module_exit(led_exit);

测试程序

#include 
#include 
#include 
#include 

#define PATHNAME "dev/LED_GPIO_TEST"

#define LED1 0
#define LED2 1
#define LED3 2
#define LED4 3

#define ON 11
#define OFF 22 

static void led_cmd(int fd,int num,int cmd);
/**
 *led control command
 *@fd - file descrip
 *@num - the led numbers
 *@cmd - command the led become ON or OFF
 */
static void led_cmd(int fd,int num,int cmd)
{
        unsigned char buf=0;
        unsigned int ret;
        /*the buf's 7th bit is 1 means ON,is 0 means OFF*/
        if (cmd == ON) 
                buf |= (1<<7);
        else if (cmd == OFF)
                buf = 0;
        buf |= (1<sizeof(buf));
        if (ret == -1)
                printf("the led_cmd func's write wrong!!!!!\n");
}

void led_poll(int fd)
{
        led_cmd(fd,LED1,ON);
        sleep(1);
        led_cmd(fd,LED2,ON);
        sleep(1);
        led_cmd(fd,LED3,ON);
        sleep(1);
        led_cmd(fd,LED4,ON);
        sleep(1);
        led_cmd(fd,LED1,OFF);
        sleep(1);
        led_cmd(fd,LED2,OFF);
        sleep(1);
        led_cmd(fd,LED3,OFF);
        sleep(1);
        led_cmd(fd,LED4,OFF);
}
int main(void)
{
        unsigned int fd;
        unsigned char cmd;
        fd = open(PATHNAME,O_WRONLY);
        if( -1 == fd) {
            printf("there is no dev node - %s\n",PATHNAME);
        }
        led_poll(fd);
        close(fd);
        return 0;
}

shell脚本

insmod led.ko
cat proc/devices
mknod dev/LED_GPIO_TEST c 252 0
ls dev/LED*

你可能感兴趣的:(linux驱动)