Hi Lukas, On 12.05.2018 03:49, Lukas Rusak wrote: > This driver is a simple implementation to get the controller working > and mapped properly. > This driver does not include functionality for the touchpad (yet). The > original driver > was taken from from the ouya linux tree and has been simplified. It > seems there may have > been other versions of the controller present that had a broken report > descriptor. I have > removed that for now. Would be nice if we have native Ouya support, also have two of those controllers here :-) Btw, commit text should be broken at around 70 characters or so. > > V2: > - updated original authors email > > --- > drivers/hid/Kconfig | 6 ++ > drivers/hid/Makefile | 1 + > drivers/hid/hid-ids.h | 3 + > drivers/hid/hid-ouya.c | 131 +++++++++++++++++++++++++++++++++++++++ > drivers/hid/hid-quirks.c | 3 + > 5 files changed, 144 insertions(+) > create mode 100644 drivers/hid/hid-ouya.c > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 60252fd796f6..6be2c454e72e 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -659,6 +659,12 @@ config HID_ORTEK > - Ortek WKB-2000 > - Skycable wireless presenter > > +config HID_OUYA > + tristate "OUYA Game Controller" > + depends on USB_HID > + ---help--- > + Support for OUYA Game Controller. > + > config HID_PANTHERLORD > tristate "Pantherlord/GreenAsia game controller" > depends on HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index 17a8bd97da9d..4425890934e4 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -71,6 +71,7 @@ obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o > obj-$(CONFIG_HID_NTI) += hid-nti.o > obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o > obj-$(CONFIG_HID_ORTEK) += hid-ortek.o > +obj-$(CONFIG_HID_OUYA) += hid-ouya.o > obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o > obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o > obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 0b5cc910f62e..0528efb825fa 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -859,6 +859,9 @@ > #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 > #define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003 > > +#define USB_VENDOR_ID_OUYA 0x2836 > +#define USB_DEVICE_ID_OUYA_CONTROLLER 0x0001 > + > #define USB_VENDOR_ID_PLANTRONICS 0x047f > > #define USB_VENDOR_ID_PANASONIC 0x04da > diff --git a/drivers/hid/hid-ouya.c b/drivers/hid/hid-ouya.c > new file mode 100644 > index 000000000000..4344a47b40af > --- /dev/null > +++ b/drivers/hid/hid-ouya.c > @@ -0,0 +1,131 @@ > +/* > + * HID driver for OUYA Game Controller(s) > + * > + * Copyright (c) 2013 OUYA > + * Copyright (c) 2013 Gregorios Leach <optikflux@xxxxxxxxx> > + * Copyright (c) 2018 Lukas Rusak <lorusak@xxxxxxxxx> > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/input.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +static const unsigned int ouya_absmap[] = { > + [0x30] = ABS_X, /* left stick X */ > + [0x31] = ABS_Y, /* left stick Y */ > + [0x32] = ABS_Z, /* L2 */ > + [0x33] = ABS_RX, /* right stick X */ > + [0x34] = ABS_RY, /* right stick Y */ > + [0x35] = ABS_RZ, /* R2 */ > +}; > + > +static const unsigned int ouya_keymap[] = { > + [0x1] = BTN_SOUTH, /* O */ > + [0x2] = BTN_WEST, /* U */ > + [0x3] = BTN_NORTH, /* Y */ > + [0x4] = BTN_EAST, /* A */ > + [0x5] = BTN_TL, /* L1 */ > + [0x6] = BTN_TR, /* R1 */ > + [0x7] = BTN_THUMBL, /* L3 */ > + [0x8] = BTN_THUMBR, /* R3 */ > + [0x9] = BTN_DPAD_UP, /* Up */ > + [0xa] = BTN_DPAD_DOWN, /* Down */ > + [0xb] = BTN_DPAD_LEFT, /* Left */ > + [0xc] = BTN_DPAD_RIGHT, /* Right */ > + [0xd] = BTN_TL2, /* L2 */ > + [0xe] = BTN_TR2, /* R2 */ > + [0xf] = BTN_MODE, /* Power */ > +}; > + > +static int ouya_input_mapping(struct hid_device *hdev, struct hid_input *hi, > + struct hid_field *field, struct hid_usage *usage, > + unsigned long **bit, int *max) > +{ > + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { > + unsigned int key = usage->hid & HID_USAGE; > + > + if (key >= ARRAY_SIZE(ouya_keymap)) > + return -1; > + > + key = ouya_keymap[key]; > + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); > + > + return 1; > + > + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { > + unsigned int abs = usage->hid & HID_USAGE; > + > + if (abs >= ARRAY_SIZE(ouya_absmap)) > + return -1; > + > + abs = ouya_absmap[abs]; > + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); > + > + return 1; > + } > + > + return 0; > +} > + > +static int ouya_probe(struct hid_device *hdev, const struct hid_device_id *id) > +{ > + int ret; > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "parse failed\n"); > + goto err_free; Since you do not do anything in free, you can return here directly. > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto err_free; Same here. > + } > + > + return 0; > + > +err_free: And remove that label. > + return ret; > +} > + > +static void ouya_remove(struct hid_device *hdev) > +{ > + hid_hw_stop(hdev); > + kfree(hid_get_drvdata(hdev)); You don't allocate/set drvdata, so this is probably not required. > +} > + > +static const struct hid_device_id ouya_devices[] = { > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, > + { } > +}; > +MODULE_DEVICE_TABLE(hid, ouya_devices); > + > +static struct hid_driver ouya_driver = { > + .name = "ouya", > + .id_table = ouya_devices, > + .input_mapping = ouya_input_mapping, > + .probe = ouya_probe, > + .remove = ouya_remove, > +}; > + > +static int __init ouya_init(void) > +{ > + return hid_register_driver(&ouya_driver); > +} > + > +static void __exit ouya_exit(void) > +{ > + hid_unregister_driver(&ouya_driver); > +} > + > +module_init(ouya_init); > +module_exit(ouya_exit); There is module_hid_driver which should make that part a bit simpler. -- Stefan > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Lukas Rusak <lorusak@xxxxxxxxx>"); > +MODULE_AUTHOR("Gregorios Leach <optikflux@xxxxxxxxx>"); > +MODULE_DESCRIPTION("Ouya Controller Driver"); > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c > index 587e2681a53f..b5adc13e0df1 100644 > --- a/drivers/hid/hid-quirks.c > +++ b/drivers/hid/hid-quirks.c > @@ -538,6 +538,9 @@ static const struct hid_device_id > hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S) }, > { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, > USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, > #endif > +#if IS_ENABLED(CONFIG_HID_OUYA) > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, > +#endif > #if IS_ENABLED(CONFIG_HID_PANTHERLORD) > { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, > USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, > { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, > USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },