Re: HID certification using PTS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

- when kernel (2.6.22) receives a VIRTUAL_CABLE_UNPLUG from PTS (tests TC_HOS_HCR_BV_02_I and TC_HOS_HCR_BV_04_I) it does not close the L2CAP channels as PTS waits for. I take a look in 2.6.22 sources, and it seems to me this disconnection should happen, am I right ?
Is it fixed in later kernel ?

Regarding this problem I wrote a patch in kernel that allows to poll the HIDP control socket and set it to IO_HUP when receiving the virtual cable unplug command.
I update the input service to watch the HIDP control socket and close l2cap sockets if IO_HUP is set on HIDP control socket.

Is it OK ?

Regards

Fred

--
-----------------------------------------------
It is not by improving the oil lamp that one invents the electric bulb!
-----------------------------------------------
Danis Frederic                   Access Company
Software engineer
Mail : mailto:frederic.danis@xxxxxxxxxxxxxxxxxx
-----------------------------------------------
diff -Naur linux-2.6.24.4/net/bluetooth/hidp.orig/core.c linux-2.6.24.4/net/bluetooth/hidp/core.c
--- linux-2.6.24.4/net/bluetooth/hidp.orig/core.c	2008-03-24 19:49:18.000000000 +0100
+++ linux-2.6.24.4/net/bluetooth/hidp/core.c	2008-04-01 11:14:05.000000000 +0200
@@ -378,8 +378,12 @@
 		skb_queue_purge(&session->ctrl_transmit);
 		skb_queue_purge(&session->intr_transmit);
 
+		if (session->hidp_sock)
+			session->hidp_sock->sk->sk_shutdown = SHUTDOWN_MASK;
+
 		/* Kill session thread */
 		atomic_inc(&session->terminate);
+		hidp_schedule(session);
 		break;
 
 	case HIDP_CTRL_HARD_RESET:
@@ -743,7 +747,7 @@
 		hid->claimed |= HID_CLAIMED_INPUT;
 }
 
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock, struct socket *hidp_sock)
 {
 	struct hidp_session *session, *s;
 	int err;
@@ -809,6 +813,7 @@
 
 	session->ctrl_sock = ctrl_sock;
 	session->intr_sock = intr_sock;
+	session->hidp_sock = hidp_sock;
 	session->state     = BT_CONNECTED;
 
 	init_timer(&session->timer);
@@ -952,6 +957,24 @@
 	return err;
 }
 
+void hidp_remove_hidp_sock_ref(struct socket *hidp_sock)
+{
+	struct list_head *p;
+
+	down_read(&hidp_session_sem);
+
+	list_for_each(p, &hidp_session_list) {
+		struct hidp_session *session;
+
+		session = list_entry(p, struct hidp_session, list);
+
+		if (session->hidp_sock == hidp_sock)
+			session->hidp_sock = NULL;
+	}
+
+	up_read(&hidp_session_sem);
+}
+
 static int __init hidp_init(void)
 {
 	l2cap_load();
diff -Naur linux-2.6.24.4/net/bluetooth/hidp.orig/hidp.h linux-2.6.24.4/net/bluetooth/hidp/hidp.h
--- linux-2.6.24.4/net/bluetooth/hidp.orig/hidp.h	2008-03-24 19:49:18.000000000 +0100
+++ linux-2.6.24.4/net/bluetooth/hidp/hidp.h	2008-04-01 11:14:33.000000000 +0200
@@ -117,10 +117,11 @@
 	struct hidp_conninfo __user *ci;
 };
 
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock, struct socket *hidp_sock);
 int hidp_del_connection(struct hidp_conndel_req *req);
 int hidp_get_connlist(struct hidp_connlist_req *req);
 int hidp_get_conninfo(struct hidp_conninfo *ci);
+void hidp_remove_hidp_sock_ref(struct socket *hidp_sock);
 
 /* HIDP session defines */
 struct hidp_session {
@@ -128,6 +129,7 @@
 
 	struct socket *ctrl_sock;
 	struct socket *intr_sock;
+	struct socket *hidp_sock;
 
 	bdaddr_t bdaddr;
 
diff -Naur linux-2.6.24.4/net/bluetooth/hidp.orig/sock.c linux-2.6.24.4/net/bluetooth/hidp/sock.c
--- linux-2.6.24.4/net/bluetooth/hidp.orig/sock.c	2008-03-24 19:49:18.000000000 +0100
+++ linux-2.6.24.4/net/bluetooth/hidp/sock.c	2008-04-01 11:15:33.000000000 +0200
@@ -56,6 +56,8 @@
 	sock_orphan(sk);
 	sock_put(sk);
 
+	hidp_remove_hidp_sock_ref(sock);
+
 	return 0;
 }
 
@@ -96,7 +98,7 @@
 			return -EBADFD;
 		}
 
-		err = hidp_add_connection(&ca, csock, isock);
+		err = hidp_add_connection(&ca, csock, isock, sock);
 		if (!err) {
 			if (copy_to_user(argp, &ca, sizeof(ca)))
 				err = -EFAULT;
@@ -229,7 +231,7 @@
 	.getname	= sock_no_getname,
 	.sendmsg	= sock_no_sendmsg,
 	.recvmsg	= sock_no_recvmsg,
-	.poll		= sock_no_poll,
+	.poll		= bt_sock_poll,
 	.listen		= sock_no_listen,
 	.shutdown	= sock_no_shutdown,
 	.setsockopt	= sock_no_setsockopt,
Index: device.c
===================================================================
RCS file: /cvsroot/bluez/utils/input/device.c,v
retrieving revision 1.71
diff -a -u -r1.71 device.c
--- device.c	14 Mar 2008 18:44:00 -0000	1.71
+++ device.c	1 Apr 2008 15:42:26 -0000
@@ -78,8 +78,10 @@
 	char			*path;
 	int			ctrl_sk;
 	int			intr_sk;
+	int			hidp_sk;
 	guint			ctrl_watch;
 	guint			intr_watch;
+	guint			hidp_watch;
 };
 
 GSList *devices = NULL;
@@ -524,8 +526,10 @@
 			DBUS_TYPE_INVALID);
 
 	g_source_remove(idev->ctrl_watch);
+	g_source_remove(idev->hidp_watch);
 	idev->ctrl_watch = 0;
 	idev->intr_watch = 0;
+	idev->hidp_watch = 0;
 
 	/* Close control channel */
 	if (idev->ctrl_sk > 0) {
@@ -533,6 +537,12 @@
 		idev->ctrl_sk = -1;
 	}
 
+	/* Close hidp channel */
+	if (idev->hidp_sk > 0) {
+		close(idev->hidp_sk);
+		idev->hidp_sk = -1;
+	}
+
 	return FALSE;
 
 }
@@ -551,8 +561,10 @@
 			DBUS_TYPE_INVALID);
 
 	g_source_remove(idev->intr_watch);
+	g_source_remove(idev->hidp_watch);
 	idev->intr_watch = 0;
 	idev->ctrl_watch = 0;
+	idev->hidp_watch = 0;
 
 	/* Close interrupt channel */
 	if (idev->intr_sk > 0) {
@@ -560,6 +572,47 @@
 		idev->intr_sk = -1;
 	}
 
+	/* Close hidp channel */
+	if (idev->hidp_sk > 0) {
+		close(idev->hidp_sk);
+		idev->hidp_sk = -1;
+	}
+
+	return FALSE;
+}
+
+static gboolean hidp_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct device *idev = data;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		g_io_channel_close(chan);
+	}
+
+	dbus_connection_emit_signal(idev->conn,
+			idev->path,
+			INPUT_DEVICE_INTERFACE,
+			"Disconnected",
+			DBUS_TYPE_INVALID);
+
+	g_source_remove(idev->intr_watch);
+	g_source_remove(idev->ctrl_watch);
+	idev->intr_watch = 0;
+	idev->ctrl_watch = 0;
+	idev->hidp_watch = 0;
+
+	/* Close interrupt channel */
+	if (idev->intr_sk > 0) {
+		close(idev->intr_sk);
+		idev->intr_sk = -1;
+	}
+
+	/* Close control channel */
+	if (idev->ctrl_sk > 0) {
+		close(idev->ctrl_sk);
+		idev->ctrl_sk = -1;
+	}
+
 	return FALSE;
 }
 
@@ -620,12 +673,10 @@
 
 	err = ioctl(ctl, HIDPCONNADD, &req);
 cleanup:
-	close(ctl);
-
 	if (req.rd_data)
 		free(req.rd_data);
 
-	return err;
+	return ctl;
 }
 
 static gboolean interrupt_connect_cb(GIOChannel *chan,
@@ -663,13 +714,14 @@
 	}
 
 	idev->intr_sk = isk;
-	err = hidp_connadd(&idev->src, &idev->dst,
+	idev->hidp_sk = hidp_connadd(&idev->src, &idev->dst,
 			idev->ctrl_sk, idev->intr_sk, idev->name);
-	if (err < 0)
+	if (idev->hidp_sk < 0)
 		goto failed;
 
 	idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev);
 	idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev);
+	idev->hidp_watch = create_watch(idev->hidp_sk, hidp_watch_cb, idev);
 	dbus_connection_emit_signal(idev->conn,
 			idev->path,
 			INPUT_DEVICE_INTERFACE,
@@ -802,10 +854,15 @@
 		idev->intr_sk = -1;
 	}
 
-	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-	if (ctl < 0) {
-		error("Can't open HIDP control socket");
-		return -errno;
+	if (idev->hidp_sk >= 0) {
+		ctl = idev->hidp_sk;
+		idev->hidp_sk = -1;
+	} else {
+		ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+		if (ctl < 0) {
+			error("Can't open HIDP control socket");
+			return -errno;
+		}
 	}
 
 	memset(&ci, 0, sizeof(ci));
@@ -1181,6 +1238,9 @@
 	 * to access the D-Bus data assigned to this path
 	 * because the object path data was destroyed.
 	 */
+	if (idev->hidp_watch)
+		g_source_remove(idev->hidp_watch);
+
 	if (idev->ctrl_watch)
 		g_source_remove(idev->ctrl_watch);
 
@@ -1364,8 +1424,15 @@
 		fake->disconnect = fake_hid_disconnect;
 		fake->priv = fake_hid;
 		err = fake_hid_connadd(fake, idev->intr_sk, fake_hid);
-	} else
-		err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+	} else {
+		idev->hidp_sk = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+		if (idev->hidp_sk < 0) {
+			err = idev->hidp_sk;
+		} else {
+			err = 0;
+			idev->hidp_watch = create_watch(idev->hidp_sk, hidp_watch_cb, idev);
+		}
+	}
 	if (err < 0)
 		goto error;
 
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Bluez-devel mailing list
Bluez-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/bluez-devel

[Index of Archives]     [Linux Bluetooth Devel]     [Linux USB Devel]     [Network Devel]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux