debuggers.hg

view tools/python/xen/xend/server/usbif.py @ 4672:d781b9d08e80

bitkeeper revision 1.1327.2.4 (426918a34Af7gihN8mTkq-P3KrAZXg)

Remove twisted from save/migrate handling.
This needs to use threads, so add thread support for
http server requests.

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Fri Apr 22 15:30:43 2005 +0000 (2005-04-22)
parents c69fbe48a357
children 369e382b2f81
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
2 # Copyright (C) 2004 Intel Research Cambridge
3 # Copyright (C) 2004 Mark Williamson <mark.williamson@cl.cam.ac.uk>
4 """Support for virtual USB hubs.
5 """
7 from xen.xend import sxp
8 from xen.xend.XendLogging import log
9 from xen.xend.XendError import XendError
11 import channel
12 from controller import Dev, DevController
13 from messages import *
15 class UsbBackend:
16 """Handler for the 'back-end' channel to a USB device driver domain
17 on behalf of a front-end domain.
18 """
19 def __init__(self, controller, id, dom):
20 self.controller = controller
21 self.id = id
22 self.destroyed = False
23 self.connected = False
24 self.connecting = False
25 self.frontendDomain = self.controller.getDomain()
26 self.backendDomain = dom
27 self.frontendChannel = None
28 self.backendChannel = None
30 def init(self, recreate=False, reboot=False):
31 self.frontendChannel = self.controller.getChannel()
32 cf = channel.channelFactory()
33 self.backendChannel = cf.openChannel(self.backendDomain)
35 def __str__(self):
36 return ('<UsbifBackend frontend=%d backend=%d id=%d>'
37 % (self.frontendDomain,
38 self.backendDomain,
39 self.id))
41 def closeEvtchn(self):
42 if self.evtchn:
43 channel.eventChannelClose(self.evtchn)
44 self.evtchn = None
46 def openEvtchn(self):
47 self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
49 def getEventChannelBackend(self):
50 val = 0
51 if self.evtchn:
52 val = self.evtchn['port1']
53 return val
55 def getEventChannelFrontend(self):
56 val = 0
57 if self.evtchn:
58 val = self.evtchn['port2']
59 return val
61 def connect(self, recreate=False):
62 """Connect the controller to the usbif control interface.
64 @param recreate: true if after xend restart
65 """
66 log.debug("Connecting usbif %s", str(self))
67 if recreate or self.connected or self.connecting:
68 pass
69 else:
70 self.send_be_create()
72 def send_be_create(self):
73 msg = packMsg('usbif_be_create_t',
74 { 'domid' : self.frontendDomain })
75 msg = self.backendChannel.requestResponse(msg)
76 val = unpackMsg('usbif_be_create_t', msg)
77 log.debug('>UsbifBackendController>respond_be_create> %s', str(val))
78 self.connected = True
80 def destroy(self, reboot=False):
81 """Disconnect from the usbif control interface and destroy it.
82 """
83 self.destroyed = True
84 self.send_be_disconnect()
85 self.send_be_destroy()
86 self.closeEvtchn()
88 def send_be_disconnect(self):
89 log.debug('>UsbifBackendController>send_be_disconnect> %s', str(self))
90 msg = packMsg('usbif_be_disconnect_t',
91 { 'domid' : self.frontendDomain })
92 self.backendChannel.writeRequest(msg)
94 def send_be_destroy(self, response=None):
95 log.debug('>UsbifBackendController>send_be_destroy> %s', str(self))
96 msg = packMsg('usbif_be_destroy_t',
97 { 'domid' : self.frontendDomain })
98 self.backendChannel.writeRequest(msg, response=response)
101 def connectInterface(self, val):
102 self.openEvtchn()
103 log.debug(">UsbifBackendController>connectInterface> connecting usbif to event channel %s ports=%d:%d",
104 str(self),
105 self.getEventChannelBackend(),
106 self.getEventChannelFrontend())
107 msg = packMsg('usbif_be_connect_t',
108 { 'domid' : self.frontendDomain,
109 'evtchn' : self.getEventChannelBackend(),
110 'shmem_frame' : val['shmem_frame'],
111 'bandwidth' : 500 # XXX fix bandwidth!
112 })
113 msg = self.backendChannel.requestResponse(msg)
114 self.respond_be_connect(msg)
116 def respond_be_connect(self, msg):
117 """Response handler for a be_connect message.
119 @param msg: message
120 @type msg: xu message
121 """
122 val = unpackMsg('usbif_be_connect_t', msg)
123 log.debug('>UsbifBackendController>respond_be_connect> %s, %s', str(self), str(val))
124 self.send_fe_interface_status_changed()
125 log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.frontendDomain)
126 self.controller.claim_ports()
128 def send_fe_interface_status_changed(self):
129 msg = packMsg('usbif_fe_interface_status_changed_t',
130 { 'status' : USBIF_INTERFACE_STATUS_CONNECTED,
131 'domid' : self.backendDomain,
132 'evtchn' : self.getEventChannelFrontend(),
133 'bandwidth' : 500,
134 'num_ports' : len(self.controller.devices)
135 })
136 self.frontendChannel.writeRequest(msg)
138 def interfaceChanged(self):
139 self.send_fe_interface_status_changed()
142 class UsbDev(Dev):
144 def __init__(self, controller, id, config, recreate=False):
145 Dev.__init__(self, controller, id, config, recreate=recreate)
146 self.port = id
147 self.path = None
148 self.frontendDomain = self.getDomain()
149 self.frontendChannel = None
150 self.backendDomain = 0
151 self.backendChannel = None
152 self.configure(self.config, recreate=recreate)
154 def init(self, recreate=False, reboot=False):
155 self.destroyed = False
156 self.frontendDomain = self.getDomain()
157 self.frontendChannel = self.getChannel()
158 backend = self.getBackend()
159 self.backendChannel = backend.backendChannel
161 def configure(self, config, change=False, recreate=False):
162 if change:
163 raise XendError("cannot reconfigure usb")
164 #todo: FIXME: Use sxp access methods to get this value.
165 # Must not use direct indexing.
166 self.path = config[1][1]
168 #todo: FIXME: Support configuring the backend domain.
169 ## try:
170 ## self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
171 ## except:
172 ## raise XendError('invalid backend domain')
174 def attach(self, recreate=False, change=False):
175 if recreate:
176 pass
177 else:
178 self.attachBackend()
179 if change:
180 self.interfaceChanged()
182 def sxpr(self):
183 val = ['usb',
184 ['id', self.id],
185 ['port', self.port],
186 ['path', self.path],
187 ]
188 val.append(['index', self.getIndex()])
189 return val
191 def getBackend(self):
192 return self.controller.getBackend(self.backendDomain)
194 def destroy(self, change=False, reboot=False):
195 """Destroy the device. If 'change' is true notify the front-end interface.
197 @param change: change flag
198 """
199 self.destroyed = True
200 log.debug("Destroying usb domain=%d id=%s", self.frontendDomain, self.id)
201 self.send_be_release_port()
202 if change:
203 self.interfaceChanged()
205 def interfaceChanged(self):
206 """Tell the back-end to notify the front-end that a device has been
207 added or removed.
208 """
209 self.getBackend().interfaceChanged()
211 def attachBackend(self):
212 """Attach the device to its controller.
214 """
215 self.getBackend().connect()
217 def send_be_claim_port(self):
218 log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % self.path)
219 msg = packMsg('usbif_be_claim_port_t',
220 { 'domid' : self.frontendDomain,
221 'path' : self.path,
222 'usbif_port' : self.port,
223 'status' : 0})
224 self.backendChannel.writeRequest(msg)
225 log.debug(">UsbifBackendController> Claim port completed")
226 # No need to add any callbacks, since the guest polls its virtual ports
227 # anyhow, somewhat like a UHCI controller ;-)
229 def send_be_release_port(self):
230 msg = packMsg('usbif_be_release_port_t',
231 { 'domid' : self.frontendDomain,
232 'path' : self.path })
233 self.backendChannel.writeRequest(msg)
234 log.debug(">UsbifBackendController> Release port completed")
235 # No need to add any callbacks, since the guest polls its virtual ports
236 # anyhow, somewhat like a UHCI controller ;-)
238 class UsbifController(DevController):
239 """USB device interface controller. Handles all USB devices
240 for a domain.
241 """
243 def __init__(self, dctype, vm, recreate=False):
244 """Create a USB device controller.
245 """
246 DevController.__init__(self, dctype, vm, recreate=recreate)
247 self.backends = {}
248 self.backendId = 0
249 self.rcvr = None
251 def init(self, recreate=False, reboot=False):
252 self.destroyed = False
253 self.rcvr = CtrlMsgRcvr(self.getChannel())
254 self.rcvr.addHandler(CMSG_USBIF_FE,
255 CMSG_USBIF_FE_DRIVER_STATUS_CHANGED,
256 self.recv_fe_driver_status_changed)
257 self.rcvr.addHandler(CMSG_USBIF_FE,
258 CMSG_USBIF_FE_INTERFACE_CONNECT,
259 self.recv_fe_interface_connect)
260 self.rcvr.registerChannel()
261 if reboot:
262 self.rebootBackends()
263 self.rebootDevices()
265 def sxpr(self):
266 val = ['usbif',
267 ['dom', self.getDomain()]]
268 return val
270 def newDevice(self, id, config, recreate=False):
271 return UsbDev(self, id, config, recreate=recreate)
273 def destroyController(self, reboot=False):
274 """Destroy the controller and all devices.
275 """
276 self.destroyed = True
277 log.debug("Destroying blkif domain=%d", self.getDomain())
278 self.destroyDevices(reboot=reboot)
279 self.destroyBackends(reboot=reboot)
280 if self.rcvr:
281 self.rcvr.deregisterChannel()
283 def rebootBackends(self):
284 for backend in self.backends.values():
285 backend.init(reboot=True)
287 def getBackendById(self, id):
288 return self.backends.get(id)
290 def getBackendByDomain(self, dom):
291 for backend in self.backends.values():
292 if backend.backendDomain == dom:
293 return backend
294 return None
296 def getBackend(self, dom):
297 backend = self.getBackendByDomain(dom)
298 if backend: return backend
299 backend = UsbBackend(self, self.backendId, dom)
300 self.backendId += 1
301 self.backends[backend.getId()] = backend
302 backend.init()
303 return backend
305 def destroyBackends(self, reboot=False):
306 for backend in self.backends.values():
307 backend.destroy(reboot=reboot)
309 def recv_fe_driver_status_changed(self, msg):
310 val = unpackMsg('usbif_fe_driver_status_changed_t', msg)
311 log.debug('>UsbifController>recv_fe_driver_status_changed> %s', str(val))
312 #todo: FIXME: For each backend?
313 msg = packMsg('usbif_fe_interface_status_changed_t',
314 { 'status' : USBIF_INTERFACE_STATUS_DISCONNECTED,
315 'domid' : 0, #todo: FIXME: should be domid of backend
316 'evtchn' : 0 })
317 msg = self.getChannel().requestResponse(msg)
318 self.disconnected_resp(msg)
320 def disconnected_resp(self, msg):
321 val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
322 if val['status'] != USBIF_INTERFACE_STATUS_DISCONNECTED:
323 log.error(">UsbifController>disconnected_resp> unexpected status change")
324 else:
325 log.debug(">UsbifController>disconnected_resp> interface disconnected OK")
327 def recv_fe_interface_connect(self, msg):
328 val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
329 log.debug(">UsbifController>recv_fe_interface_connect> notifying backend")
330 #todo: FIXME: generalise to more than one backend.
331 id = 0
332 backend = self.getBackendById(id)
333 if backend:
334 try:
335 backend.connectInterface(val)
336 except IOError, ex:
337 log.error("Exception connecting backend: %s", ex)
338 else:
339 log.error('interface connect on unknown interface: id=%d', id)
341 def claim_ports(self):
342 for dev in self.devices.values():
343 dev.send_be_claim_port()