利用IOCTL点亮LED灯

目的:通过ioctl传递命令码,实现在终端输入指定命令点灯

具体代码

1.驱动代码

#include 
#include 
#include 
#include 
#include "mycled.h"
#include 
#include 
#define Cname "mycled"

char kbuf[128] = {0};
unsigned int *rcc_gpio;
unsigned int *gpioe_moder;
unsigned int *gpioe_odr;
unsigned int *gpiof_moder;
unsigned int *gpiof_odr;
struct class *cls;
struct device *dev;
ssize_t my_read(struct file *file, char __user *ubuf, size_t t, loff_t *lt)
{
    // int ret;
    // printk("this is %s\n", __func__);
    // if (t > sizeof(kbuf))
    //     t = sizeof(kbuf);
    // ret = copy_to_user(ubuf, kbuf, t);
    // if (ret)
    // {
    //     printk("recive faild\n");
    //     return -EIO;
    // }
    return 0;
}
ssize_t my_write(struct file *file, const char __user *ubuf, size_t t, loff_t *lt)
{
    // int ret;
    // printk("this is %s\n", __func__);
    // if (t <= sizeof(kbuf))
    // {
    //     ret = copy_from_user(kbuf, ubuf, t);
    // }
    // else
    // {
    //     ret = copy_from_user(kbuf, ubuf, sizeof(kbuf));
    // }
    // if (ret)
    // {
    //     printk("recive faild\n");
    //     return -EIO;
    // }
    // if (kbuf[0] == '2')
    // {
    //     *gpioe_odr &= (~(0x1 << 10));
    // }
    // else if (kbuf[0] == '1')
    // {
    //     *gpioe_odr |= ((0x1 << 10));
    // }
    // else if (kbuf[0] == '3')
    // {
    //     *gpiof_odr |= ((0x1 << 10));
    // }
    // else if (kbuf[0] == '4')
    // {
    //     *gpiof_odr &= (~(0x1 << 10));
    // }
    // else if (kbuf[0] == '5')
    // {
    //     *gpioe_odr |= ((0x1 << 8));
    // }
    // else if (kbuf[0] == '6')
    // {
    //     *gpioe_odr &= (~(0x1 << 8));
    // }

    return 0;
}
int my_open(struct inode *inode, struct file *file)
{
    //LED初始化
    printk("this is %s\n", __func__);
    rcc_gpio = ioremap(PHY_RCC_GPIO, 4);
    if (rcc_gpio == NULL)
    {
        printk("rcc_gpio error\n");
        return -ENOMEM;
    }
    gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
    if (gpioe_moder == NULL)
    {
        printk("gpioe_moder error\n");
        return -ENOMEM;
    }
    gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
    if (gpioe_odr == NULL)
    {
        printk("gpioe_odr error\n");
        return -ENOMEM;
    }
    gpiof_moder = ioremap(PHY_GPIOF_MODER, 4);
    if (gpiof_moder == NULL)
    {
        printk("gpiof_moder error\n");
        return -ENOMEM;
    }
    gpiof_odr = ioremap(PHY_GPIOF_ODR, 4);
    if (gpiof_odr == NULL)
    {
        printk("gpiof_odr error\n");
        return -ENOMEM;
    }
    *rcc_gpio |= (0x1 << 4);
    *rcc_gpio |= (0x1 << 5);
    *gpioe_moder &= (~(0x3 << 20));
    *gpioe_moder |= (0x1 << 20);
    *gpioe_moder &= (~(0x3 << 16));
    *gpioe_moder |= (0x1 << 16);
    *gpiof_moder &= (~(0x3 << 20));
    *gpiof_moder |= (0x1 << 20);
    *gpioe_odr &= (~(0x1 << 10));
    *gpioe_odr &= (~(0x1 << 8));
    *gpiof_odr &= (~(0x1 << 10));

    return 0;
}
int my_close(struct inode *inode, struct file *file)
{
    printk("this is %s\n", __func__);
    return 0;
}
long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int data;
    int ret;
    switch (cmd)
    {
    case LED_ON:
        ret = copy_from_user(&data, (int *)arg, sizeof(int));
        if (ret)
        {
            printk("recive faild\n");
            return -EIO;
        }
        switch (data)
        {
        case 0:
            *gpioe_odr |= ((0x1 << 10));
            break;
        case 1:
            *gpiof_odr |= ((0x1 << 10));
            break;
        case 2:
            *gpioe_odr |= ((0x1 << 8));
            break;

        default:
            break;
        }
        break;
    case LED_OFF:
        ret = copy_from_user(&data, (int *)arg, sizeof(int));
        if (ret)
        {
            printk("recive faild\n");
            return -EIO;
        }
        switch (data)
        {
        case 0:
            *gpioe_odr &= (~(0x1 << 10));
            break;
        case 1:
            *gpiof_odr &= (~(0x1 << 10));
            break;
        case 2:
            *gpioe_odr &= (~(0x1 << 8));
            break;

        default:
            break;
        }
        break;
    default:
        break;
    }
    return 0;
}
struct file_operations fops =
    {
        .open = my_open,
        .release = my_close,
        .read = my_read,
        .write = my_write,
        .unlocked_ioctl = my_ioctl,
};
int major; // 存放主设备号
static int __init mycdev_init(void)
{
    major = register_chrdev(0, Cname, &fops); // 申请设备号
    if (major > 0)
    {
        printk("major create sucess major= %d\n", major);
    }
    else
    {
        printk("major create fault\n");
        return major;
    }
    cls = class_create(THIS_MODULE, "led");
    if (IS_ERR(cls))
    {
        printk("class create error\n");
        return PTR_ERR(cls);
    }
    printk("class create success\n");
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycled");
    if (IS_ERR(dev))
    {
        printk("device create error\n");
        return PTR_ERR(dev);
    }
    printk("device create success\n");

    return 0;
}
static void __exit mycdev_exit(void)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, Cname);
    iounmap(rcc_gpio);
    iounmap(gpioe_moder);
    iounmap(gpioe_odr);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

1.2驱动头文件

#ifndef __MYCLED_H__
#define __MYCLED_H__
#define PHY_RCC_GPIO 0x50000A28
#define PHY_GPIOE_MODER 0x50006000
#define PHY_GPIOE_ODR 0x50006014
#define PHY_GPIOF_MODER 0x50007000
#define PHY_GPIOF_ODR 0x50007014
#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
#endif

1.3应用层测试代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "mycled.h"
int fd;
char buf[128] = {0};
pthread_t thread;
int data=0;
void LED1_ON(void)
{
    data=0;
    ioctl(fd,LED_ON,&data);
}
void LED1_OFF(void)
{
    data=0;
    ioctl(fd,LED_OFF,&data);
}
void LED2_ON(void)
{
    data=1;
    ioctl(fd,LED_ON,&data);
}
void LED2_OFF(void)
{
    data=1;
    ioctl(fd,LED_OFF,&data);
}
void LED3_ON(void)
{
    data=2;
    ioctl(fd,LED_ON,&data);
}
void LED3_OFF(void)
{
    data=2;
    ioctl(fd,LED_OFF,&data);
}
void *callBack(void *arg)
{
    while (1)
    {
        if (buf[0] == 'l')
        {  
                data = data %3;
                ioctl(fd,LED_ON,&data);
                sleep(1);
                ioctl(fd,LED_OFF,&data);
                data++;
        }
         else if (buf[0] == 'q')
        {
            pthread_exit(NULL);
        }
        else if (buf[0]=='1')
        {
            LED1_ON();
        }
        else if (buf[0]=='2')
        {
            LED1_OFF();
        }
        else if (buf[0]=='3')
        {
            LED2_ON();
        }
        else if (buf[0]=='4')
        {
            LED2_OFF();
        }
        else if (buf[0]=='5')
        {
            LED3_ON();
        }
        else if (buf[0]=='6')
        {
            LED3_OFF();
        }
    }
    return NULL;
}
int main(int argc, const char *argv[])
{
    fd = open("/dev/mycled", O_RDWR);
    if (fd < 0)
    {
        perror("open error");
    }
    pthread_create(&thread, NULL, callBack, NULL);  //利用多线程
   
    while (1)
    {
        printf("请输入--->: 1(led1开灯) 2(led1关灯) 3(led2开灯) 4(led2关灯) 5(led3开灯) 6(led3关灯)l(流水灯)\n");
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf) - 1] = 0;
        if(buf[0]=='q')
        {
           sleep(1);
            break;
        }
    }
    close(fd);
    return 0;
}

实验结果

利用IOCTL点亮LED灯_第1张图片

 

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