if (!connection)
return NULL;
- INIT_LIST_HEAD(&connection->protocol_links);
/* XXX Will have to establish connections to get version */
- if (!gb_protocol_get(connection, protocol_id, major, minor)) {
+ connection->protocol = gb_protocol_get(protocol_id, major, minor);
+ if (!connection->protocol) {
pr_err("protocol 0x%02hhx not found\n", protocol_id);
kfree(connection);
return NULL;
hd = interface->gmod->hd;
connection->hd = hd;
if (!gb_connection_hd_cport_id_alloc(connection)) {
- gb_protocol_put(connection);
+ gb_protocol_put(connection->protocol);
kfree(connection);
return NULL;
}
pr_err("failed to add connection device for cport 0x%04hx\n",
cport_id);
gb_connection_hd_cport_id_free(connection);
- gb_protocol_put(connection);
+ gb_protocol_put(connection->protocol);
put_device(&connection->dev);
return NULL;
}
spin_unlock_irq(&gb_connections_lock);
gb_connection_hd_cport_id_free(connection);
- /* kref_put(connection->hd); */
- gb_protocol_put(connection);
+ gb_protocol_put(connection->protocol);
device_del(&connection->dev);
}
return NULL;
}
-/* This is basically for debug */
-static struct gb_protocol *gb_protocol_find(u8 id, u8 major, u8 minor)
-{
- struct gb_protocol *protocol;
-
- spin_lock_irq(&gb_protocols_lock);
- protocol = _gb_protocol_find(id, major, minor);
- spin_unlock_irq(&gb_protocols_lock);
-
- return protocol;
-}
-
/* Returns true if protocol was succesfully registered, false otherwise */
bool gb_protocol_register(u8 id, u8 major, u8 minor)
{
protocol->id = id;
protocol->major = major;
protocol->minor = minor;
- INIT_LIST_HEAD(&protocol->connections);
spin_lock_irq(&gb_protocols_lock);
existing = _gb_protocol_find(id, major, minor);
/* Returns true if successful, false otherwise */
bool gb_protocol_deregister(struct gb_protocol *protocol)
{
+ u8 protocol_count;
+
spin_lock_irq(&gb_protocols_lock);
- if (list_empty(&protocol->connections))
- list_del(&protocol->links);
- else
- protocol = NULL; /* Protocol is still in use */
+ protocol = _gb_protocol_find(protocol->id, protocol->major,
+ protocol->minor);
+ if (protocol) {
+ protocol_count = protocol->count;
+ if (!protocol_count)
+ list_del(&protocol->links);
+ }
spin_unlock_irq(&gb_protocols_lock);
kfree(protocol);
- return protocol != NULL;
+ return protocol && !protocol_count;
}
-/* Returns true if successful, false otherwise */
-bool
-gb_protocol_get(struct gb_connection *connection, u8 id, u8 major, u8 minor)
+/* Returns the requested protocol if available, or a null pointer */
+struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor)
{
struct gb_protocol *protocol;
-
- /* Sanity */
- if (!list_empty(&connection->protocol_links) ||
- !connection->protocol->id) {
- gb_connection_err(connection,
- "connection already has protocol");
- return false;
- }
+ u8 protocol_count;
spin_lock_irq(&gb_protocols_lock);
protocol = _gb_protocol_find(id, major, minor);
- if (protocol)
- list_add(&connection->protocol_links, &protocol->connections);
+ if (protocol) {
+ protocol_count = protocol->count;
+ if (protocol_count != U8_MAX)
+ protocol->count++;
+ }
spin_unlock_irq(&gb_protocols_lock);
- connection->protocol = protocol;
- return protocol != NULL;
+ if (protocol)
+ WARN_ON(protocol_count == U8_MAX);
+ else
+ pr_err("protocol id %hhu version %hhu.%hhu not found\n",
+ id, major, minor);
+
+ return protocol;
}
-void gb_protocol_put(struct gb_connection *connection)
+void gb_protocol_put(struct gb_protocol *protocol)
{
- struct gb_protocol *protocol = connection->protocol;
u8 major = protocol->major;
u8 minor = protocol->minor;
-
- /* Sanity checks */
- if (list_empty(&connection->protocol_links)) {
- gb_connection_err(connection,
- "connection protocol not recorded");
- return;
- }
- if (!protocol) {
- gb_connection_err(connection, "connection has no protocol");
- return;
- }
- if (gb_protocol_find(protocol->id, major, minor) != protocol) {
- gb_connection_err(connection, "connection protocol not found");
- return;
- }
+ u8 protocol_count;
spin_lock_irq(&gb_protocols_lock);
- list_del(&connection->protocol_links);
- connection->protocol = NULL;
+ protocol = _gb_protocol_find(protocol->id, protocol->major,
+ protocol->minor);
+ if (protocol) {
+ protocol_count = protocol->count;
+ if (protocol_count)
+ protocol->count--;
+ }
spin_unlock_irq(&gb_protocols_lock);
+ if (protocol)
+ WARN_ON(!protocol_count);
+ else
+ pr_err("protocol id %hhu version %hhu.%hhu not found\n",
+ protocol->id, major, minor);
}