Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edad6388 authored by Marcel Holtmann's avatar Marcel Holtmann
Browse files

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: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 9eba32b8
Loading
Loading
Loading
Loading
+41 −21
Original line number Diff line number Diff line
@@ -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 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,

	__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);

+2 −0
Original line number Diff line number Diff line
@@ -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;