`
dawuafang
  • 浏览: 1110907 次
文章分类
社区版块
存档分类
最新评论

驱动实战-----OK6410驱动编程之led驱动2

 
阅读更多

混杂设备实现led点灯

一、为了简单方便操作,linux提供了混杂设备驱动编程这一方法,混杂设备驱动程序是指那些简单的字符驱动程序,它们拥有一些相同的特性,内核将这些相同的特性抽象至一个API(drivers/char/misc.c)中。由此可见混杂设备在某种程度上来说也是属于字符驱动的。这能够大大的简化我们字符驱动的编程工作量。

首先来看下我们的字符驱动程序会做什么事情:

1、通过alloc_chrdev_region来注册主次设备号

2、使用device_creat来创建设备结点,当然,如果实验的时候你是可以手动创建设备结点

3、使用cdev_init和cdev_add函数来将自身注册为字符驱动

但是我们使用的混杂设备的功能又是什么呢,具有什么优势呢?


上面三个步骤如果使用混杂设备来做的话,那么将会变得相当简单

1、声明结构体

static struct miscdevice led_dev = {
  .minor = MINOR_NUM,
  .name = "s3c6410_led",        //这个名字含义:挂载驱动后将会自动在/dev目录下面生成s3c6410_led设备文件,这归功于混杂设备。
  .fops = &led_fops,
};


直接使用混杂设备注册函数

misc_deregister(&led_dev);

至于混杂设备注册函数里面做了什么,我想大家都能够猜到,必然也是做了上面的事情,只不过我们这里偷了个懒,使用linux内核给我们提供的api罢了。

还是将注册代码贴上来

int misc_register(struct miscdevice * misc)
{
	struct miscdevice *c;
	dev_t dev;
	int err = 0;

	INIT_LIST_HEAD(&misc->list);

	mutex_lock(&misc_mtx);
	list_for_each_entry(c, &misc_list, list) {
		if (c->minor == misc->minor) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
	}

	if (misc->minor == MISC_DYNAMIC_MINOR) {
		int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
		if (i >= DYNAMIC_MINORS) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
		misc->minor = DYNAMIC_MINORS - i - 1;
		set_bit(i, misc_minors);
	}

	dev = MKDEV(MISC_MAJOR, misc->minor);

	misc->this_device = device_create(misc_class, misc->parent, dev,
					  misc, "%s", misc->name);
	if (IS_ERR(misc->this_device)) {
		int i = DYNAMIC_MINORS - misc->minor - 1;
		if (i < DYNAMIC_MINORS && i >= 0)
			clear_bit(i, misc_minors);
		err = PTR_ERR(misc->this_device);
		goto out;
	}

	/*
	 * Add it to the front, so that later devices can "override"
	 * earlier defaults
	 */
	list_add(&misc->list, &misc_list);
 out:
	mutex_unlock(&misc_mtx);
	return err;
}



上面可以知道混杂设备都使用同一个主设备号10。

二、在接下来就将之前的led点灯驱动变身一下
1、先看驱动代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>

#define GPIOM_BASE 0x7F008820
#define MINOR_NUM  1

unsigned long VA;
unsigned long gpmdat,gpmpud,gpmcon;

/* open函数完成的功能:初始化gpio为输出方向   */
int s3c6410_led_open(struct inode *inodep, struct file *filp)
{
    unsigned tmp;
    tmp = ioread32(gpmcon); 
    printk("tmp = %x ... \n",tmp);  
    tmp &= (~0xFFFF);
	tmp |= (0x1111);  
	iowrite32(tmp,gpmcon);   
	
	printk("s3c6410_led_open ... \n");  
    return 0;
}

long s3c6410_led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
    unsigned tmp;
    switch(cmd){
        
    case 0:
	    tmp = ioread32(gpmdat);
	    tmp &= 0x10;
        iowrite32(tmp,gpmdat);	        
        break;
    case 1:
       	tmp = ioread32(gpmdat);
	    tmp |= 0x1f;
        iowrite32(tmp,gpmdat);	
        break;    
        
    default:
        break;
    }    
    printk("s3c6410_led_ioctl ... \n");
    return 0; 
}
int s3c6410_led_release(struct inode *inodep,struct file *filp)
{
    printk("s3c6410_led_release ... \n");   
    return 0; 
}

static struct file_operations led_fops = {
  .owner = THIS_MODULE,  
  .unlocked_ioctl = s3c6410_led_ioctl,
  .open = s3c6410_led_open,
  .release = s3c6410_led_release, 
};

static struct miscdevice led_dev = {
  .minor = MINOR_NUM,
  .name = "s3c6410_led",        //这个名字含义:挂载驱动后将会自动在/dev目录下面生成s3c6410_led设备文件,这归功于混杂设备。
  .fops = &led_fops,
};
static int __init led_init(void)
{
    int ret = 0;
    VA = (unsigned long)ioremap(GPIOM_BASE,0x0c);
    gpmcon = VA + 0x00;
    gpmdat = VA + 0x04;
    gpmpud = VA + 0x08;
      
    ret = misc_register(&led_dev); 
    printk("led_init   ...\n");   
    return ret;    
}

static void __exit led_exit(void)
{
    misc_deregister(&led_dev);
    printk("led_exit   ...\n");           
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");



其实代码和led1的版本没什么本质的区别,底层操作还是一样的,只是运用了一些小手段使之能够和应用程序打交道ioctl

这里我没有使用魔数的方法来定义CMD。

misc_register和misc_deregister是成对出现的

2、再看测试程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>


int main(int argc,char **argv)
{
    int ret = 0;
    int i = 0;
    int fd = open("/dev/s3c6410_led",2,777);
    if(fd < 0)
    {
        printf("open led dev failed \n");    
    }
    printf("open led dev success ! \n");
    for(i = 0; i < 10; i ++)
    {
        ioctl(fd,0);
        sleep(1);
        ioctl(fd,1);
        sleep(1);
    }
    return ret;    
}




简单的led闪烁灯就实现了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics