linux设备驱动里的cdev字符设备

一个先前在2440板子上跑过的cdev字符设备的例子。整理一下

mygpio.c

#include <linux/module.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <asm/io.h>

#include "mygpio.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zl");

/*
 *注: 调用request_mem_region()不是必须的,但是建议使用。该函数的任务是检查申请的资源是否可用,如果可用则申请成功,并标志为已经使用,其他驱动想再申请该资源时就会失败。
 */

struct  mygpio_device {
    unsigned long io_phys, io_virt;
    volatile unsigned long *gpfcon, *gpfdat, *gpfup;
    void (*on)(struct mygpio_device *);
    void (*off)(struct mygpio_device *);

    struct cdev dev;
    dev_t   no;
};

void led_on(struct  mygpio_device* mydev)
{
    *(mydev->gpfcon) &= ~(0x3 << 8);
    *(mydev->gpfcon) |= (0x1 << 8);

    *(mydev->gpfup) |= (0x1 << 4);
    *(mydev->gpfdat) &= ~(0x1 << 4);
}

void led_off(struct  mygpio_device* mydev)
{
    *(mydev->gpfcon) &= ~(0x3 << 8);
    *(mydev->gpfcon) |= (0x1 << 8);

    *(mydev->gpfup) |= (0x1 << 4);
    *(mydev->gpfdat) |= (0x1 << 4);
}

int init_gpiodev(struct  mygpio_device* mydev)
{
    int ret = 0;
    struct  resource *res = NULL;
    mydev->io_phys = 0x56000000;

    res = request_mem_region(mydev->io_phys, SZ_4K, "mygpio device");
    if(NULL == res)
    {
        ret = -EBUSY;
        printk("request_mem_region failed!\n");

        return  ret;
    }

    mydev->io_virt = (unsigned long)ioremap(mydev->io_phys, SZ_4K);
    mydev->gpfcon = (volatile unsigned long *)(mydev->io_virt + 0x50);
    mydev->gpfdat = (volatile unsigned long *)(mydev->io_virt + 0x54);
    mydev->gpfup  = (volatile unsigned long *)(mydev->io_virt + 0x58);

    mydev->on = led_on;
    mydev->off = led_off;

    return  ret;
}

void destory_gpiodev(struct  mygpio_device* mydev)
{
    release_mem_region(mydev->io_phys, SZ_4K);
    iounmap((void*)mydev->io_virt);

    mydev->on = NULL;
    mydev->off = NULL;
}

struct mygpio_device my_dev;

ssize_t my_write(struct file *fp, const char __user *buf, size_t count, loff_t *off)
{
    return  0;
}

ssize_t my_read(struct file *fp, char __user *buf, size_t count, loff_t *off)
{
    return  0;
}

ssize_t my_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    int ret;
    struct  mygpio_device *mydev = fp->private_data;
    switch(cmd) {
        case LED_ON:
            mydev->on(mydev);
        break;
    
        case LED_OFF:
            mydev->off(mydev);
        break;

        default:
            ret = -EINVAL;
        break;
    }
    return  0;
}

loff_t my_lseek (struct file *fp, loff_t offset, int whence)
{
    return  0;
}

int my_open(struct inode *no, struct file *fp)
{
    //Note: How did the open function get the device struct.
    fp->private_data = container_of(no->i_cdev, struct mygpio_device, dev);

    return  0;
}

int my_release(struct inode *no, struct file *fp)
{
    return  0;
}

struct file_operations my_ops = {
	.open = my_open,
	.release = my_release,
	.read = my_read,
	.write = my_write,
	.unlocked_ioctl = my_ioctl,
	.llseek =  my_lseek,
};

int test_init(void)
{
    int ret;
    ret = init_gpiodev(&my_dev);
    if(0 != ret)
    {
        printk("init_gpiodev.\n");
        goto err0;
    }

    my_dev.no = MKDEV(52,0);
    ret = register_chrdev_region(my_dev.no, 1, "mygpio_dev");
    if(0 != ret)
    {
        printk("register_chrdev_region.\n");
        goto err1;
    }

    cdev_init(&my_dev.dev, &my_ops);
    cdev_add(&my_dev.dev, my_dev.no, 1);

    return  0;
err1:
    destory_gpiodev(&my_dev);
err0:
    return  ret;
}

void test_exit(void)
{
    cdev_del(&my_dev.dev);
    unregister_chrdev_region(my_dev.no, 1);
    destory_gpiodev(&my_dev);
}

module_init(test_init);
module_exit(test_exit);

ioctl函数用到的命令,单独定义在.h文件中:mygpio.h

#ifndef __MYGPIO_H__
#define __MYGPIO_h__

#define LED_TYPE 'Z'
#define LED_ON      _IOW(LED_TYPE, 0x0, int)
#define LED_OFF     _IOW(LED_TYPE, 0x1, int)

#endif /*__MYGPIO_H__*/

Makefile

KERNELDIR = /lib/modules/$(shell uname -r)/build

default:
	make -C $(KERNELDIR)	M=$(shell pwd)	modules
clean:
	make -C $(KERNELDIR)	M=$(shell pwd)	modules clean

obj-m	+= mygpio.o

编译生成mygpio.ko文件

验证代码

app.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "mygpio.h"

int parse_command(const char *cmd)
{
    if (!strncasecmp(cmd, "on", 2)) {
        return LED_ON;
    } else if (!strncasecmp(cmd, "off", 3)) {
        return LED_OFF;
    } else {
	return 0x55;
    }
}

int main(int argc, char **argv)
{
    int fd;
    if (argc < 3) {
	printf("Usage: %s <file> <on | off>\n", argv[0]);
	return 0;
    }  

    fd = open(argv[1], O_RDWR);
    if (ioctl(fd, parse_command(argv[2]))) 	{
	perror("ioctl failed");
    }

    close(fd);
}

创建设备文件: mknod led_node c 52 0

编译生成app,执行./app led_node on 

                                ./app led_node off

查看对应led灯点亮/灭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值