|
@@ -793,3 +793,91 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
|
|
|
dprintk("bound to <%s>, max queue %d\n",
|
|
|
format_dev_t(buf, inode->i_rdev), bd->max_queue);
|
|
|
|
|
|
+ mutex_unlock(&bsg_mutex);
|
|
|
+ return bd;
|
|
|
+}
|
|
|
+
|
|
|
+static struct bsg_device *__bsg_get_device(int minor, struct request_queue *q)
|
|
|
+{
|
|
|
+ struct bsg_device *bd;
|
|
|
+ struct hlist_node *entry;
|
|
|
+
|
|
|
+ mutex_lock(&bsg_mutex);
|
|
|
+
|
|
|
+ hlist_for_each_entry(bd, entry, bsg_dev_idx_hash(minor), dev_list) {
|
|
|
+ if (bd->queue == q) {
|
|
|
+ atomic_inc(&bd->ref_count);
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ bd = NULL;
|
|
|
+found:
|
|
|
+ mutex_unlock(&bsg_mutex);
|
|
|
+ return bd;
|
|
|
+}
|
|
|
+
|
|
|
+static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ struct bsg_device *bd;
|
|
|
+ struct bsg_class_device *bcd;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * find the class device
|
|
|
+ */
|
|
|
+ mutex_lock(&bsg_mutex);
|
|
|
+ bcd = idr_find(&bsg_minor_idr, iminor(inode));
|
|
|
+ if (bcd)
|
|
|
+ kref_get(&bcd->ref);
|
|
|
+ mutex_unlock(&bsg_mutex);
|
|
|
+
|
|
|
+ if (!bcd)
|
|
|
+ return ERR_PTR(-ENODEV);
|
|
|
+
|
|
|
+ bd = __bsg_get_device(iminor(inode), bcd->queue);
|
|
|
+ if (bd)
|
|
|
+ return bd;
|
|
|
+
|
|
|
+ bd = bsg_add_device(inode, bcd->queue, file);
|
|
|
+ if (IS_ERR(bd))
|
|
|
+ kref_put(&bcd->ref, bsg_kref_release_function);
|
|
|
+
|
|
|
+ return bd;
|
|
|
+}
|
|
|
+
|
|
|
+static int bsg_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ struct bsg_device *bd;
|
|
|
+
|
|
|
+ bd = bsg_get_device(inode, file);
|
|
|
+
|
|
|
+ if (IS_ERR(bd))
|
|
|
+ return PTR_ERR(bd);
|
|
|
+
|
|
|
+ file->private_data = bd;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int bsg_release(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ struct bsg_device *bd = file->private_data;
|
|
|
+
|
|
|
+ file->private_data = NULL;
|
|
|
+ return bsg_put_device(bd);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int bsg_poll(struct file *file, poll_table *wait)
|
|
|
+{
|
|
|
+ struct bsg_device *bd = file->private_data;
|
|
|
+ unsigned int mask = 0;
|
|
|
+
|
|
|
+ poll_wait(file, &bd->wq_done, wait);
|
|
|
+ poll_wait(file, &bd->wq_free, wait);
|
|
|
+
|
|
|
+ spin_lock_irq(&bd->lock);
|
|
|
+ if (!list_empty(&bd->done_list))
|
|
|
+ mask |= POLLIN | POLLRDNORM;
|
|
|
+ if (bd->queued_cmds < bd->max_queue)
|
|
|
+ mask |= POLLOUT;
|
|
|
+ spin_unlock_irq(&bd->lock);
|
|
|
+
|
|
|
+ return mask;
|