char 设备驱动程序(二)

怎样创建char device driver

1  动态分配设备号

从代码看有可能分配失败,所以要对返回值进行检查

/**
 * 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,
            const char *name)
{
    struct char_device_struct *cd;
    /*如果是动态分配设备号,__register_chrdev_region的major参数是0*/
    cd = __register_chrdev_region(0, baseminor, count, name);
    if (IS_ERR(cd))
        return PTR_ERR(cd);
    *dev = MKDEV(cd->major, cd->baseminor);
    return 0;
}

/*
 * 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;
    /*the standard way of allocating kernel memory and initialized to 0*/
    cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
    if (cd == NULL)
        return ERR_PTR(-ENOMEM);

    mutex_lock(&chrdevs_lock);
    
    /* temporary, the auto allocate flag: major == 0 */
    if (major == 0) {/*start from the end to get empty one*/
        for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
            if (chrdevs[i] == NULL)
                break;
        }

        if (i == 0) {/*cannot get one in the array*/
            ret = -EBUSY;
            goto out;
        }/*if get one, then value the major and ret*/
        major = i;
        ret = major;
    }
    /*value the char_device_struct*/
    cd->major = major;
    cd->baseminor = baseminor;
    cd->minorct = minorct;
    strlcpy(cd->name, name, sizeof(cd->name));

    i = major_to_index(major);
    ------
    mutex_unlock(&chrdevs_lock);
    return cd;
out:
    mutex_unlock(&chrdevs_lock);
    kfree(cd);
    return ERR_PTR(ret);
}


2 cdev_init初始化file_operations

/**
 * cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 *
 * Initializes @cdev, remembering @fops, making it ready to add to the
 * system with cdev_add().
 */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
    memset(cdev, 0, sizeof *cdev);
    INIT_LIST_HEAD(&cdev->list);
    kobject_init(&cdev->kobj, &ktype_cdev_default);
    cdev->ops = fops;
}


3 cdev_add建立dev_t,kobject and cdev之间的关系到cdev_map变量

/**
 * cdev_add() - add a char device to the system
 * @p: the cdev structure for the device
 * @dev: the first device number for which this device is responsible
 * @count: the number of consecutive minor numbers corresponding to this
 *         device
 *
 * cdev_add() adds the device represented by @p to the system, making it
 * live immediately.  A negative error code is returned on failure.
 */
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
    p->dev = dev;
    p->count = count;
    return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);

}

4 由class and dev_t创建一个device object

为什么需要这么做见char 设备驱动程序(一)
device_create(alb_context->alb_class, NULL,

            MKDEV(MAJOR(dev_id),0),
            NULL,
            "abcd");

5 根据inode的cdev成员传递关联内容

static int alb_open(struct inode *inode, struct file *filp)
{
    int err = 0;
    /* From the inode to get the alb_driver_context and others from the driver */
    struct alb_driver_context *alb_context = container_of(
                        inode->i_cdev,
                        struct alb_driver_context,
                        cdev);
    ----
}
从得到的inode,可以知道对应的cdev的地址,从而知道cdev 所在结构体的地址,从而知道各变量的内容。
这层关系是怎样建立起来的那?
当根据设备文件名进行系统调用的时候,可以得到对应的inode, 从inode可以得到 dev_id.根据dev_id通过函数
kobj_lookup(cdev_map, inode->i_rdev, &idx);可以得到dev_id 对应的kobject.dev_id和kobject的对应关系是由
cdev_add -> kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);建立的。
又kobject嵌入在cdev中,进而而到cdev的地址。对以上的例子而言,cdev又嵌入在alb_driver_context,进而知道该
结构体的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值