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
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 */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "[email protected]"