/* * Move the subdevice to the list of active (registered) subdevices * and associate it with a client. At the same time, associate the * client with its parent device.
*/
mutex_lock(&device->subdevs_lock);
mutex_lock(&device->clients_lock);
list_move_tail(&client->list, &device->clients);
list_move_tail(&subdev->list, &device->active);
client->host = &device->dev;
subdev->client = client;
mutex_unlock(&device->clients_lock);
mutex_unlock(&device->subdevs_lock);
if (list_empty(&device->subdevs)) {
err = device_add(&device->dev); if (err < 0)
dev_err(&device->dev, "failed to add: %d\n", err); else
device->registered = true;
}
}
/* * If all subdevices have been activated, we're about to remove the * first active subdevice, so unload the driver first.
*/ if (list_empty(&device->subdevs)) { if (device->registered) {
device->registered = false;
device_del(&device->dev);
}
}
/* * Move the subdevice back to the list of idle subdevices and remove * it from list of clients.
*/
mutex_lock(&device->clients_lock);
subdev->client = NULL;
client->host = NULL;
list_move_tail(&subdev->list, &device->subdevs); /* * XXX: Perhaps don't do this here, but rather explicitly remove it * when the device is about to be deleted. * * This is somewhat complicated by the fact that this function is * used to remove the subdevice when a client is unregistered but * also when the composite device is about to be removed.
*/
list_del_init(&client->list);
mutex_unlock(&device->clients_lock);
}
/** * host1x_device_init() - initialize a host1x logical device * @device: host1x logical device * * The driver for the host1x logical device can call this during execution of * its &host1x_driver.probe implementation to initialize each of its clients. * The client drivers access the subsystem specific driver data using the * &host1x_client.parent field and driver data associated with it (usually by * calling dev_get_drvdata()).
*/ int host1x_device_init(struct host1x_device *device)
{ struct host1x_client *client; int err;
mutex_lock(&device->clients_lock);
list_for_each_entry(client, &device->clients, list) { if (client->ops && client->ops->early_init) {
err = client->ops->early_init(client); if (err < 0) {
dev_err(&device->dev, "failed to early initialize %s: %d\n",
dev_name(client->dev), err); goto teardown_late;
}
}
}
list_for_each_entry(client, &device->clients, list) { if (client->ops && client->ops->init) {
err = client->ops->init(client); if (err < 0) {
dev_err(&device->dev, "failed to initialize %s: %d\n",
dev_name(client->dev), err); goto teardown;
}
}
}
mutex_unlock(&device->clients_lock);
return 0;
teardown:
list_for_each_entry_continue_reverse(client, &device->clients, list) if (client->ops->exit)
client->ops->exit(client);
/* reset client to end of list for late teardown */
client = list_entry(&device->clients, struct host1x_client, list);
teardown_late:
list_for_each_entry_continue_reverse(client, &device->clients, list) if (client->ops->late_exit)
client->ops->late_exit(client);
/** * host1x_device_exit() - uninitialize host1x logical device * @device: host1x logical device * * When the driver for a host1x logical device is unloaded, it can call this * function to tear down each of its clients. Typically this is done after a * subsystem-specific data structure is removed and the functionality can no * longer be used.
*/ int host1x_device_exit(struct host1x_device *device)
{ struct host1x_client *client; int err;
/* * Note that this is really only needed for backwards compatibility * with libdrm, which parses this information from sysfs and will * fail if it can't find the OF_FULLNAME, specifically.
*/ staticint host1x_device_uevent(conststruct device *dev, struct kobj_uevent_env *env)
{
of_device_uevent(dev->parent, env);
/* unregister subdevices */
list_for_each_entry_safe(subdev, sd, &device->active, list) { /* * host1x_subdev_unregister() will remove the client from * any lists, so we'll need to manually add it back to the * list of idle clients. * * XXX: Alternatively, perhaps don't remove the client from * any lists in host1x_subdev_unregister() and instead do * that explicitly from host1x_unregister_client()?
*/
client = subdev->client;
__host1x_subdev_unregister(device, subdev);
/* add the client to the list of idle clients */
mutex_lock(&clients_lock);
list_add_tail(&client->list, &clients);
mutex_unlock(&clients_lock);
}
/* * Removes a device by first unregistering any subdevices and then removing * itself from the list of devices. * * This function must be called with the host1x->devices_lock held.
*/ staticvoid host1x_device_del(struct host1x *host1x, struct host1x_device *device)
{ if (device->registered) {
device->registered = false;
device_del(&device->dev);
}
/** * host1x_register() - register a host1x controller * @host1x: host1x controller * * The host1x controller driver uses this to register a host1x controller with * the infrastructure. Note that all Tegra SoC generations have only ever come * with a single host1x instance, so this function is somewhat academic.
*/ int host1x_register(struct host1x *host1x)
{ struct host1x_driver *driver;
/** * host1x_unregister() - unregister a host1x controller * @host1x: host1x controller * * The host1x controller driver uses this to remove a host1x controller from * the infrastructure.
*/ int host1x_unregister(struct host1x *host1x)
{ struct host1x_driver *driver;
/** * host1x_driver_register_full() - register a host1x driver * @driver: host1x driver * @owner: owner module * * Drivers for host1x logical devices call this function to register a driver * with the infrastructure. Note that since these drive logical devices, the * registration of the driver actually triggers tho logical device creation. * A logical device will be created for each host1x instance.
*/ int host1x_driver_register_full(struct host1x_driver *driver, struct module *owner)
{ struct host1x *host1x;
/** * host1x_driver_unregister() - unregister a host1x driver * @driver: host1x driver * * Unbinds the driver from each of the host1x logical devices that it is * bound to, effectively removing the subsystem devices that they represent.
*/ void host1x_driver_unregister(struct host1x_driver *driver)
{ struct host1x *host1x;
/** * __host1x_client_register() - register a host1x client * @client: host1x client * * Registers a host1x client with each host1x controller instance. Note that * each client will only match their parent host1x controller and will only be * associated with that instance. Once all clients have been registered with * their parent host1x controller, the infrastructure will set up the logical * device and call host1x_device_init(), which will in turn call each client's * &host1x_client_ops.init implementation.
*/ int __host1x_client_register(struct host1x_client *client)
{ struct host1x *host1x; int err;
/** * host1x_client_unregister() - unregister a host1x client * @client: host1x client * * Removes a host1x client from its host1x controller instance. If a logical * device has already been initialized, it will be torn down.
*/ void host1x_client_unregister(struct host1x_client *client)
{ struct host1x_client *c; struct host1x *host1x; int err;
/* * When the last reference of the mapping goes away, make sure to remove the mapping from * the cache.
*/ if (mapping->cache)
list_del(&mapping->entry);
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.