linux 字符设备主设备号范围,linux下字符设备分配设备号,注册等详解

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))

#defineLED_GPIO_11

#defineLED_PIN_124

static int major =0;//定义主设备号

staticstruct 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

staticvoidled_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,

};

staticstruct cdev cdev_led;

// 模块加载函数

int light_init(void)

{

int ret;

dev_tdev= 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

9e009c758b97c0f678f73f9239be4ac7.png

@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@

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值