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

📄 usr_blk_dev.c

📁 包含MMC协议,驱动源码. 在LINUX操作系统下通过.
💻 C
📖 第 1 页 / 共 5 页
字号:
    {        info_p->media_state = USR_BLK_DEV_MEDIA_STATE_INITIALIZED;    }    tracemsg("changed: %d\n", changed);    usr_blk_dev_cmd_data_processed(info_p, USR_BLK_DEV_CMD_SRC_GEN);    return changed;}/*! * @brief Handles revalidation of the device. * * The file system/kernel will call this function when a part change is detected * (this includes the initial part detection).   It will clear out the * partition information and re-initialize it by calling register_disk(). Once * register_disk() returns the partition information will be set up.  It should * be noted, that the devices partition table will be read through the request * queue before register disk returns.  Thus, calls to this function cannot * lock up any resources used by the request queue mechanism or the partition * table will not be read and the device will lock up. * * @param i_rdev Kernel device information * * @return Always returns 0. */static int usr_blk_dev_revalidate(kdev_t i_rdev){    USR_BLK_DEV_INFO_T *info_p;    unsigned int dev_num;    unsigned int i;    tracemsg("\n");    dev_num = USR_BLK_DEV_DEVICE_NR(i_rdev);    info_p = &usr_blk_dev_info[dev_num];    if (info_p->params.device_size != 0)    {        /* Send the revalidate command to user space. */        usr_blk_dev_send_cmd_to_thread_and_wait(info_p, USR_BLK_DEV_CMD_ID_REVALIDATE,                                                dev_num, USR_BLK_DEV_CMD_SRC_GEN);        usr_blk_dev_cmd_data_processed(info_p, USR_BLK_DEV_CMD_SRC_GEN);        if (info_p->media_state != USR_BLK_DEV_MEDIA_STATE_ERROR)        {            i = dev_num<<USR_BLK_DEV_SHIFT;            /*             * Reset the sizes and partition data based on the data which was received from             * device during the initialization sequence.             */            while (i < (dev_num+1)<<USR_BLK_DEV_SHIFT)            {                memset(&usr_blk_dev_partitions[i], 0, sizeof(usr_blk_dev_partitions[0]));                usr_blk_dev_sizes[i] = 0;                usr_blk_dev_max_sectors[i] = USR_BLK_DEV_MAX_SECTORS_PER_REQ;                usr_blk_dev_blksizes[i] = info_p->params.read_block_len;                usr_blk_dev_gendisk.part[i].nr_sects = 0;                i++;            }            /* Get the partition data from the device which is attached. */            register_disk(&usr_blk_dev_gendisk,                          i_rdev,                          dev_num<<USR_BLK_DEV_SHIFT,                          (struct block_device_operations *)&usr_blk_dev_ops,                          info_p->params.device_size);            info_p->media_state = USR_BLK_DEV_MEDIA_STATE_VALIDATED;            tracemsg("Disk registered\n");            for (i=dev_num<<USR_BLK_DEV_SHIFT; i<(dev_num+1)<<USR_BLK_DEV_SHIFT; i++)            {                tracemsg("%02d: nr_sects: %010ld start_sect: %010ld blk_size: %08d part_size: %08d\n", i,                         usr_blk_dev_gendisk.part[i].nr_sects,                         usr_blk_dev_gendisk.part[i].start_sect,                         usr_blk_dev_blksizes[i],                         usr_blk_dev_sizes[i]);            }        }        else        {            printk(KERN_ERR "usr_blk_dev: Media error encountered while attempting to revalidate device %d.\n", dev_num);        }    }    else    {        printk(KERN_WARNING "usr_blk_dev: Attempt to revalidate an uninitialized device %d.\n", dev_num);    }    return 0;}/*! * @brief Handles the i/o control calls for the device. * * Handles the following ioctl requests:<BR> *   BLKRRPART   - Reread the partition table.<BR> *   HDIO_GETGEO - Return the disk geometry.  In this case the number of *                 cylinders is set to the number if sectors on the disk and *                 the start value of the geometry is set to the start sector. *                 See struct hd_geometry in the kernel for more information.<BR> *   General     - Many other requests are handled by the the general purpose *                 block device ioctl handler blk_ioctl(). * * @param inode_p A pointer to the files inode. * @param file_p  Pointer to the file structure for the operation. * @param cmd     The IOCTL command to operate on. * @param arg     The argument information for cmd. * * @return General:<BR> *            -EFAULT upon a copy to or from user problem.<BR> *            -EACCES upon an user access problem.<BR> *            -ENOTTY if an unsupported request is made.<BR> *         BLKRRPART:<BR> *             Returns 0 upon success.<BR> *         HDIO_GETGEO:<BR> *             Returns 0 upon success. *              */static int usr_blk_dev_ioctl(struct inode *inode_p, struct file *file_p,                             unsigned int cmd, unsigned long arg){    int minor;    int dev_num;    int ret_val;    long ret;    long tmp;    USR_BLK_DEV_INFO_T *info_p;    struct hd_geometry geometry;    tracemsg("cmd: %08x\n", cmd);    minor = MINOR(inode_p->i_rdev);    dev_num = USR_BLK_DEV_DEVICE_NR(inode_p->i_rdev);    info_p = &usr_blk_dev_info[dev_num];    switch (cmd)    {        case BLKRRPART:            if (!capable(CAP_SYS_ADMIN))            {                return -EACCES;            }            return usr_blk_dev_revalidate(inode_p->i_rdev);                    case HDIO_GETGEO:            geometry.cylinders = usr_blk_dev_partitions[minor].nr_sects;            geometry.heads = 1;            geometry.sectors = 1;            geometry.start = usr_blk_dev_partitions[minor].start_sect;            if (copy_to_user((void *)arg, &geometry, sizeof(geometry)))            {                return -EFAULT;            }            tracemsg("geometry.cylinders: %d geometry.start: %ld\n", geometry.cylinders, geometry.start);            return 0;        case _IOR('I', 0x0f05, int):  /* Temporary support for old MMC defines. */        case IOCMMCGETCARDSTATUS:            /*             * The existing MMC driver returns the following statuses:             *   0x01 - Card is write protected             *   0x02 - Card is locked             *   0x04 - Attempt at a the last lock failed               *   0x08 - Locking not supported             *             * The following is new to this driver:             *   0x10 - Card has changed since the last call.  To clear this bit, it must be set before             *          ioctl is called (see comment below).             */            if (get_user(tmp, (unsigned long *)arg))            {                return -EFAULT;            }            ret = IOCMMC_STATUS_LOCK_NOT_SUPPORTED;            ret |= (info_p->ioctl_media_changed ? IOCMMC_STATUS_MEDIA_CHANGED : 0);            /* Clear the bit if it was requested. */            if (tmp & IOCMMC_STATUS_MEDIA_CHANGED)            {                info_p->ioctl_media_changed = false;            }            return put_user(ret, (unsigned long *)arg);                    case _IOR('I', 0x0f06, int):  /* Temporary support for old MMC defines. */        case IOCMMCGETCARDTYPE:            /*             * Return the card type as follows (this is the same as the MMC driver):             *  0 - MMC Card             *  1 - SD Card             */            /* TODO - Needs to be updated to get the information from the user driver. */            return put_user((unsigned long)IOCMMC_TYPE_SD, (unsigned long *)arg);        case _IOR('I', 0x0f09, int):  /* Temporary support for old MMC defines. */        case IOCMMCGETSIZE:            /*             * Returns the size in bytes as opposed to block as is done by BLKGETSIZE.             */            return put_user(usr_blk_dev_partitions[minor].nr_sects*usr_blk_dev_blksizes[minor], (unsigned long *)arg);        case _IOR('I', 0x0f02, int):   /* Temporary support for old MMC defines. */        case IOCMMCGETCARDCID:            /*             * Returns the 16 byte CID register as read in the user space driver.  For devices             * which do not have a CID an array of 16 0's will be returned.             */            memset(info_p->cmd[USR_BLK_DEV_CMD_SRC_GEN].data.cmd_data_from_usr.cid,                   0, sizeof(info_p->cmd[USR_BLK_DEV_CMD_SRC_GEN].data.cmd_data_from_usr.cid));            usr_blk_dev_send_cmd_to_thread_and_wait(info_p, USR_BLK_DEV_CMD_ID_READ_CID,                                                    dev_num, USR_BLK_DEV_CMD_SRC_GEN);            ret_val = copy_to_user((void *)arg,                                   info_p->cmd[USR_BLK_DEV_CMD_SRC_GEN].data.cmd_data_from_usr.cid,                                   sizeof(info_p->cmd[USR_BLK_DEV_CMD_SRC_GEN].data.cmd_data_from_usr.cid));            usr_blk_dev_cmd_data_processed(info_p, USR_BLK_DEV_CMD_SRC_GEN);            if (info_p->media_state != USR_BLK_DEV_MEDIA_STATE_ERROR)            {                return -EIO;            }            if (ret_val)            {                return -EFAULT;            }            return 0;                    default:            return blk_ioctl(inode_p->i_rdev, cmd, arg);    }    return -ENOTTY;}/*! * @brief Handle media requests for the block device. * * Handles media requests which are sent to the driver via the request queue. * Two different types of requests can be sent, they are for reads and writes * to the device.  In general this driver is set up to allow multiple request * queues, one per physical device attached.  All of these queues go through * this handler function.  Since multiple queues are supported none of the * general purpose handlers in blk.h can be used. * * This handler is called by the kernel when it needs to read or write data * to the device.  This may or may not be in a user context.  As a result * it cannot block under any circumstances.  This is accomplished by sending * the request to the user block thread for handling.  Once the thread receives * a read or write command the queue is operated on by the function * usr_blk_dev_thread_rw_cmd() which will loop until all requests have been * removed from the queue. * * If a request is received while the user block thread is currently acting * on a read or write command, nothing is done.  The transfer will be * handled by the user block thread. * * @param req_queue_p Pointer to the head node on the request queue. */static void usr_blk_dev_request(request_queue_t *req_queue_p){    USR_BLK_DEV_INFO_T *info_p;    struct request *req_p;    unsigned int dev_num;    tracemsg("\n");    req_p = blkdev_entry_next_request(&req_queue_p->queue_head);    if (req_p == NULL)    {        tracemsg("Error: request pointer is NULL.\n");        return;    }    dev_num = USR_BLK_DEV_DEVICE_NR(req_p->rq_dev);    info_p = &usr_blk_dev_info[dev_num];    tracemsg("Request for device %d state: %d\n", dev_num, (int)info_p->cmd[USR_BLK_DEV_CMD_SRC_REQ].state);    if (info_p->media_state <= USR_BLK_DEV_MEDIA_STATE_ERROR)    {        tracemsg("Error: Request made while device not attached.\n");    }    if ((info_p->cmd[USR_BLK_DEV_CMD_SRC_REQ].state == USR_BLK_DEV_CMD_STATE_NONE) &&        (!list_empty(&req_queue_p->queue_head)))    {        /*         * At this point a valid request can be sent to the user mode driver.  Since         * this function cannot block, the usr block dev thread is used to send the         * command and complete the request.         */        usr_blk_dev_send_cmd_to_thread((req_p->cmd == WRITE) ? USR_BLK_DEV_CMD_ID_WRITE : USR_BLK_DEV_CMD_ID_READ,                                       dev_num,                                       USR_BLK_DEV_CMD_SRC_REQ);    }}/*! * @brief Returns a pointer to the request queue for the device. * * @param dev Kernel device information * * @return A pointer to the request queue for the device */request_queue_t *usr_blk_dev_find_req_queue(kdev_t dev){    unsigned int dev_num;    static int count = 0;    dev_num = USR_BLK_DEV_DEVICE_NR(dev);    if (dev_num >= USR_BLK_DEV_NUM_DEVICES)    {        if (count < 5)        {            count++;            printk(KERN_WARNING "usr_blk_dev: Request for unknown device: %d", dev_num);        }        return NULL;    }    return &usr_blk_dev_info[dev_num].req_queue;}/*! * @brief Defines the file operations supported by the user space block *        driver device.  */static const struct block_device_operations usr_blk_dev_ops ={    .check_media_change = usr_blk_dev_check_media_change,    .ioctl              = usr_blk_dev_ioctl,    .open               = usr_blk_dev_open,    .release            = usr_blk_dev_release,    .revalidate         = usr_blk_dev_revalidate};/*! * @brief Defines the files operations supported by the proc entry *        used for communication with user space. */static const struct file_operations usr_blk_dev_proc_ops ={    .open =    usr_blk_dev_proc_open,    .poll =    usr_blk_dev_proc_poll,    .read =    usr_blk_dev_proc_read,    .release = usr_blk_dev_proc_release,    .write =   usr_blk_dev_proc_write};/*! * @brief Handles the init command from within the user block device thread. * * Handles the init command from the user block thread.  This will pass the init * command on to user space and wait for a response.  Once the response is * received the necessary data will be copied into the devices information * structure and hotplug will be called. * * @param info_p  Pointer to the devices information structure * @param dev_num The device number (not the minor number) */static void usr_blk_dev_thread_init_cmd(

⌨️ 快捷键说明

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