9.13 作业

通过字符设备驱动分布注册方式编写led驱动,完成设备文件和设备的绑定

mycdev.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "head.h"

int major = 0;
int minor = 0;
int count = 3;
char *devname = "mycdev";
char buf[128] = {0};
unsigned int *rcc; // 存放rcc的地址
gpio_t *gpioe;
gpio_t *gpiof;
struct class *cls;
struct device *dev;
struct cdev *cdev;

void led_on_off(gpio_t *gpio, short pin, unsigned int flag)
{
    switch (flag)
    {
    case LEDX_OFF:
        gpio->ODR &= ~(1 << pin);
        break;
    case LEDX_ON:
        gpio->ODR |= 1 << pin;
        break;
    case LEDX_REV:
        gpio->ODR ^= 1 << pin;
        break;
    }
}

int my_register_chrdev(const struct file_operations *fops)
{
    int flag;
    dev_t d;
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("申请字符设备驱动对象空间失败\n");
        flag = EFAULT;
        goto out1;
    }
    cdev_init(cdev, fops);

    if (major)
    {
        flag = register_chrdev_region(MKDEV(major, minor), count, devname);
    }
    else
    {
        flag = alloc_chrdev_region(&d, minor, count, devname);
        major = MAJOR(d);
        minor = MINOR(d);
    }
    if (flag)
    {
        printk("申请设备号失败\n");
        goto out2;
    }

    flag = cdev_add(cdev, MKDEV(major, minor), count);
    if (flag)
    {
        printk("注册驱动失败\n");
        goto out3;
    }
    return 0;
out3:
    unregister_chrdev_region(MKDEV(major, minor), count);
out2:
    kfree(cdev);
out1:
    return flag;
}

void my_unregister_chrdev(void)
{
    cdev_del(cdev);
    unregister_chrdev_region(MKDEV(major, minor), count);
    kfree(cdev);
}

int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    file->private_data = (void *)MINOR(inode->i_rdev);
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    long ref;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    ref = copy_to_user(ubuf, buf, size > sizeof(buf) ? size : sizeof(buf));
    if (ref)
    {
        printk("copy_to_user err\n");
        return -EIO;
    }
    return ref;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    long ref;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    ref = copy_from_user(buf, ubuf, size > sizeof(buf) ? size : sizeof(buf));
    if (ref)
    {
        printk("copy_from_user err\n");
        return -EIO;
    }
    return ref;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int min;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    min = (int)file->private_data;
    if (minor == min)
    {
        led_on_off(gpioe, 10, cmd);
    }
    else if (minor + 1 == min)
    {
        led_on_off(gpiof, 10, cmd);
    }
    else if (minor + 2 == min)
    {
        led_on_off(gpioe, 8, cmd);
    }
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    int flag,i,j;
    // 注册
    flag = my_register_chrdev(&fops);
    if (flag < 0)
    {
        printk("注册失败\n");
        goto out1;
    }
    printk("success major=%d\n", major);

    // 物理内存映射
    rcc = ioremap(RCC, 4);
    flag = -EFAULT;
    if (!rcc)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        goto out2;
    }
    gpioe = ioremap(GPIOE, sizeof(gpio_t));
    if (!gpioe)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        goto out3;
    }
    gpiof = ioremap(GPIOF, sizeof(gpio_t));
    if (!gpiof)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        goto out4;
    }

    // 使能
    *rcc |= 3 << 4;
    gpioe->MODER &= ~(3 << 20);
    gpioe->MODER |= 1 << 20;
    gpioe->MODER &= ~(3 << 16);
    gpioe->MODER |= 1 << 16;
    gpiof->MODER &= ~(3 << 20);
    gpiof->MODER |= 1 << 20;

    cls = class_create(THIS_MODULE, devname);
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        flag = -PTR_ERR(cls);
        goto out5;
    }
    printk("向上提交目录成功\n");

    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, minor + i), NULL, "%s%d", devname, minor + i);
        if (IS_ERR(cls))
        {
            printk("向上提交设备节点失败\n");
            flag = -PTR_ERR(cls);
            goto out6;
        }
    }
    printk("向上提交设备节点成功\n");

    return 0;

out6:
    for (j = 0; j < i; j++)
    {
        device_destroy(cls, MKDEV(major, minor + j));
    }
    class_destroy(cls);
out5:
    iounmap(gpiof);
out4:
    iounmap(gpioe);
out3:
    iounmap(rcc);
out2:
    my_unregister_chrdev();
out1:
    return flag;
}

static void __exit mycdev_exit(void)
{
    int i;
    for (i = 0; i < count; i++)
    {
        device_destroy(cls, MKDEV(major, minor + i));
    }
    class_destroy(cls);
    // 取消物理内存映射
    iounmap(rcc);
    iounmap(gpiof);
    iounmap(gpioe);
    // 取消注册
    my_unregister_chrdev();
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

#define RCC 0x50000a28
typedef struct{
    unsigned int MODER;
    unsigned int OTYPER;
    unsigned int OSPEEDR;
    unsigned int PUPDR;
    unsigned int IDR;
    unsigned int ODR;
}gpio_t;

#define GPIOE 0x50006000
#define GPIOF 0x50007000

#define LEDX_ON _IO('l',1)
#define LEDX_OFF _IO('l',0)
#define LEDX_REV _IO('l',2)

#endif

test.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "head.h"

int main()
{
    char buf[128] = {0};
    int fd0 = open("/dev/mycdev0", O_RDWR);
    int fd1 = open("/dev/mycdev1", O_RDWR);
    int fd2 = open("/dev/mycdev2", O_RDWR);
    if (fd0 < 0|fd1 < 0|fd2 < 0)
    {
        printf("文件打开失败\n");
        return -1;
    }
    int t;
    while (1)
    {
        ioctl(fd0, LEDX_REV);
        sleep(1);
        ioctl(fd0, LEDX_REV);
        sleep(1);
        ioctl(fd1, LEDX_REV);
        sleep(1);
        ioctl(fd1, LEDX_REV);
        sleep(1);
        ioctl(fd2, LEDX_REV);
        sleep(1);
        ioctl(fd2, LEDX_REV);
        sleep(1);
    }
    close(fd0);
    close(fd1);
    close(fd2);

    return 0;
}

你可能感兴趣的:(c)