Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Jun 2019 19:46:05 +0200
From:      Stephane D'Alu <sdalu@sdalu.com>
To:        Hans Petter Selasky <hps@selasky.org>, freebsd-usb@freebsd.org
Subject:   Re: xbox one controller
Message-ID:  <e72b3805-3f44-ef57-fc93-60c41e0bd054@sdalu.com>
In-Reply-To: <884190d4-ca12-3f25-451c-57faaeee9259@selasky.org>
References:  <4effaa16-d02c-5054-46c5-6d9d581f7237@sdalu.com> <77e98272-5a92-c962-58ad-c5fb5b1929da@selasky.org> <bc601ee7-076f-85a3-5a48-ab60c3980802@sdalu.com> <4b7169ec-3bca-4eb3-a191-1d74cd7cb120@selasky.org> <533a834a-c5a0-0813-3762-85c1bc7a4504@sdalu.com> <884190d4-ca12-3f25-451c-57faaeee9259@selasky.org>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------44F08131385CD5D54FD36EC0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit

On 6/25/19 9:16 AM, Hans Petter Selasky wrote:
>> [...]
>> Found my device (vendor=0x045e, product=0x02ea) in 
>> media_tree/drivers/input/joystick/xpad.c but the module_param present 
>> in that file dont seem useful (related to button/sticks behavior or 
>> wireless)
>>
>> Well, the xpad.c file doesn't seem to be compiled in
>> (and INPUT is set in port config)
>>
>>
> 
> The xpad.c has some compile failures, but if you want to fix them, I'm 
> happy to submit the patches!
> 

I don't know how to fix this line in kernel/linux_defs.h
#define	IS_ENABLED(x,...) defined(x##__VA_ARGS__)

that's seems to be problematic when using clang preprocessor as 
"defined" is not interpreted after macro expantion.
so I've been forced to patch xpad.c which is ugly

Otherwise I added the necessary structure and missing functions,
it seems to work, at least I have /dev/input/js0 which is outputing data 
when precessing gamepad button or using sticks.

I know nothing about usb stack, so my patch will need strong review.


This bring another question on the gamepad/joystick side,
I'm using the port emulators/qmc2, which detect gamepad/joystick when 
provided as uhid interface but doesn't seems to catch it as 
/dev/input/js0. Am I still missing a step?

-- 
Stephane D'Alu

--------------44F08131385CD5D54FD36EC0
Content-Type: text/x-patch;
 name="xpad.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="xpad.diff"

diff -ru webcamd/work/webcamd-4.20.0.1/config_input.in webcamd.0/work/webcamd-4.20.0.1/config_input.in
--- webcamd/work/webcamd-4.20.0.1/config_input.in	2017-05-19 13:26:34.000000000 +0200
+++ webcamd.0/work/webcamd-4.20.0.1/config_input.in	2019-06-25 10:51:47.472055000 +0200
@@ -88,6 +88,7 @@
 CONFIG_IR_STREAMZAP=y
 CONFIG_IR_TTUSBIR=y
 CONFIG_IR_XMP_DECODER=y
+CONFIG_JOYSTICK_XPAD=y
 CONFIG_LIRC=y
 CONFIG_LIRC_IGORPLUGUSB=y
 CONFIG_LIRC_STAGING=y
diff -ru webcamd/work/webcamd-4.20.0.1/kernel/linux_usb.c webcamd.0/work/webcamd-4.20.0.1/kernel/linux_usb.c
--- webcamd/work/webcamd-4.20.0.1/kernel/linux_usb.c	2018-06-05 15:51:24.000000000 +0200
+++ webcamd.0/work/webcamd-4.20.0.1/kernel/linux_usb.c	2019-06-25 13:25:18.434807000 +0200
@@ -29,6 +29,8 @@
 
 #include <linux/input.h>
 
+#define to_urb(d) container_of(d, struct urb, kref)
+
 static int min_bufsize;
 
 module_param(min_bufsize, int, 0644);
@@ -1368,7 +1370,7 @@
 
 	urb = malloc(size);
 	if (urb) {
-		memset(urb, 0, size);
+		usb_init_urb(urb);
 		urb->number_of_packets = iso_packets;
 	}
 	return (urb);
@@ -1586,14 +1588,14 @@
 	free(addr);
 }
 
+
 /*------------------------------------------------------------------------*
- *	usb_free_urb
+ *	urb_destroy
  *------------------------------------------------------------------------*/
-void
-usb_free_urb(struct urb *urb)
+static void
+urb_destroy(struct kref *kref)
 {
-	if (urb == NULL)
-		return;
+	struct urb *urb = to_urb(kref);
 
 	/* make sure that the current URB is not active */
 	usb_kill_urb(urb);
@@ -1607,6 +1609,20 @@
 }
 
 /*------------------------------------------------------------------------*
+ *	usb_free_urb
+ *------------------------------------------------------------------------*/
+void
+usb_free_urb(struct urb *urb)
+{
+	if (urb == NULL)
+		return;
+	kref_put(&urb->kref, urb_destroy);
+}
+
+
+
+
+/*------------------------------------------------------------------------*
  *	usb_init_urb
  *
  * The following function can be used to initialize a custom URB. It
@@ -1620,6 +1636,8 @@
 		return;
 
 	memset(urb, 0, sizeof(*urb));
+	kref_init(&urb->kref);
+	INIT_LIST_HEAD(&urb->anchor_list);
 }
 
 /*------------------------------------------------------------------------*
@@ -2611,4 +2629,99 @@
 		return (-EINVAL);
 
 	return (0);
+}
+
+struct urb *
+usb_get_urb(struct urb *urb)
+{
+	if (urb)
+    		kref_get(&urb->kref);
+	return urb;
+}
+
+static int
+usb_anchor_check_wakeup(struct usb_anchor *anchor)
+{
+	return atomic_read(&anchor->suspend_wakeups) == 0 &&
+		list_empty(&anchor->urb_list);
+}
+
+
+int
+usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+				  unsigned int timeout)
+{
+	return wait_event_timeout(anchor->wait,
+				  usb_anchor_check_wakeup(anchor),
+				  msecs_to_jiffies(timeout));
+}
+
+static void
+__usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+	urb->anchor = NULL;
+	list_del(&urb->anchor_list);
+	usb_put_urb(urb);
+	if (usb_anchor_check_wakeup(anchor))
+		wake_up(&anchor->wait);
+}
+
+void
+usb_unanchor_urb(struct urb *urb)
+{
+	unsigned long flags;
+	struct usb_anchor *anchor;
+
+	if (!urb)
+		return;
+
+	anchor = urb->anchor;
+	if (!anchor)
+		return;
+
+	spin_lock_irqsave(&anchor->lock, flags);
+	/*
+	 * At this point, we could be competing with another thread which
+	 * has the same intention. To protect the urb from being unanchored
+	 * twice, only the winner of the race gets the job.
+	 */
+	if (likely(anchor == urb->anchor))
+		__usb_unanchor_urb(urb, anchor);
+	spin_unlock_irqrestore(&anchor->lock, flags);
+}
+
+void
+usb_kill_anchored_urbs(struct usb_anchor *anchor)
+{
+	struct urb *victim;
+
+	spin_lock_irq(&anchor->lock);
+	while (!list_empty(&anchor->urb_list)) {
+		victim = list_entry(anchor->urb_list.prev, struct urb,
+				    anchor_list);
+		/* we must make sure the URB isn't freed before we kill it*/
+		usb_get_urb(victim);
+		spin_unlock_irq(&anchor->lock);
+		/* this will unanchor the URB */
+		usb_kill_urb(victim);
+		usb_put_urb(victim);
+		spin_lock_irq(&anchor->lock);
+	}
+	spin_unlock_irq(&anchor->lock);
+}
+
+void
+usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&anchor->lock, flags);
+	usb_get_urb(urb);
+	list_add_tail(&urb->anchor_list, &anchor->urb_list);
+	urb->anchor = anchor;
+
+	if (unlikely(anchor->poisoned))
+		atomic_inc(&urb->reject);
+
+	spin_unlock_irqrestore(&anchor->lock, flags);
 }
diff -ru webcamd/work/webcamd-4.20.0.1/kernel/linux_usb.h webcamd.0/work/webcamd-4.20.0.1/kernel/linux_usb.h
--- webcamd/work/webcamd-4.20.0.1/kernel/linux_usb.h	2018-06-05 15:51:24.000000000 +0200
+++ webcamd.0/work/webcamd-4.20.0.1/kernel/linux_usb.h	2019-06-25 13:20:08.650938000 +0200
@@ -539,6 +539,9 @@
 	char   *manufacturer;		/* iManufacturer string, if present */
 	char   *serial;			/* iSerialNumber string, if present */
 
+	uint32_t quirks;		/* field compatibility, 
+					   logic not implemented */
+    
 	uint16_t devnum;
 	uint16_t bsd_last_ms;		/* completion time of last ISOC
 					 * transfer */
@@ -588,6 +591,10 @@
 	uint32_t timeout;		/* (in) FreeBSD specific */
 	uint32_t reject;		/* (internal) reject URB */
 
+	struct kref kref;		/* reference count of the URB */
+    struct list_head anchor_list;	/* the URB may be anchored */
+	struct usb_anchor *anchor;
+    
 	uint16_t transfer_flags;	/* (in) */
 #define	URB_SHORT_NOT_OK	0x0001	/* report short transfers like errors */
 #define	URB_ISO_ASAP		0x0002	/* ignore "start_frame" field */
@@ -802,5 +809,34 @@
 
 struct usb_host_endpoint *usb_pipe_endpoint(struct usb_device *, unsigned int);
 int usb_urb_ep_type_check(const struct urb *);
+
+
+struct usb_anchor {
+	struct list_head urb_list;
+	wait_queue_head_t wait;
+	spinlock_t lock;
+	atomic_t suspend_wakeups;
+	unsigned int poisoned:1;
+};
+
+extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor);
+extern void usb_unanchor_urb(struct urb *urb);
+
+
+static inline void init_usb_anchor(struct usb_anchor *anchor)
+{
+	memset(anchor, 0, sizeof(*anchor));
+	INIT_LIST_HEAD(&anchor->urb_list);
+	init_waitqueue_head(&anchor->wait);
+	spin_lock_init(&anchor->lock);
+}
+
+extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout);
+
+extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
+
+#define usb_put_urb usb_free_urb
+
+
 
 #endif					/* _LINUX_USB_H_ */
diff -ru webcamd/work/webcamd-4.20.0.1/media_tree/drivers/input/joystick/xpad.c webcamd.0/work/webcamd-4.20.0.1/media_tree/drivers/input/joystick/xpad.c
--- webcamd/work/webcamd-4.20.0.1/media_tree/drivers/input/joystick/xpad.c	2018-12-13 11:51:48.000000000 +0100
+++ webcamd.0/work/webcamd-4.20.0.1/media_tree/drivers/input/joystick/xpad.c	2019-06-25 11:03:14.319817000 +0200
@@ -543,12 +543,26 @@
 	bool pending;
 };
 
+
+#if defined(CONFIG_JOYSTICK_XPAD_FF)
+#define VAL_CONFIG_JOYSTICK_XPAD_FF 1
+#else
+#define VAL_CONFIG_JOYSTICK_XPAD_FF 0
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#define VAL_CONFIG_JOYSTICK_XPAD_LEDS 1
+#else
+#define VAL_CONFIG_JOYSTICK_XPAD_LEDS 0
+#endif
+
+
 #define XPAD_OUT_CMD_IDX	0
 #define XPAD_OUT_FF_IDX		1
-#define XPAD_OUT_LED_IDX	(1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF))
+#define XPAD_OUT_LED_IDX	(1 + VAL_CONFIG_JOYSTICK_XPAD_FF)
 #define XPAD_NUM_OUT_PACKETS	(1 + \
-				 IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \
-				 IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS))
+				 VAL_CONFIG_JOYSTICK_XPAD_FF + \
+				 VAL_CONFIG_JOYSTICK_XPAD_LEDS)
 
 struct usb_xpad {
 	struct input_dev *dev;		/* input device interface */

--------------44F08131385CD5D54FD36EC0--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?e72b3805-3f44-ef57-fc93-60c41e0bd054>