字符设备实例(学习笔记)

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/fs.h>           /* everything... */
#include <linux/interrupt.h>    /* request_irq() */
#include <linux/delay.h>        /* mdelay() */
#include <linux/device.h>       /*class_create()*/
#include <linux/slab.h>

#include <asm/uaccess.h>  



#ifndef LED_MAJOR
#define LED_MAJOR 0
#endif
#define DEVICENAME "led"
int led_major = LED_MAJOR;
int led_minor = 0;

static unsigned char led_inc = 0;

static struct class *led_class;

static char kbuf[50];

struct led_dev 
{
    unsigned long     size;
    struct semaphore  sem;
    struct cdev       cdev;
};
struct led_dev *led_dev;//定义一个设备结构体指针

static ssize_t led_open(struct inode *inode, struct file *filp)
{
    struct led_dev *dev;

    if(led_inc)
    {
        printk(KERN_NOTICE,"led has already opend begin");
        return -ERESTARTSYS;
    }
    led_inc++;
    dev = container_of(inode->i_cdev,struct led_dev,cdev);
    filp->private_data = dev ;

    printk("led dev opend");

    return 0;
}

static ssize_t led_read(struct file *filp, char *buf, size_t count, loff_t *f_ops)
{
 
      if(copy_to_user(buf, kbuf, count))
      {
            return -EFAULT;
      }
            printk("read led dev OK\n");
      return sizeof(int); //return the write cont
}

static ssize_t led_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
 
  if(copy_from_user(kbuf, buf, len))
  {
    return -EFAULT;
  }
  printk("write led dev OK\n");
  return sizeof(int); //return the write cont
}

static int led_release(struct inode *inode, struct file *filp)
{
      printk("close led dev OK\n");
      led_inc--;
      return 0;
}

struct file_operations led_fops = {
    .owner   = THIS_MODULE,
    .open    = led_open,
    .read    = led_read,
    .write   = led_write,
    //.unlocked_ioctl   = led_ioctl,
    .release = led_release,
};

static int __init led_init(void)
{
    int result;
    unsigned dev_cont = 1;//定义设备数
    dev_t led_dev_t;//定义led 设备号变量

    if(led_major){
        //获取设备号
        led_dev_t = MKDEV(led_major,led_minor);
        result = register_chrdev_region(led_dev_t, dev_cont, DEVICENAME);
    }
    else {
    //动态获取设备号
        result = alloc_chrdev_region(&led_dev_t, led_minor, dev_cont,DEVICENAME);
        led_major = MAJOR(led_dev_t);
    }
    if(result < 0)
    {
        printk(KERN_WARNING,"get majot fail!!!\n");
        return result;
    }
    //在内核中为设备申请空间
    led_dev = kmalloc( sizeof(struct led_dev),GFP_KERNEL);
    if(!led_dev)
    {
        unregister_chrdev_region(led_dev_t, 1);
        return -ENOMEM;
    }
    memset(led_dev,0,sizeof(struct led_dev));


    cdev_init(&led_dev->cdev,&led_fops);
    result = cdev_add(&led_dev->cdev,led_dev_t,1);


    // 加载模块是 自动创建设备节点
    led_class = class_create(THIS_MODULE,"Led_class");
    device_create(led_class,NULL,MKDEV(led_major,led_minor),NULL,DEVICENAME);


    if(result < 0)
    {
        kfree(led_dev);
        unregister_chrdev_region(led_dev_t, 1);
        printk(KERN_NOTICE,"add led device fail !!!!\n");
    }
    return result;
}

static void led_exit(void)
{
    dev_t led_dev_t;


    led_dev_t = MKDEV(led_major,led_minor);
    if(led_dev){
        cdev_del(&led_dev->cdev);
        kfree(led_dev);
    }
    unregister_chrdev_region(led_dev_t, 1);
    //  卸载模块时 自动删除设备节点
    device_destroy(led_class, MKDEV(led_major, led_minor));
    class_destroy(led_class);

}

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值