驱动开发 串口输入ECHO点灯

华清远见上海中心22071班

串口输入

echo 1 > /dev/myled0 ---->led1灯点亮

echo 0 > /dev/myled0 ---->led1灯熄灭

echo 1 > /dev/myled1 ---->led1灯点亮

echo 0 > /dev/myled1 ---->led1灯熄灭

echo 1 > /dev/myled2 ---->led1灯点亮

echo 0 > /dev/myled2 ---->led1灯熄灭

 

 

 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "led.h"

#if 0
#define LED_MAJOR 500
#else
#define LED_MAJOR 0
#endif

#define COUNT 3
#define SEQNUM 0
#define DRIVERNAME "myled"

struct cdev *ledcdev;
struct class *cls;
struct device *dce;
volatile unsigned int *virt_RCC;
volatile gpio_t *virt_gpioe;
volatile gpio_t *virt_gpiof;
int major = LED_MAJOR;
int minor = 0;

int mycdevopen(struct inode *inode, struct file *file)
{
    int ledmajor, ledminor;
    ledmajor = MAJOR(inode->i_rdev);
    ledminor = MINOR(inode->i_rdev);
    printk("ledmajor=%d ledminor = %d\n", ledmajor, ledminor);
    printk("open success\n");
    file->private_data = (void *)(ledminor);
    return 0;
}

int mycdevrelease(struct inode *inode, struct file *file)
{
    printk("release success\n");
    return 0;
}

ssize_t mycdevread(struct file *file, char __user *ubuf, size_t size, loff_t *loffs)
{
    return 0;
}

ssize_t mycdevwrite(struct file *file, const char __user *ubuf, size_t size, loff_t *loffs)
{
    int ledminor;
    unsigned long res;
    char kbuf[128] = "";
    ledminor = (int)file->private_data;

    switch (ledminor)
    {

    case 0:
        if (size > sizeof(kbuf))
        {
            size = sizeof(kbuf);
        }

        res = copy_from_user(kbuf, ubuf, size);
        if (res)
        {
            printk("copy_from_user failed (err %ld)", res);
            return res;
        }
        if ('0' == kbuf[0])
        {
            virt_gpioe->ODR &= (~(0x1 << 10));
        }
        else
        {
            virt_gpioe->ODR |= (0x1 << 10);
        }
        break;
    case 1:
        if (size > sizeof(kbuf))
        {
            size = sizeof(kbuf);
        }

        res = copy_from_user(kbuf, ubuf, size);
        if (res)
        {
            printk("copy_from_user failed (err %ld)", res);
            return res;
        }
        if ('0' == kbuf[0])
        {
            virt_gpiof->ODR &= (~(0x1 << 10));
        }
        else
        {
            virt_gpiof->ODR |= (0x1 << 10);
        }
        break;
    case 2:
        if (size > sizeof(kbuf))
        {
            size = sizeof(kbuf);
        }

        res = copy_from_user(kbuf, ubuf, size);
        if (res)
        {
            printk("copy_from_user failed (err %ld)", res);
            return res;
        }
        if ('0' == kbuf[0])
        {
            virt_gpioe->ODR &= (~(0x1 << 8));
        }
        else
        {
            virt_gpioe->ODR |= (0x1 << 8);
        }
        break;
    }
    return size;
}

struct file_operations fops = {
    .open = mycdevopen,
    .read = mycdevread,
    .write = mycdevwrite,
    .release = mycdevrelease};

static int __init
led_init(void)
{
    int res, i;
    dev_t devt;
    // cdev的创建
    ledcdev = cdev_alloc();
    if (NULL == ledcdev)
    {
        printk("cdev alloc failed\n");
        res = -ENOMEM;
        goto ERR1;
    }

    // cdev的初始化
    cdev_init(ledcdev, &fops);

    // 条件判断是否动/静态注册设备号
    if (LED_MAJOR > 0)
    {
        res = register_chrdev_region(MKDEV(LED_MAJOR, SEQNUM), COUNT, DRIVERNAME);
        if (res)
        {
            printk("Unable to register char major %d\n", LED_MAJOR);
            goto ERR2;
        }
        major = LED_MAJOR;
        minor = SEQNUM;
    }
    else
    {
        res = alloc_chrdev_region(&devt, 0, COUNT, DRIVERNAME);
        if (res)
        {
            printk("Could not allocate chrdev region (err %d)\n", -res);
            goto ERR2;
        }
        major = MAJOR(devt);
        minor = MINOR(devt);
    }

    // 字符设备驱动添加至系统
    res = cdev_add(ledcdev, MKDEV(major, minor), COUNT);
    if (res)
    {
        printk("Unable register character device add (err %d)\n", -res);
        goto ERR3;
    }

    // 上传目录
    cls = class_create(THIS_MODULE, DRIVERNAME);
    if (IS_ERR(cls))
    {
        res = PTR_ERR(cls);
        printk("Class create failed (err %d)\n", -res);
        goto ERR4;
    }

    // 上传节点
    for (i = 0; i < COUNT; i++)
    {
        dce = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dce))
        {
            res = PTR_ERR(dce);
            printk("Device create failed (err %d)\n", res);
            goto ERR5;
        }
    }

    //映射RCC_MP_AHB4ENSETR
    virt_RCC = (unsigned int *)ioremap(RCC, 4);
    if (NULL == virt_RCC)
    {
        printk("rcc ioremap failed\n");
        return -ENOMEM;
    }

    //映射gpioe的地址
    virt_gpioe = (gpio_t *)ioremap(GPIOE, sizeof(gpio_t));
    if (NULL == virt_gpioe)
    {
        printk("gpioe ioremap failed\n");
        return -ENOMEM;
    }

    //映射gpiof的地址
    virt_gpiof = (gpio_t *)ioremap(GPIOF, sizeof(gpio_t));
    if (NULL == virt_gpiof)
    {
        printk("gpiof ioremap failed\n");
        return -ENOMEM;
    }

    // RCC使能GPIOE,GPIOF
    *virt_RCC |= (0x1 << 4);
    *virt_RCC |= (0x1 << 5);

    // PE10,PE8设置为输出模式[21:20]=01 [17:16]=01
    virt_gpioe->MODER &= (~(0x3 << 20));
    virt_gpioe->MODER |= (0x1 << 20);

    virt_gpioe->MODER &= (~(0x3 << 16));
    virt_gpioe->MODER |= (0x1 << 16);
    // PF10设置为输出模式[21:20]=01
    virt_gpiof->MODER &= (~(0x3 << 20));
    virt_gpiof->MODER |= (0x1 << 20);

    //初始化PE10,PE8,PF10为熄灭状态
    virt_gpiof->ODR &= (~(0x1 << 10));
    virt_gpioe->ODR &= (~(0x1 << 10));
    virt_gpioe->ODR &= (~(0x1 << 8));
    return 0;
ERR5:
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
ERR4:
    cdev_del(ledcdev);
ERR3:
    unregister_chrdev_region(MKDEV(major, minor), COUNT);
ERR2:
    kfree(ledcdev);
ERR1:
    return res;
}

static void __exit led_exit(void)
{
    int i;
    iounmap(virt_RCC);
    iounmap(virt_gpioe);
    iounmap(virt_gpiof);
    for (i = 0; i < COUNT; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
    cdev_del(ledcdev);
    unregister_chrdev_region(MKDEV(major, minor), COUNT);
    kfree(ledcdev);
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值