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

来源:互联网 发布:安全知识网络答题活动 编辑:程序博客网 时间:2024/05/17 12:00
#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);
0 0