⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usr_blk_dev.c

📁 包含MMC协议,驱动源码. 在LINUX操作系统下通过.
💻 C
📖 第 1 页 / 共 5 页
字号:
        return;    }    wake_up(&cmd_p->wait_for_thread);}/* * @brief Sends a command to user space and waits for the user mode driver to *        complete processing of the command. * * Sends a command from the user block device thread to user space and waits for * the user space driver to respond.  This function will block until the response * is received from user space. * * @param info_p  Pointer to the information structure for the device the *                command must be sent to. * @param id      The command which must be sent. * @param dev_num The device number to which the command must be sent. */static void usr_blk_dev_send_cmd_to_usr_and_wait(    USR_BLK_DEV_INFO_T *info_p,    USR_BLK_DEV_CMD_ID_T id,    unsigned int dev_num){    struct usr_blk_dev_cmd_s *cmd_p;        tracemsg("id: %d cmd_src: %d\n", id, info_p->cmd_src);    /*     * Set up to send the command.     */    cmd_p = &info_p->cmd[info_p->cmd_src];    cmd_p->data.id = id;    cmd_p->data.media_state = info_p->media_state;    cmd_p->data.device_num = dev_num;    cmd_p->state = USR_BLK_DEV_CMD_STATE_USR_READ;    wake_up(&info_p->wait_for_usr_read);    /* Wait for the user space driver to respond to the command. */    wait_event(info_p->wait_for_usr_write,               ((cmd_p->state == USR_BLK_DEV_CMD_STATE_USR_DONE) ||                (info_p->media_state == USR_BLK_DEV_MEDIA_STATE_ERROR)));    tracemsg("User command response received.\n");}/*! * @brief Handles reads from the /proc entry from the user mode process. * * Called when a user space application attempts to read from the /proc * entry for the usr_blk_dev.  When read is called the currently active * command is copied into the callers buffer. * * @param file  Pointer to the file structure for the operation. * @param buf   Pointer to the user space buffer in which to place the data read. * @param count The maximum number of bytes which can be placed in buf. * @param pos   The user file position. */static ssize_t usr_blk_dev_proc_read(struct file *file, char *buf, size_t count, loff_t *pos){    struct usr_blk_dev_cmd_s *cmd_p;    USR_BLK_DEV_INFO_T *info_p;    /* Send the current thread command to the usr driver. */    info_p = (USR_BLK_DEV_INFO_T *)file->private_data;    cmd_p = &info_p->cmd[info_p->cmd_src];    tracemsg("cmd_src: %d\n", info_p->cmd_src);    if (count < sizeof(cmd_p->data))    {        tracemsg("Warning: Size requested (%d) is too small.\n", count);        usr_blk_dev_abort_cmd(info_p);        return -EINVAL;    }    if (copy_to_user(buf, &cmd_p->data, sizeof(cmd_p->data)))    {        usr_blk_dev_abort_cmd(info_p);        return -EFAULT;    }    cmd_p->state = USR_BLK_DEV_CMD_STATE_USR_WAIT;    return sizeof(cmd_p->data);}/*! * @brief Handles writes to the /proc entry from the user mode process. * * Once the user space driver has completed a command it calls write to send * the data back to the kernel driver.  This routine handles the call to write. * As a result of the call the data is copied from the user space process, and * the routine waiting on the data is woken up. * * @param file  Pointer to the file structure for the operation. * @param buf   Pointer to the user space buffer which the data must be taken from. * @param count The maximum number of bytes which can be read from buf. * @param pos   The user file position. */static ssize_t usr_blk_dev_proc_write(struct file *file, const char *buf, size_t count, loff_t *pos){    struct usr_blk_dev_cmd_s *cmd_p;    USR_BLK_DEV_INFO_T *info_p;    info_p = (USR_BLK_DEV_INFO_T *)file->private_data;    cmd_p = &info_p->cmd[info_p->cmd_src];    tracemsg("count %d cmd_src: %d\n", count, info_p->cmd_src);    if (count > sizeof(USR_BLK_DEV_CMD_T))    {        tracemsg("Warning: count (%d) is too large.\n", count);        count = sizeof(USR_BLK_DEV_CMD_T);    }    if (cmd_p->state != USR_BLK_DEV_CMD_STATE_USR_WAIT)    {        tracemsg("Warning: Command write done in an invalid state (%d).\n", cmd_p->state);        return 0;    }    if (count == sizeof(USR_BLK_DEV_CMD_T))    {        if (copy_from_user(&cmd_p->data, buf, count))        {            printk(KERN_ERR "usr_blk_dev: Error copying data from user space.\n");            usr_blk_dev_abort_cmd(info_p);            return -EFAULT;        }        cmd_p->state = USR_BLK_DEV_CMD_STATE_USR_DONE;        wake_up(&info_p->wait_for_usr_write);        return count;    }    else    {        tracemsg("Warning: Not enough data %d bytes.\n", count);    }    return 0;}/*! * @brief Handles calls to poll or select on the /proc entry from the user mode *        driver. * * Called when the user mode application polls on the /proc entry.  It must * return 0 when the wait must happen and a positive value when data is * available. * * @param file  Pointer to the file structure for the operation. * @param wait  Points to the kernel wait table for poll. * * @return Returns 0 when no data is available or valid POLL flags when data is *         available for reading. */static unsigned int usr_blk_dev_proc_poll(struct file *file, poll_table *wait){    USR_BLK_DEV_INFO_T *info_p;    info_p = (USR_BLK_DEV_INFO_T *)file->private_data;    tracemsg("info_p: %p usr_blk_dev_info: %p wait: %p\n",             info_p, usr_blk_dev_info, wait);    poll_wait(file, &info_p->wait_for_usr_read, wait);    if ((info_p->cmd[info_p->cmd_src].data.id != USR_BLK_DEV_CMD_ID_NONE) &&        (info_p->cmd[info_p->cmd_src].state == USR_BLK_DEV_CMD_STATE_USR_READ))    {        return (POLLIN | POLLRDNORM);    }    /*     * In the case of an error or sporadic wakeup the user code is required to     * do nothing, since reading the data makes no sense.  If it does read it     * will see the error state in the media state field.     */    return 0;}/*! * @brief Handles calls to open on the /proc entry from the user mode process. * * Called when the user process attempts to open the /proc entry.  The function * sets up a pointer to the proc data, and increments the use count. * * @param inode A pointer to the files inode. * @param file  Pointer to the file structure for the operation. * * @return 0 upon success.<BR> *         -EBUSY if too many instances are already open. */static int usr_blk_dev_proc_open(struct inode *inode, struct file *file){    const struct proc_dir_entry *proc_p = inode->u.generic_ip;    USR_BLK_DEV_INFO_T *info_p;    USR_BLK_DEV_CMD_ID_T cmd;    unsigned int dev_num;    unsigned long irq_flags;    info_p = (USR_BLK_DEV_INFO_T *)proc_p->data;    if (info_p == NULL)    {        return -ENODEV;    }    tracemsg("proc_opens: %d data: %p\n", info_p->proc_opens, proc_p->data);    if (info_p->proc_opens >= USR_BLK_DEV_MAX_PROC_OPENS)    {        return -EBUSY;    }    file->private_data = proc_p->data;    /*     * If this is the first open and the device is not initialized, send     * the init command.     */    if (info_p->proc_opens == 0)    {        /* Find the device number. */        dev_num = 0;        while ((info_p != &usr_blk_dev_info[dev_num]) && (dev_num < USR_BLK_DEV_NUM_DEVICES))        {            dev_num++;        }        if (dev_num < USR_BLK_DEV_NUM_DEVICES)        {            local_irq_save(irq_flags);                        cmd = USR_BLK_DEV_CMD_ID_REMOVE;            if (info_p->media_state > USR_BLK_DEV_MEDIA_STATE_ERROR)            {                cmd = USR_BLK_DEV_CMD_ID_INIT;            }            /*             * The code cannot wait here, since the user process which opened /proc must respond             * to the command.  For this reason the IRQ source is used which will emulate the insert             * or remove command coming from the interrupt.  It would have come from the interrupt             * normally, but when the card was detected no proc entry was open, so the command             * could not be sent.             */            usr_blk_dev_send_cmd_to_thread(cmd, dev_num, USR_BLK_DEV_CMD_SRC_IRQ);        }        else        {            printk(KERN_ERR "usr_blk_dev: Unable to determine device number in usr_blk_dev_proc_open.\n");            return -ENODEV;        }    }    info_p->proc_opens++;    return 0;}/*! * @brief Handles calls to close on the /proc entry from the user mode process. * * Called when the user process attempts to close the /proc entry.  It simply * decrements the use counter. * * @param inode A pointer to the files inode. * @param file  Pointer to the file structure for the operation. * * @return 0 upon success.<BR> *         -ENODEV if the device is not currently open. */static int usr_blk_dev_proc_release(struct inode *inode, struct file *file){    USR_BLK_DEV_INFO_T *info_p;    info_p = (USR_BLK_DEV_INFO_T *)file->private_data;    tracemsg("proc_opens: %d", info_p->proc_opens);    if (info_p->proc_opens > 0)    {        info_p->proc_opens--;        return 0;    }    return -ENODEV;}/*! * @brief Handles opening the media device * * Called by the kernel block code when a user attempts to mount/open the block * device. * * @param inode_p A pointer to the files inode. * @param file_p  Pointer to the file structure for the operation. * * @return 0 upon success.<BR> *         -ENODEV upon failure. * * @note Only the i_rdev record of the inode_p is valid when called to mount *       the device.  For file_p only f_mode and f_flags are valid when mounting. */static int usr_blk_dev_open(struct inode *inode_p, struct file *file_p){    USR_BLK_DEV_INFO_T *info_p;        tracemsg("dev: %d minor: %d\n", USR_BLK_DEV_DEVICE_NR(inode_p->i_rdev), MINOR(inode_p->i_rdev));    info_p = &usr_blk_dev_info[USR_BLK_DEV_DEVICE_NR(inode_p->i_rdev)];    if ((info_p->media_state > USR_BLK_DEV_MEDIA_STATE_REMOVED) &&        (info_p->params.device_size != 0))    {        /* Make sure the disk has been validated before the first open. */        if (info_p->media_state != USR_BLK_DEV_MEDIA_STATE_VALIDATED)        {            check_disk_change(inode_p->i_rdev);        }        MOD_INC_USE_COUNT;        tracemsg("Open successful.\n");        return 0;    }    return -ENODEV;}/*! * @brief Handles closing device. * * Called when the kernel block code or the user wishes to close the media * device.   The file system is resynced to handle the umount command. * * @param inode_p A pointer to the files inode. * @param file_p  Pointer to the file structure for the operation. * * @return Always returns 0. */static int usr_blk_dev_release(struct inode *inode_p, struct file *file_p){    tracemsg("\n");    tracemsg("blksize: %d\n", usr_blk_dev_blksizes[1]);    MOD_DEC_USE_COUNT;    return 0;}/*! * @brief Handles checking for a media change for the device. * * Called by the kernel to determine if a media changes has happened.  This * determination is passed up to user space since it handles communication * with the part.  This allows for the case where a part is removed, but * then re-inserted.  In this case it will be reinitialized when the part is * detected as inserted, so we have no reason to re-initialize.  If it is * the same part there is no reason to inform the file system, since nothing * in the block cache needs to change. * * @param i_rdev A pointer to the kernel device information * * @return Returns 0 when the device has not changed, or 1 when it has. */static int usr_blk_dev_check_media_change(kdev_t i_rdev){    USR_BLK_DEV_INFO_T *info_p;    unsigned int dev_num;    int changed;    tracemsg("\n");    dev_num = USR_BLK_DEV_DEVICE_NR(i_rdev);    info_p = &usr_blk_dev_info[dev_num];    usr_blk_dev_send_cmd_to_thread_and_wait(info_p, USR_BLK_DEV_CMD_ID_MEDIA_CHANGE,                                            dev_num, USR_BLK_DEV_CMD_SRC_GEN);    changed = (int)(info_p->cmd[USR_BLK_DEV_CMD_SRC_GEN].data.cmd_data_from_usr.media_changed);    if (changed)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -