forked from Minki/linux
Bluetooth: Let HIDP grab the device reference for connections
The core exports the hci_conn_hold_device() and hci_conn_put_device() functions for device reference of connections. Use this to ensure that the uevents from the parent are send after the child ones. Based on a report by Brian Rogers <brian@xyzw.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
9eba32b86d
commit
edad638869
@ -93,10 +93,14 @@ static void __hidp_link_session(struct hidp_session *session)
|
||||
{
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&session->list, &hidp_session_list);
|
||||
|
||||
hci_conn_hold_device(session->conn);
|
||||
}
|
||||
|
||||
static void __hidp_unlink_session(struct hidp_session *session)
|
||||
{
|
||||
hci_conn_put_device(session->conn);
|
||||
|
||||
list_del(&session->list);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
@ -577,7 +581,9 @@ static int hidp_session(void *arg)
|
||||
hidinput_disconnect(session->hid);
|
||||
if (session->hid->claimed & HID_CLAIMED_HIDRAW)
|
||||
hidraw_disconnect(session->hid);
|
||||
|
||||
hid_destroy_device(session->hid);
|
||||
session->hid = NULL;
|
||||
}
|
||||
|
||||
/* Wakeup user-space polling for socket errors */
|
||||
@ -605,25 +611,27 @@ static struct device *hidp_get_device(struct hidp_session *session)
|
||||
{
|
||||
bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
|
||||
bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
|
||||
struct device *device = NULL;
|
||||
struct hci_dev *hdev;
|
||||
struct hci_conn *conn;
|
||||
|
||||
hdev = hci_get_route(dst, src);
|
||||
if (!hdev)
|
||||
return NULL;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
if (session->conn)
|
||||
device = &session->conn->dev;
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return conn ? &conn->dev : NULL;
|
||||
return device;
|
||||
}
|
||||
|
||||
static int hidp_setup_input(struct hidp_session *session,
|
||||
struct hidp_connadd_req *req)
|
||||
{
|
||||
struct input_dev *input;
|
||||
int i;
|
||||
int err, i;
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input)
|
||||
@ -670,7 +678,13 @@ static int hidp_setup_input(struct hidp_session *session,
|
||||
|
||||
input->event = hidp_input_event;
|
||||
|
||||
return input_register_device(input);
|
||||
err = input_register_device(input);
|
||||
if (err < 0) {
|
||||
hci_conn_put_device(session->conn);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hidp_open(struct hid_device *hid)
|
||||
@ -752,13 +766,11 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
{
|
||||
struct hid_device *hid;
|
||||
bdaddr_t src, dst;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid)) {
|
||||
ret = PTR_ERR(session->hid);
|
||||
goto err;
|
||||
}
|
||||
if (IS_ERR(hid))
|
||||
return PTR_ERR(session->hid);
|
||||
|
||||
session->hid = hid;
|
||||
session->req = req;
|
||||
@ -780,16 +792,17 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
hid->dev.parent = hidp_get_device(session);
|
||||
hid->ll_driver = &hidp_hid_driver;
|
||||
|
||||
ret = hid_add_device(hid);
|
||||
if (ret)
|
||||
goto err_hid;
|
||||
err = hid_add_device(hid);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
return 0;
|
||||
err_hid:
|
||||
|
||||
failed:
|
||||
hid_destroy_device(hid);
|
||||
session->hid = NULL;
|
||||
err:
|
||||
return ret;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
|
||||
@ -839,13 +852,13 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
||||
if (req->rd_size > 0) {
|
||||
err = hidp_setup_hid(session, req);
|
||||
if (err && err != -ENODEV)
|
||||
goto err_skb;
|
||||
goto purge;
|
||||
}
|
||||
|
||||
if (!session->hid) {
|
||||
err = hidp_setup_input(session, req);
|
||||
if (err < 0)
|
||||
goto err_skb;
|
||||
goto purge;
|
||||
}
|
||||
|
||||
__hidp_link_session(session);
|
||||
@ -873,13 +886,20 @@ unlink:
|
||||
|
||||
__hidp_unlink_session(session);
|
||||
|
||||
if (session->input)
|
||||
if (session->input) {
|
||||
input_unregister_device(session->input);
|
||||
if (session->hid)
|
||||
session->input = NULL;
|
||||
}
|
||||
|
||||
if (session->hid) {
|
||||
hid_destroy_device(session->hid);
|
||||
err_skb:
|
||||
session->hid = NULL;
|
||||
}
|
||||
|
||||
purge:
|
||||
skb_queue_purge(&session->ctrl_transmit);
|
||||
skb_queue_purge(&session->intr_transmit);
|
||||
|
||||
failed:
|
||||
up_write(&hidp_session_sem);
|
||||
|
||||
|
@ -126,6 +126,8 @@ int hidp_get_conninfo(struct hidp_conninfo *ci);
|
||||
struct hidp_session {
|
||||
struct list_head list;
|
||||
|
||||
struct hci_conn *conn;
|
||||
|
||||
struct socket *ctrl_sock;
|
||||
struct socket *intr_sock;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user