?? usr_blk_dev.c
字號:
{ 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 + -