/* * busid_tables defines matching busids that usbip can grab. A user can change * dynamically what device is locally used and what device is exported to a * remote host.
*/ #define MAX_BUSID 16 staticstruct bus_id_priv busid_table[MAX_BUSID]; static DEFINE_SPINLOCK(busid_table_lock);
staticvoid init_busid_table(void)
{ int i;
/* * This also sets the bus_table[i].status to * STUB_BUSID_OTHER, which is 0.
*/
memset(busid_table, 0, sizeof(busid_table));
for (i = 0; i < MAX_BUSID; i++)
spin_lock_init(&busid_table[i].busid_lock);
}
/* * Find the index of the busid by name. * Must be called with busid_table_lock held.
*/ staticint get_busid_idx(constchar *busid)
{ int i; int idx = -1;
for (i = 0; i < MAX_BUSID; i++) {
spin_lock(&busid_table[i].busid_lock); if (busid_table[i].name[0]) if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
idx = i;
spin_unlock(&busid_table[i].busid_lock); break;
}
spin_unlock(&busid_table[i].busid_lock);
} return idx;
}
/* Returns holding busid_lock. Should call put_busid_priv() to unlock */ struct bus_id_priv *get_busid_priv(constchar *busid)
{ int idx; struct bus_id_priv *bid = NULL;
spin_lock(&busid_table_lock);
idx = get_busid_idx(busid); if (idx >= 0) {
bid = &(busid_table[idx]); /* get busid_lock before returning */
spin_lock(&bid->busid_lock);
}
spin_unlock(&busid_table_lock);
return bid;
}
void put_busid_priv(struct bus_id_priv *bid)
{ if (bid)
spin_unlock(&bid->busid_lock);
}
staticint add_match_busid(char *busid)
{ int i; int ret = -1;
spin_lock(&busid_table_lock); /* already registered? */ if (get_busid_idx(busid) >= 0) {
ret = 0; goto out;
}
for (i = 0; i < MAX_BUSID; i++) {
spin_lock(&busid_table[i].busid_lock); if (!busid_table[i].name[0]) {
strscpy(busid_table[i].name, busid, BUSID_SIZE); if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
(busid_table[i].status != STUB_BUSID_REMOV))
busid_table[i].status = STUB_BUSID_ADDED;
ret = 0;
spin_unlock(&busid_table[i].busid_lock); break;
}
spin_unlock(&busid_table[i].busid_lock);
}
out:
spin_unlock(&busid_table_lock);
return ret;
}
int del_match_busid(char *busid)
{ int idx; int ret = -1;
spin_lock(&busid_table_lock);
idx = get_busid_idx(busid); if (idx < 0) goto out;
/* found */
ret = 0;
spin_lock(&busid_table[idx].busid_lock);
if (busid_table[idx].status == STUB_BUSID_OTHER)
memset(busid_table[idx].name, 0, BUSID_SIZE);
spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) {
spin_lock(&busid_table[i].busid_lock); if (busid_table[i].name[0])
out += sprintf(out, "%s ", busid_table[i].name);
spin_unlock(&busid_table[i].busid_lock);
}
spin_unlock(&busid_table_lock);
out += sprintf(out, "\n");
staticint do_rebind(char *busid, struct bus_id_priv *busid_priv)
{ int ret = 0;
/* device_attach() callers should hold parent lock for USB */ if (busid_priv->udev->dev.parent)
device_lock(busid_priv->udev->dev.parent);
ret = device_attach(&busid_priv->udev->dev); if (busid_priv->udev->dev.parent)
device_unlock(busid_priv->udev->dev.parent); if (ret < 0)
dev_err(&busid_priv->udev->dev, "rebind failed\n"); return ret;
}
staticvoid stub_device_rebind(void)
{ #if IS_MODULE(CONFIG_USBIP_HOST) struct bus_id_priv *busid_priv; int i;
/* update status to STUB_BUSID_OTHER so probe ignores the device */
spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) { if (busid_table[i].name[0] &&
busid_table[i].shutdown_busid) {
busid_priv = &(busid_table[i]);
busid_priv->status = STUB_BUSID_OTHER;
}
}
spin_unlock(&busid_table_lock);
/* now run rebind - no need to hold locks. driver files are removed */ for (i = 0; i < MAX_BUSID; i++) { if (busid_table[i].name[0] &&
busid_table[i].shutdown_busid) {
busid_priv = &(busid_table[i]);
do_rebind(busid_table[i].name, busid_priv);
}
} #endif
}
static ssize_t rebind_store(struct device_driver *dev, constchar *buf,
size_t count)
{ int ret; int len; struct bus_id_priv *bid;
/* buf length should be less that BUSID_SIZE */
len = strnlen(buf, BUSID_SIZE);
if (!(len < BUSID_SIZE)) return -EINVAL;
bid = get_busid_priv(buf); if (!bid) return -ENODEV;
/* mark the device for deletion so probe ignores it during rescan */
bid->status = STUB_BUSID_OTHER; /* release the busid lock */
put_busid_priv(bid);
ret = do_rebind((char *) buf, bid); if (ret < 0) return ret;
/* delete device from busid_table */
del_match_busid((char *) buf);
/* * deregister() calls stub_disconnect() for all devices. Device * specific data is cleared in stub_disconnect().
*/
usb_deregister_device_driver(&stub_driver);
/* initiate scan to attach devices */
stub_device_rebind();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.