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