Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145175
  • 博文数量: 101
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 9
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-17 08:11
文章分类
文章存档

2017年(91)

2016年(10)

我的朋友

分类: 嵌入式

2017-03-21 09:37:28

PC操作系统:ubuntu 11.10

使用的开发板:am335x_evm

开发板使用的操作系统:linux 3.2


测试用例:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include     //register_chrdev_region
#include 
#include 
#include 


MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("SM");
MODULE_VERSION("0.0.1");
//MODULE_DEVICE("global memory");
MODULE_DESCRIPTION("led ...");
MODULE_ALIAS("LED");



/*******************************************/

#define NAME "leds" 
#define GPIO_TO_PIN(bank, gpio)        (32 * (bank) + (gpio))
#define	LED_GPIO_1						1
#define	LED_PIN_1						24



static 	int 	major =0;//定义主设备号 
static	struct class 	*led_class;

/*******************************************/

void led_on(void)

{    
     gpio_set_value(GPIO_TO_PIN(LED_GPIO_1,LED_PIN_1), 1);

}
EXPORT_SYMBOL(led_on);



void led_off(void)

{    
     gpio_set_value(GPIO_TO_PIN(LED_GPIO_1,LED_PIN_1), 0);

}
EXPORT_SYMBOL(led_off);



void led_init(void)

{ 
        int result;

         /* Allocating GPIOs and setting direction */
		gpio_free(GPIO_TO_PIN(LED_GPIO_1,LED_PIN_1));
        result = gpio_request(GPIO_TO_PIN(LED_GPIO_1,LED_PIN_1), "Leds");//usr1
        if (result != 0)
                printk("gpio_request(%d_%d) failed!\n",LED_GPIO_1,LED_PIN_1);

        result = gpio_direction_output(GPIO_TO_PIN(LED_GPIO_1,LED_PIN_1), 1);
        if (result != 0)
                printk("gpio_direction(%d_%d) failed!\n",LED_GPIO_1,LED_PIN_1);
}




struct light_dev

{
    struct cdev cdev;
    unsigned char value;
};



struct light_dev *light_devp;


// 打开和关闭函数

int light_open(struct inode *inode,struct file *filp)

{
    struct light_dev *dev;

    // 获得设备结构体指针
    dev = container_of(inode->i_cdev,struct light_dev,cdev);

    // 让设备结构体作为设备的私有信息
    filp->private_data = dev;

    return 0;

}



int light_release(struct inode *inode,struct file *filp)

{
    return 0;    

}





// ioctl

long light_ioctl(struct file *filp,unsigned int cmd,

unsigned long arg)

{
    struct light_dev *dev = filp->private_data;

    switch(cmd)

    {
        case 0:
            dev->value = 0;
            led_off();         
        	break;

        case 1:
            dev->value = 1;
            led_on();
 	       break;

        default:
	     	return -ENOTTY;
        // break;
    }

    return 0;
}  

//set up the cdev structure for a device
static	void	led_setup_cdev(struct cdev* dev,int minor,struct file_operations *fops)
{
	int 	err, devno 	= MKDEV(major,minor);

	cdev_init(dev,fops);
	dev->owner	= THIS_MODULE;
	dev->ops	= fops;
	err			= cdev_add(dev,devno,1);

	if(err)
		printk(KERN_NOTICE"Error %d adding led%d",err,minor);
}   



struct file_operations light_fops = 

{
    .owner = THIS_MODULE,
    .unlocked_ioctl = light_ioctl,
    .open  = light_open,
    .release = light_release,
};


static	struct cdev cdev_led;
// 模块加载函数
int light_init(void)

{
    int ret;
	dev_t	dev	= MKDEV(major,0);

    led_init();
    printk(KERN_ALERT "led modules is install\n");   

 //   ret=register_chrdev(major,NAME,&light_fops);   
	if(major)
		ret	= register_chrdev_region(dev,1,NAME);
	else
	{
		ret	= alloc_chrdev_region(&dev,0,1,NAME);
		major	= MAJOR(dev);
	}
    if(ret<0)   
    {   
      printk("unable to register myled driver!\n");   
      return ret;   
     }     

	printk(KERN_DEBUG"led device number : %x\n",dev);

	led_setup_cdev(&cdev_led,0,&light_fops);       

	led_class	= class_create(THIS_MODULE,"led_class");
	if(IS_ERR(led_class))
	{
		printk(KERN_INFO"create led class error\n");
		return -1;
	}

	device_create(led_class,NULL,dev,NULL,"led" "%d",MINOR(dev));


    return 0;  
}



// 模块卸载函数

void light_cleanup(void)

{
 //   unregister_chrdev(major,NAME);   
	device_destroy(led_class,MKDEV(major,0));
	class_destroy(led_class);
	cdev_del(&cdev_led); unregister_chrdev_region(MKDEV(major,0),1);

    printk("Goodbye,cruel world!\n"); 
}

module_init(light_init);
module_exit(light_cleanup);






详解:

@a1@ 动态分配设备号


/**
 * alloc_chrdev_region() - register a range of char device numbers
 * @dev: output parameter for first assigned number
 * @baseminor: first of the requested range of minor numbers
 * @count: the number of minor numbers required
 * @name: the name of the associated device or driver
 *
 * Allocates a range of char device numbers.  The major number will be
 * chosen dynamically, and returned (along with the first minor number)
 * in @dev.  Returns zero or a negative error code.
 */
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,  //alloc_chrdev_region(0,0,1,"leds")
			const char *name)
{
	struct char_device_struct *cd;
	cd = __register_chrdev_region(0, baseminor, count, name);
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	*dev = MKDEV(cd->major, cd->baseminor);
	return 0;
}


    @b1@ 获得并注册设备号


/*
 * Register a single major with a specified minor range.
 *
 * If major == 0 this functions will dynamically allocate a major and return
 * its number.
 *
 * If major > 0 this function will attempt to reserve the passed range of
 * minors and will return zero on success.
 *
 * Returns a -ve errno on failure.
 */
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
			   int minorct, const char *name)
{
	struct char_device_struct *cd, **cp;
	int ret = 0;
	int i;

        //分配并清空内存空间用以保存这个设备的主设备号等信息
	cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
	if (cd == NULL)
		return ERR_PTR(-ENOMEM);

        //锁住临界区
	mutex_lock(&chrdevs_lock);

        //动态分配主设备号
	/* temporary */
	if (major == 0) {
		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
			if (chrdevs[i] == NULL)
				break;
		}
                //当前没有可用的主设备号,异常退出
		if (i == 0) {
			ret = -EBUSY;
			goto out;
		}
                //成功获得主设备号
                major = i;
		ret = major;
	}

        //根据当前例子填充数据
	cd->major = major;        //动态分配的主设备号
	cd->baseminor = baseminor;//当前为 0 (如果有多个设备,其表示第一个次设备号)
	cd->minorct = minorct;    //设备个数 1
	strlcpy(cd->name, name, sizeof(cd->name)); //设备名为 "leds"

        //主设备号是通过hash表来管理的
	i = major_to_index(major);    //当前动态获得的主设备号在所有设备中的索引值(即位于那条hash列中)
/*
#if 0
/* fs/char_dev.c */
#define CHRDEV_MAJOR_HASH_SIZE    255
/* index in the above */
static inline int major_to_index(unsigned major)
{
    return major % CHRDEV_MAJOR_HASH_SIZE;
}
static struct char_device_struct {
    struct char_device_struct *next;
    unsigned int major;
    unsigned int baseminor;
    int minorct;
    char name[64];
    struct cdev *cdev;        /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
#endif
 */

        /*    chrdevs[i]    
              @1@ 假设主设备号28并没有被使用,dev1的主设备号为28,

              @2@

              @3@
         */
        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
		if ((*cp)->major > major ||
		    ((*cp)->major == major &&
		     (((*cp)->baseminor >= baseminor) ||
		      ((*cp)->baseminor + (*cp)->minorct > baseminor))))
			break;

	/* Check for overlapping minor ranges.  */
	if (*cp && (*cp)->major == major) {
		int old_min = (*cp)->baseminor;
		int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
		int new_min = baseminor;
		int new_max = baseminor + minorct - 1;

		/* New driver overlaps from the left.  */
		if (new_max >= old_min && new_max <= old_max) {
			ret = -EBUSY;
			goto out;
		}

		/* New driver overlaps from the right.  */
		if (new_min <= old_max && new_min >= old_min) {
			ret = -EBUSY;
			goto out;
		}
	}

	cd->next = *cp;
	*cp = cd;
	mutex_unlock(&chrdevs_lock);
	return cd;
out:
	mutex_unlock(&chrdevs_lock);
	kfree(cd);
	return ERR_PTR(ret);
}
hjhk


    @b2@返回设备号


    @b DONE@

@a2@ 初始化设备

    @b1@


    @b2@


    @b3@


    @b DONE@


@a3@ 添加设备

    @b1@


    @b2@


    @b3@


    @b DONE@


@a4@ 在 sysfs 中创建设备类型

    @b1@


    @b2@


    @b3@


    @b DONE@


@a5@ 在 sysfs 中对应的设备类型中添加设备

    @b1@


    @b2@


    @b3@


    @b DONE@


@a DONE@


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