Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1213139
  • 博文数量: 261
  • 博客积分: 4196
  • 博客等级: 上校
  • 技术积分: 3410
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-17 17:05
文章分类

全部博文(261)

文章存档

2018年(1)

2017年(22)

2016年(2)

2015年(8)

2014年(27)

2013年(40)

2012年(161)

分类: LINUX

2013-03-13 14:40:35

Misc(或miscellaneous)驱动是一些拥有着共同特性的简单字符设备驱动。内核抽象出这些特性而形成一些API(在文件 drivers/char/misc.c中实现),以简化这些设备驱动程序的初始化。所有的misc设备被分配同一个主设备号 MISC_MAJOR(10),但是每一个可以选择一个单独的次设备号。如果一个字符设备驱动要驱动多个设备,那么它就不应该用misc设备来实现。如下:
================================================================================================
.c文件:
/*
 *  this is just a led driver test
 *  just for fun and train
 *
 *  author : hyy
 *  time : 2012-08-31 11:21:20
 *
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  "my_led.h"


static int b_flg = 0;
struct cdev *led_device;
struct class *myclass;
static struct tast_struct * led_th=NULL;
unsigned int GpioId;
static unsigned long led_table[] =
{
    ((0x02DC << 16) | (2)),//GPIO2_2_GPIO,//MFP_PIN_GPIO2_2,//blue
    ((0x02E0 << 16) | (3)),//GPIO3_2_GPIO,//MFP_PIN_GPIO3_2,//yellow
    ((0x02E4 << 16) | (4)),//GPIO4_2_GPIO,//MFP_PIN_GPIO4_2,//green
    ((0x02E8 << 16) | (5)),//GPIO5_2_GPIO,//MFP_PIN_GPIO5_2,//red
    ((0x04E0 << 16) | (83)),//GPIO83_GPIO,//MFP_PIN_GPIO83,//keypad backlight
};

static int __init light_init(void);
static void __exit light_exit (void);
int light_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
int light_open(struct inode *inode, struct file *filp);
int light_release(struct inode *inode, struct file *filp);
static void blink_led(int i);

static void blink_led(int i)
{
    pdeg(" my_led debug message: ");
    GpioId = mfp_to_gpio(led_table[i]);
    gpio_direction_output(GpioId,LED_ON);
    msleep(125);
    gpio_direction_output(GpioId,LED_OFF);
    msleep(125);
    gpio_direction_output(GpioId,LED_ON);
    msleep(125);
    gpio_direction_output(GpioId,LED_OFF);
    msleep(125);
}

int light_release(struct inode *inode, struct file *filp)
{
    pdeg(" my_led debug message: ");
    return 0;
}

int light_open(struct inode *inode, struct file *filp)
{
    pdeg(" my_led debug message: ");
    
    return 0;
}

int light_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{

    int i = 0;

    pdeg(" my_led debug message: ");

    if (arg > 5 && arg < 0 ) {
        error("arg must in 0 ~ 5\n");
        return -EINVAL;
    }

   switch(cmd) {
    case CMD_LED_OFF:
        if (arg == 5 ) {
            for (i = 0 ; i <5 ; i++ ) {
                GpioId = mfp_to_gpio(led_table[i]);
                gpio_direction_output(GpioId,LED_OFF);
            }
        }else {
            GpioId = mfp_to_gpio(led_table[arg]);
            gpio_direction_output(GpioId,LED_OFF);
        }
        break;
    case CMD_LED_ON:
        if (arg == 5 ) {
            for (i = 0 ; i <5 ; i++ ) {
                GpioId = mfp_to_gpio(led_table[i]);
                gpio_direction_output(GpioId,LED_ON);
            }
        }else {
            GpioId = mfp_to_gpio(led_table[arg]);
            gpio_direction_output(GpioId,LED_ON);
        }
        break;
    case CMD_BLINK:
        if (arg == 5 ) {
            if (!b_flg){
                led_th = kthread_run(&led_abcd,NULL,"led kernel thread");
                if (led_th == NULL ) {
                    error("create kernel thread failed!\n");
                    return -1;
                }
                b_flg = 1;
            }else {
                if (led_th ) {
                    kthread_stop(led_th);
                    led_th = NULL;
                }
                error("b_flg = %d\t led_th = %d\n",b_flg,led_th);
                b_flg = 0;
            }
        } else {
            blink_led(arg);
        }
        break;
    default:
        printk("error argument!\n");
        return -EINVAL;
    }
   return 0;
}

static struct file_operations light_fops = {
    .owner = THIS_MODULE,
    .ioctl = light_ioctl,
    .open = light_open,
    .release = light_release,
};
static struct miscdevice light_misdev =
{
    .minor = 53,
    .name = "hyy_led",
    .fops = &light_fops,
};

static int __init light_init(void)
{

    int ret = 0;
    int i, GpioId ;

    pdeg(" my_led debug message: ");

    ret = misc_register(&light_misdev);
    if (ret < 0 ) {
        printk("misc register fail! ret = %d\n",ret);
        return ret;
    }
    for (i = 0 ; i <5 ; i++ ) {
        GpioId =  mfp_to_gpio(led_table[i]);
        gpio_direction_output(GpioId,LED_OFF);
    }

    return 0;
}

static void __exit light_exit (void)
{

    pdeg(" my_led debug message: ");

    misc_deregister(&light_misdev);

    // free the kthread
    if (led_th ) {
        kthread_stop(led_th);
        led_th = NULL;
    }

}
module_init(light_init);
module_exit(light_exit);
MODULE_AUTHOR("hyy");
MODULE_LICENSE("GPL");
================================================================================================
.h 文件和makefile 文件和(一)相同,使用miscdevice 的时候,简化了,申请设备号,用udev创建设备文件等等一系列的代码工作,从而简化了驱动。
所以使用miscdevice的目的就是为了简化、方便字符设备的驱动的编写。

在struct miscdevice 中
struct miscdevice {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const char *nodename;
    mode_t mode;
};

如果指定nodename则 misc 会创建其指定的名字作为设备结点文件的名字,如果不指定,则会默认使用 name

阅读(1083) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~