/* * gameport_mutex protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered.
*/ static DEFINE_MUTEX(gameport_mutex);
list_for_each_entry_safe(e, next, &gameport_event_list, node) { if (event->object == e->object) { /* * If this event is of different type we should not * look further - we only suppress duplicate events * that were sent back-to-back.
*/ if (event->type != e->type) break;
/* * Note that we handle only one event here to give swsusp * a chance to freeze kgameportd thread. Gameport events * should be pretty rare so we are not concerned about * taking performance hit.
*/ if ((event = gameport_get_event())) {
switch (event->type) {
case GAMEPORT_REGISTER_PORT:
gameport_add_port(event->object); break;
case GAMEPORT_ATTACH_DRIVER:
gameport_attach_driver(event->object); break;
}
/* * Scan event list for the other events for the same gameport port, * starting with the most recent one. If event is the same we * do not need add new one. If event is of different type we * need to add this event and should not look further because * we need to preserve sequence of distinct events.
*/
list_for_each_entry_reverse(event, &gameport_event_list, node) { if (event->object == object) { if (event->type == event_type) goto out; break;
}
}
/* * Remove all events that have been submitted for a given object, * be it a gameport port or a driver.
*/ staticvoid gameport_remove_pending_events(void *object)
{ struct gameport_event *event, *next; unsignedlong flags;
/* * Destroy child gameport port (if any) that has not been fully registered yet. * * Note that we rely on the fact that port can have only one child and therefore * only one child registration request can be pending. Additionally, children * are registered by driver's connect() handler so there can't be a grandchild * pending registration together with a child.
*/ staticstruct gameport *gameport_get_pending_child(struct gameport *parent)
{ struct gameport_event *event; struct gameport *gameport, *child = NULL; unsignedlong flags;
staticvoid gameport_setup_default_handlers(struct gameport *gameport)
{ if ((!gameport->trigger || !gameport->read) &&
!IS_ENABLED(CONFIG_HAS_IOPORT))
dev_err(&gameport->dev, "I/O port access is required for %s (%s) but is not available\n",
gameport->phys, gameport->name);
if (!gameport->trigger)
gameport->trigger = gameport_default_trigger; if (!gameport->read)
gameport->read = gameport_default_read;
}
/* * Prepare gameport port for registration.
*/ staticvoid gameport_init_port(struct gameport *gameport)
{ static atomic_t gameport_no = ATOMIC_INIT(-1);
/* * Complete gameport port registration. * Driver core will attempt to find appropriate driver for the port.
*/ staticvoid gameport_add_port(struct gameport *gameport)
{ int error;
if (gameport->parent)
gameport->parent->child = gameport;
if (gameport->io)
dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
gameport->name, gameport->phys, gameport->io, gameport->speed); else
dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
gameport->name, gameport->phys, gameport->speed);
error = device_add(&gameport->dev); if (error)
dev_err(&gameport->dev, "device_add() failed for %s (%s), error: %d\n",
gameport->phys, gameport->name, error);
}
/* * gameport_destroy_port() completes deregistration process and removes * port from the system
*/ staticvoid gameport_destroy_port(struct gameport *gameport)
{ struct gameport *child;
child = gameport_get_pending_child(gameport); if (child) {
gameport_remove_pending_events(child);
put_device(&child->dev);
}
if (gameport->parent) {
gameport->parent->child = NULL;
gameport->parent = NULL;
}
if (device_is_registered(&gameport->dev))
device_del(&gameport->dev);
/* * Reconnect gameport port and all its children (re-initialize attached devices)
*/ staticvoid gameport_reconnect_port(struct gameport *gameport)
{ do { if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {
gameport_disconnect_port(gameport);
gameport_find_driver(gameport); /* Ok, old children are now gone, we are done */ break;
}
gameport = gameport->child;
} while (gameport);
}
/* * gameport_disconnect_port() unbinds a port from its driver. As a side effect * all child ports are unbound and destroyed.
*/ staticvoid gameport_disconnect_port(struct gameport *gameport)
{ struct gameport *s, *parent;
if (gameport->child) { /* * Children ports should be disconnected and destroyed * first, staring with the leaf one, since we don't want * to do recursion
*/ for (s = gameport; s->child; s = s->child) /* empty */;
do {
parent = s->parent;
device_release_driver(&s->dev);
gameport_destroy_port(s);
} while ((s = parent) != gameport);
}
/* * Ok, no children left, now disconnect this port
*/
device_release_driver(&gameport->dev);
}
/* * Submits register request to kgameportd for subsequent execution. * Note that port registration is always asynchronous.
*/ void __gameport_register_port(struct gameport *gameport, struct module *owner)
{
gameport_init_port(gameport);
gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);
}
EXPORT_SYMBOL(__gameport_register_port);
/* * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kgameportd
*/
drv->ignore = true;
error = driver_register(&drv->driver); if (error) {
pr_err("driver_register() failed for %s, error: %d\n",
drv->driver.name, error); return error;
}
/* * Reset ignore flag and let kgameportd bind the driver to free ports
*/
drv->ignore = false;
error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER); if (error) {
driver_unregister(&drv->driver); return error;
}
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.