debuggers.hg

view linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c @ 3692:03c49d1bcd6b

bitkeeper revision 1.1159.243.1 (42042ba8OAh4EZUckgdGWWSqRLutaQ)

Various cleanups, including a move to the new ring macros.
author mwilli2@equilibrium.research
date Sat Feb 05 02:12:56 2005 +0000 (2005-02-05)
parents d295396360fb
children 924777207448
line source
1 /******************************************************************************
2 * arch/xen/drivers/usbif/backend/interface.c
3 *
4 * USB device interface management.
5 *
6 * by Mark Williamson, Copyright (c) 2004
7 */
10 /******************************************************************************
11 * arch/xen/drivers/blkif/backend/interface.c
12 *
13 * Block-device interface management.
14 *
15 * Copyright (c) 2004, Keir Fraser
16 */
18 #include "common.h"
20 #define USBIF_HASHSZ 1024
21 #define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
23 static kmem_cache_t *usbif_priv_cachep;
24 static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ];
26 usbif_priv_t *usbif_find(domid_t domid)
27 {
28 usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
29 while ( (up != NULL ) && ( up->domid != domid ) )
30 up = up->hash_next;
31 return up;
32 }
34 static void __usbif_disconnect_complete(void *arg)
35 {
36 usbif_priv_t *usbif = (usbif_priv_t *)arg;
37 ctrl_msg_t cmsg;
38 usbif_be_disconnect_t disc;
40 /*
41 * These can't be done in usbif_disconnect() because at that point there
42 * may be outstanding requests at the device whose asynchronous responses
43 * must still be notified to the remote driver.
44 */
45 unbind_evtchn_from_irq(usbif->evtchn);
46 vfree(usbif->usb_ring.sring);
48 /* Construct the deferred response message. */
49 cmsg.type = CMSG_USBIF_BE;
50 cmsg.subtype = CMSG_USBIF_BE_DISCONNECT;
51 cmsg.id = usbif->disconnect_rspid;
52 cmsg.length = sizeof(usbif_be_disconnect_t);
53 disc.domid = usbif->domid;
54 disc.status = USBIF_BE_STATUS_OKAY;
55 memcpy(cmsg.msg, &disc, sizeof(disc));
57 /*
58 * Make sure message is constructed /before/ status change, because
59 * after the status change the 'usbif' structure could be deallocated at
60 * any time. Also make sure we send the response /after/ status change,
61 * as otherwise a subsequent CONNECT request could spuriously fail if
62 * another CPU doesn't see the status change yet.
63 */
64 mb();
65 if ( usbif->status != DISCONNECTING )
66 BUG();
67 usbif->status = DISCONNECTED;
68 mb();
70 /* Send the successful response. */
71 ctrl_if_send_response(&cmsg);
72 }
74 void usbif_disconnect_complete(usbif_priv_t *up)
75 {
76 INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
77 schedule_work(&up->work);
78 }
80 void usbif_create(usbif_be_create_t *create)
81 {
82 domid_t domid = create->domid;
83 usbif_priv_t **pup, *up;
85 if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
86 {
87 DPRINTK("Could not create usbif: out of memory\n");
88 create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
89 return;
90 }
92 memset(up, 0, sizeof(*up));
93 up->domid = domid;
94 up->status = DISCONNECTED;
95 spin_lock_init(&up->usb_ring_lock);
96 atomic_set(&up->refcnt, 0);
98 pup = &usbif_priv_hash[USBIF_HASH(domid)];
99 while ( *pup != NULL )
100 {
101 if ( (*pup)->domid == domid )
102 {
103 create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
104 kmem_cache_free(usbif_priv_cachep, up);
105 return;
106 }
107 pup = &(*pup)->hash_next;
108 }
110 up->hash_next = *pup;
111 *pup = up;
113 create->status = USBIF_BE_STATUS_OKAY;
114 }
116 void usbif_destroy(usbif_be_destroy_t *destroy)
117 {
118 domid_t domid = destroy->domid;
119 usbif_priv_t **pup, *up;
121 pup = &usbif_priv_hash[USBIF_HASH(domid)];
122 while ( (up = *pup) != NULL )
123 {
124 if ( up->domid == domid )
125 {
126 if ( up->status != DISCONNECTED )
127 goto still_connected;
128 goto destroy;
129 }
130 pup = &up->hash_next;
131 }
133 destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
134 return;
136 still_connected:
137 destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
138 return;
140 destroy:
141 *pup = up->hash_next;
142 usbif_release_ports(up);
143 kmem_cache_free(usbif_priv_cachep, up);
144 destroy->status = USBIF_BE_STATUS_OKAY;
145 }
147 void usbif_connect(usbif_be_connect_t *connect)
148 {
149 domid_t domid = connect->domid;
150 unsigned int evtchn = connect->evtchn;
151 unsigned long shmem_frame = connect->shmem_frame;
152 struct vm_struct *vma;
153 pgprot_t prot;
154 int error;
155 usbif_priv_t *up;
156 usbif_sring_t *sring;
158 up = usbif_find(domid);
159 if ( unlikely(up == NULL) )
160 {
161 DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n",
162 connect->domid);
163 connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
164 return;
165 }
167 if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
168 {
169 connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
170 return;
171 }
173 prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
174 error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
175 shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
176 prot, domid);
177 if ( error != 0 )
178 {
179 if ( error == -ENOMEM )
180 connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
181 else if ( error == -EFAULT )
182 connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
183 else
184 connect->status = USBIF_BE_STATUS_ERROR;
185 vfree(vma->addr);
186 return;
187 }
189 if ( up->status != DISCONNECTED )
190 {
191 connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
192 vfree(vma->addr);
193 return;
194 }
196 sring = (usbif_sring_t *)vma->addr;
197 SHARED_RING_INIT(USBIF_RING, sring);
198 BACK_RING_INIT(USBIF_RING, &up->usb_ring, sring);
200 up->evtchn = evtchn;
201 up->irq = bind_evtchn_to_irq(evtchn);
202 up->shmem_frame = shmem_frame;
203 up->status = CONNECTED;
204 usbif_get(up);
206 request_irq(up->irq, usbif_be_int, 0, "usbif-backend", up);
208 connect->status = USBIF_BE_STATUS_OKAY;
209 }
211 /* Remove URBs for this interface before destroying it. */
212 void usbif_deschedule(usbif_priv_t *up)
213 {
214 remove_from_usbif_list(up);
215 }
217 int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
218 {
219 domid_t domid = disconnect->domid;
220 usbif_priv_t *up;
222 up = usbif_find(domid);
223 if ( unlikely(up == NULL) )
224 {
225 DPRINTK("usbif_disconnect attempted for non-existent usbif"
226 " (%u)\n", disconnect->domid);
227 disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
228 return 1; /* Caller will send response error message. */
229 }
231 if ( up->status == CONNECTED )
232 {
233 up->status = DISCONNECTING;
234 up->disconnect_rspid = rsp_id;
235 wmb(); /* Let other CPUs see the status change. */
236 free_irq(up->irq, up);
237 usbif_deschedule(up);
238 usbif_put(up);
239 return 0; /* Caller should not send response message. */
240 }
242 disconnect->status = USBIF_BE_STATUS_OKAY;
243 return 1;
244 }
246 void __init usbif_interface_init(void)
247 {
248 usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
249 sizeof(usbif_priv_t),
250 0, 0, NULL, NULL);
251 memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
252 }