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>