Changeset 0892663a in mainline for uspace/lib/usbhost/src/bus.c
- Timestamp:
- 2018-01-11T04:14:37Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9848c77
- Parents:
- bad4a05
- git-author:
- Ondřej Hlavatý <aearsis@…> (2018-01-11 03:59:03)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2018-01-11 04:14:37)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/bus.c
rbad4a05 r0892663a 43 43 #include <mem.h> 44 44 #include <stdio.h> 45 #include <str_error.h> 45 46 #include <usb/debug.h> 46 47 … … 97 98 /** 98 99 * Invoke the device_enumerate bus operation. 100 * 101 * There's no need to synchronize here, because no one knows the device yet. 99 102 */ 100 103 int bus_device_enumerate(device_t *dev) … … 106 109 return ENOTSUP; 107 110 108 return ops->device_enumerate(dev); 109 } 110 111 /** 112 * Invoke the device_remove bus operation. 111 if (dev->online) { 112 fibril_mutex_unlock(&dev->guard); 113 return EINVAL; 114 } 115 116 const int r = ops->device_enumerate(dev); 117 if (!r) { 118 dev->online = true; 119 120 fibril_mutex_lock(&dev->hub->guard); 121 list_append(&dev->link, &dev->hub->devices); 122 fibril_mutex_unlock(&dev->hub->guard); 123 } 124 125 return r; 126 } 127 128 /** 129 * Clean endpoints and children that could have been left behind after 130 * asking the driver of device to offline/remove a device. 131 * 132 * Note that EP0's lifetime is shared with the device, and as such is not 133 * touched. 134 */ 135 static void device_clean_ep_children(device_t *dev, const char *op) 136 { 137 assert(fibril_mutex_is_locked(&dev->guard)); 138 139 /* Unregister endpoints left behind. */ 140 for (usb_endpoint_t i = 1; i < USB_ENDPOINT_MAX; ++i) { 141 if (!dev->endpoints[i]) 142 continue; 143 144 usb_log_warning("USB device '%s' driver left endpoint %u registered after %s.", 145 ddf_fun_get_name(dev->fun), i, op); 146 147 endpoint_t * const ep = dev->endpoints[i]; 148 endpoint_add_ref(ep); 149 150 fibril_mutex_unlock(&dev->guard); 151 bus_endpoint_remove(ep); 152 fibril_mutex_lock(&dev->guard); 153 154 assert(dev->endpoints[i] == NULL); 155 } 156 157 /* Remove also orphaned children. */ 158 while (!list_empty(&dev->devices)) { 159 device_t * const child = list_get_instance(list_first(&dev->devices), device_t, link); 160 161 usb_log_warning("USB device '%s' driver left device '%s' behind after %s.", 162 ddf_fun_get_name(dev->fun), ddf_fun_get_name(child->fun), op); 163 /* 164 * The child node won't disappear, because its parent's driver 165 * is already dead. And the child will need the guard to remove 166 * itself from the list. 167 */ 168 fibril_mutex_unlock(&dev->guard); 169 bus_device_remove(child); 170 fibril_mutex_lock(&dev->guard); 171 } 172 assert(list_empty(&dev->devices)); 173 } 174 175 /** 176 * Resolve a USB device that is gone. 113 177 */ 114 178 void bus_device_remove(device_t *dev) 115 179 { 116 180 assert(dev); 181 assert(dev->fun == NULL); 117 182 118 183 const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_remove); 119 184 assert(ops); 120 185 121 return ops->device_remove(dev); 122 } 123 124 /** 125 * Invoke the device_online bus operation. 186 /* First, block new transfers and operations. */ 187 fibril_mutex_lock(&dev->guard); 188 dev->online = false; 189 190 /* Unbinding will need guard unlocked. */ 191 fibril_mutex_unlock(&dev->guard); 192 193 /* Remove our device from our hub's children. */ 194 fibril_mutex_lock(&dev->hub->guard); 195 list_remove(&dev->link); 196 fibril_mutex_unlock(&dev->hub->guard); 197 198 /* 199 * Unbind the DDF function. That will result in dev_gone called in 200 * driver, which shall destroy its pipes and remove its children. 201 */ 202 const int err = ddf_fun_unbind(dev->fun); 203 if (err) { 204 usb_log_error("Failed to unbind USB device '%s': %s", 205 ddf_fun_get_name(dev->fun), str_error(err)); 206 return; 207 } 208 209 /* Remove what driver left behind */ 210 fibril_mutex_lock(&dev->guard); 211 device_clean_ep_children(dev, "removing"); 212 213 /* Tell the HC to release its resources. */ 214 ops->device_remove(dev); 215 216 /* Release the EP0 bus reference */ 217 endpoint_del_ref(dev->endpoints[0]); 218 219 /* Destroy the function, freeing also the device, unlocking mutex. */ 220 ddf_fun_destroy(dev->fun); 221 } 222 223 /** 224 * The user wants this device back online. 126 225 */ 127 226 int bus_device_online(device_t *dev) 128 227 { 228 int err; 129 229 assert(dev); 130 230 231 fibril_mutex_lock(&dev->guard); 232 if (dev->online) { 233 fibril_mutex_unlock(&dev->guard); 234 return EINVAL; 235 } 236 237 /* First, tell the HC driver. */ 131 238 const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_online); 132 if (!ops) 133 return ENOTSUP; 134 135 return ops->device_online(dev); 136 } 137 138 /** 139 * Invoke the device_offline bus operation. 239 if (ops && (err = ops->device_online(dev))) { 240 usb_log_warning("Host controller refused to make device '%s' online: %s", 241 ddf_fun_get_name(dev->fun), str_error(err)); 242 return err; 243 } 244 245 /* Allow creation of new endpoints and communication with the device. */ 246 dev->online = true; 247 248 /* Onlining will need the guard */ 249 fibril_mutex_unlock(&dev->guard); 250 251 if ((err = ddf_fun_online(dev->fun))) { 252 usb_log_warning("Failed to take device '%s' online: %s", 253 ddf_fun_get_name(dev->fun), str_error(err)); 254 return err; 255 } 256 257 usb_log_info("USB Device '%s' offlined.", ddf_fun_get_name(dev->fun)); 258 return EOK; 259 } 260 261 /** 262 * The user requested to take this device offline. 140 263 */ 141 264 int bus_device_offline(device_t *dev) 142 265 { 266 int err; 143 267 assert(dev); 144 268 269 /* Make sure we're the one who offlines this device */ 270 if (!dev->online) 271 return ENOENT; 272 273 /* 274 * XXX: If the device is removed/offlined just now, this can fail on 275 * assertion. We most probably need some kind of enum status field to 276 * make the synchronization work. 277 */ 278 279 /* Tear down all drivers working with the device. */ 280 if ((err = ddf_fun_offline(dev->fun))) { 281 return err; 282 } 283 284 fibril_mutex_lock(&dev->guard); 285 dev->online = false; 286 device_clean_ep_children(dev, "offlining"); 287 288 /* Tell also the HC driver. */ 145 289 const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_offline); 146 if (!ops) 147 return ENOTSUP; 148 149 return ops->device_offline(dev); 290 if (ops) 291 ops->device_offline(dev); 292 293 fibril_mutex_unlock(&dev->guard); 294 usb_log_info("USB Device '%s' offlined.", ddf_fun_get_name(dev->fun)); 295 return EOK; 150 296 } 151 297 … … 269 415 fibril_mutex_unlock(&device->guard); 270 416 271 /* Abort a transfer batch, if there was any */272 endpoint_abort(ep);273 274 417 /* Bus reference */ 275 418 endpoint_del_ref(ep);
Note:
See TracChangeset
for help on using the changeset viewer.