Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/interface.c
--- a/drivers/xen/usbback/interface.c Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/interface.c Tue Oct 06 15:18:27 2009 +0900
@@ -48,7 +48,7 @@
static LIST_HEAD(usbif_list);
static DEFINE_SPINLOCK(usbif_list_lock);
-usbif_t *find_usbif(int dom_id, int dev_id)
+usbif_t *find_usbif(domid_t domid, unsigned int handle)
{
usbif_t *usbif;
int found = 0;
@@ -56,8 +56,8 @@
spin_lock_irqsave(&usbif_list_lock, flags);
list_for_each_entry(usbif, &usbif_list, usbif_list) {
- if (usbif->domid == dom_id
- && usbif->handle == dev_id) {
+ if (usbif->domid == domid
+ && usbif->handle == handle) {
found = 1;
break;
}
@@ -82,16 +82,16 @@
usbif->domid = domid;
usbif->handle = handle;
- spin_lock_init(&usbif->ring_lock);
+ spin_lock_init(&usbif->urb_ring_lock);
+ spin_lock_init(&usbif->conn_ring_lock);
atomic_set(&usbif->refcnt, 0);
init_waitqueue_head(&usbif->wq);
init_waitqueue_head(&usbif->waiting_to_free);
- spin_lock_init(&usbif->plug_lock);
- INIT_LIST_HEAD(&usbif->plugged_devices);
+ spin_lock_init(&usbif->stub_lock);
+ INIT_LIST_HEAD(&usbif->stub_list);
spin_lock_init(&usbif->addr_lock);
- for (i = 0; i < USB_DEV_ADDR_SIZE; i++) {
+ for (i = 0; i < USB_DEV_ADDR_SIZE; i++)
usbif->addr_table[i] = NULL;
- }
spin_lock_irqsave(&usbif_list_lock, flags);
list_add(&usbif->usbif_list, &usbif_list);
@@ -100,70 +100,109 @@
return usbif;
}
-static int map_frontend_page(usbif_t *usbif, unsigned long shared_page)
+static int map_frontend_pages(usbif_t *usbif,
+ grant_ref_t urb_ring_ref,
+ grant_ref_t conn_ring_ref)
{
struct gnttab_map_grant_ref op;
- gnttab_set_map_op(&op, (unsigned long)usbif->ring_area->addr,
- GNTMAP_host_map, shared_page, usbif->domid);
+ gnttab_set_map_op(&op, (unsigned long)usbif->urb_ring_area->addr,
+ GNTMAP_host_map, urb_ring_ref, usbif->domid);
if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
BUG();
if (op.status) {
- printk(KERN_ERR "grant table operation failure\n");
+ printk(KERN_ERR "grant table failure mapping urb_ring_ref\n");
return op.status;
}
- usbif->shmem_ref = shared_page;
- usbif->shmem_handle = op.handle;
+ usbif->urb_shmem_ref = urb_ring_ref;
+ usbif->urb_shmem_handle = op.handle;
+
+ gnttab_set_map_op(&op, (unsigned long)usbif->conn_ring_area->addr,
+ GNTMAP_host_map, conn_ring_ref, usbif->domid);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status) {
+ struct gnttab_unmap_grant_ref unop;
+ gnttab_set_unmap_op(&unop,
+ (unsigned long) usbif->urb_ring_area->addr,
+ GNTMAP_host_map, usbif->urb_shmem_handle);
+ VOID(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop,
+ 1));
+ printk(KERN_ERR "grant table failure mapping conn_ring_ref\n");
+ return op.status;
+ }
+
+ usbif->conn_shmem_ref = conn_ring_ref;
+ usbif->conn_shmem_handle = op.handle;
return 0;
}
-static void unmap_frontend_page(usbif_t *usbif)
+static void unmap_frontend_pages(usbif_t *usbif)
{
struct gnttab_unmap_grant_ref op;
- gnttab_set_unmap_op(&op, (unsigned long)usbif->ring_area->addr,
- GNTMAP_host_map, usbif->shmem_handle);
+ gnttab_set_unmap_op(&op, (unsigned long)usbif->urb_ring_area->addr,
+ GNTMAP_host_map, usbif->urb_shmem_handle);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ gnttab_set_unmap_op(&op, (unsigned long)usbif->conn_ring_area->addr,
+ GNTMAP_host_map, usbif->conn_shmem_handle);
if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
BUG();
}
-int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn)
+int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref,
+ unsigned long conn_ring_ref, unsigned int evtchn)
{
- int err;
- usbif_sring_t *sring;
+ int err = -ENOMEM;
+
+ usbif_urb_sring_t *urb_sring;
+ usbif_conn_sring_t *conn_sring;
if (usbif->irq)
return 0;
- if ((usbif->ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
- return -ENOMEM;
+ if ((usbif->urb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
+ return err;
+ if ((usbif->conn_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
+ goto fail_alloc;
- err = map_frontend_page(usbif, shared_page);
- if (err) {
- free_vm_area(usbif->ring_area);
- return err;
- }
-
- sring = (usbif_sring_t *) usbif->ring_area->addr;
- BACK_RING_INIT(&usbif->ring, sring, PAGE_SIZE);
+ err = map_frontend_pages(usbif, urb_ring_ref, conn_ring_ref);
+ if (err)
+ goto fail_map;
err = bind_interdomain_evtchn_to_irqhandler(
- usbif->domid, evtchn, usbbk_be_int, 0, "usbif-backend",
usbif);
+ usbif->domid, evtchn, usbbk_be_int, 0,
+ "usbif-backend", usbif);
if (err < 0)
- {
- unmap_frontend_page(usbif);
- free_vm_area(usbif->ring_area);
- usbif->ring.sring = NULL;
- return err;
- }
+ goto fail_evtchn;
usbif->irq = err;
+ urb_sring = (usbif_urb_sring_t *) usbif->urb_ring_area->addr;
+ BACK_RING_INIT(&usbif->urb_ring, urb_sring, PAGE_SIZE);
+
+ conn_sring = (usbif_conn_sring_t *) usbif->conn_ring_area->addr;
+ BACK_RING_INIT(&usbif->conn_ring, conn_sring, PAGE_SIZE);
+
return 0;
+
+fail_evtchn:
+ unmap_frontend_pages(usbif);
+fail_map:
+ free_vm_area(usbif->conn_ring_area);
+fail_alloc:
+ free_vm_area(usbif->urb_ring_area);
+
+ return err;
}
void usbif_disconnect(usbif_t *usbif)
@@ -176,12 +215,12 @@
usbif->xenusbd = NULL;
}
- spin_lock_irqsave(&usbif->plug_lock, flags);
- list_for_each_entry_safe(stub, tmp, &usbif->plugged_devices,
plugged_list) {
+ spin_lock_irqsave(&usbif->stub_lock, flags);
+ list_for_each_entry_safe(stub, tmp, &usbif->stub_list, dev_list) {
usbbk_unlink_urbs(stub);
detach_device_without_lock(usbif, stub);
}
- spin_unlock_irqrestore(&usbif->plug_lock, flags);
+ spin_unlock_irqrestore(&usbif->stub_lock, flags);
wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0);
@@ -190,10 +229,12 @@
usbif->irq = 0;
}
- if (usbif->ring.sring) {
- unmap_frontend_page(usbif);
- free_vm_area(usbif->ring_area);
- usbif->ring.sring = NULL;
+ if (usbif->urb_ring.sring) {
+ unmap_frontend_pages(usbif);
+ free_vm_area(usbif->urb_ring_area);
+ free_vm_area(usbif->conn_ring_area);
+ usbif->urb_ring.sring = NULL;
+ usbif->conn_ring.sring = NULL;
}
}
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbback.c
--- a/drivers/xen/usbback/usbback.c Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbback.c Tue Oct 06 15:18:27 2009 +0900
@@ -107,7 +107,7 @@
#define pending_handle(_req, _seg) \
(pending_grant_handles[vaddr_pagenr(_req, _seg)])
-static pending_req_t* alloc_req(void)
+static pending_req_t *alloc_req(void)
{
pending_req_t *req = NULL;
unsigned long flags;
@@ -222,7 +222,7 @@
}
}
-static int usbbk_alloc_urb(usbif_request_t *req, pending_req_t *pending_req)
+static int usbbk_alloc_urb(usbif_urb_request_t *req, pending_req_t
*pending_req)
{
int ret;
@@ -298,21 +298,21 @@
int32_t actual_length, int32_t
error_count, uint16_t start_frame)
{
usbif_t *usbif = pending_req->usbif;
- usbif_response_t *ring_res;
+ usbif_urb_response_t *res;
unsigned long flags;
int notify;
- spin_lock_irqsave(&usbif->ring_lock, flags);
- ring_res = RING_GET_RESPONSE(&usbif->ring, usbif->ring.rsp_prod_pvt);
- ring_res->id = pending_req->id;
- ring_res->status = status;
- ring_res->actual_length = actual_length;
- ring_res->error_count = error_count;
- ring_res->start_frame = start_frame;
- usbif->ring.rsp_prod_pvt++;
+ spin_lock_irqsave(&usbif->urb_ring_lock, flags);
+ res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt);
+ res->id = pending_req->id;
+ res->status = status;
+ res->actual_length = actual_length;
+ res->error_count = error_count;
+ res->start_frame = start_frame;
+ usbif->urb_ring.rsp_prod_pvt++;
barrier();
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->ring, notify);
- spin_unlock_irqrestore(&usbif->ring_lock, flags);
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify);
+ spin_unlock_irqrestore(&usbif->urb_ring_lock, flags);
if (notify)
notify_remote_via_irq(usbif->irq);
@@ -346,7 +346,7 @@
}
static int usbbk_gnttab_map(usbif_t *usbif,
- usbif_request_t *req, pending_req_t *pending_req)
+ usbif_urb_request_t *req, pending_req_t *pending_req)
{
int i, ret;
unsigned int nr_segs;
@@ -434,7 +434,7 @@
return ret;
}
-static void usbbk_init_urb(usbif_request_t *req, pending_req_t *pending_req)
+static void usbbk_init_urb(usbif_urb_request_t *req, pending_req_t
*pending_req)
{
unsigned int pipe;
struct usb_device *udev = pending_req->stub->udev;
@@ -671,14 +671,14 @@
int found = 0;
unsigned long flags;
- spin_lock_irqsave(&usbif->plug_lock, flags);
- list_for_each_entry(stub, &usbif->plugged_devices, plugged_list) {
- if (stub->id->portnum == portnum) {
+ spin_lock_irqsave(&usbif->stub_lock, flags);
+ list_for_each_entry(stub, &usbif->stub_list, dev_list) {
+ if (stub->portid->portnum == portnum) {
found = 1;
break;
}
}
- spin_unlock_irqrestore(&usbif->plug_lock, flags);
+ spin_unlock_irqrestore(&usbif->stub_lock, flags);
if (found)
return stub;
@@ -686,7 +686,47 @@
return NULL;
}
-static int check_and_submit_special_ctrlreq(usbif_t *usbif, usbif_request_t
*req, pending_req_t *pending_req)
+static void process_unlink_req(usbif_t *usbif,
+ usbif_urb_request_t *req, pending_req_t *pending_req)
+{
+ pending_req_t *unlink_req = NULL;
+ int devnum;
+ int ret = 0;
+ unsigned long flags;
+
+ devnum = usb_pipedevice(req->pipe);
+ if (unlikely(devnum == 0)) {
+ pending_req->stub = find_attached_device(usbif,
usbif_pipeportnum(req->pipe));
+ if (unlikely(!pending_req->stub)) {
+ ret = -ENODEV;
+ goto fail_response;
+ }
+ } else {
+ if (unlikely(!usbif->addr_table[devnum])) {
+ ret = -ENODEV;
+ goto fail_response;
+ }
+ pending_req->stub = usbif->addr_table[devnum];
+ }
+
+ spin_lock_irqsave(&pending_req->stub->submitting_lock, flags);
+ list_for_each_entry(unlink_req, &pending_req->stub->submitting_list,
urb_list) {
+ if (unlink_req->id == req->u.unlink.unlink_id) {
+ ret = usb_unlink_urb(unlink_req->urb);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pending_req->stub->submitting_lock, flags);
+
+fail_response:
+ usbbk_do_response(pending_req, ret, 0, 0, 0);
+ usbif_put(usbif);
+ free_req(pending_req);
+ return;
+}
+
+static int check_and_submit_special_ctrlreq(usbif_t *usbif,
+ usbif_urb_request_t *req, pending_req_t *pending_req)
{
int devnum;
struct usbstub *stub = NULL;
@@ -824,7 +864,7 @@
}
static void dispatch_request_to_pending_reqs(usbif_t *usbif,
- usbif_request_t *req,
+ usbif_urb_request_t *req,
pending_req_t *pending_req)
{
int ret;
@@ -834,17 +874,13 @@
barrier();
- /*
- * TODO:
- * receive unlink request and cancel the urb in backend
- */
-#if 0
- if (unlikely(usb_pipeunlink(req->pipe))) {
+ usbif_get(usbif);
+ /* unlink request */
+ if (unlikely(usbif_pipeunlink(req->pipe))) {
+ process_unlink_req(usbif, req, pending_req);
+ return;
}
-#endif
-
- usbif_get(usbif);
if (usb_pipecontrol(req->pipe)) {
if (check_and_submit_special_ctrlreq(usbif, req, pending_req))
@@ -927,18 +963,18 @@
static int usbbk_start_submit_urb(usbif_t *usbif)
{
- usbif_back_ring_t *usb_ring = &usbif->ring;
- usbif_request_t *ring_req;
+ usbif_urb_back_ring_t *urb_ring = &usbif->urb_ring;
+ usbif_urb_request_t *req;
pending_req_t *pending_req;
RING_IDX rc, rp;
int more_to_do = 0;
- rc = usb_ring->req_cons;
- rp = usb_ring->sring->req_prod;
+ rc = urb_ring->req_cons;
+ rp = urb_ring->sring->req_prod;
rmb();
while (rc != rp) {
- if (RING_REQUEST_CONS_OVERFLOW(usb_ring, rc)) {
+ if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) {
printk(KERN_WARNING "RING_REQUEST_CONS_OVERFLOW\n");
break;
}
@@ -949,73 +985,100 @@
break;
}
- ring_req = RING_GET_REQUEST(usb_ring, rc);
- usb_ring->req_cons = ++rc;
+ req = RING_GET_REQUEST(urb_ring, rc);
+ urb_ring->req_cons = ++rc;
- dispatch_request_to_pending_reqs(usbif, ring_req,
+ dispatch_request_to_pending_reqs(usbif, req,
pending_req);
}
- RING_FINAL_CHECK_FOR_REQUESTS(&usbif->ring, more_to_do);
+ RING_FINAL_CHECK_FOR_REQUESTS(&usbif->urb_ring, more_to_do);
cond_resched();
return more_to_do;
}
+void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed)
+{
+ usbif_conn_back_ring_t *ring = &usbif->conn_ring;
+ usbif_conn_request_t *req;
+ usbif_conn_response_t *res;
+ unsigned long flags;
+ u16 id;
+ int notify;
+
+ spin_lock_irqsave(&usbif->conn_ring_lock, flags);
+
+ req = RING_GET_REQUEST(ring, ring->req_cons);;
+ id = req->id;
+ ring->req_cons++;
+ ring->sring->req_event = ring->req_cons + 1;
+
+ res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+ res->id = id;
+ res->portnum = portnum;
+ res->speed = speed;
+ ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+ spin_unlock_irqrestore(&usbif->conn_ring_lock, flags);
+
+ if (notify)
+ notify_remote_via_irq(usbif->irq);
+}
+
int usbbk_schedule(void *arg)
{
- usbif_t *usbif = (usbif_t *)arg;
+ usbif_t *usbif = (usbif_t *) arg;
- usbif_get(usbif);
+ usbif_get(usbif);
- while(!kthread_should_stop()) {
- wait_event_interruptible(
- usbif->wq,
- usbif->waiting_reqs || kthread_should_stop());
- wait_event_interruptible(
- pending_free_wq,
- !list_empty(&pending_free) ||
kthread_should_stop());
- usbif->waiting_reqs = 0;
- smp_mb();
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ usbif->wq,
+ usbif->waiting_reqs || kthread_should_stop());
+ wait_event_interruptible(
+ pending_free_wq,
+ !list_empty(&pending_free) || kthread_should_stop());
+ usbif->waiting_reqs = 0;
+ smp_mb();
- if (usbbk_start_submit_urb(usbif))
- usbif->waiting_reqs = 1;
- }
+ if (usbbk_start_submit_urb(usbif))
+ usbif->waiting_reqs = 1;
+ }
- usbif->xenusbd = NULL;
- usbif_put(usbif);
+ usbif->xenusbd = NULL;
+ usbif_put(usbif);
- return 0;
+ return 0;
}
/*
- * attach the grabbed device to usbif.
+ * attach usbstub device to usbif.
*/
-void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub)
+void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub)
{
unsigned long flags;
- spin_lock_irqsave(&usbif->plug_lock, flags);
- list_add(&stub->plugged_list, &usbif->plugged_devices);
- spin_unlock_irqrestore(&usbif->plug_lock, flags);
- stub->plugged = 1;
+ spin_lock_irqsave(&usbif->stub_lock, flags);
+ list_add(&stub->dev_list, &usbif->stub_list);
+ spin_unlock_irqrestore(&usbif->stub_lock, flags);
stub->usbif = usbif;
}
/*
- * detach the grabbed device from usbif.
+ * detach usbstub device from usbif.
*/
-void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub)
+void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub)
{
unsigned long flags;
if (stub->addr)
usbbk_set_address(usbif, stub, stub->addr, 0);
- spin_lock_irqsave(&usbif->plug_lock, flags);
- list_del(&stub->plugged_list);
- spin_unlock_irqrestore(&usbif->plug_lock, flags);
- stub->plugged = 0;
+ spin_lock_irqsave(&usbif->stub_lock, flags);
+ list_del(&stub->dev_list);
+ spin_unlock_irqrestore(&usbif->stub_lock, flags);
stub->usbif = NULL;
}
@@ -1023,8 +1086,7 @@
{
if (stub->addr)
usbbk_set_address(usbif, stub, stub->addr, 0);
- list_del(&stub->plugged_list);
- stub->plugged = 0;
+ list_del(&stub->dev_list);
stub->usbif = NULL;
}
@@ -1054,9 +1116,8 @@
memset(pending_reqs, 0, sizeof(pending_reqs));
INIT_LIST_HEAD(&pending_free);
- for (i = 0; i < usbif_reqs; i++) {
+ for (i = 0; i < usbif_reqs; i++)
list_add_tail(&pending_reqs[i].free_list, &pending_free);
- }
usbback_xenbus_init();
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbback.h
--- a/drivers/xen/usbback/usbback.h Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbback.h Tue Oct 06 15:18:27 2009 +0900
@@ -59,6 +59,7 @@
#include <xen/gnttab.h>
#include <xen/driver_util.h>
#include <xen/interface/xen.h>
+#include <xen/xenbus.h>
#include <xen/interface/io/usbif.h>
struct usbstub;
@@ -66,89 +67,103 @@
#define USB_DEV_ADDR_SIZE 128
typedef struct usbif_st {
- domid_t domid;
- unsigned int handle;
+ domid_t domid;
+ unsigned int handle;
+ int num_ports;
+ enum usb_spec_version usb_ver;
+
struct xenbus_device *xbdev;
struct list_head usbif_list;
unsigned int irq;
- usbif_back_ring_t ring;
- struct vm_struct *ring_area;
+ usbif_urb_back_ring_t urb_ring;
+ usbif_conn_back_ring_t conn_ring;
+ struct vm_struct *urb_ring_area;
+ struct vm_struct *conn_ring_area;
- spinlock_t ring_lock;
+ spinlock_t urb_ring_lock;
+ spinlock_t conn_ring_lock;
atomic_t refcnt;
- grant_handle_t shmem_handle;
- grant_ref_t shmem_ref;
+
+ grant_handle_t urb_shmem_handle;
+ grant_ref_t urb_shmem_ref;
+ grant_handle_t conn_shmem_handle;
+ grant_ref_t conn_shmem_ref;
+
+ struct xenbus_watch backend_watch;
/* device address lookup table */
+ struct usbstub *addr_table[USB_DEV_ADDR_SIZE];
spinlock_t addr_lock;
- struct usbstub *addr_table[USB_DEV_ADDR_SIZE];
- /* plugged device list */
- unsigned plaggable:1;
- spinlock_t plug_lock;
- struct list_head plugged_devices;
+ /* connected device list */
+ struct list_head stub_list;
+ spinlock_t stub_lock;
/* request schedule */
struct task_struct *xenusbd;
unsigned int waiting_reqs;
wait_queue_head_t waiting_to_free;
wait_queue_head_t wq;
-
} usbif_t;
-struct usbstub_id
-{
+struct vusb_port_id {
struct list_head id_list;
- char bus_id[BUS_ID_SIZE];
- int dom_id;
- int dev_id;
+ char phys_bus[BUS_ID_SIZE];
+ domid_t domid;
+ unsigned int handle;
int portnum;
+ unsigned is_connected:1;
};
-struct usbstub
-{
- struct usbstub_id *id;
+struct usbstub {
+ struct kref kref;
+ struct list_head dev_list;
+
+ struct vusb_port_id *portid;
struct usb_device *udev;
- struct usb_interface *interface;
usbif_t *usbif;
-
- struct list_head grabbed_list;
-
- unsigned plugged:1;
- struct list_head plugged_list;
-
int addr;
+ struct list_head submitting_list;
spinlock_t submitting_lock;
- struct list_head submitting_list;
};
usbif_t *usbif_alloc(domid_t domid, unsigned int handle);
void usbif_disconnect(usbif_t *usbif);
void usbif_free(usbif_t *usbif);
-int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn);
+int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref,
+ unsigned long conn_ring_ref, unsigned int evtchn);
#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
#define usbif_put(_b) \
do { \
if (atomic_dec_and_test(&(_b)->refcnt)) \
- wake_up(&(_b)->waiting_to_free); \
+ wake_up(&(_b)->waiting_to_free); \
} while (0)
+usbif_t *find_usbif(domid_t domid, unsigned int handle);
void usbback_xenbus_init(void);
void usbback_xenbus_exit(void);
-
+struct vusb_port_id *find_portid_by_busid(const char *busid);
+struct vusb_port_id *find_portid(const domid_t domid,
+ const unsigned int handle,
+ const int portnum);
+int portid_add(const char *busid,
+ const domid_t domid,
+ const unsigned int handle,
+ const int portnum);
+int portid_remove(const domid_t domid,
+ const unsigned int handle,
+ const int portnum);
irqreturn_t usbbk_be_int(int irq, void *dev_id, struct pt_regs *regs);
int usbbk_schedule(void *arg);
struct usbstub *find_attached_device(usbif_t *usbif, int port);
-struct usbstub *find_grabbed_device(int dom_id, int dev_id, int port);
-usbif_t *find_usbif(int dom_id, int dev_id);
-void usbback_reconfigure(usbif_t *usbif);
-void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub);
-void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed);
void detach_device_without_lock(usbif_t *usbif, struct usbstub *stub);
void usbbk_unlink_urbs(struct usbstub *stub);
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbstub.c
--- a/drivers/xen/usbback/usbstub.c Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbstub.c Tue Oct 06 15:18:27 2009 +0900
@@ -45,36 +45,106 @@
#include "usbback.h"
-static LIST_HEAD(usbstub_ids);
-static DEFINE_SPINLOCK(usbstub_ids_lock);
-static LIST_HEAD(grabbed_devices);
-static DEFINE_SPINLOCK(grabbed_devices_lock);
+static LIST_HEAD(port_list);
+static DEFINE_SPINLOCK(port_list_lock);
-struct usbstub *find_grabbed_device(int dom_id, int dev_id, int portnum)
+struct vusb_port_id *find_portid_by_busid(const char *busid)
{
- struct usbstub *stub;
+ struct vusb_port_id *portid;
int found = 0;
unsigned long flags;
- spin_lock_irqsave(&grabbed_devices_lock, flags);
- list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
- if (stub->id->dom_id == dom_id
- && stub->id->dev_id == dev_id
- && stub->id->portnum == portnum) {
+ spin_lock_irqsave(&port_list_lock, flags);
+ list_for_each_entry(portid, &port_list, id_list) {
+ if (!(strncmp(portid->phys_bus, busid, BUS_ID_SIZE))) {
found = 1;
break;
}
}
- spin_unlock_irqrestore(&grabbed_devices_lock, flags);
+ spin_unlock_irqrestore(&port_list_lock, flags);
if (found)
- return stub;
+ return portid;
return NULL;
}
-static struct usbstub *usbstub_alloc(struct usb_interface *interface,
- struct usbstub_id *stub_id)
+struct vusb_port_id *find_portid(const domid_t domid,
+ const unsigned int handle,
+ const int portnum)
+{
+ struct vusb_port_id *portid;
+ int found = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port_list_lock, flags);
+ list_for_each_entry(portid, &port_list, id_list) {
+ if ((portid->domid == domid)
+ && (portid->handle == handle)
+ && (portid->portnum == portnum)) {
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&port_list_lock, flags);
+
+ if (found)
+ return portid;
+
+ return NULL;
+}
+
+int portid_add(const char *busid,
+ const domid_t domid,
+ const unsigned int handle,
+ const int portnum)
+{
+ struct vusb_port_id *portid;
+ unsigned long flags;
+
+ portid = kzalloc(sizeof(*portid), GFP_KERNEL);
+ if (!portid)
+ return -ENOMEM;
+
+ portid->domid = domid;
+ portid->handle = handle;
+ portid->portnum = portnum;
+
+ strncpy(portid->phys_bus, busid, BUS_ID_SIZE);
+
+ spin_lock_irqsave(&port_list_lock, flags);
+ list_add(&portid->id_list, &port_list);
+ spin_unlock_irqrestore(&port_list_lock, flags);
+
+ return 0;
+}
+
+int portid_remove(const domid_t domid,
+ const unsigned int handle,
+ const int portnum)
+{
+ struct vusb_port_id *portid, *tmp;
+ int err = -ENOENT;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port_list_lock, flags);
+ list_for_each_entry_safe(portid, tmp, &port_list, id_list) {
+ if (portid->domid == domid
+ && portid->handle == handle
+ && portid->portnum == portnum) {
+ list_del(&portid->id_list);
+ kfree(portid);
+
+ err = 0;
+ }
+ }
+ spin_unlock_irqrestore(&port_list_lock, flags);
+
+ return err;
+}
+
+static struct usbstub *usbstub_alloc(struct usb_device *udev,
+ struct vusb_port_id *portid)
{
struct usbstub *stub;
@@ -83,314 +153,135 @@
printk(KERN_ERR "no memory for alloc usbstub\n");
return NULL;
}
-
- stub->udev = usb_get_dev(interface_to_usbdev(interface));
- stub->interface = interface;
- stub->id = stub_id;
+ kref_init(&stub->kref);
+ stub->udev = usb_get_dev(udev);
+ stub->portid = portid;
spin_lock_init(&stub->submitting_lock);
INIT_LIST_HEAD(&stub->submitting_list);
return stub;
}
-static int usbstub_free(struct usbstub *stub)
+static void usbstub_release(struct kref *kref)
{
- if (!stub)
- return -EINVAL;
+ struct usbstub *stub;
+
+ stub = container_of(kref, struct usbstub, kref);
usb_put_dev(stub->udev);
- stub->interface = NULL;
stub->udev = NULL;
- stub->id = NULL;
+ stub->portid = NULL;
kfree(stub);
-
- return 0;
}
-static int usbstub_match_one(struct usb_interface *interface,
- struct usbstub_id *stub_id)
+static inline void usbstub_get(struct usbstub *stub)
{
- char *udev_busid = interface->dev.parent->bus_id;
-
- if (!(strncmp(stub_id->bus_id, udev_busid, BUS_ID_SIZE))) {
- return 1;
- }
-
- return 0;
+ kref_get(&stub->kref);
}
-static struct usbstub_id *usbstub_match(struct usb_interface *interface)
+static inline void usbstub_put(struct usbstub *stub)
{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct usbstub_id *stub_id;
- unsigned long flags;
- int found = 0;
+ kref_put(&stub->kref, usbstub_release);
+}
+
+static int usbstub_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char *busid = intf->dev.parent->bus_id;
+ struct vusb_port_id *portid = NULL;
+ struct usbstub *stub = NULL;
+ usbif_t *usbif = NULL;
+ int retval = -ENODEV;
/* hub currently not supported, so skip. */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
- return NULL;
+ goto out;
- spin_lock_irqsave(&usbstub_ids_lock, flags);
- list_for_each_entry(stub_id, &usbstub_ids, id_list) {
- if (usbstub_match_one(interface, stub_id)) {
- found = 1;
+ portid = find_portid_by_busid(busid);
+ if (!portid)
+ goto out;
+
+ usbif = find_usbif(portid->domid, portid->handle);
+ if (!usbif)
+ goto out;
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ break;
+ case USB_SPEED_HIGH:
+ if (usbif->usb_ver >= USB_VER_USB20)
break;
- }
+ /* fall through */
+ default:
+ goto out;
}
- spin_unlock_irqrestore(&usbstub_ids_lock, flags);
- if (found)
- return stub_id;
-
- return NULL;
-}
-
-static void add_to_grabbed_devices(struct usbstub *stub)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&grabbed_devices_lock, flags);
- list_add(&stub->grabbed_list, &grabbed_devices);
- spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-}
-
-static void remove_from_grabbed_devices(struct usbstub *stub)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&grabbed_devices_lock, flags);
- list_del(&stub->grabbed_list);
- spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-}
-
-static int usbstub_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usbstub_id *stub_id = NULL;
- struct usbstub *stub = NULL;
- usbif_t *usbif = NULL;
- int retval = 0;
-
- if ((stub_id = usbstub_match(interface))) {
- stub = usbstub_alloc(interface, stub_id);
+ stub = find_attached_device(usbif, portid->portnum);
+ if (!stub) {
+ /* new connection */
+ stub = usbstub_alloc(udev, portid);
if (!stub)
return -ENOMEM;
+ usbbk_attach_device(usbif, stub);
+ usbbk_hotplug_notify(usbif, portid->portnum, udev->speed);
+ } else {
+ /* maybe already called and connected by other intf */
+ if (strncmp(stub->portid->phys_bus, busid, BUS_ID_SIZE))
+ goto out; /* invalid call */
+ }
- usb_set_intfdata(interface, stub);
- add_to_grabbed_devices(stub);
- usbif = find_usbif(stub_id->dom_id, stub_id->dev_id);
- if (usbif) {
- usbbk_plug_device(usbif, stub);
- usbback_reconfigure(usbif);
- }
+ usbstub_get(stub);
+ usb_set_intfdata(intf, stub);
+ retval = 0;
- } else
- retval = -ENODEV;
-
+out:
return retval;
}
-static void usbstub_disconnect(struct usb_interface *interface)
+static void usbstub_disconnect(struct usb_interface *intf)
{
struct usbstub *stub
- = (struct usbstub *) usb_get_intfdata(interface);
+ = (struct usbstub *) usb_get_intfdata(intf);
- usb_set_intfdata(interface, NULL);
+ usb_set_intfdata(intf, NULL);
if (!stub)
return;
if (stub->usbif) {
- usbback_reconfigure(stub->usbif);
- usbbk_unplug_device(stub->usbif, stub);
+ usbbk_hotplug_notify(stub->usbif, stub->portid->portnum, 0);
+ usbbk_detach_device(stub->usbif, stub);
}
-
usbbk_unlink_urbs(stub);
-
- remove_from_grabbed_devices(stub);
-
- usbstub_free(stub);
-
- return;
+ usbstub_put(stub);
}
-static inline int str_to_vport(const char *buf,
- char *phys_bus,
- int *dom_id,
- int *dev_id,
- int *port)
-{
- char *p;
- int len;
- int err;
-
- /* no physical bus */
- if (!(p = strchr(buf, ':')))
- return -EINVAL;
-
- len = p - buf;
-
- /* bad physical bus */
- if (len + 1 > BUS_ID_SIZE)
- return -EINVAL;
-
- strlcpy(phys_bus, buf, len + 1);
- err = sscanf(p + 1, "%d:%d:%d", dom_id, dev_id, port);
- if (err == 3)
- return 0;
- else
- return -EINVAL;
-}
-
-static int usbstub_id_add(const char *bus_id,
- const int dom_id,
- const int dev_id,
- const int portnum)
-{
- struct usbstub_id *stub_id;
- unsigned long flags;
-
- stub_id = kzalloc(sizeof(*stub_id), GFP_KERNEL);
- if (!stub_id)
- return -ENOMEM;
-
- stub_id->dom_id = dom_id;
- stub_id->dev_id = dev_id;
- stub_id->portnum = portnum;
-
- strncpy(stub_id->bus_id, bus_id, BUS_ID_SIZE);
-
- spin_lock_irqsave(&usbstub_ids_lock, flags);
- list_add(&stub_id->id_list, &usbstub_ids);
- spin_unlock_irqrestore(&usbstub_ids_lock, flags);
-
- return 0;
-}
-
-static int usbstub_id_remove(const char *phys_bus,
- const int dom_id,
- const int dev_id,
- const int portnum)
-{
- struct usbstub_id *stub_id, *tmp;
- int err = -ENOENT;
- unsigned long flags;
-
- spin_lock_irqsave(&usbstub_ids_lock, flags);
- list_for_each_entry_safe(stub_id, tmp, &usbstub_ids, id_list) {
- if (stub_id->dom_id == dom_id
- && stub_id->dev_id == dev_id
- && stub_id->portnum == portnum) {
- list_del(&stub_id->id_list);
- kfree(stub_id);
-
- err = 0;
- }
- }
- spin_unlock_irqrestore(&usbstub_ids_lock, flags);
-
- return err;
-}
-
-static ssize_t usbstub_vport_add(struct device_driver *driver,
- const char *buf, size_t count)
-{
- int err = 0;
-
- char bus_id[BUS_ID_SIZE];
- int dom_id;
- int dev_id;
- int portnum;
-
- err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
- if (err)
- goto out;
-
- err = usbstub_id_add(&bus_id[0], dom_id, dev_id, portnum);
-
-out:
- if (!err)
- err = count;
- return err;
-}
-
-DRIVER_ATTR(new_vport, S_IWUSR, NULL, usbstub_vport_add);
-
-static ssize_t usbstub_vport_remove(struct device_driver *driver,
- const char *buf, size_t count)
-{
- int err = 0;
-
- char bus_id[BUS_ID_SIZE];
- int dom_id;
- int dev_id;
- int portnum;
-
- err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
- if (err)
- goto out;
-
- err = usbstub_id_remove(&bus_id[0], dom_id, dev_id, portnum);
-
-out:
- if (!err)
- err = count;
- return err;
-}
-
-DRIVER_ATTR(remove_vport, S_IWUSR, NULL, usbstub_vport_remove);
-
-static ssize_t usbstub_vport_show(struct device_driver *driver,
+static ssize_t usbstub_show_portids(struct device_driver *driver,
char *buf)
{
- struct usbstub_id *stub_id;
+ struct vusb_port_id *portid;
size_t count = 0;
unsigned long flags;
- spin_lock_irqsave(&usbstub_ids_lock, flags);
- list_for_each_entry(stub_id, &usbstub_ids, id_list) {
+ spin_lock_irqsave(&port_list_lock, flags);
+ list_for_each_entry(portid, &port_list, id_list) {
if (count >= PAGE_SIZE)
break;
count += scnprintf((char *)buf + count, PAGE_SIZE - count,
"%s:%d:%d:%d\n",
- &stub_id->bus_id[0],
- stub_id->dom_id,
- stub_id->dev_id,
- stub_id->portnum);
+ &portid->phys_bus[0],
+ portid->domid,
+ portid->handle,
+ portid->portnum);
}
- spin_unlock_irqrestore(&usbstub_ids_lock, flags);
+ spin_unlock_irqrestore(&port_list_lock, flags);
return count;
}
-DRIVER_ATTR(vports, S_IRUSR, usbstub_vport_show, NULL);
-
-static ssize_t usbstub_devices_show(struct device_driver *driver,
- char *buf)
-{
- struct usbstub *stub;
- size_t count = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&grabbed_devices_lock, flags);
- list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
- if (count >= PAGE_SIZE)
- break;
-
- count += scnprintf((char *)buf + count, PAGE_SIZE - count,
- "%u-%s:%u.%u\n",
- stub->udev->bus->busnum,
- stub->udev->devpath,
-
stub->udev->config->desc.bConfigurationValue,
-
stub->interface->cur_altsetting->desc.bInterfaceNumber);
-
- }
- spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-
- return count;
-}
-
-DRIVER_ATTR(grabbed_devices, S_IRUSR, usbstub_devices_show, NULL);
+DRIVER_ATTR(port_ids, S_IRUSR, usbstub_show_portids, NULL);
/* table of devices that matches any usbdevice */
static struct usb_device_id usbstub_table[] = {
@@ -404,44 +295,31 @@
.probe = usbstub_probe,
.disconnect = usbstub_disconnect,
.id_table = usbstub_table,
+ .no_dynamic_id = 1,
};
int __init usbstub_init(void)
{
- int err;
+ int err;
err = usb_register(&usbback_usb_driver);
- if (err < 0)
+ if (err < 0) {
+ printk(KERN_ERR "usbback: usb_register failed (error %d)\n",
err);
goto out;
- if (!err)
- err = driver_create_file(&usbback_usb_driver.driver,
- &driver_attr_new_vport);
- if (!err)
- err = driver_create_file(&usbback_usb_driver.driver,
- &driver_attr_remove_vport);
- if (!err)
- err = driver_create_file(&usbback_usb_driver.driver,
- &driver_attr_vports);
- if (!err)
- err = driver_create_file(&usbback_usb_driver.driver,
- &driver_attr_grabbed_devices);
+ }
+
+ err = driver_create_file(&usbback_usb_driver.driver,
+ &driver_attr_port_ids);
if (err)
- usbstub_exit();
+ usb_deregister(&usbback_usb_driver);
out:
return err;
}
-void usbstub_exit(void)
+void __exit usbstub_exit(void)
{
driver_remove_file(&usbback_usb_driver.driver,
- &driver_attr_new_vport);
- driver_remove_file(&usbback_usb_driver.driver,
- &driver_attr_remove_vport);
- driver_remove_file(&usbback_usb_driver.driver,
- &driver_attr_vports);
- driver_remove_file(&usbback_usb_driver.driver,
- &driver_attr_grabbed_devices);
-
+ &driver_attr_port_ids);
usb_deregister(&usbback_usb_driver);
}
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/xenbus.c
--- a/drivers/xen/usbback/xenbus.c Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/xenbus.c Tue Oct 06 15:18:27 2009 +0900
@@ -43,29 +43,118 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include <xen/xenbus.h>
#include "usbback.h"
static int start_xenusbd(usbif_t *usbif)
{
- int err = 0;
- char name[TASK_COMM_LEN];
+ int err = 0;
+ char name[TASK_COMM_LEN];
- snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid,
usbif->handle);
- usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
- if (IS_ERR(usbif->xenusbd)) {
- err = PTR_ERR(usbif->xenusbd);
- usbif->xenusbd = NULL;
- xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
- }
- return err;
+ snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid,
+ usbif->handle);
+ usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
+ if (IS_ERR(usbif->xenusbd)) {
+ err = PTR_ERR(usbif->xenusbd);
+ usbif->xenusbd = NULL;
+ xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
+ }
+
+ return err;
+}
+
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenbus_transaction xbt;
+ int err;
+ int i;
+ char node[8];
+ char *busid;
+ struct vusb_port_id *portid = NULL;
+
+ usbif_t *usbif = container_of(watch, usbif_t, backend_watch);
+ struct xenbus_device *dev = usbif->xbdev;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ return;
+ }
+
+ for (i = 1; i <= usbif->num_ports; i++) {
+ sprintf(node, "port/%d", i);
+ busid = xenbus_read(xbt, dev->nodename, node, NULL);
+ if (IS_ERR(busid)) {
+ err = PTR_ERR(busid);
+ xenbus_dev_fatal(dev, err, "reading port/%d", i);
+ goto abort;
+ }
+
+ /*
+ * remove portid, if the port is not connected,
+ */
+ if (strlen(busid) == 0) {
+ portid = find_portid(usbif->domid, usbif->handle, i);
+ if (portid) {
+ if (portid->is_connected)
+ xenbus_dev_fatal(dev, err,
+ "can't remove port/%d, unbind
first", i);
+ else
+ portid_remove(usbif->domid,
usbif->handle, i);
+ }
+ continue; /* never configured, ignore */
+ }
+
+ /*
+ * add portid,
+ * if the port is not configured and not used from other usbif.
+ */
+ portid = find_portid(usbif->domid, usbif->handle, i);
+ if (portid) {
+ if ((strncmp(portid->phys_bus, busid, BUS_ID_SIZE)))
+ xenbus_dev_fatal(dev, err,
+ "can't add port/%d, remove first", i);
+ else
+ continue; /* already configured, ignore */
+ } else {
+ if (find_portid_by_busid(busid))
+ xenbus_dev_fatal(dev, err,
+ "can't add port/%d, busid already
used", i);
+ else
+ portid_add(busid, usbif->domid, usbif->handle,
i);
+ }
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+ if (err)
+ xenbus_dev_fatal(dev, err, "completing transaction");
+
+ return;
+
+abort:
+ xenbus_transaction_end(xbt, 1);
+
+ return;
}
static int usbback_remove(struct xenbus_device *dev)
{
usbif_t *usbif = dev->dev.driver_data;
+ int i;
+
+ if (usbif->backend_watch.node) {
+ unregister_xenbus_watch(&usbif->backend_watch);
+ kfree(usbif->backend_watch.node);
+ usbif->backend_watch.node = NULL;
+ }
if (usbif) {
+ /* remove all ports */
+ for (i = 1; i <= usbif->num_ports; i++)
+ portid_remove(usbif->domid, usbif->handle, i);
usbif_disconnect(usbif);
usbif_free(usbif);;
}
@@ -79,12 +168,14 @@
{
usbif_t *usbif;
unsigned int handle;
+ int num_ports;
+ int usb_ver;
int err;
if (usb_disabled())
return -ENODEV;
- handle = simple_strtoul(strrchr(dev->otherend,'/')+1, NULL, 0);
+ handle = simple_strtoul(strrchr(dev->otherend, '/') + 1, NULL, 0);
usbif = usbif_alloc(dev->otherend_id, handle);
if (!usbif) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface");
@@ -93,6 +184,34 @@
usbif->xbdev = dev;
dev->dev.driver_data = usbif;
+ err = xenbus_scanf(XBT_NIL, dev->nodename,
+ "num-ports", "%d", &num_ports);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading num-ports");
+ goto fail;
+ }
+ if (num_ports < 1 || num_ports > USB_MAXCHILDREN) {
+ xenbus_dev_fatal(dev, err, "invalid num-ports");
+ goto fail;
+ }
+ usbif->num_ports = num_ports;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename,
+ "usb-ver", "%d", &usb_ver);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading usb-ver");
+ goto fail;
+ }
+ switch (usb_ver) {
+ case USB_VER_USB11:
+ case USB_VER_USB20:
+ usbif->usb_ver = usb_ver;
+ break;
+ default:
+ xenbus_dev_fatal(dev, err, "invalid usb-ver");
+ goto fail;
+ }
+
err = xenbus_switch_state(dev, XenbusStateInitWait);
if (err)
goto fail;
@@ -104,15 +223,17 @@
return err;
}
-static int connect_ring(usbif_t *usbif)
+static int connect_rings(usbif_t *usbif)
{
struct xenbus_device *dev = usbif->xbdev;
- unsigned long ring_ref;
+ unsigned long urb_ring_ref;
+ unsigned long conn_ring_ref;
unsigned int evtchn;
int err;
err = xenbus_gather(XBT_NIL, dev->otherend,
- "ring-ref", "%lu", &ring_ref,
+ "urb-ring-ref", "%lu", &urb_ring_ref,
+ "conn-ring-ref", "%lu", &conn_ring_ref,
"event-channel", "%u", &evtchn, NULL);
if (err) {
xenbus_dev_fatal(dev, err,
@@ -121,81 +242,32 @@
return err;
}
- printk("usbback: ring-ref %ld, event-channel %d\n",
- ring_ref, evtchn);
+ printk("usbback: urb-ring-ref %ld, conn-ring-ref %ld, event-channel
%d\n",
+ urb_ring_ref, conn_ring_ref, evtchn);
- err = usbif_map(usbif, ring_ref, evtchn);
+ err = usbif_map(usbif, urb_ring_ref, conn_ring_ref, evtchn);
if (err) {
- xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
- ring_ref, evtchn);
+ xenbus_dev_fatal(dev, err,
+ "mapping urb-ring-ref %lu conn-ring-ref %lu
port %u",
+ urb_ring_ref, conn_ring_ref, evtchn);
return err;
}
return 0;
}
-void usbback_do_hotplug(usbif_t *usbif)
-{
- struct xenbus_transaction xbt;
- struct xenbus_device *dev = usbif->xbdev;
- struct usbstub *stub = NULL;
- int err;
- char port_str[8];
- int i;
- int num_ports;
- int state;
-
-again:
- err = xenbus_transaction_start(&xbt);
- if (err) {
- xenbus_dev_fatal(dev, err, "starting transaction");
- return;
- }
-
- err = xenbus_scanf(xbt, dev->nodename,
- "num-ports", "%d", &num_ports);
-
- for (i = 1; i <= num_ports; i++) {
- stub = find_attached_device(usbif, i);
- if (stub)
- state = stub->udev->speed;
- else
- state = 0;
- sprintf(port_str, "port-%d", i);
- err = xenbus_printf(xbt, dev->nodename, port_str, "%d",
state);
- if (err) {
- xenbus_dev_fatal(dev, err, "writing port-%d
state", i);
- goto abort;
- }
- }
-
- err = xenbus_transaction_end(xbt, 0);
- if (err == -EAGAIN)
- goto again;
- if (err)
- xenbus_dev_fatal(dev, err, "completing transaction");
-
- return;
-
-abort:
- xenbus_transaction_end(xbt, 1);
-}
-
-void usbback_reconfigure(usbif_t *usbif)
-{
- struct xenbus_device *dev = usbif->xbdev;
-
- if (dev->state == XenbusStateConnected)
- xenbus_switch_state(dev, XenbusStateReconfiguring);
-}
-
-void frontend_changed(struct xenbus_device *dev,
+static void frontend_changed(struct xenbus_device *dev,
enum xenbus_state frontend_state)
{
usbif_t *usbif = dev->dev.driver_data;
int err;
switch (frontend_state) {
+ case XenbusStateInitialised:
+ case XenbusStateReconfiguring:
+ case XenbusStateReconfigured:
+ break;
+
case XenbusStateInitialising:
if (dev->state == XenbusStateClosed) {
printk("%s: %s: prepare for reconnect\n",
@@ -204,17 +276,18 @@
}
break;
- case XenbusStateInitialised:
- err = connect_ring(usbif);
+ case XenbusStateConnected:
+ if (dev->state == XenbusStateConnected)
+ break;
+ err = connect_rings(usbif);
if (err)
break;
- start_xenusbd(usbif);
- usbback_do_hotplug(usbif);
- xenbus_switch_state(dev, XenbusStateConnected);
- break;
-
- case XenbusStateConnected:
- if (dev->state == XenbusStateConnected)
+ err = start_xenusbd(usbif);
+ if (err)
+ break;
+ err = xenbus_watch_path2(dev, dev->nodename, "port",
+ &usbif->backend_watch, backend_changed);
+ if (err)
break;
xenbus_switch_state(dev, XenbusStateConnected);
break;
@@ -226,13 +299,9 @@
case XenbusStateClosed:
xenbus_switch_state(dev, XenbusStateClosed);
- break;
-
- case XenbusStateReconfiguring:
- usbback_do_hotplug(usbif);
- xenbus_switch_state(dev, XenbusStateReconfigured);
- break;
-
+ if (xenbus_dev_is_online(dev))
+ break;
+ /* fall through if not online */
case XenbusStateUnknown:
device_unregister(&dev->dev);
break;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|