diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..47459e1 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/Makefile b/Makefile index f930ed3..d722c53 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,12 @@ all: make -C /lib/modules/$(KVERSION)/build V=1 M=$(PWD) modules clean: test ! -d /lib/modules/$(KVERSION) || make -C /lib/modules/$(KVERSION)/build V=1 M=$(PWD) clean + +## Allow Install on Gentoo to work [huge thanks to hurikhan77 for figuring this part out]: +## Note: you need to make the xpad built in driver set to module in kernel config for this to work +## Once installed, run modprobe xpad to start it and it should work +KERNEL_SOURCE_DIR := /lib/modules/$(shell uname -r)/source +LD := ld.bfd + +modules_install: + $(MAKE) -C $(KERNEL_SOURCE_DIR) INSTALL_MOD_DIR="kernel/drivers/input/joystick" LD=$(LD) M=$(shell pwd) $@ diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1c87ac --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Updated Xpad Linux Kernel Driver +Driver for the Xbox/ Xbox 360/ Xbox 360 Wireless/ Xbox One Controllers + +This driver includes the latest changes in the upstream linux kernel and additionally carries the following staging changes: + +* enable debug outputs to ease resolving issues +* some minor code refactoring improving readability + + +**This driver does not support the XBox One Wireless Adapter (WiFi)** +To get that running, see: [medusalix/xow](https://github.com/medusalix/xow) + +# Installing +``` +sudo git clone https://github.com/paroj/xpad.git /usr/src/xpad-0.4 +sudo dkms install -m xpad -v 0.4 +``` +# Updating +``` +cd /usr/src/xpad-0.4 +sudo git fetch +sudo git checkout origin/master +sudo dkms remove -m xpad -v 0.4 --all +sudo dkms install -m xpad -v 0.4 +``` +# Removing +``` +sudo dkms remove -m xpad -v 0.4 --all +sudo rm -rf /usr/src/xpad-0.4 +``` +# Usage +This driver creates three devices for each attached gamepad + +1. /dev/input/js**N** + * example `jstest /dev/input/js0` +2. /sys/class/leds/xpad**N**/brightness + * example `echo COMMAND > /sys/class/leds/xpad0/brightness` where COMMAND is one of + * 0: off + * 1: all blink, then previous setting + * 2: 1/top-left blink, then on + * 3: 2/top-right blink, then on + * 4: 3/bottom-left blink, then on + * 5: 4/bottom-right blink, then on + * 6: 1/top-left on + * 7: 2/top-right on + * 8: 3/bottom-left on + * 9: 4/bottom-right on + * 10: rotate + * 11: blink, based on previous setting + * 12: slow blink, based on previous setting + * 13: rotate with two lights + * 14: persistent slow all blink + * 15: blink once, then previous setting +3. the generic event device + * example `fftest /dev/input/by-id/usb-*360*event*` + +# Debugging +As a regular unpriveledged user + +Setup console to display kernel log. +`dmesg --level=debug --follow` + +Open a new console and access the device with jstest. +`jstest /dev/input/jsX` + +Interact with the device and observe that data packets recieved from device are printed to kernel log. +``` +[ 3968.772128] xpad-dbg: 00000000: 20 00 b5 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 40 fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.772135] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.804137] xpad-dbg: 00000000: 20 00 b6 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 fc fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.804145] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3969.152120] xpad-dbg: 00000000: 20 00 b7 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 b8 fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3969.152129] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +Save dmesg buffer and attach to bug report, don't forget to describe button sequences in bug report. +`dmesg --level=debug > dmesg.txt` + +Ctrl+C to close interactive console sessions when finished. + +# Sending Upstream + +1. `git format-patch --cover-letter upstream..master` +2. `git send-email --to xxx *.patch` diff --git a/stress_urb_out.sh b/stress_urb_out.sh new file mode 100755 index 0000000..2e5c235 --- /dev/null +++ b/stress_urb_out.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# stress test irq_urb_out. provokes URB request dropping. +# script by Laura Abbott +# see: http://www.spinics.net/lists/linux-input/msg40477.html + +while true; do + for i in $(seq 0 5); do + echo $i > /sys/class/leds/xpad0/subsystem/xpad0/brightness + done +done diff --git a/xpad.c b/xpad.c index e7baa98..8d3623f 100644 --- a/xpad.c +++ b/xpad.c @@ -60,7 +60,7 @@ * * Later changes can be tracked in SCM. */ - +// #define DEBUG #include #include #include @@ -490,6 +490,20 @@ static const u8 xboxone_s_init[] = { 0x05, 0x20, 0x00, 0x0f, 0x06 }; +/* + * This packet is required for some zeroplus pads (0x045e:0x02ea) + */ +static const u8 xboxone_zeroplus_init1[] = { + 0x04, 0x20, 0x01, 0x00 +}; +/* + * This packet is required for some zeroplus pads (0x045e:0x02ea) + */ +static const u8 xboxone_zeroplus_init2[] = { + 0x01, 0x20, 0x01, 0x09, 0x00, 0x1e, 0x20, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + /* * This packet is required for the Titanfall 2 Xbox One pads * (0x0e6f:0x0165) to finish initialization and for Hori pads @@ -549,6 +563,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = { XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), + XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_zeroplus_init1), + XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_zeroplus_init2), XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1), XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2), @@ -609,11 +625,13 @@ struct usb_xpad { int pad_nr; /* the order x360 pads were attached */ const char *name; /* name of the device */ struct work_struct work; /* init/remove device from callback */ + time64_t mode_btn_down_ts; }; static int xpad_init_input(struct usb_xpad *xpad); static void xpad_deinit_input(struct usb_xpad *xpad); static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); +static void xpad360w_poweroff_controller(struct usb_xpad *xpad); /* * xpad_process_packet @@ -765,6 +783,23 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, } input_sync(dev); + + /* XBOX360W controllers can't be turned off without driver assistance */ + if (xpad->xtype == XTYPE_XBOX360W) { + if (xpad->mode_btn_down_ts > 0 + && xpad->pad_present + && (ktime_get_seconds() - xpad->mode_btn_down_ts) >= 5) { + xpad360w_poweroff_controller(xpad); + xpad->mode_btn_down_ts = 0; + return; + } + + /* mode button down/up */ + if (data[3] & 0x04) + xpad->mode_btn_down_ts = ktime_get_seconds(); + else + xpad->mode_btn_down_ts = 0; + } } static void xpad_presence_work(struct work_struct *work) @@ -952,6 +987,13 @@ static void xpad_irq_in(struct urb *urb) goto exit; } +#if defined(DEBUG_VERBOSE) + /* If you set rowsize to larger than 32 it defaults to 16? + * Otherwise I would set it to XPAD_PKT_LEN V + */ + print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, xpad->idata, XPAD_PKT_LEN, 0); +#endif + switch (xpad->xtype) { case XTYPE_XBOX360: xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata); @@ -1970,7 +2012,6 @@ static struct usb_driver xpad_driver = { .disconnect = xpad_disconnect, .suspend = xpad_suspend, .resume = xpad_resume, - .reset_resume = xpad_resume, .id_table = xpad_table, };