18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Device Modules for Nintendo Wii / Wii U HID Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * Wiimote Modules 128c2ecf20Sopenharmony_ci * Nintendo devices provide different peripherals and many new devices lack 138c2ecf20Sopenharmony_ci * initial features like the IR camera. Therefore, each peripheral device is 148c2ecf20Sopenharmony_ci * implemented as an independent module and we probe on each device only the 158c2ecf20Sopenharmony_ci * modules for the hardware that really is available. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Module registration is sequential. Unregistration is done in reverse order. 188c2ecf20Sopenharmony_ci * After device detection, the needed modules are loaded. Users can trigger 198c2ecf20Sopenharmony_ci * re-detection which causes all modules to be unloaded and then reload the 208c2ecf20Sopenharmony_ci * modules for the new detected device. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * wdata->input is a shared input device. It is always initialized prior to 238c2ecf20Sopenharmony_ci * module registration. If at least one registered module is marked as 248c2ecf20Sopenharmony_ci * WIIMOD_FLAG_INPUT, then the input device will get registered after all 258c2ecf20Sopenharmony_ci * modules were registered. 268c2ecf20Sopenharmony_ci * Please note that it is unregistered _before_ the "remove" callbacks are 278c2ecf20Sopenharmony_ci * called. This guarantees that no input interaction is done, anymore. However, 288c2ecf20Sopenharmony_ci * the wiimote core keeps a reference to the input device so it is freed only 298c2ecf20Sopenharmony_ci * after all modules were removed. It is safe to send events to unregistered 308c2ecf20Sopenharmony_ci * input devices. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/device.h> 348c2ecf20Sopenharmony_ci#include <linux/hid.h> 358c2ecf20Sopenharmony_ci#include <linux/input.h> 368c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 378c2ecf20Sopenharmony_ci#include "hid-wiimote.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Keys 418c2ecf20Sopenharmony_ci * The initial Wii Remote provided a bunch of buttons that are reported as 428c2ecf20Sopenharmony_ci * part of the core protocol. Many later devices dropped these and report 438c2ecf20Sopenharmony_ci * invalid data in the core button reports. Load this only on devices which 448c2ecf20Sopenharmony_ci * correctly send button reports. 458c2ecf20Sopenharmony_ci * It uses the shared input device. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const __u16 wiimod_keys_map[] = { 498c2ecf20Sopenharmony_ci KEY_LEFT, /* WIIPROTO_KEY_LEFT */ 508c2ecf20Sopenharmony_ci KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ 518c2ecf20Sopenharmony_ci KEY_UP, /* WIIPROTO_KEY_UP */ 528c2ecf20Sopenharmony_ci KEY_DOWN, /* WIIPROTO_KEY_DOWN */ 538c2ecf20Sopenharmony_ci KEY_NEXT, /* WIIPROTO_KEY_PLUS */ 548c2ecf20Sopenharmony_ci KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ 558c2ecf20Sopenharmony_ci BTN_1, /* WIIPROTO_KEY_ONE */ 568c2ecf20Sopenharmony_ci BTN_2, /* WIIPROTO_KEY_TWO */ 578c2ecf20Sopenharmony_ci BTN_A, /* WIIPROTO_KEY_A */ 588c2ecf20Sopenharmony_ci BTN_B, /* WIIPROTO_KEY_B */ 598c2ecf20Sopenharmony_ci BTN_MODE, /* WIIPROTO_KEY_HOME */ 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT], 658c2ecf20Sopenharmony_ci !!(keys[0] & 0x01)); 668c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT], 678c2ecf20Sopenharmony_ci !!(keys[0] & 0x02)); 688c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN], 698c2ecf20Sopenharmony_ci !!(keys[0] & 0x04)); 708c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP], 718c2ecf20Sopenharmony_ci !!(keys[0] & 0x08)); 728c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS], 738c2ecf20Sopenharmony_ci !!(keys[0] & 0x10)); 748c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO], 758c2ecf20Sopenharmony_ci !!(keys[1] & 0x01)); 768c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE], 778c2ecf20Sopenharmony_ci !!(keys[1] & 0x02)); 788c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B], 798c2ecf20Sopenharmony_ci !!(keys[1] & 0x04)); 808c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A], 818c2ecf20Sopenharmony_ci !!(keys[1] & 0x08)); 828c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS], 838c2ecf20Sopenharmony_ci !!(keys[1] & 0x10)); 848c2ecf20Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME], 858c2ecf20Sopenharmony_ci !!(keys[1] & 0x80)); 868c2ecf20Sopenharmony_ci input_sync(wdata->input); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int wiimod_keys_probe(const struct wiimod_ops *ops, 908c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci unsigned int i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->input->evbit); 958c2ecf20Sopenharmony_ci for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) 968c2ecf20Sopenharmony_ci set_bit(wiimod_keys_map[i], wdata->input->keybit); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_keys = { 1028c2ecf20Sopenharmony_ci .flags = WIIMOD_FLAG_INPUT, 1038c2ecf20Sopenharmony_ci .arg = 0, 1048c2ecf20Sopenharmony_ci .probe = wiimod_keys_probe, 1058c2ecf20Sopenharmony_ci .remove = NULL, 1068c2ecf20Sopenharmony_ci .in_keys = wiimod_keys_in_keys, 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * Rumble 1118c2ecf20Sopenharmony_ci * Nearly all devices provide a rumble feature. A small motor for 1128c2ecf20Sopenharmony_ci * force-feedback effects. We provide an FF_RUMBLE memless ff device on the 1138c2ecf20Sopenharmony_ci * shared input device if this module is loaded. 1148c2ecf20Sopenharmony_ci * The rumble motor is controlled via a flag on almost every output report so 1158c2ecf20Sopenharmony_ci * the wiimote core handles the rumble flag. But if a device doesn't provide 1168c2ecf20Sopenharmony_ci * the rumble motor, this flag shouldn't be set. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* used by wiimod_rumble and wiipro_rumble */ 1208c2ecf20Sopenharmony_cistatic void wiimod_rumble_worker(struct work_struct *work) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct wiimote_data *wdata = container_of(work, struct wiimote_data, 1238c2ecf20Sopenharmony_ci rumble_worker); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 1268c2ecf20Sopenharmony_ci wiiproto_req_rumble(wdata, wdata->state.cache_rumble); 1278c2ecf20Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int wiimod_rumble_play(struct input_dev *dev, void *data, 1318c2ecf20Sopenharmony_ci struct ff_effect *eff) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 1348c2ecf20Sopenharmony_ci __u8 value; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * The wiimote supports only a single rumble motor so if any magnitude 1388c2ecf20Sopenharmony_ci * is set to non-zero then we start the rumble motor. If both are set to 1398c2ecf20Sopenharmony_ci * zero, we stop the rumble motor. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude) 1438c2ecf20Sopenharmony_ci value = 1; 1448c2ecf20Sopenharmony_ci else 1458c2ecf20Sopenharmony_ci value = 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Locking state.lock here might deadlock with input_event() calls. 1488c2ecf20Sopenharmony_ci * schedule_work acts as barrier. Merging multiple changes is fine. */ 1498c2ecf20Sopenharmony_ci wdata->state.cache_rumble = value; 1508c2ecf20Sopenharmony_ci schedule_work(&wdata->rumble_worker); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int wiimod_rumble_probe(const struct wiimod_ops *ops, 1568c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci set_bit(FF_RUMBLE, wdata->input->ffbit); 1618c2ecf20Sopenharmony_ci if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play)) 1628c2ecf20Sopenharmony_ci return -ENOMEM; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void wiimod_rumble_remove(const struct wiimod_ops *ops, 1688c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci unsigned long flags; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci cancel_work_sync(&wdata->rumble_worker); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 1758c2ecf20Sopenharmony_ci wiiproto_req_rumble(wdata, 0); 1768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_rumble = { 1808c2ecf20Sopenharmony_ci .flags = WIIMOD_FLAG_INPUT, 1818c2ecf20Sopenharmony_ci .arg = 0, 1828c2ecf20Sopenharmony_ci .probe = wiimod_rumble_probe, 1838c2ecf20Sopenharmony_ci .remove = wiimod_rumble_remove, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * Battery 1888c2ecf20Sopenharmony_ci * 1 byte of battery capacity information is sent along every protocol status 1898c2ecf20Sopenharmony_ci * report. The wiimote core caches it but we try to update it on every 1908c2ecf20Sopenharmony_ci * user-space request. 1918c2ecf20Sopenharmony_ci * This is supported by nearly every device so it's almost always enabled. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic enum power_supply_property wiimod_battery_props[] = { 1958c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY, 1968c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_SCOPE, 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int wiimod_battery_get_property(struct power_supply *psy, 2008c2ecf20Sopenharmony_ci enum power_supply_property psp, 2018c2ecf20Sopenharmony_ci union power_supply_propval *val) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct wiimote_data *wdata = power_supply_get_drvdata(psy); 2048c2ecf20Sopenharmony_ci int ret = 0, state; 2058c2ecf20Sopenharmony_ci unsigned long flags; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (psp == POWER_SUPPLY_PROP_SCOPE) { 2088c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_DEVICE; 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci } else if (psp != POWER_SUPPLY_PROP_CAPACITY) { 2118c2ecf20Sopenharmony_ci return -EINVAL; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 2158c2ecf20Sopenharmony_ci if (ret) 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 2198c2ecf20Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0); 2208c2ecf20Sopenharmony_ci wiiproto_req_status(wdata); 2218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci wiimote_cmd_wait(wdata); 2248c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 2278c2ecf20Sopenharmony_ci state = wdata->state.cmd_battery; 2288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci val->intval = state * 100 / 255; 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int wiimod_battery_probe(const struct wiimod_ops *ops, 2358c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct power_supply_config psy_cfg = { .drv_data = wdata, }; 2388c2ecf20Sopenharmony_ci int ret; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci wdata->battery_desc.properties = wiimod_battery_props; 2418c2ecf20Sopenharmony_ci wdata->battery_desc.num_properties = ARRAY_SIZE(wiimod_battery_props); 2428c2ecf20Sopenharmony_ci wdata->battery_desc.get_property = wiimod_battery_get_property; 2438c2ecf20Sopenharmony_ci wdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 2448c2ecf20Sopenharmony_ci wdata->battery_desc.use_for_apm = 0; 2458c2ecf20Sopenharmony_ci wdata->battery_desc.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s", 2468c2ecf20Sopenharmony_ci wdata->hdev->uniq); 2478c2ecf20Sopenharmony_ci if (!wdata->battery_desc.name) 2488c2ecf20Sopenharmony_ci return -ENOMEM; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci wdata->battery = power_supply_register(&wdata->hdev->dev, 2518c2ecf20Sopenharmony_ci &wdata->battery_desc, 2528c2ecf20Sopenharmony_ci &psy_cfg); 2538c2ecf20Sopenharmony_ci if (IS_ERR(wdata->battery)) { 2548c2ecf20Sopenharmony_ci hid_err(wdata->hdev, "cannot register battery device\n"); 2558c2ecf20Sopenharmony_ci ret = PTR_ERR(wdata->battery); 2568c2ecf20Sopenharmony_ci goto err_free; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci power_supply_powers(wdata->battery, &wdata->hdev->dev); 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cierr_free: 2638c2ecf20Sopenharmony_ci kfree(wdata->battery_desc.name); 2648c2ecf20Sopenharmony_ci wdata->battery_desc.name = NULL; 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic void wiimod_battery_remove(const struct wiimod_ops *ops, 2698c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci if (!wdata->battery_desc.name) 2728c2ecf20Sopenharmony_ci return; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci power_supply_unregister(wdata->battery); 2758c2ecf20Sopenharmony_ci kfree(wdata->battery_desc.name); 2768c2ecf20Sopenharmony_ci wdata->battery_desc.name = NULL; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_battery = { 2808c2ecf20Sopenharmony_ci .flags = 0, 2818c2ecf20Sopenharmony_ci .arg = 0, 2828c2ecf20Sopenharmony_ci .probe = wiimod_battery_probe, 2838c2ecf20Sopenharmony_ci .remove = wiimod_battery_remove, 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * LED 2888c2ecf20Sopenharmony_ci * 0 to 4 player LEDs are supported by devices. The "arg" field of the 2898c2ecf20Sopenharmony_ci * wiimod_ops structure specifies which LED this module controls. This allows 2908c2ecf20Sopenharmony_ci * to register a limited number of LEDs. 2918c2ecf20Sopenharmony_ci * State is managed by wiimote core. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic enum led_brightness wiimod_led_get(struct led_classdev *led_dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct device *dev = led_dev->dev->parent; 2978c2ecf20Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 2988c2ecf20Sopenharmony_ci int i; 2998c2ecf20Sopenharmony_ci unsigned long flags; 3008c2ecf20Sopenharmony_ci bool value = false; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 3038c2ecf20Sopenharmony_ci if (wdata->leds[i] == led_dev) { 3048c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 3058c2ecf20Sopenharmony_ci value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1); 3068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return value ? LED_FULL : LED_OFF; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void wiimod_led_set(struct led_classdev *led_dev, 3158c2ecf20Sopenharmony_ci enum led_brightness value) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct device *dev = led_dev->dev->parent; 3188c2ecf20Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 3198c2ecf20Sopenharmony_ci int i; 3208c2ecf20Sopenharmony_ci unsigned long flags; 3218c2ecf20Sopenharmony_ci __u8 state, flag; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 3248c2ecf20Sopenharmony_ci if (wdata->leds[i] == led_dev) { 3258c2ecf20Sopenharmony_ci flag = WIIPROTO_FLAG_LED(i + 1); 3268c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 3278c2ecf20Sopenharmony_ci state = wdata->state.flags; 3288c2ecf20Sopenharmony_ci if (value == LED_OFF) 3298c2ecf20Sopenharmony_ci wiiproto_req_leds(wdata, state & ~flag); 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci wiiproto_req_leds(wdata, state | flag); 3328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int wiimod_led_probe(const struct wiimod_ops *ops, 3398c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct device *dev = &wdata->hdev->dev; 3428c2ecf20Sopenharmony_ci size_t namesz = strlen(dev_name(dev)) + 9; 3438c2ecf20Sopenharmony_ci struct led_classdev *led; 3448c2ecf20Sopenharmony_ci unsigned long flags; 3458c2ecf20Sopenharmony_ci char *name; 3468c2ecf20Sopenharmony_ci int ret; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); 3498c2ecf20Sopenharmony_ci if (!led) 3508c2ecf20Sopenharmony_ci return -ENOMEM; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci name = (void*)&led[1]; 3538c2ecf20Sopenharmony_ci snprintf(name, namesz, "%s:blue:p%lu", dev_name(dev), ops->arg); 3548c2ecf20Sopenharmony_ci led->name = name; 3558c2ecf20Sopenharmony_ci led->brightness = 0; 3568c2ecf20Sopenharmony_ci led->max_brightness = 1; 3578c2ecf20Sopenharmony_ci led->brightness_get = wiimod_led_get; 3588c2ecf20Sopenharmony_ci led->brightness_set = wiimod_led_set; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci wdata->leds[ops->arg] = led; 3618c2ecf20Sopenharmony_ci ret = led_classdev_register(dev, led); 3628c2ecf20Sopenharmony_ci if (ret) 3638c2ecf20Sopenharmony_ci goto err_free; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* enable LED1 to stop initial LED-blinking */ 3668c2ecf20Sopenharmony_ci if (ops->arg == 0) { 3678c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 3688c2ecf20Sopenharmony_ci wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); 3698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cierr_free: 3758c2ecf20Sopenharmony_ci wdata->leds[ops->arg] = NULL; 3768c2ecf20Sopenharmony_ci kfree(led); 3778c2ecf20Sopenharmony_ci return ret; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void wiimod_led_remove(const struct wiimod_ops *ops, 3818c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci if (!wdata->leds[ops->arg]) 3848c2ecf20Sopenharmony_ci return; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci led_classdev_unregister(wdata->leds[ops->arg]); 3878c2ecf20Sopenharmony_ci kfree(wdata->leds[ops->arg]); 3888c2ecf20Sopenharmony_ci wdata->leds[ops->arg] = NULL; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_leds[4] = { 3928c2ecf20Sopenharmony_ci { 3938c2ecf20Sopenharmony_ci .flags = 0, 3948c2ecf20Sopenharmony_ci .arg = 0, 3958c2ecf20Sopenharmony_ci .probe = wiimod_led_probe, 3968c2ecf20Sopenharmony_ci .remove = wiimod_led_remove, 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci { 3998c2ecf20Sopenharmony_ci .flags = 0, 4008c2ecf20Sopenharmony_ci .arg = 1, 4018c2ecf20Sopenharmony_ci .probe = wiimod_led_probe, 4028c2ecf20Sopenharmony_ci .remove = wiimod_led_remove, 4038c2ecf20Sopenharmony_ci }, 4048c2ecf20Sopenharmony_ci { 4058c2ecf20Sopenharmony_ci .flags = 0, 4068c2ecf20Sopenharmony_ci .arg = 2, 4078c2ecf20Sopenharmony_ci .probe = wiimod_led_probe, 4088c2ecf20Sopenharmony_ci .remove = wiimod_led_remove, 4098c2ecf20Sopenharmony_ci }, 4108c2ecf20Sopenharmony_ci { 4118c2ecf20Sopenharmony_ci .flags = 0, 4128c2ecf20Sopenharmony_ci .arg = 3, 4138c2ecf20Sopenharmony_ci .probe = wiimod_led_probe, 4148c2ecf20Sopenharmony_ci .remove = wiimod_led_remove, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* 4198c2ecf20Sopenharmony_ci * Accelerometer 4208c2ecf20Sopenharmony_ci * 3 axis accelerometer data is part of nearly all DRMs. If not supported by a 4218c2ecf20Sopenharmony_ci * device, it's mostly cleared to 0. This module parses this data and provides 4228c2ecf20Sopenharmony_ci * it via a separate input device. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void wiimod_accel_in_accel(struct wiimote_data *wdata, 4268c2ecf20Sopenharmony_ci const __u8 *accel) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci __u16 x, y, z; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL)) 4318c2ecf20Sopenharmony_ci return; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* 4348c2ecf20Sopenharmony_ci * payload is: BB BB XX YY ZZ 4358c2ecf20Sopenharmony_ci * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ 4368c2ecf20Sopenharmony_ci * contain the upper 8 bits of each value. The lower 2 bits are 4378c2ecf20Sopenharmony_ci * contained in the buttons data BB BB. 4388c2ecf20Sopenharmony_ci * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the 4398c2ecf20Sopenharmony_ci * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y 4408c2ecf20Sopenharmony_ci * accel value and bit 6 is the second bit of the Z value. 4418c2ecf20Sopenharmony_ci * The first bit of Y and Z values is not available and always set to 0. 4428c2ecf20Sopenharmony_ci * 0x200 is returned on no movement. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci x = accel[2] << 2; 4468c2ecf20Sopenharmony_ci y = accel[3] << 2; 4478c2ecf20Sopenharmony_ci z = accel[4] << 2; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci x |= (accel[0] >> 5) & 0x3; 4508c2ecf20Sopenharmony_ci y |= (accel[1] >> 4) & 0x2; 4518c2ecf20Sopenharmony_ci z |= (accel[1] >> 5) & 0x2; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci input_report_abs(wdata->accel, ABS_RX, x - 0x200); 4548c2ecf20Sopenharmony_ci input_report_abs(wdata->accel, ABS_RY, y - 0x200); 4558c2ecf20Sopenharmony_ci input_report_abs(wdata->accel, ABS_RZ, z - 0x200); 4568c2ecf20Sopenharmony_ci input_sync(wdata->accel); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int wiimod_accel_open(struct input_dev *dev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 4628c2ecf20Sopenharmony_ci unsigned long flags; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 4658c2ecf20Sopenharmony_ci wiiproto_req_accel(wdata, true); 4668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic void wiimod_accel_close(struct input_dev *dev) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 4748c2ecf20Sopenharmony_ci unsigned long flags; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 4778c2ecf20Sopenharmony_ci wiiproto_req_accel(wdata, false); 4788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int wiimod_accel_probe(const struct wiimod_ops *ops, 4828c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci wdata->accel = input_allocate_device(); 4878c2ecf20Sopenharmony_ci if (!wdata->accel) 4888c2ecf20Sopenharmony_ci return -ENOMEM; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci input_set_drvdata(wdata->accel, wdata); 4918c2ecf20Sopenharmony_ci wdata->accel->open = wiimod_accel_open; 4928c2ecf20Sopenharmony_ci wdata->accel->close = wiimod_accel_close; 4938c2ecf20Sopenharmony_ci wdata->accel->dev.parent = &wdata->hdev->dev; 4948c2ecf20Sopenharmony_ci wdata->accel->id.bustype = wdata->hdev->bus; 4958c2ecf20Sopenharmony_ci wdata->accel->id.vendor = wdata->hdev->vendor; 4968c2ecf20Sopenharmony_ci wdata->accel->id.product = wdata->hdev->product; 4978c2ecf20Sopenharmony_ci wdata->accel->id.version = wdata->hdev->version; 4988c2ecf20Sopenharmony_ci wdata->accel->name = WIIMOTE_NAME " Accelerometer"; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->accel->evbit); 5018c2ecf20Sopenharmony_ci set_bit(ABS_RX, wdata->accel->absbit); 5028c2ecf20Sopenharmony_ci set_bit(ABS_RY, wdata->accel->absbit); 5038c2ecf20Sopenharmony_ci set_bit(ABS_RZ, wdata->accel->absbit); 5048c2ecf20Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4); 5058c2ecf20Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4); 5068c2ecf20Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ret = input_register_device(wdata->accel); 5098c2ecf20Sopenharmony_ci if (ret) { 5108c2ecf20Sopenharmony_ci hid_err(wdata->hdev, "cannot register input device\n"); 5118c2ecf20Sopenharmony_ci goto err_free; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cierr_free: 5178c2ecf20Sopenharmony_ci input_free_device(wdata->accel); 5188c2ecf20Sopenharmony_ci wdata->accel = NULL; 5198c2ecf20Sopenharmony_ci return ret; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic void wiimod_accel_remove(const struct wiimod_ops *ops, 5238c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci if (!wdata->accel) 5268c2ecf20Sopenharmony_ci return; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci input_unregister_device(wdata->accel); 5298c2ecf20Sopenharmony_ci wdata->accel = NULL; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_accel = { 5338c2ecf20Sopenharmony_ci .flags = 0, 5348c2ecf20Sopenharmony_ci .arg = 0, 5358c2ecf20Sopenharmony_ci .probe = wiimod_accel_probe, 5368c2ecf20Sopenharmony_ci .remove = wiimod_accel_remove, 5378c2ecf20Sopenharmony_ci .in_accel = wiimod_accel_in_accel, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* 5418c2ecf20Sopenharmony_ci * IR Cam 5428c2ecf20Sopenharmony_ci * Up to 4 IR sources can be tracked by a normal Wii Remote. The IR cam needs 5438c2ecf20Sopenharmony_ci * to be initialized with a fairly complex procedure and consumes a lot of 5448c2ecf20Sopenharmony_ci * power. Therefore, as long as no application uses the IR input device, it is 5458c2ecf20Sopenharmony_ci * kept offline. 5468c2ecf20Sopenharmony_ci * Nearly no other device than the normal Wii Remotes supports the IR cam so 5478c2ecf20Sopenharmony_ci * you can disable this module for these devices. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void wiimod_ir_in_ir(struct wiimote_data *wdata, const __u8 *ir, 5518c2ecf20Sopenharmony_ci bool packed, unsigned int id) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci __u16 x, y; 5548c2ecf20Sopenharmony_ci __u8 xid, yid; 5558c2ecf20Sopenharmony_ci bool sync = false; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAGS_IR)) 5588c2ecf20Sopenharmony_ci return; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci switch (id) { 5618c2ecf20Sopenharmony_ci case 0: 5628c2ecf20Sopenharmony_ci xid = ABS_HAT0X; 5638c2ecf20Sopenharmony_ci yid = ABS_HAT0Y; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci case 1: 5668c2ecf20Sopenharmony_ci xid = ABS_HAT1X; 5678c2ecf20Sopenharmony_ci yid = ABS_HAT1Y; 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci case 2: 5708c2ecf20Sopenharmony_ci xid = ABS_HAT2X; 5718c2ecf20Sopenharmony_ci yid = ABS_HAT2Y; 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci case 3: 5748c2ecf20Sopenharmony_ci xid = ABS_HAT3X; 5758c2ecf20Sopenharmony_ci yid = ABS_HAT3Y; 5768c2ecf20Sopenharmony_ci sync = true; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci return; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* 5838c2ecf20Sopenharmony_ci * Basic IR data is encoded into 3 bytes. The first two bytes are the 5848c2ecf20Sopenharmony_ci * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits 5858c2ecf20Sopenharmony_ci * of both. 5868c2ecf20Sopenharmony_ci * If data is packed, then the 3rd byte is put first and slightly 5878c2ecf20Sopenharmony_ci * reordered. This allows to interleave packed and non-packed data to 5888c2ecf20Sopenharmony_ci * have two IR sets in 5 bytes instead of 6. 5898c2ecf20Sopenharmony_ci * The resulting 10bit X/Y values are passed to the ABS_HAT? input dev. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (packed) { 5938c2ecf20Sopenharmony_ci x = ir[1] | ((ir[0] & 0x03) << 8); 5948c2ecf20Sopenharmony_ci y = ir[2] | ((ir[0] & 0x0c) << 6); 5958c2ecf20Sopenharmony_ci } else { 5968c2ecf20Sopenharmony_ci x = ir[0] | ((ir[2] & 0x30) << 4); 5978c2ecf20Sopenharmony_ci y = ir[1] | ((ir[2] & 0xc0) << 2); 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci input_report_abs(wdata->ir, xid, x); 6018c2ecf20Sopenharmony_ci input_report_abs(wdata->ir, yid, y); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (sync) 6048c2ecf20Sopenharmony_ci input_sync(wdata->ir); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int wiimod_ir_change(struct wiimote_data *wdata, __u16 mode) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int ret; 6108c2ecf20Sopenharmony_ci unsigned long flags; 6118c2ecf20Sopenharmony_ci __u8 format = 0; 6128c2ecf20Sopenharmony_ci static const __u8 data_enable[] = { 0x01 }; 6138c2ecf20Sopenharmony_ci static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01, 6148c2ecf20Sopenharmony_ci 0x00, 0xaa, 0x00, 0x64 }; 6158c2ecf20Sopenharmony_ci static const __u8 data_sens2[] = { 0x63, 0x03 }; 6168c2ecf20Sopenharmony_ci static const __u8 data_fin[] = { 0x08 }; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) { 6218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (mode == 0) { 6268c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAGS_IR; 6278c2ecf20Sopenharmony_ci wiiproto_req_ir1(wdata, 0); 6288c2ecf20Sopenharmony_ci wiiproto_req_ir2(wdata, 0); 6298c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 6308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 6378c2ecf20Sopenharmony_ci if (ret) 6388c2ecf20Sopenharmony_ci return ret; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* send PIXEL CLOCK ENABLE cmd first */ 6418c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 6428c2ecf20Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0); 6438c2ecf20Sopenharmony_ci wiiproto_req_ir1(wdata, 0x06); 6448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = wiimote_cmd_wait(wdata); 6478c2ecf20Sopenharmony_ci if (ret) 6488c2ecf20Sopenharmony_ci goto unlock; 6498c2ecf20Sopenharmony_ci if (wdata->state.cmd_err) { 6508c2ecf20Sopenharmony_ci ret = -EIO; 6518c2ecf20Sopenharmony_ci goto unlock; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* enable IR LOGIC */ 6558c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 6568c2ecf20Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0); 6578c2ecf20Sopenharmony_ci wiiproto_req_ir2(wdata, 0x06); 6588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci ret = wiimote_cmd_wait(wdata); 6618c2ecf20Sopenharmony_ci if (ret) 6628c2ecf20Sopenharmony_ci goto unlock; 6638c2ecf20Sopenharmony_ci if (wdata->state.cmd_err) { 6648c2ecf20Sopenharmony_ci ret = -EIO; 6658c2ecf20Sopenharmony_ci goto unlock; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* enable IR cam but do not make it send data, yet */ 6698c2ecf20Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00030, data_enable, 6708c2ecf20Sopenharmony_ci sizeof(data_enable)); 6718c2ecf20Sopenharmony_ci if (ret) 6728c2ecf20Sopenharmony_ci goto unlock; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* write first sensitivity block */ 6758c2ecf20Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1, 6768c2ecf20Sopenharmony_ci sizeof(data_sens1)); 6778c2ecf20Sopenharmony_ci if (ret) 6788c2ecf20Sopenharmony_ci goto unlock; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* write second sensitivity block */ 6818c2ecf20Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2, 6828c2ecf20Sopenharmony_ci sizeof(data_sens2)); 6838c2ecf20Sopenharmony_ci if (ret) 6848c2ecf20Sopenharmony_ci goto unlock; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* put IR cam into desired state */ 6878c2ecf20Sopenharmony_ci switch (mode) { 6888c2ecf20Sopenharmony_ci case WIIPROTO_FLAG_IR_FULL: 6898c2ecf20Sopenharmony_ci format = 5; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case WIIPROTO_FLAG_IR_EXT: 6928c2ecf20Sopenharmony_ci format = 3; 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case WIIPROTO_FLAG_IR_BASIC: 6958c2ecf20Sopenharmony_ci format = 1; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format)); 6998c2ecf20Sopenharmony_ci if (ret) 7008c2ecf20Sopenharmony_ci goto unlock; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* make IR cam send data */ 7038c2ecf20Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin)); 7048c2ecf20Sopenharmony_ci if (ret) 7058c2ecf20Sopenharmony_ci goto unlock; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* request new DRM mode compatible to IR mode */ 7088c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 7098c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAGS_IR; 7108c2ecf20Sopenharmony_ci wdata->state.flags |= mode & WIIPROTO_FLAGS_IR; 7118c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 7128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ciunlock: 7158c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 7168c2ecf20Sopenharmony_ci return ret; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int wiimod_ir_open(struct input_dev *dev) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return wiimod_ir_change(wdata, WIIPROTO_FLAG_IR_BASIC); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic void wiimod_ir_close(struct input_dev *dev) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci wiimod_ir_change(wdata, 0); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int wiimod_ir_probe(const struct wiimod_ops *ops, 7348c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci int ret; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci wdata->ir = input_allocate_device(); 7398c2ecf20Sopenharmony_ci if (!wdata->ir) 7408c2ecf20Sopenharmony_ci return -ENOMEM; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci input_set_drvdata(wdata->ir, wdata); 7438c2ecf20Sopenharmony_ci wdata->ir->open = wiimod_ir_open; 7448c2ecf20Sopenharmony_ci wdata->ir->close = wiimod_ir_close; 7458c2ecf20Sopenharmony_ci wdata->ir->dev.parent = &wdata->hdev->dev; 7468c2ecf20Sopenharmony_ci wdata->ir->id.bustype = wdata->hdev->bus; 7478c2ecf20Sopenharmony_ci wdata->ir->id.vendor = wdata->hdev->vendor; 7488c2ecf20Sopenharmony_ci wdata->ir->id.product = wdata->hdev->product; 7498c2ecf20Sopenharmony_ci wdata->ir->id.version = wdata->hdev->version; 7508c2ecf20Sopenharmony_ci wdata->ir->name = WIIMOTE_NAME " IR"; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->ir->evbit); 7538c2ecf20Sopenharmony_ci set_bit(ABS_HAT0X, wdata->ir->absbit); 7548c2ecf20Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->ir->absbit); 7558c2ecf20Sopenharmony_ci set_bit(ABS_HAT1X, wdata->ir->absbit); 7568c2ecf20Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->ir->absbit); 7578c2ecf20Sopenharmony_ci set_bit(ABS_HAT2X, wdata->ir->absbit); 7588c2ecf20Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->ir->absbit); 7598c2ecf20Sopenharmony_ci set_bit(ABS_HAT3X, wdata->ir->absbit); 7608c2ecf20Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->ir->absbit); 7618c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4); 7628c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4); 7638c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4); 7648c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4); 7658c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4); 7668c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4); 7678c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4); 7688c2ecf20Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ret = input_register_device(wdata->ir); 7718c2ecf20Sopenharmony_ci if (ret) { 7728c2ecf20Sopenharmony_ci hid_err(wdata->hdev, "cannot register input device\n"); 7738c2ecf20Sopenharmony_ci goto err_free; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cierr_free: 7798c2ecf20Sopenharmony_ci input_free_device(wdata->ir); 7808c2ecf20Sopenharmony_ci wdata->ir = NULL; 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic void wiimod_ir_remove(const struct wiimod_ops *ops, 7858c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci if (!wdata->ir) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci input_unregister_device(wdata->ir); 7918c2ecf20Sopenharmony_ci wdata->ir = NULL; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_ir = { 7958c2ecf20Sopenharmony_ci .flags = 0, 7968c2ecf20Sopenharmony_ci .arg = 0, 7978c2ecf20Sopenharmony_ci .probe = wiimod_ir_probe, 7988c2ecf20Sopenharmony_ci .remove = wiimod_ir_remove, 7998c2ecf20Sopenharmony_ci .in_ir = wiimod_ir_in_ir, 8008c2ecf20Sopenharmony_ci}; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci/* 8038c2ecf20Sopenharmony_ci * Nunchuk Extension 8048c2ecf20Sopenharmony_ci * The Nintendo Wii Nunchuk was the first official extension published by 8058c2ecf20Sopenharmony_ci * Nintendo. It provides two additional keys and a separate accelerometer. It 8068c2ecf20Sopenharmony_ci * can be hotplugged to standard Wii Remotes. 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cienum wiimod_nunchuk_keys { 8108c2ecf20Sopenharmony_ci WIIMOD_NUNCHUK_KEY_C, 8118c2ecf20Sopenharmony_ci WIIMOD_NUNCHUK_KEY_Z, 8128c2ecf20Sopenharmony_ci WIIMOD_NUNCHUK_KEY_NUM, 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic const __u16 wiimod_nunchuk_map[] = { 8168c2ecf20Sopenharmony_ci BTN_C, /* WIIMOD_NUNCHUK_KEY_C */ 8178c2ecf20Sopenharmony_ci BTN_Z, /* WIIMOD_NUNCHUK_KEY_Z */ 8188c2ecf20Sopenharmony_ci}; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci __s16 x, y, z, bx, by; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 | 8258c2ecf20Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 8268c2ecf20Sopenharmony_ci * 1 | Button X <7:0> | 8278c2ecf20Sopenharmony_ci * 2 | Button Y <7:0> | 8288c2ecf20Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 8298c2ecf20Sopenharmony_ci * 3 | Speed X <9:2> | 8308c2ecf20Sopenharmony_ci * 4 | Speed Y <9:2> | 8318c2ecf20Sopenharmony_ci * 5 | Speed Z <9:2> | 8328c2ecf20Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 8338c2ecf20Sopenharmony_ci * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ | 8348c2ecf20Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 8358c2ecf20Sopenharmony_ci * Button X/Y is the analog stick. Speed X, Y and Z are the 8368c2ecf20Sopenharmony_ci * accelerometer data in the same format as the wiimote's accelerometer. 8378c2ecf20Sopenharmony_ci * The 6th byte contains the LSBs of the accelerometer data. 8388c2ecf20Sopenharmony_ci * BC and BZ are the C and Z buttons: 0 means pressed 8398c2ecf20Sopenharmony_ci * 8408c2ecf20Sopenharmony_ci * If reported interleaved with motionp, then the layout changes. The 8418c2ecf20Sopenharmony_ci * 5th and 6th byte changes to: 8428c2ecf20Sopenharmony_ci * -----+-----------------------------------+-----+ 8438c2ecf20Sopenharmony_ci * 5 | Speed Z <9:3> | EXT | 8448c2ecf20Sopenharmony_ci * -----+--------+-----+-----+----+----+----+-----+ 8458c2ecf20Sopenharmony_ci * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 | 8468c2ecf20Sopenharmony_ci * -----+--------+-----+-----+----+----+----+-----+ 8478c2ecf20Sopenharmony_ci * All three accelerometer values lose their LSB. The other data is 8488c2ecf20Sopenharmony_ci * still available but slightly moved. 8498c2ecf20Sopenharmony_ci * 8508c2ecf20Sopenharmony_ci * Center data for button values is 128. Center value for accelerometer 8518c2ecf20Sopenharmony_ci * values it 512 / 0x200 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci bx = ext[0]; 8558c2ecf20Sopenharmony_ci by = ext[1]; 8568c2ecf20Sopenharmony_ci bx -= 128; 8578c2ecf20Sopenharmony_ci by -= 128; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci x = ext[2] << 2; 8608c2ecf20Sopenharmony_ci y = ext[3] << 2; 8618c2ecf20Sopenharmony_ci z = ext[4] << 2; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 8648c2ecf20Sopenharmony_ci x |= (ext[5] >> 3) & 0x02; 8658c2ecf20Sopenharmony_ci y |= (ext[5] >> 4) & 0x02; 8668c2ecf20Sopenharmony_ci z &= ~0x4; 8678c2ecf20Sopenharmony_ci z |= (ext[5] >> 5) & 0x06; 8688c2ecf20Sopenharmony_ci } else { 8698c2ecf20Sopenharmony_ci x |= (ext[5] >> 2) & 0x03; 8708c2ecf20Sopenharmony_ci y |= (ext[5] >> 4) & 0x03; 8718c2ecf20Sopenharmony_ci z |= (ext[5] >> 6) & 0x03; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci x -= 0x200; 8758c2ecf20Sopenharmony_ci y -= 0x200; 8768c2ecf20Sopenharmony_ci z -= 0x200; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, bx); 8798c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0Y, by); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RX, x); 8828c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RY, y); 8838c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RZ, z); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 8868c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 8878c2ecf20Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z], 8888c2ecf20Sopenharmony_ci !(ext[5] & 0x04)); 8898c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 8908c2ecf20Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C], 8918c2ecf20Sopenharmony_ci !(ext[5] & 0x08)); 8928c2ecf20Sopenharmony_ci } else { 8938c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 8948c2ecf20Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z], 8958c2ecf20Sopenharmony_ci !(ext[5] & 0x01)); 8968c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 8978c2ecf20Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C], 8988c2ecf20Sopenharmony_ci !(ext[5] & 0x02)); 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int wiimod_nunchuk_open(struct input_dev *dev) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 9078c2ecf20Sopenharmony_ci unsigned long flags; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 9108c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 9118c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 9128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic void wiimod_nunchuk_close(struct input_dev *dev) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 9208c2ecf20Sopenharmony_ci unsigned long flags; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 9238c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 9248c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 9258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int wiimod_nunchuk_probe(const struct wiimod_ops *ops, 9298c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci int ret, i; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 9348c2ecf20Sopenharmony_ci if (!wdata->extension.input) 9358c2ecf20Sopenharmony_ci return -ENOMEM; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 9388c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_nunchuk_open; 9398c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_nunchuk_close; 9408c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 9418c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 9428c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 9438c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 9448c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 9458c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Nunchuk"; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 9488c2ecf20Sopenharmony_ci for (i = 0; i < WIIMOD_NUNCHUK_KEY_NUM; ++i) 9498c2ecf20Sopenharmony_ci set_bit(wiimod_nunchuk_map[i], 9508c2ecf20Sopenharmony_ci wdata->extension.input->keybit); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 9538c2ecf20Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 9548c2ecf20Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 9558c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 9568c2ecf20Sopenharmony_ci ABS_HAT0X, -120, 120, 2, 4); 9578c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 9588c2ecf20Sopenharmony_ci ABS_HAT0Y, -120, 120, 2, 4); 9598c2ecf20Sopenharmony_ci set_bit(ABS_RX, wdata->extension.input->absbit); 9608c2ecf20Sopenharmony_ci set_bit(ABS_RY, wdata->extension.input->absbit); 9618c2ecf20Sopenharmony_ci set_bit(ABS_RZ, wdata->extension.input->absbit); 9628c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 9638c2ecf20Sopenharmony_ci ABS_RX, -500, 500, 2, 4); 9648c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 9658c2ecf20Sopenharmony_ci ABS_RY, -500, 500, 2, 4); 9668c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 9678c2ecf20Sopenharmony_ci ABS_RZ, -500, 500, 2, 4); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 9708c2ecf20Sopenharmony_ci if (ret) 9718c2ecf20Sopenharmony_ci goto err_free; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cierr_free: 9768c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 9778c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 9788c2ecf20Sopenharmony_ci return ret; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic void wiimod_nunchuk_remove(const struct wiimod_ops *ops, 9828c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci if (!wdata->extension.input) 9858c2ecf20Sopenharmony_ci return; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 9888c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_nunchuk = { 9928c2ecf20Sopenharmony_ci .flags = 0, 9938c2ecf20Sopenharmony_ci .arg = 0, 9948c2ecf20Sopenharmony_ci .probe = wiimod_nunchuk_probe, 9958c2ecf20Sopenharmony_ci .remove = wiimod_nunchuk_remove, 9968c2ecf20Sopenharmony_ci .in_ext = wiimod_nunchuk_in_ext, 9978c2ecf20Sopenharmony_ci}; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/* 10008c2ecf20Sopenharmony_ci * Classic Controller 10018c2ecf20Sopenharmony_ci * Another official extension from Nintendo. It provides a classic 10028c2ecf20Sopenharmony_ci * gamecube-like controller that can be hotplugged on the Wii Remote. 10038c2ecf20Sopenharmony_ci * It has several hardware buttons and switches that are all reported via 10048c2ecf20Sopenharmony_ci * a normal extension device. 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cienum wiimod_classic_keys { 10088c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_A, 10098c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_B, 10108c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_X, 10118c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_Y, 10128c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_ZL, 10138c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_ZR, 10148c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_PLUS, 10158c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_MINUS, 10168c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_HOME, 10178c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_LEFT, 10188c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_RIGHT, 10198c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_UP, 10208c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_DOWN, 10218c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_LT, 10228c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_RT, 10238c2ecf20Sopenharmony_ci WIIMOD_CLASSIC_KEY_NUM, 10248c2ecf20Sopenharmony_ci}; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic const __u16 wiimod_classic_map[] = { 10278c2ecf20Sopenharmony_ci BTN_A, /* WIIMOD_CLASSIC_KEY_A */ 10288c2ecf20Sopenharmony_ci BTN_B, /* WIIMOD_CLASSIC_KEY_B */ 10298c2ecf20Sopenharmony_ci BTN_X, /* WIIMOD_CLASSIC_KEY_X */ 10308c2ecf20Sopenharmony_ci BTN_Y, /* WIIMOD_CLASSIC_KEY_Y */ 10318c2ecf20Sopenharmony_ci BTN_TL2, /* WIIMOD_CLASSIC_KEY_ZL */ 10328c2ecf20Sopenharmony_ci BTN_TR2, /* WIIMOD_CLASSIC_KEY_ZR */ 10338c2ecf20Sopenharmony_ci KEY_NEXT, /* WIIMOD_CLASSIC_KEY_PLUS */ 10348c2ecf20Sopenharmony_ci KEY_PREVIOUS, /* WIIMOD_CLASSIC_KEY_MINUS */ 10358c2ecf20Sopenharmony_ci BTN_MODE, /* WIIMOD_CLASSIC_KEY_HOME */ 10368c2ecf20Sopenharmony_ci KEY_LEFT, /* WIIMOD_CLASSIC_KEY_LEFT */ 10378c2ecf20Sopenharmony_ci KEY_RIGHT, /* WIIMOD_CLASSIC_KEY_RIGHT */ 10388c2ecf20Sopenharmony_ci KEY_UP, /* WIIMOD_CLASSIC_KEY_UP */ 10398c2ecf20Sopenharmony_ci KEY_DOWN, /* WIIMOD_CLASSIC_KEY_DOWN */ 10408c2ecf20Sopenharmony_ci BTN_TL, /* WIIMOD_CLASSIC_KEY_LT */ 10418c2ecf20Sopenharmony_ci BTN_TR, /* WIIMOD_CLASSIC_KEY_RT */ 10428c2ecf20Sopenharmony_ci}; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci __s8 rx, ry, lx, ly, lt, rt; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 10498c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10508c2ecf20Sopenharmony_ci * 1 | RX <5:4> | LX <5:0> | 10518c2ecf20Sopenharmony_ci * 2 | RX <3:2> | LY <5:0> | 10528c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 10538c2ecf20Sopenharmony_ci * 3 |RX<1>| LT <5:4> | RY <5:1> | 10548c2ecf20Sopenharmony_ci * -----+-----+-----------+-----------------------------+ 10558c2ecf20Sopenharmony_ci * 4 | LT <3:1> | RT <5:1> | 10568c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10578c2ecf20Sopenharmony_ci * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | 10588c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10598c2ecf20Sopenharmony_ci * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | 10608c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10618c2ecf20Sopenharmony_ci * All buttons are 0 if pressed 10628c2ecf20Sopenharmony_ci * RX and RY are right analog stick 10638c2ecf20Sopenharmony_ci * LX and LY are left analog stick 10648c2ecf20Sopenharmony_ci * LT is left trigger, RT is right trigger 10658c2ecf20Sopenharmony_ci * BLT is 0 if left trigger is fully pressed 10668c2ecf20Sopenharmony_ci * BRT is 0 if right trigger is fully pressed 10678c2ecf20Sopenharmony_ci * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons 10688c2ecf20Sopenharmony_ci * BZL is left Z button and BZR is right Z button 10698c2ecf20Sopenharmony_ci * B-, BH, B+ are +, HOME and - buttons 10708c2ecf20Sopenharmony_ci * BB, BY, BA, BX are A, B, X, Y buttons 10718c2ecf20Sopenharmony_ci * LSB of RX, RY, LT, and RT are not transmitted and always 0. 10728c2ecf20Sopenharmony_ci * 10738c2ecf20Sopenharmony_ci * With motionp enabled it changes slightly to this: 10748c2ecf20Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 10758c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10768c2ecf20Sopenharmony_ci * 1 | RX <5:4> | LX <5:1> | BDU | 10778c2ecf20Sopenharmony_ci * 2 | RX <3:2> | LY <5:1> | BDL | 10788c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------+-----+ 10798c2ecf20Sopenharmony_ci * 3 |RX<1>| LT <5:4> | RY <5:1> | 10808c2ecf20Sopenharmony_ci * -----+-----+-----------+-----------------------------+ 10818c2ecf20Sopenharmony_ci * 4 | LT <3:1> | RT <5:1> | 10828c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10838c2ecf20Sopenharmony_ci * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT | 10848c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10858c2ecf20Sopenharmony_ci * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 | 10868c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 10878c2ecf20Sopenharmony_ci * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest 10888c2ecf20Sopenharmony_ci * is the same as before. 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci static const s8 digital_to_analog[3] = {0x20, 0, -0x20}; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 10948c2ecf20Sopenharmony_ci if (wiimote_dpad_as_analog) { 10958c2ecf20Sopenharmony_ci lx = digital_to_analog[1 - !(ext[4] & 0x80) 10968c2ecf20Sopenharmony_ci + !(ext[1] & 0x01)]; 10978c2ecf20Sopenharmony_ci ly = digital_to_analog[1 - !(ext[4] & 0x40) 10988c2ecf20Sopenharmony_ci + !(ext[0] & 0x01)]; 10998c2ecf20Sopenharmony_ci } else { 11008c2ecf20Sopenharmony_ci lx = (ext[0] & 0x3e) - 0x20; 11018c2ecf20Sopenharmony_ci ly = (ext[1] & 0x3e) - 0x20; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } else { 11048c2ecf20Sopenharmony_ci if (wiimote_dpad_as_analog) { 11058c2ecf20Sopenharmony_ci lx = digital_to_analog[1 - !(ext[4] & 0x80) 11068c2ecf20Sopenharmony_ci + !(ext[5] & 0x02)]; 11078c2ecf20Sopenharmony_ci ly = digital_to_analog[1 - !(ext[4] & 0x40) 11088c2ecf20Sopenharmony_ci + !(ext[5] & 0x01)]; 11098c2ecf20Sopenharmony_ci } else { 11108c2ecf20Sopenharmony_ci lx = (ext[0] & 0x3f) - 0x20; 11118c2ecf20Sopenharmony_ci ly = (ext[1] & 0x3f) - 0x20; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci rx = (ext[0] >> 3) & 0x18; 11168c2ecf20Sopenharmony_ci rx |= (ext[1] >> 5) & 0x06; 11178c2ecf20Sopenharmony_ci rx |= (ext[2] >> 7) & 0x01; 11188c2ecf20Sopenharmony_ci ry = ext[2] & 0x1f; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci rt = ext[3] & 0x1f; 11218c2ecf20Sopenharmony_ci lt = (ext[2] >> 2) & 0x18; 11228c2ecf20Sopenharmony_ci lt |= (ext[3] >> 5) & 0x07; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci rx <<= 1; 11258c2ecf20Sopenharmony_ci ry <<= 1; 11268c2ecf20Sopenharmony_ci rt <<= 1; 11278c2ecf20Sopenharmony_ci lt <<= 1; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, lx); 11308c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1Y, ly); 11318c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20); 11328c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20); 11338c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT3X, rt); 11348c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT3Y, lt); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11378c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT], 11388c2ecf20Sopenharmony_ci !(ext[4] & 0x20)); 11398c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11408c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_MINUS], 11418c2ecf20Sopenharmony_ci !(ext[4] & 0x10)); 11428c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11438c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_HOME], 11448c2ecf20Sopenharmony_ci !(ext[4] & 0x08)); 11458c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11468c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_PLUS], 11478c2ecf20Sopenharmony_ci !(ext[4] & 0x04)); 11488c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11498c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_RT], 11508c2ecf20Sopenharmony_ci !(ext[4] & 0x02)); 11518c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11528c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZL], 11538c2ecf20Sopenharmony_ci !(ext[5] & 0x80)); 11548c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11558c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_B], 11568c2ecf20Sopenharmony_ci !(ext[5] & 0x40)); 11578c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11588c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_Y], 11598c2ecf20Sopenharmony_ci !(ext[5] & 0x20)); 11608c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11618c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_A], 11628c2ecf20Sopenharmony_ci !(ext[5] & 0x10)); 11638c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11648c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_X], 11658c2ecf20Sopenharmony_ci !(ext[5] & 0x08)); 11668c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11678c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR], 11688c2ecf20Sopenharmony_ci !(ext[5] & 0x04)); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (!wiimote_dpad_as_analog) { 11718c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11728c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT], 11738c2ecf20Sopenharmony_ci !(ext[4] & 0x80)); 11748c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11758c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN], 11768c2ecf20Sopenharmony_ci !(ext[4] & 0x40)); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 11798c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11808c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], 11818c2ecf20Sopenharmony_ci !(ext[1] & 0x01)); 11828c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11838c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], 11848c2ecf20Sopenharmony_ci !(ext[0] & 0x01)); 11858c2ecf20Sopenharmony_ci } else { 11868c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11878c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], 11888c2ecf20Sopenharmony_ci !(ext[5] & 0x02)); 11898c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 11908c2ecf20Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], 11918c2ecf20Sopenharmony_ci !(ext[5] & 0x01)); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int wiimod_classic_open(struct input_dev *dev) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 12018c2ecf20Sopenharmony_ci unsigned long flags; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 12048c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 12058c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 12068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return 0; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic void wiimod_classic_close(struct input_dev *dev) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 12148c2ecf20Sopenharmony_ci unsigned long flags; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 12178c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 12188c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 12198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic int wiimod_classic_probe(const struct wiimod_ops *ops, 12238c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci int ret, i; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 12288c2ecf20Sopenharmony_ci if (!wdata->extension.input) 12298c2ecf20Sopenharmony_ci return -ENOMEM; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 12328c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_classic_open; 12338c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_classic_close; 12348c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 12358c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 12368c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 12378c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 12388c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 12398c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Classic Controller"; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 12428c2ecf20Sopenharmony_ci for (i = 0; i < WIIMOD_CLASSIC_KEY_NUM; ++i) 12438c2ecf20Sopenharmony_ci set_bit(wiimod_classic_map[i], 12448c2ecf20Sopenharmony_ci wdata->extension.input->keybit); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 12478c2ecf20Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 12488c2ecf20Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->extension.input->absbit); 12498c2ecf20Sopenharmony_ci set_bit(ABS_HAT2X, wdata->extension.input->absbit); 12508c2ecf20Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->extension.input->absbit); 12518c2ecf20Sopenharmony_ci set_bit(ABS_HAT3X, wdata->extension.input->absbit); 12528c2ecf20Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->extension.input->absbit); 12538c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12548c2ecf20Sopenharmony_ci ABS_HAT1X, -30, 30, 1, 1); 12558c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12568c2ecf20Sopenharmony_ci ABS_HAT1Y, -30, 30, 1, 1); 12578c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12588c2ecf20Sopenharmony_ci ABS_HAT2X, -30, 30, 1, 1); 12598c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12608c2ecf20Sopenharmony_ci ABS_HAT2Y, -30, 30, 1, 1); 12618c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12628c2ecf20Sopenharmony_ci ABS_HAT3X, -30, 30, 1, 1); 12638c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 12648c2ecf20Sopenharmony_ci ABS_HAT3Y, -30, 30, 1, 1); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 12678c2ecf20Sopenharmony_ci if (ret) 12688c2ecf20Sopenharmony_ci goto err_free; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cierr_free: 12738c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 12748c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 12758c2ecf20Sopenharmony_ci return ret; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic void wiimod_classic_remove(const struct wiimod_ops *ops, 12798c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci if (!wdata->extension.input) 12828c2ecf20Sopenharmony_ci return; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 12858c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_classic = { 12898c2ecf20Sopenharmony_ci .flags = 0, 12908c2ecf20Sopenharmony_ci .arg = 0, 12918c2ecf20Sopenharmony_ci .probe = wiimod_classic_probe, 12928c2ecf20Sopenharmony_ci .remove = wiimod_classic_remove, 12938c2ecf20Sopenharmony_ci .in_ext = wiimod_classic_in_ext, 12948c2ecf20Sopenharmony_ci}; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci/* 12978c2ecf20Sopenharmony_ci * Balance Board Extension 12988c2ecf20Sopenharmony_ci * The Nintendo Wii Balance Board provides four hardware weight sensor plus a 12998c2ecf20Sopenharmony_ci * single push button. No other peripherals are available. However, the 13008c2ecf20Sopenharmony_ci * balance-board data is sent via a standard Wii Remote extension. All other 13018c2ecf20Sopenharmony_ci * data for non-present hardware is zeroed out. 13028c2ecf20Sopenharmony_ci * Some 3rd party devices react allergic if we try to access normal Wii Remote 13038c2ecf20Sopenharmony_ci * hardware, so this extension module should be the only module that is loaded 13048c2ecf20Sopenharmony_ci * on balance boards. 13058c2ecf20Sopenharmony_ci * The balance board needs 8 bytes extension data instead of basic 6 bytes so 13068c2ecf20Sopenharmony_ci * it needs the WIIMOD_FLAG_EXT8 flag. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic void wiimod_bboard_in_keys(struct wiimote_data *wdata, const __u8 *keys) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, BTN_A, 13128c2ecf20Sopenharmony_ci !!(keys[1] & 0x08)); 13138c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic void wiimod_bboard_in_ext(struct wiimote_data *wdata, 13178c2ecf20Sopenharmony_ci const __u8 *ext) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci __s32 val[4], tmp, div; 13208c2ecf20Sopenharmony_ci unsigned int i; 13218c2ecf20Sopenharmony_ci struct wiimote_state *s = &wdata->state; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* 13248c2ecf20Sopenharmony_ci * Balance board data layout: 13258c2ecf20Sopenharmony_ci * 13268c2ecf20Sopenharmony_ci * Byte | 8 7 6 5 4 3 2 1 | 13278c2ecf20Sopenharmony_ci * -----+--------------------------+ 13288c2ecf20Sopenharmony_ci * 1 | Top Right <15:8> | 13298c2ecf20Sopenharmony_ci * 2 | Top Right <7:0> | 13308c2ecf20Sopenharmony_ci * -----+--------------------------+ 13318c2ecf20Sopenharmony_ci * 3 | Bottom Right <15:8> | 13328c2ecf20Sopenharmony_ci * 4 | Bottom Right <7:0> | 13338c2ecf20Sopenharmony_ci * -----+--------------------------+ 13348c2ecf20Sopenharmony_ci * 5 | Top Left <15:8> | 13358c2ecf20Sopenharmony_ci * 6 | Top Left <7:0> | 13368c2ecf20Sopenharmony_ci * -----+--------------------------+ 13378c2ecf20Sopenharmony_ci * 7 | Bottom Left <15:8> | 13388c2ecf20Sopenharmony_ci * 8 | Bottom Left <7:0> | 13398c2ecf20Sopenharmony_ci * -----+--------------------------+ 13408c2ecf20Sopenharmony_ci * 13418c2ecf20Sopenharmony_ci * These values represent the weight-measurements of the Wii-balance 13428c2ecf20Sopenharmony_ci * board with 16bit precision. 13438c2ecf20Sopenharmony_ci * 13448c2ecf20Sopenharmony_ci * The balance-board is never reported interleaved with motionp. 13458c2ecf20Sopenharmony_ci */ 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci val[0] = ext[0]; 13488c2ecf20Sopenharmony_ci val[0] <<= 8; 13498c2ecf20Sopenharmony_ci val[0] |= ext[1]; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci val[1] = ext[2]; 13528c2ecf20Sopenharmony_ci val[1] <<= 8; 13538c2ecf20Sopenharmony_ci val[1] |= ext[3]; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci val[2] = ext[4]; 13568c2ecf20Sopenharmony_ci val[2] <<= 8; 13578c2ecf20Sopenharmony_ci val[2] |= ext[5]; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci val[3] = ext[6]; 13608c2ecf20Sopenharmony_ci val[3] <<= 8; 13618c2ecf20Sopenharmony_ci val[3] |= ext[7]; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* apply calibration data */ 13648c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 13658c2ecf20Sopenharmony_ci if (val[i] <= s->calib_bboard[i][0]) { 13668c2ecf20Sopenharmony_ci tmp = 0; 13678c2ecf20Sopenharmony_ci } else if (val[i] < s->calib_bboard[i][1]) { 13688c2ecf20Sopenharmony_ci tmp = val[i] - s->calib_bboard[i][0]; 13698c2ecf20Sopenharmony_ci tmp *= 1700; 13708c2ecf20Sopenharmony_ci div = s->calib_bboard[i][1] - s->calib_bboard[i][0]; 13718c2ecf20Sopenharmony_ci tmp /= div ? div : 1; 13728c2ecf20Sopenharmony_ci } else { 13738c2ecf20Sopenharmony_ci tmp = val[i] - s->calib_bboard[i][1]; 13748c2ecf20Sopenharmony_ci tmp *= 1700; 13758c2ecf20Sopenharmony_ci div = s->calib_bboard[i][2] - s->calib_bboard[i][1]; 13768c2ecf20Sopenharmony_ci tmp /= div ? div : 1; 13778c2ecf20Sopenharmony_ci tmp += 1700; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci val[i] = tmp; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, val[0]); 13838c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0Y, val[1]); 13848c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, val[2]); 13858c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1Y, val[3]); 13868c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int wiimod_bboard_open(struct input_dev *dev) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 13928c2ecf20Sopenharmony_ci unsigned long flags; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 13958c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 13968c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 13978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci return 0; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic void wiimod_bboard_close(struct input_dev *dev) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 14058c2ecf20Sopenharmony_ci unsigned long flags; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 14088c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 14098c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 14108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_cistatic ssize_t wiimod_bboard_calib_show(struct device *dev, 14148c2ecf20Sopenharmony_ci struct device_attribute *attr, 14158c2ecf20Sopenharmony_ci char *out) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 14188c2ecf20Sopenharmony_ci int i, j, ret; 14198c2ecf20Sopenharmony_ci __u16 val; 14208c2ecf20Sopenharmony_ci __u8 buf[24], offs; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 14238c2ecf20Sopenharmony_ci if (ret) 14248c2ecf20Sopenharmony_ci return ret; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12); 14278c2ecf20Sopenharmony_ci if (ret != 12) { 14288c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14298c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12); 14328c2ecf20Sopenharmony_ci if (ret != 12) { 14338c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14348c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 14408c2ecf20Sopenharmony_ci offs = 0; 14418c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) { 14428c2ecf20Sopenharmony_ci for (j = 0; j < 4; ++j) { 14438c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] = buf[offs]; 14448c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] <<= 8; 14458c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] |= buf[offs + 1]; 14468c2ecf20Sopenharmony_ci offs += 2; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci ret = 0; 14528c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) { 14538c2ecf20Sopenharmony_ci for (j = 0; j < 4; ++j) { 14548c2ecf20Sopenharmony_ci val = wdata->state.calib_bboard[j][i]; 14558c2ecf20Sopenharmony_ci if (i == 2 && j == 3) 14568c2ecf20Sopenharmony_ci ret += sprintf(&out[ret], "%04x\n", val); 14578c2ecf20Sopenharmony_ci else 14588c2ecf20Sopenharmony_ci ret += sprintf(&out[ret], "%04x:", val); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci return ret; 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic DEVICE_ATTR(bboard_calib, S_IRUGO, wiimod_bboard_calib_show, NULL); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic int wiimod_bboard_probe(const struct wiimod_ops *ops, 14688c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci int ret, i, j; 14718c2ecf20Sopenharmony_ci __u8 buf[24], offs; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci wiimote_cmd_acquire_noint(wdata); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12); 14768c2ecf20Sopenharmony_ci if (ret != 12) { 14778c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14788c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12); 14818c2ecf20Sopenharmony_ci if (ret != 12) { 14828c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14838c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EIO; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci wiimote_cmd_release(wdata); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci offs = 0; 14898c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) { 14908c2ecf20Sopenharmony_ci for (j = 0; j < 4; ++j) { 14918c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] = buf[offs]; 14928c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] <<= 8; 14938c2ecf20Sopenharmony_ci wdata->state.calib_bboard[j][i] |= buf[offs + 1]; 14948c2ecf20Sopenharmony_ci offs += 2; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 14998c2ecf20Sopenharmony_ci if (!wdata->extension.input) 15008c2ecf20Sopenharmony_ci return -ENOMEM; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci ret = device_create_file(&wdata->hdev->dev, 15038c2ecf20Sopenharmony_ci &dev_attr_bboard_calib); 15048c2ecf20Sopenharmony_ci if (ret) { 15058c2ecf20Sopenharmony_ci hid_err(wdata->hdev, "cannot create sysfs attribute\n"); 15068c2ecf20Sopenharmony_ci goto err_free; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 15108c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_bboard_open; 15118c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_bboard_close; 15128c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 15138c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 15148c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 15158c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 15168c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 15178c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Balance Board"; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 15208c2ecf20Sopenharmony_ci set_bit(BTN_A, wdata->extension.input->keybit); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 15238c2ecf20Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 15248c2ecf20Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 15258c2ecf20Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 15268c2ecf20Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->extension.input->absbit); 15278c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 15288c2ecf20Sopenharmony_ci ABS_HAT0X, 0, 65535, 2, 4); 15298c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 15308c2ecf20Sopenharmony_ci ABS_HAT0Y, 0, 65535, 2, 4); 15318c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 15328c2ecf20Sopenharmony_ci ABS_HAT1X, 0, 65535, 2, 4); 15338c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 15348c2ecf20Sopenharmony_ci ABS_HAT1Y, 0, 65535, 2, 4); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 15378c2ecf20Sopenharmony_ci if (ret) 15388c2ecf20Sopenharmony_ci goto err_file; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return 0; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cierr_file: 15438c2ecf20Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 15448c2ecf20Sopenharmony_ci &dev_attr_bboard_calib); 15458c2ecf20Sopenharmony_cierr_free: 15468c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 15478c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 15488c2ecf20Sopenharmony_ci return ret; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic void wiimod_bboard_remove(const struct wiimod_ops *ops, 15528c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci if (!wdata->extension.input) 15558c2ecf20Sopenharmony_ci return; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 15588c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 15598c2ecf20Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 15608c2ecf20Sopenharmony_ci &dev_attr_bboard_calib); 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_bboard = { 15648c2ecf20Sopenharmony_ci .flags = WIIMOD_FLAG_EXT8, 15658c2ecf20Sopenharmony_ci .arg = 0, 15668c2ecf20Sopenharmony_ci .probe = wiimod_bboard_probe, 15678c2ecf20Sopenharmony_ci .remove = wiimod_bboard_remove, 15688c2ecf20Sopenharmony_ci .in_keys = wiimod_bboard_in_keys, 15698c2ecf20Sopenharmony_ci .in_ext = wiimod_bboard_in_ext, 15708c2ecf20Sopenharmony_ci}; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci/* 15738c2ecf20Sopenharmony_ci * Pro Controller 15748c2ecf20Sopenharmony_ci * Released with the Wii U was the Nintendo Wii U Pro Controller. It does not 15758c2ecf20Sopenharmony_ci * work together with the classic Wii, but only with the new Wii U. However, it 15768c2ecf20Sopenharmony_ci * uses the same protocol and provides a builtin "classic controller pro" 15778c2ecf20Sopenharmony_ci * extension, few standard buttons, a rumble motor, 4 LEDs and a battery. 15788c2ecf20Sopenharmony_ci * We provide all these via a standard extension device as the device doesn't 15798c2ecf20Sopenharmony_ci * feature an extension port. 15808c2ecf20Sopenharmony_ci */ 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cienum wiimod_pro_keys { 15838c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_A, 15848c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_B, 15858c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_X, 15868c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_Y, 15878c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_PLUS, 15888c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_MINUS, 15898c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_HOME, 15908c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_LEFT, 15918c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_RIGHT, 15928c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_UP, 15938c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_DOWN, 15948c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_TL, 15958c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_TR, 15968c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_ZL, 15978c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_ZR, 15988c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_THUMBL, 15998c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_THUMBR, 16008c2ecf20Sopenharmony_ci WIIMOD_PRO_KEY_NUM, 16018c2ecf20Sopenharmony_ci}; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_cistatic const __u16 wiimod_pro_map[] = { 16048c2ecf20Sopenharmony_ci BTN_EAST, /* WIIMOD_PRO_KEY_A */ 16058c2ecf20Sopenharmony_ci BTN_SOUTH, /* WIIMOD_PRO_KEY_B */ 16068c2ecf20Sopenharmony_ci BTN_NORTH, /* WIIMOD_PRO_KEY_X */ 16078c2ecf20Sopenharmony_ci BTN_WEST, /* WIIMOD_PRO_KEY_Y */ 16088c2ecf20Sopenharmony_ci BTN_START, /* WIIMOD_PRO_KEY_PLUS */ 16098c2ecf20Sopenharmony_ci BTN_SELECT, /* WIIMOD_PRO_KEY_MINUS */ 16108c2ecf20Sopenharmony_ci BTN_MODE, /* WIIMOD_PRO_KEY_HOME */ 16118c2ecf20Sopenharmony_ci BTN_DPAD_LEFT, /* WIIMOD_PRO_KEY_LEFT */ 16128c2ecf20Sopenharmony_ci BTN_DPAD_RIGHT, /* WIIMOD_PRO_KEY_RIGHT */ 16138c2ecf20Sopenharmony_ci BTN_DPAD_UP, /* WIIMOD_PRO_KEY_UP */ 16148c2ecf20Sopenharmony_ci BTN_DPAD_DOWN, /* WIIMOD_PRO_KEY_DOWN */ 16158c2ecf20Sopenharmony_ci BTN_TL, /* WIIMOD_PRO_KEY_TL */ 16168c2ecf20Sopenharmony_ci BTN_TR, /* WIIMOD_PRO_KEY_TR */ 16178c2ecf20Sopenharmony_ci BTN_TL2, /* WIIMOD_PRO_KEY_ZL */ 16188c2ecf20Sopenharmony_ci BTN_TR2, /* WIIMOD_PRO_KEY_ZR */ 16198c2ecf20Sopenharmony_ci BTN_THUMBL, /* WIIMOD_PRO_KEY_THUMBL */ 16208c2ecf20Sopenharmony_ci BTN_THUMBR, /* WIIMOD_PRO_KEY_THUMBR */ 16218c2ecf20Sopenharmony_ci}; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci __s16 rx, ry, lx, ly; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 16288c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 16298c2ecf20Sopenharmony_ci * 1 | LX <7:0> | 16308c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16318c2ecf20Sopenharmony_ci * 2 | 0 0 0 0 | LX <11:8> | 16328c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16338c2ecf20Sopenharmony_ci * 3 | RX <7:0> | 16348c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16358c2ecf20Sopenharmony_ci * 4 | 0 0 0 0 | RX <11:8> | 16368c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16378c2ecf20Sopenharmony_ci * 5 | LY <7:0> | 16388c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16398c2ecf20Sopenharmony_ci * 6 | 0 0 0 0 | LY <11:8> | 16408c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16418c2ecf20Sopenharmony_ci * 7 | RY <7:0> | 16428c2ecf20Sopenharmony_ci * -----+-----------------------+-----------------------+ 16438c2ecf20Sopenharmony_ci * 8 | 0 0 0 0 | RY <11:8> | 16448c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 16458c2ecf20Sopenharmony_ci * 9 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | 16468c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 16478c2ecf20Sopenharmony_ci * 10 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | 16488c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 16498c2ecf20Sopenharmony_ci * 11 | 1 | BATTERY | USB |CHARG|LTHUM|RTHUM| 16508c2ecf20Sopenharmony_ci * -----+-----+-----------------+-----------+-----+-----+ 16518c2ecf20Sopenharmony_ci * All buttons are low-active (0 if pressed) 16528c2ecf20Sopenharmony_ci * RX and RY are right analog stick 16538c2ecf20Sopenharmony_ci * LX and LY are left analog stick 16548c2ecf20Sopenharmony_ci * BLT is left trigger, BRT is right trigger. 16558c2ecf20Sopenharmony_ci * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons 16568c2ecf20Sopenharmony_ci * BZL is left Z button and BZR is right Z button 16578c2ecf20Sopenharmony_ci * B-, BH, B+ are +, HOME and - buttons 16588c2ecf20Sopenharmony_ci * BB, BY, BA, BX are A, B, X, Y buttons 16598c2ecf20Sopenharmony_ci * 16608c2ecf20Sopenharmony_ci * Bits marked as 0/1 are unknown and never changed during tests. 16618c2ecf20Sopenharmony_ci * 16628c2ecf20Sopenharmony_ci * Not entirely verified: 16638c2ecf20Sopenharmony_ci * CHARG: 1 if uncharging, 0 if charging 16648c2ecf20Sopenharmony_ci * USB: 1 if not connected, 0 if connected 16658c2ecf20Sopenharmony_ci * BATTERY: battery capacity from 000 (empty) to 100 (full) 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci lx = (ext[0] & 0xff) | ((ext[1] & 0x0f) << 8); 16698c2ecf20Sopenharmony_ci rx = (ext[2] & 0xff) | ((ext[3] & 0x0f) << 8); 16708c2ecf20Sopenharmony_ci ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8); 16718c2ecf20Sopenharmony_ci ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* zero-point offsets */ 16748c2ecf20Sopenharmony_ci lx -= 0x800; 16758c2ecf20Sopenharmony_ci ly = 0x800 - ly; 16768c2ecf20Sopenharmony_ci rx -= 0x800; 16778c2ecf20Sopenharmony_ci ry = 0x800 - ry; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci /* Trivial automatic calibration. We don't know any calibration data 16808c2ecf20Sopenharmony_ci * in the EEPROM so we must use the first report to calibrate the 16818c2ecf20Sopenharmony_ci * null-position of the analog sticks. Users can retrigger calibration 16828c2ecf20Sopenharmony_ci * via sysfs, or set it explicitly. If data is off more than abs(500), 16838c2ecf20Sopenharmony_ci * we skip calibration as the sticks are likely to be moved already. */ 16848c2ecf20Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAG_PRO_CALIB_DONE)) { 16858c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; 16868c2ecf20Sopenharmony_ci if (abs(lx) < 500) 16878c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[0] = -lx; 16888c2ecf20Sopenharmony_ci if (abs(ly) < 500) 16898c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[1] = -ly; 16908c2ecf20Sopenharmony_ci if (abs(rx) < 500) 16918c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[2] = -rx; 16928c2ecf20Sopenharmony_ci if (abs(ry) < 500) 16938c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[3] = -ry; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci /* apply calibration data */ 16978c2ecf20Sopenharmony_ci lx += wdata->state.calib_pro_sticks[0]; 16988c2ecf20Sopenharmony_ci ly += wdata->state.calib_pro_sticks[1]; 16998c2ecf20Sopenharmony_ci rx += wdata->state.calib_pro_sticks[2]; 17008c2ecf20Sopenharmony_ci ry += wdata->state.calib_pro_sticks[3]; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, lx); 17038c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, ly); 17048c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RX, rx); 17058c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RY, ry); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17088c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT], 17098c2ecf20Sopenharmony_ci !(ext[8] & 0x80)); 17108c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17118c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_DOWN], 17128c2ecf20Sopenharmony_ci !(ext[8] & 0x40)); 17138c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17148c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_TL], 17158c2ecf20Sopenharmony_ci !(ext[8] & 0x20)); 17168c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17178c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_MINUS], 17188c2ecf20Sopenharmony_ci !(ext[8] & 0x10)); 17198c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17208c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_HOME], 17218c2ecf20Sopenharmony_ci !(ext[8] & 0x08)); 17228c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17238c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_PLUS], 17248c2ecf20Sopenharmony_ci !(ext[8] & 0x04)); 17258c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17268c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_TR], 17278c2ecf20Sopenharmony_ci !(ext[8] & 0x02)); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17308c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_ZL], 17318c2ecf20Sopenharmony_ci !(ext[9] & 0x80)); 17328c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17338c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_B], 17348c2ecf20Sopenharmony_ci !(ext[9] & 0x40)); 17358c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17368c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_Y], 17378c2ecf20Sopenharmony_ci !(ext[9] & 0x20)); 17388c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17398c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_A], 17408c2ecf20Sopenharmony_ci !(ext[9] & 0x10)); 17418c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17428c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_X], 17438c2ecf20Sopenharmony_ci !(ext[9] & 0x08)); 17448c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17458c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_ZR], 17468c2ecf20Sopenharmony_ci !(ext[9] & 0x04)); 17478c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17488c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_LEFT], 17498c2ecf20Sopenharmony_ci !(ext[9] & 0x02)); 17508c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17518c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_UP], 17528c2ecf20Sopenharmony_ci !(ext[9] & 0x01)); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17558c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_THUMBL], 17568c2ecf20Sopenharmony_ci !(ext[10] & 0x02)); 17578c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 17588c2ecf20Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_THUMBR], 17598c2ecf20Sopenharmony_ci !(ext[10] & 0x01)); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic int wiimod_pro_open(struct input_dev *dev) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 17678c2ecf20Sopenharmony_ci unsigned long flags; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 17708c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 17718c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 17728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci return 0; 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic void wiimod_pro_close(struct input_dev *dev) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 17808c2ecf20Sopenharmony_ci unsigned long flags; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 17838c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 17848c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 17858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 17868c2ecf20Sopenharmony_ci} 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic int wiimod_pro_play(struct input_dev *dev, void *data, 17898c2ecf20Sopenharmony_ci struct ff_effect *eff) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 17928c2ecf20Sopenharmony_ci __u8 value; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* 17958c2ecf20Sopenharmony_ci * The wiimote supports only a single rumble motor so if any magnitude 17968c2ecf20Sopenharmony_ci * is set to non-zero then we start the rumble motor. If both are set to 17978c2ecf20Sopenharmony_ci * zero, we stop the rumble motor. 17988c2ecf20Sopenharmony_ci */ 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude) 18018c2ecf20Sopenharmony_ci value = 1; 18028c2ecf20Sopenharmony_ci else 18038c2ecf20Sopenharmony_ci value = 0; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* Locking state.lock here might deadlock with input_event() calls. 18068c2ecf20Sopenharmony_ci * schedule_work acts as barrier. Merging multiple changes is fine. */ 18078c2ecf20Sopenharmony_ci wdata->state.cache_rumble = value; 18088c2ecf20Sopenharmony_ci schedule_work(&wdata->rumble_worker); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return 0; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic ssize_t wiimod_pro_calib_show(struct device *dev, 18148c2ecf20Sopenharmony_ci struct device_attribute *attr, 18158c2ecf20Sopenharmony_ci char *out) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 18188c2ecf20Sopenharmony_ci int r; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci r = 0; 18218c2ecf20Sopenharmony_ci r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[0]); 18228c2ecf20Sopenharmony_ci r += sprintf(&out[r], "%+06hd ", wdata->state.calib_pro_sticks[1]); 18238c2ecf20Sopenharmony_ci r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[2]); 18248c2ecf20Sopenharmony_ci r += sprintf(&out[r], "%+06hd\n", wdata->state.calib_pro_sticks[3]); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci return r; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic ssize_t wiimod_pro_calib_store(struct device *dev, 18308c2ecf20Sopenharmony_ci struct device_attribute *attr, 18318c2ecf20Sopenharmony_ci const char *buf, size_t count) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 18348c2ecf20Sopenharmony_ci int r; 18358c2ecf20Sopenharmony_ci s16 x1, y1, x2, y2; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (!strncmp(buf, "scan\n", 5)) { 18388c2ecf20Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 18398c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; 18408c2ecf20Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 18418c2ecf20Sopenharmony_ci } else { 18428c2ecf20Sopenharmony_ci r = sscanf(buf, "%hd:%hd %hd:%hd", &x1, &y1, &x2, &y2); 18438c2ecf20Sopenharmony_ci if (r != 4) 18448c2ecf20Sopenharmony_ci return -EINVAL; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 18478c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; 18488c2ecf20Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[0] = x1; 18518c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[1] = y1; 18528c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[2] = x2; 18538c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[3] = y2; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci return strnlen(buf, PAGE_SIZE); 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pro_calib, S_IRUGO|S_IWUSR|S_IWGRP, wiimod_pro_calib_show, 18608c2ecf20Sopenharmony_ci wiimod_pro_calib_store); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cistatic int wiimod_pro_probe(const struct wiimod_ops *ops, 18638c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci int ret, i; 18668c2ecf20Sopenharmony_ci unsigned long flags; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); 18698c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[0] = 0; 18708c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[1] = 0; 18718c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[2] = 0; 18728c2ecf20Sopenharmony_ci wdata->state.calib_pro_sticks[3] = 0; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 18758c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; 18768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 18798c2ecf20Sopenharmony_ci if (!wdata->extension.input) 18808c2ecf20Sopenharmony_ci return -ENOMEM; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci set_bit(FF_RUMBLE, wdata->extension.input->ffbit); 18838c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci if (input_ff_create_memless(wdata->extension.input, NULL, 18868c2ecf20Sopenharmony_ci wiimod_pro_play)) { 18878c2ecf20Sopenharmony_ci ret = -ENOMEM; 18888c2ecf20Sopenharmony_ci goto err_free; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ret = device_create_file(&wdata->hdev->dev, 18928c2ecf20Sopenharmony_ci &dev_attr_pro_calib); 18938c2ecf20Sopenharmony_ci if (ret) { 18948c2ecf20Sopenharmony_ci hid_err(wdata->hdev, "cannot create sysfs attribute\n"); 18958c2ecf20Sopenharmony_ci goto err_free; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_pro_open; 18998c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_pro_close; 19008c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 19018c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 19028c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 19038c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 19048c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 19058c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Pro Controller"; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 19088c2ecf20Sopenharmony_ci for (i = 0; i < WIIMOD_PRO_KEY_NUM; ++i) 19098c2ecf20Sopenharmony_ci set_bit(wiimod_pro_map[i], 19108c2ecf20Sopenharmony_ci wdata->extension.input->keybit); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 19138c2ecf20Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 19148c2ecf20Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 19158c2ecf20Sopenharmony_ci set_bit(ABS_RX, wdata->extension.input->absbit); 19168c2ecf20Sopenharmony_ci set_bit(ABS_RY, wdata->extension.input->absbit); 19178c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 19188c2ecf20Sopenharmony_ci ABS_X, -0x400, 0x400, 4, 100); 19198c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 19208c2ecf20Sopenharmony_ci ABS_Y, -0x400, 0x400, 4, 100); 19218c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 19228c2ecf20Sopenharmony_ci ABS_RX, -0x400, 0x400, 4, 100); 19238c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 19248c2ecf20Sopenharmony_ci ABS_RY, -0x400, 0x400, 4, 100); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 19278c2ecf20Sopenharmony_ci if (ret) 19288c2ecf20Sopenharmony_ci goto err_file; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci return 0; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cierr_file: 19338c2ecf20Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 19348c2ecf20Sopenharmony_ci &dev_attr_pro_calib); 19358c2ecf20Sopenharmony_cierr_free: 19368c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 19378c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 19388c2ecf20Sopenharmony_ci return ret; 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic void wiimod_pro_remove(const struct wiimod_ops *ops, 19428c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci unsigned long flags; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci if (!wdata->extension.input) 19478c2ecf20Sopenharmony_ci return; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 19508c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 19518c2ecf20Sopenharmony_ci cancel_work_sync(&wdata->rumble_worker); 19528c2ecf20Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 19538c2ecf20Sopenharmony_ci &dev_attr_pro_calib); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 19568c2ecf20Sopenharmony_ci wiiproto_req_rumble(wdata, 0); 19578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_pro = { 19618c2ecf20Sopenharmony_ci .flags = WIIMOD_FLAG_EXT16, 19628c2ecf20Sopenharmony_ci .arg = 0, 19638c2ecf20Sopenharmony_ci .probe = wiimod_pro_probe, 19648c2ecf20Sopenharmony_ci .remove = wiimod_pro_remove, 19658c2ecf20Sopenharmony_ci .in_ext = wiimod_pro_in_ext, 19668c2ecf20Sopenharmony_ci}; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci/* 19698c2ecf20Sopenharmony_ci * Drums 19708c2ecf20Sopenharmony_ci * Guitar-Hero, Rock-Band and other games came bundled with drums which can 19718c2ecf20Sopenharmony_ci * be plugged as extension to a Wiimote. Drum-reports are still not entirely 19728c2ecf20Sopenharmony_ci * figured out, but the most important information is known. 19738c2ecf20Sopenharmony_ci * We create a separate device for drums and report all information via this 19748c2ecf20Sopenharmony_ci * input device. 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_cistatic inline void wiimod_drums_report_pressure(struct wiimote_data *wdata, 19788c2ecf20Sopenharmony_ci __u8 none, __u8 which, 19798c2ecf20Sopenharmony_ci __u8 pressure, __u8 onoff, 19808c2ecf20Sopenharmony_ci __u8 *store, __u16 code, 19818c2ecf20Sopenharmony_ci __u8 which_code) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci static const __u8 default_pressure = 3; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci if (!none && which == which_code) { 19868c2ecf20Sopenharmony_ci *store = pressure; 19878c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, code, *store); 19888c2ecf20Sopenharmony_ci } else if (onoff != !!*store) { 19898c2ecf20Sopenharmony_ci *store = onoff ? default_pressure : 0; 19908c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, code, *store); 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_cistatic void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext) 19958c2ecf20Sopenharmony_ci{ 19968c2ecf20Sopenharmony_ci __u8 pressure, which, none, hhp, sx, sy; 19978c2ecf20Sopenharmony_ci __u8 o, r, y, g, b, bass, bm, bp; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 20008c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20018c2ecf20Sopenharmony_ci * 1 | 0 | 0 | SX <5:0> | 20028c2ecf20Sopenharmony_ci * 2 | 0 | 0 | SY <5:0> | 20038c2ecf20Sopenharmony_ci * -----+-----+-----+-----------------------------+-----+ 20048c2ecf20Sopenharmony_ci * 3 | HPP | NON | WHICH <5:1> | ? | 20058c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20068c2ecf20Sopenharmony_ci * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | 20078c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20088c2ecf20Sopenharmony_ci * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? | 20098c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20108c2ecf20Sopenharmony_ci * 6 | O | R | Y | G | B | BSS | 1 | 1 | 20118c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20128c2ecf20Sopenharmony_ci * All buttons are 0 if pressed 20138c2ecf20Sopenharmony_ci * 20148c2ecf20Sopenharmony_ci * With Motion+ enabled, the following bits will get invalid: 20158c2ecf20Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 20168c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20178c2ecf20Sopenharmony_ci * 1 | 0 | 0 | SX <5:1> |XXXXX| 20188c2ecf20Sopenharmony_ci * 2 | 0 | 0 | SY <5:1> |XXXXX| 20198c2ecf20Sopenharmony_ci * -----+-----+-----+-----------------------------+-----+ 20208c2ecf20Sopenharmony_ci * 3 | HPP | NON | WHICH <5:1> | ? | 20218c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20228c2ecf20Sopenharmony_ci * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | 20238c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20248c2ecf20Sopenharmony_ci * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX| 20258c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20268c2ecf20Sopenharmony_ci * 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX| 20278c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 20288c2ecf20Sopenharmony_ci */ 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci pressure = 7 - (ext[3] >> 5); 20318c2ecf20Sopenharmony_ci which = (ext[2] >> 1) & 0x1f; 20328c2ecf20Sopenharmony_ci none = !!(ext[2] & 0x40); 20338c2ecf20Sopenharmony_ci hhp = !(ext[2] & 0x80); 20348c2ecf20Sopenharmony_ci sx = ext[0] & 0x3f; 20358c2ecf20Sopenharmony_ci sy = ext[1] & 0x3f; 20368c2ecf20Sopenharmony_ci o = !(ext[5] & 0x80); 20378c2ecf20Sopenharmony_ci r = !(ext[5] & 0x40); 20388c2ecf20Sopenharmony_ci y = !(ext[5] & 0x20); 20398c2ecf20Sopenharmony_ci g = !(ext[5] & 0x10); 20408c2ecf20Sopenharmony_ci b = !(ext[5] & 0x08); 20418c2ecf20Sopenharmony_ci bass = !(ext[5] & 0x04); 20428c2ecf20Sopenharmony_ci bm = !(ext[4] & 0x10); 20438c2ecf20Sopenharmony_ci bp = !(ext[4] & 0x04); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 20468c2ecf20Sopenharmony_ci sx &= 0x3e; 20478c2ecf20Sopenharmony_ci sy &= 0x3e; 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 20518c2ecf20Sopenharmony_ci o, &wdata->state.pressure_drums[0], 20528c2ecf20Sopenharmony_ci ABS_HAT2Y, 0x0e); 20538c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 20548c2ecf20Sopenharmony_ci r, &wdata->state.pressure_drums[1], 20558c2ecf20Sopenharmony_ci ABS_HAT0X, 0x19); 20568c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 20578c2ecf20Sopenharmony_ci y, &wdata->state.pressure_drums[2], 20588c2ecf20Sopenharmony_ci ABS_HAT2X, 0x11); 20598c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 20608c2ecf20Sopenharmony_ci g, &wdata->state.pressure_drums[3], 20618c2ecf20Sopenharmony_ci ABS_HAT1X, 0x12); 20628c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 20638c2ecf20Sopenharmony_ci b, &wdata->state.pressure_drums[4], 20648c2ecf20Sopenharmony_ci ABS_HAT0Y, 0x0f); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci /* Bass shares pressure with hi-hat (set via hhp) */ 20678c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure, 20688c2ecf20Sopenharmony_ci bass, &wdata->state.pressure_drums[5], 20698c2ecf20Sopenharmony_ci ABS_HAT3X, 0x1b); 20708c2ecf20Sopenharmony_ci /* Hi-hat has no on/off values, just pressure. Force to off/0. */ 20718c2ecf20Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure, 20728c2ecf20Sopenharmony_ci 0, &wdata->state.pressure_drums[6], 20738c2ecf20Sopenharmony_ci ABS_HAT3Y, 0x0e); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); 20768c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, BTN_START, bp); 20798c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, BTN_SELECT, bm); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic int wiimod_drums_open(struct input_dev *dev) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 20878c2ecf20Sopenharmony_ci unsigned long flags; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 20908c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 20918c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 20928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci return 0; 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_cistatic void wiimod_drums_close(struct input_dev *dev) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 21008c2ecf20Sopenharmony_ci unsigned long flags; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 21038c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 21048c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 21058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 21068c2ecf20Sopenharmony_ci} 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_cistatic int wiimod_drums_probe(const struct wiimod_ops *ops, 21098c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 21108c2ecf20Sopenharmony_ci{ 21118c2ecf20Sopenharmony_ci int ret; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 21148c2ecf20Sopenharmony_ci if (!wdata->extension.input) 21158c2ecf20Sopenharmony_ci return -ENOMEM; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 21188c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_drums_open; 21198c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_drums_close; 21208c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 21218c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 21228c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 21238c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 21248c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 21258c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Drums"; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 21288c2ecf20Sopenharmony_ci set_bit(BTN_START, wdata->extension.input->keybit); 21298c2ecf20Sopenharmony_ci set_bit(BTN_SELECT, wdata->extension.input->keybit); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 21328c2ecf20Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 21338c2ecf20Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 21348c2ecf20Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 21358c2ecf20Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 21368c2ecf20Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 21378c2ecf20Sopenharmony_ci set_bit(ABS_HAT2X, wdata->extension.input->absbit); 21388c2ecf20Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->extension.input->absbit); 21398c2ecf20Sopenharmony_ci set_bit(ABS_HAT3X, wdata->extension.input->absbit); 21408c2ecf20Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->extension.input->absbit); 21418c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21428c2ecf20Sopenharmony_ci ABS_X, -32, 31, 1, 1); 21438c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21448c2ecf20Sopenharmony_ci ABS_Y, -32, 31, 1, 1); 21458c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21468c2ecf20Sopenharmony_ci ABS_HAT0X, 0, 7, 0, 0); 21478c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21488c2ecf20Sopenharmony_ci ABS_HAT0Y, 0, 7, 0, 0); 21498c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21508c2ecf20Sopenharmony_ci ABS_HAT1X, 0, 7, 0, 0); 21518c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21528c2ecf20Sopenharmony_ci ABS_HAT2X, 0, 7, 0, 0); 21538c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21548c2ecf20Sopenharmony_ci ABS_HAT2Y, 0, 7, 0, 0); 21558c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21568c2ecf20Sopenharmony_ci ABS_HAT3X, 0, 7, 0, 0); 21578c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 21588c2ecf20Sopenharmony_ci ABS_HAT3Y, 0, 7, 0, 0); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 21618c2ecf20Sopenharmony_ci if (ret) 21628c2ecf20Sopenharmony_ci goto err_free; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci return 0; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cierr_free: 21678c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 21688c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 21698c2ecf20Sopenharmony_ci return ret; 21708c2ecf20Sopenharmony_ci} 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_cistatic void wiimod_drums_remove(const struct wiimod_ops *ops, 21738c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 21748c2ecf20Sopenharmony_ci{ 21758c2ecf20Sopenharmony_ci if (!wdata->extension.input) 21768c2ecf20Sopenharmony_ci return; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 21798c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_drums = { 21838c2ecf20Sopenharmony_ci .flags = 0, 21848c2ecf20Sopenharmony_ci .arg = 0, 21858c2ecf20Sopenharmony_ci .probe = wiimod_drums_probe, 21868c2ecf20Sopenharmony_ci .remove = wiimod_drums_remove, 21878c2ecf20Sopenharmony_ci .in_ext = wiimod_drums_in_ext, 21888c2ecf20Sopenharmony_ci}; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci/* 21918c2ecf20Sopenharmony_ci * Guitar 21928c2ecf20Sopenharmony_ci * Guitar-Hero, Rock-Band and other games came bundled with guitars which can 21938c2ecf20Sopenharmony_ci * be plugged as extension to a Wiimote. 21948c2ecf20Sopenharmony_ci * We create a separate device for guitars and report all information via this 21958c2ecf20Sopenharmony_ci * input device. 21968c2ecf20Sopenharmony_ci */ 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_cienum wiimod_guitar_keys { 21998c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_G, 22008c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_R, 22018c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_Y, 22028c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_B, 22038c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_O, 22048c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_UP, 22058c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_DOWN, 22068c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_PLUS, 22078c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_MINUS, 22088c2ecf20Sopenharmony_ci WIIMOD_GUITAR_KEY_NUM, 22098c2ecf20Sopenharmony_ci}; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_cistatic const __u16 wiimod_guitar_map[] = { 22128c2ecf20Sopenharmony_ci BTN_1, /* WIIMOD_GUITAR_KEY_G */ 22138c2ecf20Sopenharmony_ci BTN_2, /* WIIMOD_GUITAR_KEY_R */ 22148c2ecf20Sopenharmony_ci BTN_3, /* WIIMOD_GUITAR_KEY_Y */ 22158c2ecf20Sopenharmony_ci BTN_4, /* WIIMOD_GUITAR_KEY_B */ 22168c2ecf20Sopenharmony_ci BTN_5, /* WIIMOD_GUITAR_KEY_O */ 22178c2ecf20Sopenharmony_ci BTN_DPAD_UP, /* WIIMOD_GUITAR_KEY_UP */ 22188c2ecf20Sopenharmony_ci BTN_DPAD_DOWN, /* WIIMOD_GUITAR_KEY_DOWN */ 22198c2ecf20Sopenharmony_ci BTN_START, /* WIIMOD_GUITAR_KEY_PLUS */ 22208c2ecf20Sopenharmony_ci BTN_SELECT, /* WIIMOD_GUITAR_KEY_MINUS */ 22218c2ecf20Sopenharmony_ci}; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 22288c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22298c2ecf20Sopenharmony_ci * 1 | 0 | 0 | SX <5:0> | 22308c2ecf20Sopenharmony_ci * 2 | 0 | 0 | SY <5:0> | 22318c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 22328c2ecf20Sopenharmony_ci * 3 | 0 | 0 | 0 | TB <4:0> | 22338c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 22348c2ecf20Sopenharmony_ci * 4 | 0 | 0 | 0 | WB <4:0> | 22358c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22368c2ecf20Sopenharmony_ci * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 | 22378c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22388c2ecf20Sopenharmony_ci * 6 | BO | BR | BB | BG | BY | 1 | 1 | BU | 22398c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22408c2ecf20Sopenharmony_ci * All buttons are 0 if pressed 22418c2ecf20Sopenharmony_ci * 22428c2ecf20Sopenharmony_ci * With Motion+ enabled, it will look like this: 22438c2ecf20Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 22448c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22458c2ecf20Sopenharmony_ci * 1 | 0 | 0 | SX <5:1> | BU | 22468c2ecf20Sopenharmony_ci * 2 | 0 | 0 | SY <5:1> | 1 | 22478c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------+-----+ 22488c2ecf20Sopenharmony_ci * 3 | 0 | 0 | 0 | TB <4:0> | 22498c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 22508c2ecf20Sopenharmony_ci * 4 | 0 | 0 | 0 | WB <4:0> | 22518c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22528c2ecf20Sopenharmony_ci * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX| 22538c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22548c2ecf20Sopenharmony_ci * 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX| 22558c2ecf20Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 22568c2ecf20Sopenharmony_ci */ 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci sx = ext[0] & 0x3f; 22598c2ecf20Sopenharmony_ci sy = ext[1] & 0x3f; 22608c2ecf20Sopenharmony_ci tb = ext[2] & 0x1f; 22618c2ecf20Sopenharmony_ci wb = ext[3] & 0x1f; 22628c2ecf20Sopenharmony_ci bd = !(ext[4] & 0x40); 22638c2ecf20Sopenharmony_ci bm = !(ext[4] & 0x10); 22648c2ecf20Sopenharmony_ci bp = !(ext[4] & 0x04); 22658c2ecf20Sopenharmony_ci bo = !(ext[5] & 0x80); 22668c2ecf20Sopenharmony_ci br = !(ext[5] & 0x40); 22678c2ecf20Sopenharmony_ci bb = !(ext[5] & 0x20); 22688c2ecf20Sopenharmony_ci bg = !(ext[5] & 0x10); 22698c2ecf20Sopenharmony_ci by = !(ext[5] & 0x08); 22708c2ecf20Sopenharmony_ci bu = !(ext[5] & 0x01); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 22738c2ecf20Sopenharmony_ci bu = !(ext[0] & 0x01); 22748c2ecf20Sopenharmony_ci sx &= 0x3e; 22758c2ecf20Sopenharmony_ci sy &= 0x3e; 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); 22798c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); 22808c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, tb); 22818c2ecf20Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, wb - 0x10); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22848c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], 22858c2ecf20Sopenharmony_ci bg); 22868c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22878c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], 22888c2ecf20Sopenharmony_ci br); 22898c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22908c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], 22918c2ecf20Sopenharmony_ci by); 22928c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22938c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], 22948c2ecf20Sopenharmony_ci bb); 22958c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22968c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], 22978c2ecf20Sopenharmony_ci bo); 22988c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 22998c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], 23008c2ecf20Sopenharmony_ci bu); 23018c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 23028c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], 23038c2ecf20Sopenharmony_ci bd); 23048c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 23058c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], 23068c2ecf20Sopenharmony_ci bp); 23078c2ecf20Sopenharmony_ci input_report_key(wdata->extension.input, 23088c2ecf20Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], 23098c2ecf20Sopenharmony_ci bm); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci input_sync(wdata->extension.input); 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_cistatic int wiimod_guitar_open(struct input_dev *dev) 23158c2ecf20Sopenharmony_ci{ 23168c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 23178c2ecf20Sopenharmony_ci unsigned long flags; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 23208c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 23218c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 23228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci return 0; 23258c2ecf20Sopenharmony_ci} 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_cistatic void wiimod_guitar_close(struct input_dev *dev) 23288c2ecf20Sopenharmony_ci{ 23298c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 23308c2ecf20Sopenharmony_ci unsigned long flags; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 23338c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 23348c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 23358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 23368c2ecf20Sopenharmony_ci} 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_cistatic int wiimod_guitar_probe(const struct wiimod_ops *ops, 23398c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci int ret, i; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci wdata->extension.input = input_allocate_device(); 23448c2ecf20Sopenharmony_ci if (!wdata->extension.input) 23458c2ecf20Sopenharmony_ci return -ENOMEM; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 23488c2ecf20Sopenharmony_ci wdata->extension.input->open = wiimod_guitar_open; 23498c2ecf20Sopenharmony_ci wdata->extension.input->close = wiimod_guitar_close; 23508c2ecf20Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 23518c2ecf20Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 23528c2ecf20Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 23538c2ecf20Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 23548c2ecf20Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 23558c2ecf20Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Guitar"; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 23588c2ecf20Sopenharmony_ci for (i = 0; i < WIIMOD_GUITAR_KEY_NUM; ++i) 23598c2ecf20Sopenharmony_ci set_bit(wiimod_guitar_map[i], 23608c2ecf20Sopenharmony_ci wdata->extension.input->keybit); 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 23638c2ecf20Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 23648c2ecf20Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 23658c2ecf20Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 23668c2ecf20Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 23678c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 23688c2ecf20Sopenharmony_ci ABS_X, -32, 31, 1, 1); 23698c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 23708c2ecf20Sopenharmony_ci ABS_Y, -32, 31, 1, 1); 23718c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 23728c2ecf20Sopenharmony_ci ABS_HAT0X, 0, 0x1f, 1, 1); 23738c2ecf20Sopenharmony_ci input_set_abs_params(wdata->extension.input, 23748c2ecf20Sopenharmony_ci ABS_HAT1X, 0, 0x0f, 1, 1); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci ret = input_register_device(wdata->extension.input); 23778c2ecf20Sopenharmony_ci if (ret) 23788c2ecf20Sopenharmony_ci goto err_free; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci return 0; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_cierr_free: 23838c2ecf20Sopenharmony_ci input_free_device(wdata->extension.input); 23848c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 23858c2ecf20Sopenharmony_ci return ret; 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_cistatic void wiimod_guitar_remove(const struct wiimod_ops *ops, 23898c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 23908c2ecf20Sopenharmony_ci{ 23918c2ecf20Sopenharmony_ci if (!wdata->extension.input) 23928c2ecf20Sopenharmony_ci return; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci input_unregister_device(wdata->extension.input); 23958c2ecf20Sopenharmony_ci wdata->extension.input = NULL; 23968c2ecf20Sopenharmony_ci} 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_guitar = { 23998c2ecf20Sopenharmony_ci .flags = 0, 24008c2ecf20Sopenharmony_ci .arg = 0, 24018c2ecf20Sopenharmony_ci .probe = wiimod_guitar_probe, 24028c2ecf20Sopenharmony_ci .remove = wiimod_guitar_remove, 24038c2ecf20Sopenharmony_ci .in_ext = wiimod_guitar_in_ext, 24048c2ecf20Sopenharmony_ci}; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci/* 24078c2ecf20Sopenharmony_ci * Builtin Motion Plus 24088c2ecf20Sopenharmony_ci * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which 24098c2ecf20Sopenharmony_ci * disables polling for Motion-Plus. This should be set only for devices which 24108c2ecf20Sopenharmony_ci * don't allow MP hotplugging. 24118c2ecf20Sopenharmony_ci */ 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_cistatic int wiimod_builtin_mp_probe(const struct wiimod_ops *ops, 24148c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 24158c2ecf20Sopenharmony_ci{ 24168c2ecf20Sopenharmony_ci unsigned long flags; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 24198c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP; 24208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci return 0; 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cistatic void wiimod_builtin_mp_remove(const struct wiimod_ops *ops, 24268c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 24278c2ecf20Sopenharmony_ci{ 24288c2ecf20Sopenharmony_ci unsigned long flags; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 24318c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP; 24328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_builtin_mp = { 24368c2ecf20Sopenharmony_ci .flags = 0, 24378c2ecf20Sopenharmony_ci .arg = 0, 24388c2ecf20Sopenharmony_ci .probe = wiimod_builtin_mp_probe, 24398c2ecf20Sopenharmony_ci .remove = wiimod_builtin_mp_remove, 24408c2ecf20Sopenharmony_ci}; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci/* 24438c2ecf20Sopenharmony_ci * No Motion Plus 24448c2ecf20Sopenharmony_ci * This module simply sets the WIIPROTO_FLAG_NO_MP protocol flag which 24458c2ecf20Sopenharmony_ci * disables motion-plus. This is needed for devices that advertise this but we 24468c2ecf20Sopenharmony_ci * don't know how to use it (or whether it is actually present). 24478c2ecf20Sopenharmony_ci */ 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistatic int wiimod_no_mp_probe(const struct wiimod_ops *ops, 24508c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 24518c2ecf20Sopenharmony_ci{ 24528c2ecf20Sopenharmony_ci unsigned long flags; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 24558c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_NO_MP; 24568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci return 0; 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_cistatic void wiimod_no_mp_remove(const struct wiimod_ops *ops, 24628c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 24638c2ecf20Sopenharmony_ci{ 24648c2ecf20Sopenharmony_ci unsigned long flags; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 24678c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_NO_MP; 24688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_no_mp = { 24728c2ecf20Sopenharmony_ci .flags = 0, 24738c2ecf20Sopenharmony_ci .arg = 0, 24748c2ecf20Sopenharmony_ci .probe = wiimod_no_mp_probe, 24758c2ecf20Sopenharmony_ci .remove = wiimod_no_mp_remove, 24768c2ecf20Sopenharmony_ci}; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci/* 24798c2ecf20Sopenharmony_ci * Motion Plus 24808c2ecf20Sopenharmony_ci * The Motion Plus extension provides rotation sensors (gyro) as a small 24818c2ecf20Sopenharmony_ci * extension device for Wii Remotes. Many devices have them built-in so 24828c2ecf20Sopenharmony_ci * you cannot see them from the outside. 24838c2ecf20Sopenharmony_ci * Motion Plus extensions are special because they are on a separate extension 24848c2ecf20Sopenharmony_ci * port and allow other extensions to be used simultaneously. This is all 24858c2ecf20Sopenharmony_ci * handled by the Wiimote Core so we don't have to deal with it. 24868c2ecf20Sopenharmony_ci */ 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_cistatic void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci __s32 x, y, z; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci /* | 8 7 6 5 4 3 | 2 | 1 | 24938c2ecf20Sopenharmony_ci * -----+------------------------------+-----+-----+ 24948c2ecf20Sopenharmony_ci * 1 | Yaw Speed <7:0> | 24958c2ecf20Sopenharmony_ci * 2 | Roll Speed <7:0> | 24968c2ecf20Sopenharmony_ci * 3 | Pitch Speed <7:0> | 24978c2ecf20Sopenharmony_ci * -----+------------------------------+-----+-----+ 24988c2ecf20Sopenharmony_ci * 4 | Yaw Speed <13:8> | Yaw |Pitch| 24998c2ecf20Sopenharmony_ci * -----+------------------------------+-----+-----+ 25008c2ecf20Sopenharmony_ci * 5 | Roll Speed <13:8> |Roll | Ext | 25018c2ecf20Sopenharmony_ci * -----+------------------------------+-----+-----+ 25028c2ecf20Sopenharmony_ci * 6 | Pitch Speed <13:8> | 1 | 0 | 25038c2ecf20Sopenharmony_ci * -----+------------------------------+-----+-----+ 25048c2ecf20Sopenharmony_ci * The single bits Yaw, Roll, Pitch in the lower right corner specify 25058c2ecf20Sopenharmony_ci * whether the wiimote is rotating fast (0) or slow (1). Speed for slow 25068c2ecf20Sopenharmony_ci * roation is 8192/440 units / deg/s and for fast rotation 8192/2000 25078c2ecf20Sopenharmony_ci * units / deg/s. To get a linear scale for fast rotation we multiply 25088c2ecf20Sopenharmony_ci * by 2000/440 = ~4.5454 and scale both fast and slow by 9 to match the 25098c2ecf20Sopenharmony_ci * previous scale reported by this driver. 25108c2ecf20Sopenharmony_ci * This leaves a linear scale with 8192*9/440 (~167.564) units / deg/s. 25118c2ecf20Sopenharmony_ci * If the wiimote is not rotating the sensor reports 2^13 = 8192. 25128c2ecf20Sopenharmony_ci * Ext specifies whether an extension is connected to the motionp. 25138c2ecf20Sopenharmony_ci * which is parsed by wiimote-core. 25148c2ecf20Sopenharmony_ci */ 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci x = ext[0]; 25178c2ecf20Sopenharmony_ci y = ext[1]; 25188c2ecf20Sopenharmony_ci z = ext[2]; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci x |= (((__u16)ext[3]) << 6) & 0xff00; 25218c2ecf20Sopenharmony_ci y |= (((__u16)ext[4]) << 6) & 0xff00; 25228c2ecf20Sopenharmony_ci z |= (((__u16)ext[5]) << 6) & 0xff00; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci x -= 8192; 25258c2ecf20Sopenharmony_ci y -= 8192; 25268c2ecf20Sopenharmony_ci z -= 8192; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (!(ext[3] & 0x02)) 25298c2ecf20Sopenharmony_ci x = (x * 2000 * 9) / 440; 25308c2ecf20Sopenharmony_ci else 25318c2ecf20Sopenharmony_ci x *= 9; 25328c2ecf20Sopenharmony_ci if (!(ext[4] & 0x02)) 25338c2ecf20Sopenharmony_ci y = (y * 2000 * 9) / 440; 25348c2ecf20Sopenharmony_ci else 25358c2ecf20Sopenharmony_ci y *= 9; 25368c2ecf20Sopenharmony_ci if (!(ext[3] & 0x01)) 25378c2ecf20Sopenharmony_ci z = (z * 2000 * 9) / 440; 25388c2ecf20Sopenharmony_ci else 25398c2ecf20Sopenharmony_ci z *= 9; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci input_report_abs(wdata->mp, ABS_RX, x); 25428c2ecf20Sopenharmony_ci input_report_abs(wdata->mp, ABS_RY, y); 25438c2ecf20Sopenharmony_ci input_report_abs(wdata->mp, ABS_RZ, z); 25448c2ecf20Sopenharmony_ci input_sync(wdata->mp); 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_cistatic int wiimod_mp_open(struct input_dev *dev) 25488c2ecf20Sopenharmony_ci{ 25498c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 25508c2ecf20Sopenharmony_ci unsigned long flags; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 25538c2ecf20Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_MP_USED; 25548c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 25558c2ecf20Sopenharmony_ci __wiimote_schedule(wdata); 25568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci return 0; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic void wiimod_mp_close(struct input_dev *dev) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 25648c2ecf20Sopenharmony_ci unsigned long flags; 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 25678c2ecf20Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_MP_USED; 25688c2ecf20Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 25698c2ecf20Sopenharmony_ci __wiimote_schedule(wdata); 25708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 25718c2ecf20Sopenharmony_ci} 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_cistatic int wiimod_mp_probe(const struct wiimod_ops *ops, 25748c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci int ret; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci wdata->mp = input_allocate_device(); 25798c2ecf20Sopenharmony_ci if (!wdata->mp) 25808c2ecf20Sopenharmony_ci return -ENOMEM; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci input_set_drvdata(wdata->mp, wdata); 25838c2ecf20Sopenharmony_ci wdata->mp->open = wiimod_mp_open; 25848c2ecf20Sopenharmony_ci wdata->mp->close = wiimod_mp_close; 25858c2ecf20Sopenharmony_ci wdata->mp->dev.parent = &wdata->hdev->dev; 25868c2ecf20Sopenharmony_ci wdata->mp->id.bustype = wdata->hdev->bus; 25878c2ecf20Sopenharmony_ci wdata->mp->id.vendor = wdata->hdev->vendor; 25888c2ecf20Sopenharmony_ci wdata->mp->id.product = wdata->hdev->product; 25898c2ecf20Sopenharmony_ci wdata->mp->id.version = wdata->hdev->version; 25908c2ecf20Sopenharmony_ci wdata->mp->name = WIIMOTE_NAME " Motion Plus"; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci set_bit(EV_ABS, wdata->mp->evbit); 25938c2ecf20Sopenharmony_ci set_bit(ABS_RX, wdata->mp->absbit); 25948c2ecf20Sopenharmony_ci set_bit(ABS_RY, wdata->mp->absbit); 25958c2ecf20Sopenharmony_ci set_bit(ABS_RZ, wdata->mp->absbit); 25968c2ecf20Sopenharmony_ci input_set_abs_params(wdata->mp, 25978c2ecf20Sopenharmony_ci ABS_RX, -16000, 16000, 4, 8); 25988c2ecf20Sopenharmony_ci input_set_abs_params(wdata->mp, 25998c2ecf20Sopenharmony_ci ABS_RY, -16000, 16000, 4, 8); 26008c2ecf20Sopenharmony_ci input_set_abs_params(wdata->mp, 26018c2ecf20Sopenharmony_ci ABS_RZ, -16000, 16000, 4, 8); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci ret = input_register_device(wdata->mp); 26048c2ecf20Sopenharmony_ci if (ret) 26058c2ecf20Sopenharmony_ci goto err_free; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci return 0; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_cierr_free: 26108c2ecf20Sopenharmony_ci input_free_device(wdata->mp); 26118c2ecf20Sopenharmony_ci wdata->mp = NULL; 26128c2ecf20Sopenharmony_ci return ret; 26138c2ecf20Sopenharmony_ci} 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_cistatic void wiimod_mp_remove(const struct wiimod_ops *ops, 26168c2ecf20Sopenharmony_ci struct wiimote_data *wdata) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci if (!wdata->mp) 26198c2ecf20Sopenharmony_ci return; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci input_unregister_device(wdata->mp); 26228c2ecf20Sopenharmony_ci wdata->mp = NULL; 26238c2ecf20Sopenharmony_ci} 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ciconst struct wiimod_ops wiimod_mp = { 26268c2ecf20Sopenharmony_ci .flags = 0, 26278c2ecf20Sopenharmony_ci .arg = 0, 26288c2ecf20Sopenharmony_ci .probe = wiimod_mp_probe, 26298c2ecf20Sopenharmony_ci .remove = wiimod_mp_remove, 26308c2ecf20Sopenharmony_ci .in_mp = wiimod_mp_in_mp, 26318c2ecf20Sopenharmony_ci}; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci/* module table */ 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic const struct wiimod_ops wiimod_dummy; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ciconst struct wiimod_ops *wiimod_table[WIIMOD_NUM] = { 26388c2ecf20Sopenharmony_ci [WIIMOD_KEYS] = &wiimod_keys, 26398c2ecf20Sopenharmony_ci [WIIMOD_RUMBLE] = &wiimod_rumble, 26408c2ecf20Sopenharmony_ci [WIIMOD_BATTERY] = &wiimod_battery, 26418c2ecf20Sopenharmony_ci [WIIMOD_LED1] = &wiimod_leds[0], 26428c2ecf20Sopenharmony_ci [WIIMOD_LED2] = &wiimod_leds[1], 26438c2ecf20Sopenharmony_ci [WIIMOD_LED3] = &wiimod_leds[2], 26448c2ecf20Sopenharmony_ci [WIIMOD_LED4] = &wiimod_leds[3], 26458c2ecf20Sopenharmony_ci [WIIMOD_ACCEL] = &wiimod_accel, 26468c2ecf20Sopenharmony_ci [WIIMOD_IR] = &wiimod_ir, 26478c2ecf20Sopenharmony_ci [WIIMOD_BUILTIN_MP] = &wiimod_builtin_mp, 26488c2ecf20Sopenharmony_ci [WIIMOD_NO_MP] = &wiimod_no_mp, 26498c2ecf20Sopenharmony_ci}; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ciconst struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { 26528c2ecf20Sopenharmony_ci [WIIMOTE_EXT_NONE] = &wiimod_dummy, 26538c2ecf20Sopenharmony_ci [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy, 26548c2ecf20Sopenharmony_ci [WIIMOTE_EXT_NUNCHUK] = &wiimod_nunchuk, 26558c2ecf20Sopenharmony_ci [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic, 26568c2ecf20Sopenharmony_ci [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, 26578c2ecf20Sopenharmony_ci [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro, 26588c2ecf20Sopenharmony_ci [WIIMOTE_EXT_DRUMS] = &wiimod_drums, 26598c2ecf20Sopenharmony_ci [WIIMOTE_EXT_GUITAR] = &wiimod_guitar, 26608c2ecf20Sopenharmony_ci}; 2661