162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device Modules for Nintendo Wii / Wii U HID Driver 462306a36Sopenharmony_ci * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * Wiimote Modules 1262306a36Sopenharmony_ci * Nintendo devices provide different peripherals and many new devices lack 1362306a36Sopenharmony_ci * initial features like the IR camera. Therefore, each peripheral device is 1462306a36Sopenharmony_ci * implemented as an independent module and we probe on each device only the 1562306a36Sopenharmony_ci * modules for the hardware that really is available. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Module registration is sequential. Unregistration is done in reverse order. 1862306a36Sopenharmony_ci * After device detection, the needed modules are loaded. Users can trigger 1962306a36Sopenharmony_ci * re-detection which causes all modules to be unloaded and then reload the 2062306a36Sopenharmony_ci * modules for the new detected device. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * wdata->input is a shared input device. It is always initialized prior to 2362306a36Sopenharmony_ci * module registration. If at least one registered module is marked as 2462306a36Sopenharmony_ci * WIIMOD_FLAG_INPUT, then the input device will get registered after all 2562306a36Sopenharmony_ci * modules were registered. 2662306a36Sopenharmony_ci * Please note that it is unregistered _before_ the "remove" callbacks are 2762306a36Sopenharmony_ci * called. This guarantees that no input interaction is done, anymore. However, 2862306a36Sopenharmony_ci * the wiimote core keeps a reference to the input device so it is freed only 2962306a36Sopenharmony_ci * after all modules were removed. It is safe to send events to unregistered 3062306a36Sopenharmony_ci * input devices. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/device.h> 3462306a36Sopenharmony_ci#include <linux/hid.h> 3562306a36Sopenharmony_ci#include <linux/input.h> 3662306a36Sopenharmony_ci#include <linux/spinlock.h> 3762306a36Sopenharmony_ci#include "hid-wiimote.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Keys 4162306a36Sopenharmony_ci * The initial Wii Remote provided a bunch of buttons that are reported as 4262306a36Sopenharmony_ci * part of the core protocol. Many later devices dropped these and report 4362306a36Sopenharmony_ci * invalid data in the core button reports. Load this only on devices which 4462306a36Sopenharmony_ci * correctly send button reports. 4562306a36Sopenharmony_ci * It uses the shared input device. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const __u16 wiimod_keys_map[] = { 4962306a36Sopenharmony_ci KEY_LEFT, /* WIIPROTO_KEY_LEFT */ 5062306a36Sopenharmony_ci KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ 5162306a36Sopenharmony_ci KEY_UP, /* WIIPROTO_KEY_UP */ 5262306a36Sopenharmony_ci KEY_DOWN, /* WIIPROTO_KEY_DOWN */ 5362306a36Sopenharmony_ci KEY_NEXT, /* WIIPROTO_KEY_PLUS */ 5462306a36Sopenharmony_ci KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ 5562306a36Sopenharmony_ci BTN_1, /* WIIPROTO_KEY_ONE */ 5662306a36Sopenharmony_ci BTN_2, /* WIIPROTO_KEY_TWO */ 5762306a36Sopenharmony_ci BTN_A, /* WIIPROTO_KEY_A */ 5862306a36Sopenharmony_ci BTN_B, /* WIIPROTO_KEY_B */ 5962306a36Sopenharmony_ci BTN_MODE, /* WIIPROTO_KEY_HOME */ 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT], 6562306a36Sopenharmony_ci !!(keys[0] & 0x01)); 6662306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT], 6762306a36Sopenharmony_ci !!(keys[0] & 0x02)); 6862306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN], 6962306a36Sopenharmony_ci !!(keys[0] & 0x04)); 7062306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP], 7162306a36Sopenharmony_ci !!(keys[0] & 0x08)); 7262306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS], 7362306a36Sopenharmony_ci !!(keys[0] & 0x10)); 7462306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO], 7562306a36Sopenharmony_ci !!(keys[1] & 0x01)); 7662306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE], 7762306a36Sopenharmony_ci !!(keys[1] & 0x02)); 7862306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B], 7962306a36Sopenharmony_ci !!(keys[1] & 0x04)); 8062306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A], 8162306a36Sopenharmony_ci !!(keys[1] & 0x08)); 8262306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS], 8362306a36Sopenharmony_ci !!(keys[1] & 0x10)); 8462306a36Sopenharmony_ci input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME], 8562306a36Sopenharmony_ci !!(keys[1] & 0x80)); 8662306a36Sopenharmony_ci input_sync(wdata->input); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int wiimod_keys_probe(const struct wiimod_ops *ops, 9062306a36Sopenharmony_ci struct wiimote_data *wdata) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci unsigned int i; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci set_bit(EV_KEY, wdata->input->evbit); 9562306a36Sopenharmony_ci for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) 9662306a36Sopenharmony_ci set_bit(wiimod_keys_map[i], wdata->input->keybit); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_keys = { 10262306a36Sopenharmony_ci .flags = WIIMOD_FLAG_INPUT, 10362306a36Sopenharmony_ci .arg = 0, 10462306a36Sopenharmony_ci .probe = wiimod_keys_probe, 10562306a36Sopenharmony_ci .remove = NULL, 10662306a36Sopenharmony_ci .in_keys = wiimod_keys_in_keys, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Rumble 11162306a36Sopenharmony_ci * Nearly all devices provide a rumble feature. A small motor for 11262306a36Sopenharmony_ci * force-feedback effects. We provide an FF_RUMBLE memless ff device on the 11362306a36Sopenharmony_ci * shared input device if this module is loaded. 11462306a36Sopenharmony_ci * The rumble motor is controlled via a flag on almost every output report so 11562306a36Sopenharmony_ci * the wiimote core handles the rumble flag. But if a device doesn't provide 11662306a36Sopenharmony_ci * the rumble motor, this flag shouldn't be set. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* used by wiimod_rumble and wiipro_rumble */ 12062306a36Sopenharmony_cistatic void wiimod_rumble_worker(struct work_struct *work) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct wiimote_data *wdata = container_of(work, struct wiimote_data, 12362306a36Sopenharmony_ci rumble_worker); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 12662306a36Sopenharmony_ci wiiproto_req_rumble(wdata, wdata->state.cache_rumble); 12762306a36Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int wiimod_rumble_play(struct input_dev *dev, void *data, 13162306a36Sopenharmony_ci struct ff_effect *eff) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 13462306a36Sopenharmony_ci __u8 value; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * The wiimote supports only a single rumble motor so if any magnitude 13862306a36Sopenharmony_ci * is set to non-zero then we start the rumble motor. If both are set to 13962306a36Sopenharmony_ci * zero, we stop the rumble motor. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude) 14362306a36Sopenharmony_ci value = 1; 14462306a36Sopenharmony_ci else 14562306a36Sopenharmony_ci value = 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Locking state.lock here might deadlock with input_event() calls. 14862306a36Sopenharmony_ci * schedule_work acts as barrier. Merging multiple changes is fine. */ 14962306a36Sopenharmony_ci wdata->state.cache_rumble = value; 15062306a36Sopenharmony_ci schedule_work(&wdata->rumble_worker); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int wiimod_rumble_probe(const struct wiimod_ops *ops, 15662306a36Sopenharmony_ci struct wiimote_data *wdata) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci set_bit(FF_RUMBLE, wdata->input->ffbit); 16162306a36Sopenharmony_ci if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play)) 16262306a36Sopenharmony_ci return -ENOMEM; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void wiimod_rumble_remove(const struct wiimod_ops *ops, 16862306a36Sopenharmony_ci struct wiimote_data *wdata) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci unsigned long flags; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci cancel_work_sync(&wdata->rumble_worker); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 17562306a36Sopenharmony_ci wiiproto_req_rumble(wdata, 0); 17662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_rumble = { 18062306a36Sopenharmony_ci .flags = WIIMOD_FLAG_INPUT, 18162306a36Sopenharmony_ci .arg = 0, 18262306a36Sopenharmony_ci .probe = wiimod_rumble_probe, 18362306a36Sopenharmony_ci .remove = wiimod_rumble_remove, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * Battery 18862306a36Sopenharmony_ci * 1 byte of battery capacity information is sent along every protocol status 18962306a36Sopenharmony_ci * report. The wiimote core caches it but we try to update it on every 19062306a36Sopenharmony_ci * user-space request. 19162306a36Sopenharmony_ci * This is supported by nearly every device so it's almost always enabled. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic enum power_supply_property wiimod_battery_props[] = { 19562306a36Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY, 19662306a36Sopenharmony_ci POWER_SUPPLY_PROP_SCOPE, 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int wiimod_battery_get_property(struct power_supply *psy, 20062306a36Sopenharmony_ci enum power_supply_property psp, 20162306a36Sopenharmony_ci union power_supply_propval *val) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct wiimote_data *wdata = power_supply_get_drvdata(psy); 20462306a36Sopenharmony_ci int ret = 0, state; 20562306a36Sopenharmony_ci unsigned long flags; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (psp == POWER_SUPPLY_PROP_SCOPE) { 20862306a36Sopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_DEVICE; 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci } else if (psp != POWER_SUPPLY_PROP_CAPACITY) { 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 21562306a36Sopenharmony_ci if (ret) 21662306a36Sopenharmony_ci return ret; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 21962306a36Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0); 22062306a36Sopenharmony_ci wiiproto_req_status(wdata); 22162306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci wiimote_cmd_wait(wdata); 22462306a36Sopenharmony_ci wiimote_cmd_release(wdata); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 22762306a36Sopenharmony_ci state = wdata->state.cmd_battery; 22862306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci val->intval = state * 100 / 255; 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int wiimod_battery_probe(const struct wiimod_ops *ops, 23562306a36Sopenharmony_ci struct wiimote_data *wdata) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct power_supply_config psy_cfg = { .drv_data = wdata, }; 23862306a36Sopenharmony_ci int ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci wdata->battery_desc.properties = wiimod_battery_props; 24162306a36Sopenharmony_ci wdata->battery_desc.num_properties = ARRAY_SIZE(wiimod_battery_props); 24262306a36Sopenharmony_ci wdata->battery_desc.get_property = wiimod_battery_get_property; 24362306a36Sopenharmony_ci wdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 24462306a36Sopenharmony_ci wdata->battery_desc.use_for_apm = 0; 24562306a36Sopenharmony_ci wdata->battery_desc.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s", 24662306a36Sopenharmony_ci wdata->hdev->uniq); 24762306a36Sopenharmony_ci if (!wdata->battery_desc.name) 24862306a36Sopenharmony_ci return -ENOMEM; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci wdata->battery = power_supply_register(&wdata->hdev->dev, 25162306a36Sopenharmony_ci &wdata->battery_desc, 25262306a36Sopenharmony_ci &psy_cfg); 25362306a36Sopenharmony_ci if (IS_ERR(wdata->battery)) { 25462306a36Sopenharmony_ci hid_err(wdata->hdev, "cannot register battery device\n"); 25562306a36Sopenharmony_ci ret = PTR_ERR(wdata->battery); 25662306a36Sopenharmony_ci goto err_free; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci power_supply_powers(wdata->battery, &wdata->hdev->dev); 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cierr_free: 26362306a36Sopenharmony_ci kfree(wdata->battery_desc.name); 26462306a36Sopenharmony_ci wdata->battery_desc.name = NULL; 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic void wiimod_battery_remove(const struct wiimod_ops *ops, 26962306a36Sopenharmony_ci struct wiimote_data *wdata) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci if (!wdata->battery_desc.name) 27262306a36Sopenharmony_ci return; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci power_supply_unregister(wdata->battery); 27562306a36Sopenharmony_ci kfree(wdata->battery_desc.name); 27662306a36Sopenharmony_ci wdata->battery_desc.name = NULL; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_battery = { 28062306a36Sopenharmony_ci .flags = 0, 28162306a36Sopenharmony_ci .arg = 0, 28262306a36Sopenharmony_ci .probe = wiimod_battery_probe, 28362306a36Sopenharmony_ci .remove = wiimod_battery_remove, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* 28762306a36Sopenharmony_ci * LED 28862306a36Sopenharmony_ci * 0 to 4 player LEDs are supported by devices. The "arg" field of the 28962306a36Sopenharmony_ci * wiimod_ops structure specifies which LED this module controls. This allows 29062306a36Sopenharmony_ci * to register a limited number of LEDs. 29162306a36Sopenharmony_ci * State is managed by wiimote core. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic enum led_brightness wiimod_led_get(struct led_classdev *led_dev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct device *dev = led_dev->dev->parent; 29762306a36Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 29862306a36Sopenharmony_ci int i; 29962306a36Sopenharmony_ci unsigned long flags; 30062306a36Sopenharmony_ci bool value = false; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci for (i = 0; i < 4; ++i) { 30362306a36Sopenharmony_ci if (wdata->leds[i] == led_dev) { 30462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 30562306a36Sopenharmony_ci value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1); 30662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return value ? LED_FULL : LED_OFF; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void wiimod_led_set(struct led_classdev *led_dev, 31562306a36Sopenharmony_ci enum led_brightness value) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct device *dev = led_dev->dev->parent; 31862306a36Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 31962306a36Sopenharmony_ci int i; 32062306a36Sopenharmony_ci unsigned long flags; 32162306a36Sopenharmony_ci __u8 state, flag; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci for (i = 0; i < 4; ++i) { 32462306a36Sopenharmony_ci if (wdata->leds[i] == led_dev) { 32562306a36Sopenharmony_ci flag = WIIPROTO_FLAG_LED(i + 1); 32662306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 32762306a36Sopenharmony_ci state = wdata->state.flags; 32862306a36Sopenharmony_ci if (value == LED_OFF) 32962306a36Sopenharmony_ci wiiproto_req_leds(wdata, state & ~flag); 33062306a36Sopenharmony_ci else 33162306a36Sopenharmony_ci wiiproto_req_leds(wdata, state | flag); 33262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int wiimod_led_probe(const struct wiimod_ops *ops, 33962306a36Sopenharmony_ci struct wiimote_data *wdata) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct device *dev = &wdata->hdev->dev; 34262306a36Sopenharmony_ci size_t namesz = strlen(dev_name(dev)) + 9; 34362306a36Sopenharmony_ci struct led_classdev *led; 34462306a36Sopenharmony_ci unsigned long flags; 34562306a36Sopenharmony_ci char *name; 34662306a36Sopenharmony_ci int ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); 34962306a36Sopenharmony_ci if (!led) 35062306a36Sopenharmony_ci return -ENOMEM; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci name = (void*)&led[1]; 35362306a36Sopenharmony_ci snprintf(name, namesz, "%s:blue:p%lu", dev_name(dev), ops->arg); 35462306a36Sopenharmony_ci led->name = name; 35562306a36Sopenharmony_ci led->brightness = 0; 35662306a36Sopenharmony_ci led->max_brightness = 1; 35762306a36Sopenharmony_ci led->brightness_get = wiimod_led_get; 35862306a36Sopenharmony_ci led->brightness_set = wiimod_led_set; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci wdata->leds[ops->arg] = led; 36162306a36Sopenharmony_ci ret = led_classdev_register(dev, led); 36262306a36Sopenharmony_ci if (ret) 36362306a36Sopenharmony_ci goto err_free; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* enable LED1 to stop initial LED-blinking */ 36662306a36Sopenharmony_ci if (ops->arg == 0) { 36762306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 36862306a36Sopenharmony_ci wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); 36962306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cierr_free: 37562306a36Sopenharmony_ci wdata->leds[ops->arg] = NULL; 37662306a36Sopenharmony_ci kfree(led); 37762306a36Sopenharmony_ci return ret; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void wiimod_led_remove(const struct wiimod_ops *ops, 38162306a36Sopenharmony_ci struct wiimote_data *wdata) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci if (!wdata->leds[ops->arg]) 38462306a36Sopenharmony_ci return; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci led_classdev_unregister(wdata->leds[ops->arg]); 38762306a36Sopenharmony_ci kfree(wdata->leds[ops->arg]); 38862306a36Sopenharmony_ci wdata->leds[ops->arg] = NULL; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_leds[4] = { 39262306a36Sopenharmony_ci { 39362306a36Sopenharmony_ci .flags = 0, 39462306a36Sopenharmony_ci .arg = 0, 39562306a36Sopenharmony_ci .probe = wiimod_led_probe, 39662306a36Sopenharmony_ci .remove = wiimod_led_remove, 39762306a36Sopenharmony_ci }, 39862306a36Sopenharmony_ci { 39962306a36Sopenharmony_ci .flags = 0, 40062306a36Sopenharmony_ci .arg = 1, 40162306a36Sopenharmony_ci .probe = wiimod_led_probe, 40262306a36Sopenharmony_ci .remove = wiimod_led_remove, 40362306a36Sopenharmony_ci }, 40462306a36Sopenharmony_ci { 40562306a36Sopenharmony_ci .flags = 0, 40662306a36Sopenharmony_ci .arg = 2, 40762306a36Sopenharmony_ci .probe = wiimod_led_probe, 40862306a36Sopenharmony_ci .remove = wiimod_led_remove, 40962306a36Sopenharmony_ci }, 41062306a36Sopenharmony_ci { 41162306a36Sopenharmony_ci .flags = 0, 41262306a36Sopenharmony_ci .arg = 3, 41362306a36Sopenharmony_ci .probe = wiimod_led_probe, 41462306a36Sopenharmony_ci .remove = wiimod_led_remove, 41562306a36Sopenharmony_ci }, 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* 41962306a36Sopenharmony_ci * Accelerometer 42062306a36Sopenharmony_ci * 3 axis accelerometer data is part of nearly all DRMs. If not supported by a 42162306a36Sopenharmony_ci * device, it's mostly cleared to 0. This module parses this data and provides 42262306a36Sopenharmony_ci * it via a separate input device. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic void wiimod_accel_in_accel(struct wiimote_data *wdata, 42662306a36Sopenharmony_ci const __u8 *accel) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci __u16 x, y, z; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL)) 43162306a36Sopenharmony_ci return; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * payload is: BB BB XX YY ZZ 43562306a36Sopenharmony_ci * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ 43662306a36Sopenharmony_ci * contain the upper 8 bits of each value. The lower 2 bits are 43762306a36Sopenharmony_ci * contained in the buttons data BB BB. 43862306a36Sopenharmony_ci * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the 43962306a36Sopenharmony_ci * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y 44062306a36Sopenharmony_ci * accel value and bit 6 is the second bit of the Z value. 44162306a36Sopenharmony_ci * The first bit of Y and Z values is not available and always set to 0. 44262306a36Sopenharmony_ci * 0x200 is returned on no movement. 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci x = accel[2] << 2; 44662306a36Sopenharmony_ci y = accel[3] << 2; 44762306a36Sopenharmony_ci z = accel[4] << 2; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci x |= (accel[0] >> 5) & 0x3; 45062306a36Sopenharmony_ci y |= (accel[1] >> 4) & 0x2; 45162306a36Sopenharmony_ci z |= (accel[1] >> 5) & 0x2; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci input_report_abs(wdata->accel, ABS_RX, x - 0x200); 45462306a36Sopenharmony_ci input_report_abs(wdata->accel, ABS_RY, y - 0x200); 45562306a36Sopenharmony_ci input_report_abs(wdata->accel, ABS_RZ, z - 0x200); 45662306a36Sopenharmony_ci input_sync(wdata->accel); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int wiimod_accel_open(struct input_dev *dev) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 46262306a36Sopenharmony_ci unsigned long flags; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 46562306a36Sopenharmony_ci wiiproto_req_accel(wdata, true); 46662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void wiimod_accel_close(struct input_dev *dev) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 47462306a36Sopenharmony_ci unsigned long flags; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 47762306a36Sopenharmony_ci wiiproto_req_accel(wdata, false); 47862306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int wiimod_accel_probe(const struct wiimod_ops *ops, 48262306a36Sopenharmony_ci struct wiimote_data *wdata) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci int ret; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci wdata->accel = input_allocate_device(); 48762306a36Sopenharmony_ci if (!wdata->accel) 48862306a36Sopenharmony_ci return -ENOMEM; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci input_set_drvdata(wdata->accel, wdata); 49162306a36Sopenharmony_ci wdata->accel->open = wiimod_accel_open; 49262306a36Sopenharmony_ci wdata->accel->close = wiimod_accel_close; 49362306a36Sopenharmony_ci wdata->accel->dev.parent = &wdata->hdev->dev; 49462306a36Sopenharmony_ci wdata->accel->id.bustype = wdata->hdev->bus; 49562306a36Sopenharmony_ci wdata->accel->id.vendor = wdata->hdev->vendor; 49662306a36Sopenharmony_ci wdata->accel->id.product = wdata->hdev->product; 49762306a36Sopenharmony_ci wdata->accel->id.version = wdata->hdev->version; 49862306a36Sopenharmony_ci wdata->accel->name = WIIMOTE_NAME " Accelerometer"; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci set_bit(EV_ABS, wdata->accel->evbit); 50162306a36Sopenharmony_ci set_bit(ABS_RX, wdata->accel->absbit); 50262306a36Sopenharmony_ci set_bit(ABS_RY, wdata->accel->absbit); 50362306a36Sopenharmony_ci set_bit(ABS_RZ, wdata->accel->absbit); 50462306a36Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4); 50562306a36Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4); 50662306a36Sopenharmony_ci input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ret = input_register_device(wdata->accel); 50962306a36Sopenharmony_ci if (ret) { 51062306a36Sopenharmony_ci hid_err(wdata->hdev, "cannot register input device\n"); 51162306a36Sopenharmony_ci goto err_free; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return 0; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cierr_free: 51762306a36Sopenharmony_ci input_free_device(wdata->accel); 51862306a36Sopenharmony_ci wdata->accel = NULL; 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void wiimod_accel_remove(const struct wiimod_ops *ops, 52362306a36Sopenharmony_ci struct wiimote_data *wdata) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci if (!wdata->accel) 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci input_unregister_device(wdata->accel); 52962306a36Sopenharmony_ci wdata->accel = NULL; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_accel = { 53362306a36Sopenharmony_ci .flags = 0, 53462306a36Sopenharmony_ci .arg = 0, 53562306a36Sopenharmony_ci .probe = wiimod_accel_probe, 53662306a36Sopenharmony_ci .remove = wiimod_accel_remove, 53762306a36Sopenharmony_ci .in_accel = wiimod_accel_in_accel, 53862306a36Sopenharmony_ci}; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* 54162306a36Sopenharmony_ci * IR Cam 54262306a36Sopenharmony_ci * Up to 4 IR sources can be tracked by a normal Wii Remote. The IR cam needs 54362306a36Sopenharmony_ci * to be initialized with a fairly complex procedure and consumes a lot of 54462306a36Sopenharmony_ci * power. Therefore, as long as no application uses the IR input device, it is 54562306a36Sopenharmony_ci * kept offline. 54662306a36Sopenharmony_ci * Nearly no other device than the normal Wii Remotes supports the IR cam so 54762306a36Sopenharmony_ci * you can disable this module for these devices. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void wiimod_ir_in_ir(struct wiimote_data *wdata, const __u8 *ir, 55162306a36Sopenharmony_ci bool packed, unsigned int id) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci __u16 x, y; 55462306a36Sopenharmony_ci __u8 xid, yid; 55562306a36Sopenharmony_ci bool sync = false; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAGS_IR)) 55862306a36Sopenharmony_ci return; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci switch (id) { 56162306a36Sopenharmony_ci case 0: 56262306a36Sopenharmony_ci xid = ABS_HAT0X; 56362306a36Sopenharmony_ci yid = ABS_HAT0Y; 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci case 1: 56662306a36Sopenharmony_ci xid = ABS_HAT1X; 56762306a36Sopenharmony_ci yid = ABS_HAT1Y; 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci case 2: 57062306a36Sopenharmony_ci xid = ABS_HAT2X; 57162306a36Sopenharmony_ci yid = ABS_HAT2Y; 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci case 3: 57462306a36Sopenharmony_ci xid = ABS_HAT3X; 57562306a36Sopenharmony_ci yid = ABS_HAT3Y; 57662306a36Sopenharmony_ci sync = true; 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci default: 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* 58362306a36Sopenharmony_ci * Basic IR data is encoded into 3 bytes. The first two bytes are the 58462306a36Sopenharmony_ci * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits 58562306a36Sopenharmony_ci * of both. 58662306a36Sopenharmony_ci * If data is packed, then the 3rd byte is put first and slightly 58762306a36Sopenharmony_ci * reordered. This allows to interleave packed and non-packed data to 58862306a36Sopenharmony_ci * have two IR sets in 5 bytes instead of 6. 58962306a36Sopenharmony_ci * The resulting 10bit X/Y values are passed to the ABS_HAT? input dev. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (packed) { 59362306a36Sopenharmony_ci x = ir[1] | ((ir[0] & 0x03) << 8); 59462306a36Sopenharmony_ci y = ir[2] | ((ir[0] & 0x0c) << 6); 59562306a36Sopenharmony_ci } else { 59662306a36Sopenharmony_ci x = ir[0] | ((ir[2] & 0x30) << 4); 59762306a36Sopenharmony_ci y = ir[1] | ((ir[2] & 0xc0) << 2); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci input_report_abs(wdata->ir, xid, x); 60162306a36Sopenharmony_ci input_report_abs(wdata->ir, yid, y); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (sync) 60462306a36Sopenharmony_ci input_sync(wdata->ir); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int wiimod_ir_change(struct wiimote_data *wdata, __u16 mode) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci unsigned long flags; 61162306a36Sopenharmony_ci __u8 format = 0; 61262306a36Sopenharmony_ci static const __u8 data_enable[] = { 0x01 }; 61362306a36Sopenharmony_ci static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01, 61462306a36Sopenharmony_ci 0x00, 0xaa, 0x00, 0x64 }; 61562306a36Sopenharmony_ci static const __u8 data_sens2[] = { 0x63, 0x03 }; 61662306a36Sopenharmony_ci static const __u8 data_fin[] = { 0x08 }; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) { 62162306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (mode == 0) { 62662306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAGS_IR; 62762306a36Sopenharmony_ci wiiproto_req_ir1(wdata, 0); 62862306a36Sopenharmony_ci wiiproto_req_ir2(wdata, 0); 62962306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 63062306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* send PIXEL CLOCK ENABLE cmd first */ 64162306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 64262306a36Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0); 64362306a36Sopenharmony_ci wiiproto_req_ir1(wdata, 0x06); 64462306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci ret = wiimote_cmd_wait(wdata); 64762306a36Sopenharmony_ci if (ret) 64862306a36Sopenharmony_ci goto unlock; 64962306a36Sopenharmony_ci if (wdata->state.cmd_err) { 65062306a36Sopenharmony_ci ret = -EIO; 65162306a36Sopenharmony_ci goto unlock; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* enable IR LOGIC */ 65562306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 65662306a36Sopenharmony_ci wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0); 65762306a36Sopenharmony_ci wiiproto_req_ir2(wdata, 0x06); 65862306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci ret = wiimote_cmd_wait(wdata); 66162306a36Sopenharmony_ci if (ret) 66262306a36Sopenharmony_ci goto unlock; 66362306a36Sopenharmony_ci if (wdata->state.cmd_err) { 66462306a36Sopenharmony_ci ret = -EIO; 66562306a36Sopenharmony_ci goto unlock; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* enable IR cam but do not make it send data, yet */ 66962306a36Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00030, data_enable, 67062306a36Sopenharmony_ci sizeof(data_enable)); 67162306a36Sopenharmony_ci if (ret) 67262306a36Sopenharmony_ci goto unlock; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* write first sensitivity block */ 67562306a36Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1, 67662306a36Sopenharmony_ci sizeof(data_sens1)); 67762306a36Sopenharmony_ci if (ret) 67862306a36Sopenharmony_ci goto unlock; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* write second sensitivity block */ 68162306a36Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2, 68262306a36Sopenharmony_ci sizeof(data_sens2)); 68362306a36Sopenharmony_ci if (ret) 68462306a36Sopenharmony_ci goto unlock; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* put IR cam into desired state */ 68762306a36Sopenharmony_ci switch (mode) { 68862306a36Sopenharmony_ci case WIIPROTO_FLAG_IR_FULL: 68962306a36Sopenharmony_ci format = 5; 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case WIIPROTO_FLAG_IR_EXT: 69262306a36Sopenharmony_ci format = 3; 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case WIIPROTO_FLAG_IR_BASIC: 69562306a36Sopenharmony_ci format = 1; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format)); 69962306a36Sopenharmony_ci if (ret) 70062306a36Sopenharmony_ci goto unlock; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* make IR cam send data */ 70362306a36Sopenharmony_ci ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin)); 70462306a36Sopenharmony_ci if (ret) 70562306a36Sopenharmony_ci goto unlock; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* request new DRM mode compatible to IR mode */ 70862306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 70962306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAGS_IR; 71062306a36Sopenharmony_ci wdata->state.flags |= mode & WIIPROTO_FLAGS_IR; 71162306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 71262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ciunlock: 71562306a36Sopenharmony_ci wiimote_cmd_release(wdata); 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic int wiimod_ir_open(struct input_dev *dev) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return wiimod_ir_change(wdata, WIIPROTO_FLAG_IR_BASIC); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void wiimod_ir_close(struct input_dev *dev) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci wiimod_ir_change(wdata, 0); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int wiimod_ir_probe(const struct wiimod_ops *ops, 73462306a36Sopenharmony_ci struct wiimote_data *wdata) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci int ret; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci wdata->ir = input_allocate_device(); 73962306a36Sopenharmony_ci if (!wdata->ir) 74062306a36Sopenharmony_ci return -ENOMEM; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci input_set_drvdata(wdata->ir, wdata); 74362306a36Sopenharmony_ci wdata->ir->open = wiimod_ir_open; 74462306a36Sopenharmony_ci wdata->ir->close = wiimod_ir_close; 74562306a36Sopenharmony_ci wdata->ir->dev.parent = &wdata->hdev->dev; 74662306a36Sopenharmony_ci wdata->ir->id.bustype = wdata->hdev->bus; 74762306a36Sopenharmony_ci wdata->ir->id.vendor = wdata->hdev->vendor; 74862306a36Sopenharmony_ci wdata->ir->id.product = wdata->hdev->product; 74962306a36Sopenharmony_ci wdata->ir->id.version = wdata->hdev->version; 75062306a36Sopenharmony_ci wdata->ir->name = WIIMOTE_NAME " IR"; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci set_bit(EV_ABS, wdata->ir->evbit); 75362306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->ir->absbit); 75462306a36Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->ir->absbit); 75562306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->ir->absbit); 75662306a36Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->ir->absbit); 75762306a36Sopenharmony_ci set_bit(ABS_HAT2X, wdata->ir->absbit); 75862306a36Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->ir->absbit); 75962306a36Sopenharmony_ci set_bit(ABS_HAT3X, wdata->ir->absbit); 76062306a36Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->ir->absbit); 76162306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4); 76262306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4); 76362306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4); 76462306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4); 76562306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4); 76662306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4); 76762306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4); 76862306a36Sopenharmony_ci input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = input_register_device(wdata->ir); 77162306a36Sopenharmony_ci if (ret) { 77262306a36Sopenharmony_ci hid_err(wdata->hdev, "cannot register input device\n"); 77362306a36Sopenharmony_ci goto err_free; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci return 0; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cierr_free: 77962306a36Sopenharmony_ci input_free_device(wdata->ir); 78062306a36Sopenharmony_ci wdata->ir = NULL; 78162306a36Sopenharmony_ci return ret; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic void wiimod_ir_remove(const struct wiimod_ops *ops, 78562306a36Sopenharmony_ci struct wiimote_data *wdata) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci if (!wdata->ir) 78862306a36Sopenharmony_ci return; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci input_unregister_device(wdata->ir); 79162306a36Sopenharmony_ci wdata->ir = NULL; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_ir = { 79562306a36Sopenharmony_ci .flags = 0, 79662306a36Sopenharmony_ci .arg = 0, 79762306a36Sopenharmony_ci .probe = wiimod_ir_probe, 79862306a36Sopenharmony_ci .remove = wiimod_ir_remove, 79962306a36Sopenharmony_ci .in_ir = wiimod_ir_in_ir, 80062306a36Sopenharmony_ci}; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/* 80362306a36Sopenharmony_ci * Nunchuk Extension 80462306a36Sopenharmony_ci * The Nintendo Wii Nunchuk was the first official extension published by 80562306a36Sopenharmony_ci * Nintendo. It provides two additional keys and a separate accelerometer. It 80662306a36Sopenharmony_ci * can be hotplugged to standard Wii Remotes. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cienum wiimod_nunchuk_keys { 81062306a36Sopenharmony_ci WIIMOD_NUNCHUK_KEY_C, 81162306a36Sopenharmony_ci WIIMOD_NUNCHUK_KEY_Z, 81262306a36Sopenharmony_ci WIIMOD_NUNCHUK_KEY_NUM, 81362306a36Sopenharmony_ci}; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic const __u16 wiimod_nunchuk_map[] = { 81662306a36Sopenharmony_ci BTN_C, /* WIIMOD_NUNCHUK_KEY_C */ 81762306a36Sopenharmony_ci BTN_Z, /* WIIMOD_NUNCHUK_KEY_Z */ 81862306a36Sopenharmony_ci}; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci __s16 x, y, z, bx, by; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 | 82562306a36Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 82662306a36Sopenharmony_ci * 1 | Button X <7:0> | 82762306a36Sopenharmony_ci * 2 | Button Y <7:0> | 82862306a36Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 82962306a36Sopenharmony_ci * 3 | Speed X <9:2> | 83062306a36Sopenharmony_ci * 4 | Speed Y <9:2> | 83162306a36Sopenharmony_ci * 5 | Speed Z <9:2> | 83262306a36Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 83362306a36Sopenharmony_ci * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ | 83462306a36Sopenharmony_ci * -----+----------+---------+---------+----+-----+ 83562306a36Sopenharmony_ci * Button X/Y is the analog stick. Speed X, Y and Z are the 83662306a36Sopenharmony_ci * accelerometer data in the same format as the wiimote's accelerometer. 83762306a36Sopenharmony_ci * The 6th byte contains the LSBs of the accelerometer data. 83862306a36Sopenharmony_ci * BC and BZ are the C and Z buttons: 0 means pressed 83962306a36Sopenharmony_ci * 84062306a36Sopenharmony_ci * If reported interleaved with motionp, then the layout changes. The 84162306a36Sopenharmony_ci * 5th and 6th byte changes to: 84262306a36Sopenharmony_ci * -----+-----------------------------------+-----+ 84362306a36Sopenharmony_ci * 5 | Speed Z <9:3> | EXT | 84462306a36Sopenharmony_ci * -----+--------+-----+-----+----+----+----+-----+ 84562306a36Sopenharmony_ci * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 | 84662306a36Sopenharmony_ci * -----+--------+-----+-----+----+----+----+-----+ 84762306a36Sopenharmony_ci * All three accelerometer values lose their LSB. The other data is 84862306a36Sopenharmony_ci * still available but slightly moved. 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * Center data for button values is 128. Center value for accelerometer 85162306a36Sopenharmony_ci * values it 512 / 0x200 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci bx = ext[0]; 85562306a36Sopenharmony_ci by = ext[1]; 85662306a36Sopenharmony_ci bx -= 128; 85762306a36Sopenharmony_ci by -= 128; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci x = ext[2] << 2; 86062306a36Sopenharmony_ci y = ext[3] << 2; 86162306a36Sopenharmony_ci z = ext[4] << 2; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 86462306a36Sopenharmony_ci x |= (ext[5] >> 3) & 0x02; 86562306a36Sopenharmony_ci y |= (ext[5] >> 4) & 0x02; 86662306a36Sopenharmony_ci z &= ~0x4; 86762306a36Sopenharmony_ci z |= (ext[5] >> 5) & 0x06; 86862306a36Sopenharmony_ci } else { 86962306a36Sopenharmony_ci x |= (ext[5] >> 2) & 0x03; 87062306a36Sopenharmony_ci y |= (ext[5] >> 4) & 0x03; 87162306a36Sopenharmony_ci z |= (ext[5] >> 6) & 0x03; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci x -= 0x200; 87562306a36Sopenharmony_ci y -= 0x200; 87662306a36Sopenharmony_ci z -= 0x200; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, bx); 87962306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0Y, by); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RX, x); 88262306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RY, y); 88362306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RZ, z); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 88662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 88762306a36Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z], 88862306a36Sopenharmony_ci !(ext[5] & 0x04)); 88962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 89062306a36Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C], 89162306a36Sopenharmony_ci !(ext[5] & 0x08)); 89262306a36Sopenharmony_ci } else { 89362306a36Sopenharmony_ci input_report_key(wdata->extension.input, 89462306a36Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z], 89562306a36Sopenharmony_ci !(ext[5] & 0x01)); 89662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 89762306a36Sopenharmony_ci wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C], 89862306a36Sopenharmony_ci !(ext[5] & 0x02)); 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci input_sync(wdata->extension.input); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic int wiimod_nunchuk_open(struct input_dev *dev) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 90762306a36Sopenharmony_ci unsigned long flags; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 91062306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 91162306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 91262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic void wiimod_nunchuk_close(struct input_dev *dev) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 92062306a36Sopenharmony_ci unsigned long flags; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 92362306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 92462306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 92562306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic int wiimod_nunchuk_probe(const struct wiimod_ops *ops, 92962306a36Sopenharmony_ci struct wiimote_data *wdata) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci int ret, i; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 93462306a36Sopenharmony_ci if (!wdata->extension.input) 93562306a36Sopenharmony_ci return -ENOMEM; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 93862306a36Sopenharmony_ci wdata->extension.input->open = wiimod_nunchuk_open; 93962306a36Sopenharmony_ci wdata->extension.input->close = wiimod_nunchuk_close; 94062306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 94162306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 94262306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 94362306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 94462306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 94562306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Nunchuk"; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 94862306a36Sopenharmony_ci for (i = 0; i < WIIMOD_NUNCHUK_KEY_NUM; ++i) 94962306a36Sopenharmony_ci set_bit(wiimod_nunchuk_map[i], 95062306a36Sopenharmony_ci wdata->extension.input->keybit); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 95362306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 95462306a36Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 95562306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 95662306a36Sopenharmony_ci ABS_HAT0X, -120, 120, 2, 4); 95762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 95862306a36Sopenharmony_ci ABS_HAT0Y, -120, 120, 2, 4); 95962306a36Sopenharmony_ci set_bit(ABS_RX, wdata->extension.input->absbit); 96062306a36Sopenharmony_ci set_bit(ABS_RY, wdata->extension.input->absbit); 96162306a36Sopenharmony_ci set_bit(ABS_RZ, wdata->extension.input->absbit); 96262306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 96362306a36Sopenharmony_ci ABS_RX, -500, 500, 2, 4); 96462306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 96562306a36Sopenharmony_ci ABS_RY, -500, 500, 2, 4); 96662306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 96762306a36Sopenharmony_ci ABS_RZ, -500, 500, 2, 4); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 97062306a36Sopenharmony_ci if (ret) 97162306a36Sopenharmony_ci goto err_free; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return 0; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cierr_free: 97662306a36Sopenharmony_ci input_free_device(wdata->extension.input); 97762306a36Sopenharmony_ci wdata->extension.input = NULL; 97862306a36Sopenharmony_ci return ret; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic void wiimod_nunchuk_remove(const struct wiimod_ops *ops, 98262306a36Sopenharmony_ci struct wiimote_data *wdata) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci if (!wdata->extension.input) 98562306a36Sopenharmony_ci return; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 98862306a36Sopenharmony_ci wdata->extension.input = NULL; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_nunchuk = { 99262306a36Sopenharmony_ci .flags = 0, 99362306a36Sopenharmony_ci .arg = 0, 99462306a36Sopenharmony_ci .probe = wiimod_nunchuk_probe, 99562306a36Sopenharmony_ci .remove = wiimod_nunchuk_remove, 99662306a36Sopenharmony_ci .in_ext = wiimod_nunchuk_in_ext, 99762306a36Sopenharmony_ci}; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci/* 100062306a36Sopenharmony_ci * Classic Controller 100162306a36Sopenharmony_ci * Another official extension from Nintendo. It provides a classic 100262306a36Sopenharmony_ci * gamecube-like controller that can be hotplugged on the Wii Remote. 100362306a36Sopenharmony_ci * It has several hardware buttons and switches that are all reported via 100462306a36Sopenharmony_ci * a normal extension device. 100562306a36Sopenharmony_ci */ 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cienum wiimod_classic_keys { 100862306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_A, 100962306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_B, 101062306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_X, 101162306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_Y, 101262306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_ZL, 101362306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_ZR, 101462306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_PLUS, 101562306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_MINUS, 101662306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_HOME, 101762306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_LEFT, 101862306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_RIGHT, 101962306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_UP, 102062306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_DOWN, 102162306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_LT, 102262306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_RT, 102362306a36Sopenharmony_ci WIIMOD_CLASSIC_KEY_NUM, 102462306a36Sopenharmony_ci}; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic const __u16 wiimod_classic_map[] = { 102762306a36Sopenharmony_ci BTN_A, /* WIIMOD_CLASSIC_KEY_A */ 102862306a36Sopenharmony_ci BTN_B, /* WIIMOD_CLASSIC_KEY_B */ 102962306a36Sopenharmony_ci BTN_X, /* WIIMOD_CLASSIC_KEY_X */ 103062306a36Sopenharmony_ci BTN_Y, /* WIIMOD_CLASSIC_KEY_Y */ 103162306a36Sopenharmony_ci BTN_TL2, /* WIIMOD_CLASSIC_KEY_ZL */ 103262306a36Sopenharmony_ci BTN_TR2, /* WIIMOD_CLASSIC_KEY_ZR */ 103362306a36Sopenharmony_ci KEY_NEXT, /* WIIMOD_CLASSIC_KEY_PLUS */ 103462306a36Sopenharmony_ci KEY_PREVIOUS, /* WIIMOD_CLASSIC_KEY_MINUS */ 103562306a36Sopenharmony_ci BTN_MODE, /* WIIMOD_CLASSIC_KEY_HOME */ 103662306a36Sopenharmony_ci KEY_LEFT, /* WIIMOD_CLASSIC_KEY_LEFT */ 103762306a36Sopenharmony_ci KEY_RIGHT, /* WIIMOD_CLASSIC_KEY_RIGHT */ 103862306a36Sopenharmony_ci KEY_UP, /* WIIMOD_CLASSIC_KEY_UP */ 103962306a36Sopenharmony_ci KEY_DOWN, /* WIIMOD_CLASSIC_KEY_DOWN */ 104062306a36Sopenharmony_ci BTN_TL, /* WIIMOD_CLASSIC_KEY_LT */ 104162306a36Sopenharmony_ci BTN_TR, /* WIIMOD_CLASSIC_KEY_RT */ 104262306a36Sopenharmony_ci}; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci __s8 rx, ry, lx, ly, lt, rt; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 104962306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 105062306a36Sopenharmony_ci * 1 | RX <5:4> | LX <5:0> | 105162306a36Sopenharmony_ci * 2 | RX <3:2> | LY <5:0> | 105262306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 105362306a36Sopenharmony_ci * 3 |RX<1>| LT <5:4> | RY <5:1> | 105462306a36Sopenharmony_ci * -----+-----+-----------+-----------------------------+ 105562306a36Sopenharmony_ci * 4 | LT <3:1> | RT <5:1> | 105662306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 105762306a36Sopenharmony_ci * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | 105862306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 105962306a36Sopenharmony_ci * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | 106062306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 106162306a36Sopenharmony_ci * All buttons are 0 if pressed 106262306a36Sopenharmony_ci * RX and RY are right analog stick 106362306a36Sopenharmony_ci * LX and LY are left analog stick 106462306a36Sopenharmony_ci * LT is left trigger, RT is right trigger 106562306a36Sopenharmony_ci * BLT is 0 if left trigger is fully pressed 106662306a36Sopenharmony_ci * BRT is 0 if right trigger is fully pressed 106762306a36Sopenharmony_ci * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons 106862306a36Sopenharmony_ci * BZL is left Z button and BZR is right Z button 106962306a36Sopenharmony_ci * B-, BH, B+ are +, HOME and - buttons 107062306a36Sopenharmony_ci * BB, BY, BA, BX are A, B, X, Y buttons 107162306a36Sopenharmony_ci * LSB of RX, RY, LT, and RT are not transmitted and always 0. 107262306a36Sopenharmony_ci * 107362306a36Sopenharmony_ci * With motionp enabled it changes slightly to this: 107462306a36Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 107562306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 107662306a36Sopenharmony_ci * 1 | RX <5:4> | LX <5:1> | BDU | 107762306a36Sopenharmony_ci * 2 | RX <3:2> | LY <5:1> | BDL | 107862306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------+-----+ 107962306a36Sopenharmony_ci * 3 |RX<1>| LT <5:4> | RY <5:1> | 108062306a36Sopenharmony_ci * -----+-----+-----------+-----------------------------+ 108162306a36Sopenharmony_ci * 4 | LT <3:1> | RT <5:1> | 108262306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 108362306a36Sopenharmony_ci * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT | 108462306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 108562306a36Sopenharmony_ci * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 | 108662306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 108762306a36Sopenharmony_ci * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest 108862306a36Sopenharmony_ci * is the same as before. 108962306a36Sopenharmony_ci */ 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci static const s8 digital_to_analog[3] = {0x20, 0, -0x20}; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 109462306a36Sopenharmony_ci if (wiimote_dpad_as_analog) { 109562306a36Sopenharmony_ci lx = digital_to_analog[1 - !(ext[4] & 0x80) 109662306a36Sopenharmony_ci + !(ext[1] & 0x01)]; 109762306a36Sopenharmony_ci ly = digital_to_analog[1 - !(ext[4] & 0x40) 109862306a36Sopenharmony_ci + !(ext[0] & 0x01)]; 109962306a36Sopenharmony_ci } else { 110062306a36Sopenharmony_ci lx = (ext[0] & 0x3e) - 0x20; 110162306a36Sopenharmony_ci ly = (ext[1] & 0x3e) - 0x20; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci } else { 110462306a36Sopenharmony_ci if (wiimote_dpad_as_analog) { 110562306a36Sopenharmony_ci lx = digital_to_analog[1 - !(ext[4] & 0x80) 110662306a36Sopenharmony_ci + !(ext[5] & 0x02)]; 110762306a36Sopenharmony_ci ly = digital_to_analog[1 - !(ext[4] & 0x40) 110862306a36Sopenharmony_ci + !(ext[5] & 0x01)]; 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci lx = (ext[0] & 0x3f) - 0x20; 111162306a36Sopenharmony_ci ly = (ext[1] & 0x3f) - 0x20; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci rx = (ext[0] >> 3) & 0x18; 111662306a36Sopenharmony_ci rx |= (ext[1] >> 5) & 0x06; 111762306a36Sopenharmony_ci rx |= (ext[2] >> 7) & 0x01; 111862306a36Sopenharmony_ci ry = ext[2] & 0x1f; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci rt = ext[3] & 0x1f; 112162306a36Sopenharmony_ci lt = (ext[2] >> 2) & 0x18; 112262306a36Sopenharmony_ci lt |= (ext[3] >> 5) & 0x07; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci rx <<= 1; 112562306a36Sopenharmony_ci ry <<= 1; 112662306a36Sopenharmony_ci rt <<= 1; 112762306a36Sopenharmony_ci lt <<= 1; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, lx); 113062306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1Y, ly); 113162306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20); 113262306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20); 113362306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT3X, rt); 113462306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT3Y, lt); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 113762306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT], 113862306a36Sopenharmony_ci !(ext[4] & 0x20)); 113962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 114062306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_MINUS], 114162306a36Sopenharmony_ci !(ext[4] & 0x10)); 114262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 114362306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_HOME], 114462306a36Sopenharmony_ci !(ext[4] & 0x08)); 114562306a36Sopenharmony_ci input_report_key(wdata->extension.input, 114662306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_PLUS], 114762306a36Sopenharmony_ci !(ext[4] & 0x04)); 114862306a36Sopenharmony_ci input_report_key(wdata->extension.input, 114962306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_RT], 115062306a36Sopenharmony_ci !(ext[4] & 0x02)); 115162306a36Sopenharmony_ci input_report_key(wdata->extension.input, 115262306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZL], 115362306a36Sopenharmony_ci !(ext[5] & 0x80)); 115462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 115562306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_B], 115662306a36Sopenharmony_ci !(ext[5] & 0x40)); 115762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 115862306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_Y], 115962306a36Sopenharmony_ci !(ext[5] & 0x20)); 116062306a36Sopenharmony_ci input_report_key(wdata->extension.input, 116162306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_A], 116262306a36Sopenharmony_ci !(ext[5] & 0x10)); 116362306a36Sopenharmony_ci input_report_key(wdata->extension.input, 116462306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_X], 116562306a36Sopenharmony_ci !(ext[5] & 0x08)); 116662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 116762306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR], 116862306a36Sopenharmony_ci !(ext[5] & 0x04)); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (!wiimote_dpad_as_analog) { 117162306a36Sopenharmony_ci input_report_key(wdata->extension.input, 117262306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT], 117362306a36Sopenharmony_ci !(ext[4] & 0x80)); 117462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 117562306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN], 117662306a36Sopenharmony_ci !(ext[4] & 0x40)); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 117962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 118062306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], 118162306a36Sopenharmony_ci !(ext[1] & 0x01)); 118262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 118362306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], 118462306a36Sopenharmony_ci !(ext[0] & 0x01)); 118562306a36Sopenharmony_ci } else { 118662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 118762306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], 118862306a36Sopenharmony_ci !(ext[5] & 0x02)); 118962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 119062306a36Sopenharmony_ci wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], 119162306a36Sopenharmony_ci !(ext[5] & 0x01)); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci input_sync(wdata->extension.input); 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic int wiimod_classic_open(struct input_dev *dev) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 120162306a36Sopenharmony_ci unsigned long flags; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 120462306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 120562306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 120662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic void wiimod_classic_close(struct input_dev *dev) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 121462306a36Sopenharmony_ci unsigned long flags; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 121762306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 121862306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 121962306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_cistatic int wiimod_classic_probe(const struct wiimod_ops *ops, 122362306a36Sopenharmony_ci struct wiimote_data *wdata) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci int ret, i; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 122862306a36Sopenharmony_ci if (!wdata->extension.input) 122962306a36Sopenharmony_ci return -ENOMEM; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 123262306a36Sopenharmony_ci wdata->extension.input->open = wiimod_classic_open; 123362306a36Sopenharmony_ci wdata->extension.input->close = wiimod_classic_close; 123462306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 123562306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 123662306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 123762306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 123862306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 123962306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Classic Controller"; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 124262306a36Sopenharmony_ci for (i = 0; i < WIIMOD_CLASSIC_KEY_NUM; ++i) 124362306a36Sopenharmony_ci set_bit(wiimod_classic_map[i], 124462306a36Sopenharmony_ci wdata->extension.input->keybit); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 124762306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 124862306a36Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->extension.input->absbit); 124962306a36Sopenharmony_ci set_bit(ABS_HAT2X, wdata->extension.input->absbit); 125062306a36Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->extension.input->absbit); 125162306a36Sopenharmony_ci set_bit(ABS_HAT3X, wdata->extension.input->absbit); 125262306a36Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->extension.input->absbit); 125362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 125462306a36Sopenharmony_ci ABS_HAT1X, -30, 30, 1, 1); 125562306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 125662306a36Sopenharmony_ci ABS_HAT1Y, -30, 30, 1, 1); 125762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 125862306a36Sopenharmony_ci ABS_HAT2X, -30, 30, 1, 1); 125962306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 126062306a36Sopenharmony_ci ABS_HAT2Y, -30, 30, 1, 1); 126162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 126262306a36Sopenharmony_ci ABS_HAT3X, -30, 30, 1, 1); 126362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 126462306a36Sopenharmony_ci ABS_HAT3Y, -30, 30, 1, 1); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 126762306a36Sopenharmony_ci if (ret) 126862306a36Sopenharmony_ci goto err_free; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cierr_free: 127362306a36Sopenharmony_ci input_free_device(wdata->extension.input); 127462306a36Sopenharmony_ci wdata->extension.input = NULL; 127562306a36Sopenharmony_ci return ret; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic void wiimod_classic_remove(const struct wiimod_ops *ops, 127962306a36Sopenharmony_ci struct wiimote_data *wdata) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci if (!wdata->extension.input) 128262306a36Sopenharmony_ci return; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 128562306a36Sopenharmony_ci wdata->extension.input = NULL; 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_classic = { 128962306a36Sopenharmony_ci .flags = 0, 129062306a36Sopenharmony_ci .arg = 0, 129162306a36Sopenharmony_ci .probe = wiimod_classic_probe, 129262306a36Sopenharmony_ci .remove = wiimod_classic_remove, 129362306a36Sopenharmony_ci .in_ext = wiimod_classic_in_ext, 129462306a36Sopenharmony_ci}; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci/* 129762306a36Sopenharmony_ci * Balance Board Extension 129862306a36Sopenharmony_ci * The Nintendo Wii Balance Board provides four hardware weight sensor plus a 129962306a36Sopenharmony_ci * single push button. No other peripherals are available. However, the 130062306a36Sopenharmony_ci * balance-board data is sent via a standard Wii Remote extension. All other 130162306a36Sopenharmony_ci * data for non-present hardware is zeroed out. 130262306a36Sopenharmony_ci * Some 3rd party devices react allergic if we try to access normal Wii Remote 130362306a36Sopenharmony_ci * hardware, so this extension module should be the only module that is loaded 130462306a36Sopenharmony_ci * on balance boards. 130562306a36Sopenharmony_ci * The balance board needs 8 bytes extension data instead of basic 6 bytes so 130662306a36Sopenharmony_ci * it needs the WIIMOD_FLAG_EXT8 flag. 130762306a36Sopenharmony_ci */ 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic void wiimod_bboard_in_keys(struct wiimote_data *wdata, const __u8 *keys) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci input_report_key(wdata->extension.input, BTN_A, 131262306a36Sopenharmony_ci !!(keys[1] & 0x08)); 131362306a36Sopenharmony_ci input_sync(wdata->extension.input); 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void wiimod_bboard_in_ext(struct wiimote_data *wdata, 131762306a36Sopenharmony_ci const __u8 *ext) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci __s32 val[4], tmp, div; 132062306a36Sopenharmony_ci unsigned int i; 132162306a36Sopenharmony_ci struct wiimote_state *s = &wdata->state; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci /* 132462306a36Sopenharmony_ci * Balance board data layout: 132562306a36Sopenharmony_ci * 132662306a36Sopenharmony_ci * Byte | 8 7 6 5 4 3 2 1 | 132762306a36Sopenharmony_ci * -----+--------------------------+ 132862306a36Sopenharmony_ci * 1 | Top Right <15:8> | 132962306a36Sopenharmony_ci * 2 | Top Right <7:0> | 133062306a36Sopenharmony_ci * -----+--------------------------+ 133162306a36Sopenharmony_ci * 3 | Bottom Right <15:8> | 133262306a36Sopenharmony_ci * 4 | Bottom Right <7:0> | 133362306a36Sopenharmony_ci * -----+--------------------------+ 133462306a36Sopenharmony_ci * 5 | Top Left <15:8> | 133562306a36Sopenharmony_ci * 6 | Top Left <7:0> | 133662306a36Sopenharmony_ci * -----+--------------------------+ 133762306a36Sopenharmony_ci * 7 | Bottom Left <15:8> | 133862306a36Sopenharmony_ci * 8 | Bottom Left <7:0> | 133962306a36Sopenharmony_ci * -----+--------------------------+ 134062306a36Sopenharmony_ci * 134162306a36Sopenharmony_ci * These values represent the weight-measurements of the Wii-balance 134262306a36Sopenharmony_ci * board with 16bit precision. 134362306a36Sopenharmony_ci * 134462306a36Sopenharmony_ci * The balance-board is never reported interleaved with motionp. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci val[0] = ext[0]; 134862306a36Sopenharmony_ci val[0] <<= 8; 134962306a36Sopenharmony_ci val[0] |= ext[1]; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci val[1] = ext[2]; 135262306a36Sopenharmony_ci val[1] <<= 8; 135362306a36Sopenharmony_ci val[1] |= ext[3]; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci val[2] = ext[4]; 135662306a36Sopenharmony_ci val[2] <<= 8; 135762306a36Sopenharmony_ci val[2] |= ext[5]; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci val[3] = ext[6]; 136062306a36Sopenharmony_ci val[3] <<= 8; 136162306a36Sopenharmony_ci val[3] |= ext[7]; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* apply calibration data */ 136462306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 136562306a36Sopenharmony_ci if (val[i] <= s->calib_bboard[i][0]) { 136662306a36Sopenharmony_ci tmp = 0; 136762306a36Sopenharmony_ci } else if (val[i] < s->calib_bboard[i][1]) { 136862306a36Sopenharmony_ci tmp = val[i] - s->calib_bboard[i][0]; 136962306a36Sopenharmony_ci tmp *= 1700; 137062306a36Sopenharmony_ci div = s->calib_bboard[i][1] - s->calib_bboard[i][0]; 137162306a36Sopenharmony_ci tmp /= div ? div : 1; 137262306a36Sopenharmony_ci } else { 137362306a36Sopenharmony_ci tmp = val[i] - s->calib_bboard[i][1]; 137462306a36Sopenharmony_ci tmp *= 1700; 137562306a36Sopenharmony_ci div = s->calib_bboard[i][2] - s->calib_bboard[i][1]; 137662306a36Sopenharmony_ci tmp /= div ? div : 1; 137762306a36Sopenharmony_ci tmp += 1700; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci val[i] = tmp; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, val[0]); 138362306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0Y, val[1]); 138462306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, val[2]); 138562306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1Y, val[3]); 138662306a36Sopenharmony_ci input_sync(wdata->extension.input); 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic int wiimod_bboard_open(struct input_dev *dev) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 139262306a36Sopenharmony_ci unsigned long flags; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 139562306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 139662306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 139762306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic void wiimod_bboard_close(struct input_dev *dev) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 140562306a36Sopenharmony_ci unsigned long flags; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 140862306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 140962306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 141062306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic ssize_t wiimod_bboard_calib_show(struct device *dev, 141462306a36Sopenharmony_ci struct device_attribute *attr, 141562306a36Sopenharmony_ci char *out) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 141862306a36Sopenharmony_ci int i, j, ret; 141962306a36Sopenharmony_ci __u16 val; 142062306a36Sopenharmony_ci __u8 buf[24], offs; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ret = wiimote_cmd_acquire(wdata); 142362306a36Sopenharmony_ci if (ret) 142462306a36Sopenharmony_ci return ret; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12); 142762306a36Sopenharmony_ci if (ret != 12) { 142862306a36Sopenharmony_ci wiimote_cmd_release(wdata); 142962306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12); 143262306a36Sopenharmony_ci if (ret != 12) { 143362306a36Sopenharmony_ci wiimote_cmd_release(wdata); 143462306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci wiimote_cmd_release(wdata); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 144062306a36Sopenharmony_ci offs = 0; 144162306a36Sopenharmony_ci for (i = 0; i < 3; ++i) { 144262306a36Sopenharmony_ci for (j = 0; j < 4; ++j) { 144362306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] = buf[offs]; 144462306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] <<= 8; 144562306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] |= buf[offs + 1]; 144662306a36Sopenharmony_ci offs += 2; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ret = 0; 145262306a36Sopenharmony_ci for (i = 0; i < 3; ++i) { 145362306a36Sopenharmony_ci for (j = 0; j < 4; ++j) { 145462306a36Sopenharmony_ci val = wdata->state.calib_bboard[j][i]; 145562306a36Sopenharmony_ci if (i == 2 && j == 3) 145662306a36Sopenharmony_ci ret += sprintf(&out[ret], "%04x\n", val); 145762306a36Sopenharmony_ci else 145862306a36Sopenharmony_ci ret += sprintf(&out[ret], "%04x:", val); 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return ret; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic DEVICE_ATTR(bboard_calib, S_IRUGO, wiimod_bboard_calib_show, NULL); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic int wiimod_bboard_probe(const struct wiimod_ops *ops, 146862306a36Sopenharmony_ci struct wiimote_data *wdata) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci int ret, i, j; 147162306a36Sopenharmony_ci __u8 buf[24], offs; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci wiimote_cmd_acquire_noint(wdata); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12); 147662306a36Sopenharmony_ci if (ret != 12) { 147762306a36Sopenharmony_ci wiimote_cmd_release(wdata); 147862306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12); 148162306a36Sopenharmony_ci if (ret != 12) { 148262306a36Sopenharmony_ci wiimote_cmd_release(wdata); 148362306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci wiimote_cmd_release(wdata); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci offs = 0; 148962306a36Sopenharmony_ci for (i = 0; i < 3; ++i) { 149062306a36Sopenharmony_ci for (j = 0; j < 4; ++j) { 149162306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] = buf[offs]; 149262306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] <<= 8; 149362306a36Sopenharmony_ci wdata->state.calib_bboard[j][i] |= buf[offs + 1]; 149462306a36Sopenharmony_ci offs += 2; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 149962306a36Sopenharmony_ci if (!wdata->extension.input) 150062306a36Sopenharmony_ci return -ENOMEM; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci ret = device_create_file(&wdata->hdev->dev, 150362306a36Sopenharmony_ci &dev_attr_bboard_calib); 150462306a36Sopenharmony_ci if (ret) { 150562306a36Sopenharmony_ci hid_err(wdata->hdev, "cannot create sysfs attribute\n"); 150662306a36Sopenharmony_ci goto err_free; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 151062306a36Sopenharmony_ci wdata->extension.input->open = wiimod_bboard_open; 151162306a36Sopenharmony_ci wdata->extension.input->close = wiimod_bboard_close; 151262306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 151362306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 151462306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 151562306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 151662306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 151762306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Balance Board"; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 152062306a36Sopenharmony_ci set_bit(BTN_A, wdata->extension.input->keybit); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 152362306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 152462306a36Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 152562306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 152662306a36Sopenharmony_ci set_bit(ABS_HAT1Y, wdata->extension.input->absbit); 152762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 152862306a36Sopenharmony_ci ABS_HAT0X, 0, 65535, 2, 4); 152962306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 153062306a36Sopenharmony_ci ABS_HAT0Y, 0, 65535, 2, 4); 153162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 153262306a36Sopenharmony_ci ABS_HAT1X, 0, 65535, 2, 4); 153362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 153462306a36Sopenharmony_ci ABS_HAT1Y, 0, 65535, 2, 4); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 153762306a36Sopenharmony_ci if (ret) 153862306a36Sopenharmony_ci goto err_file; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return 0; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_cierr_file: 154362306a36Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 154462306a36Sopenharmony_ci &dev_attr_bboard_calib); 154562306a36Sopenharmony_cierr_free: 154662306a36Sopenharmony_ci input_free_device(wdata->extension.input); 154762306a36Sopenharmony_ci wdata->extension.input = NULL; 154862306a36Sopenharmony_ci return ret; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic void wiimod_bboard_remove(const struct wiimod_ops *ops, 155262306a36Sopenharmony_ci struct wiimote_data *wdata) 155362306a36Sopenharmony_ci{ 155462306a36Sopenharmony_ci if (!wdata->extension.input) 155562306a36Sopenharmony_ci return; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 155862306a36Sopenharmony_ci wdata->extension.input = NULL; 155962306a36Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 156062306a36Sopenharmony_ci &dev_attr_bboard_calib); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_bboard = { 156462306a36Sopenharmony_ci .flags = WIIMOD_FLAG_EXT8, 156562306a36Sopenharmony_ci .arg = 0, 156662306a36Sopenharmony_ci .probe = wiimod_bboard_probe, 156762306a36Sopenharmony_ci .remove = wiimod_bboard_remove, 156862306a36Sopenharmony_ci .in_keys = wiimod_bboard_in_keys, 156962306a36Sopenharmony_ci .in_ext = wiimod_bboard_in_ext, 157062306a36Sopenharmony_ci}; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci/* 157362306a36Sopenharmony_ci * Pro Controller 157462306a36Sopenharmony_ci * Released with the Wii U was the Nintendo Wii U Pro Controller. It does not 157562306a36Sopenharmony_ci * work together with the classic Wii, but only with the new Wii U. However, it 157662306a36Sopenharmony_ci * uses the same protocol and provides a builtin "classic controller pro" 157762306a36Sopenharmony_ci * extension, few standard buttons, a rumble motor, 4 LEDs and a battery. 157862306a36Sopenharmony_ci * We provide all these via a standard extension device as the device doesn't 157962306a36Sopenharmony_ci * feature an extension port. 158062306a36Sopenharmony_ci */ 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cienum wiimod_pro_keys { 158362306a36Sopenharmony_ci WIIMOD_PRO_KEY_A, 158462306a36Sopenharmony_ci WIIMOD_PRO_KEY_B, 158562306a36Sopenharmony_ci WIIMOD_PRO_KEY_X, 158662306a36Sopenharmony_ci WIIMOD_PRO_KEY_Y, 158762306a36Sopenharmony_ci WIIMOD_PRO_KEY_PLUS, 158862306a36Sopenharmony_ci WIIMOD_PRO_KEY_MINUS, 158962306a36Sopenharmony_ci WIIMOD_PRO_KEY_HOME, 159062306a36Sopenharmony_ci WIIMOD_PRO_KEY_LEFT, 159162306a36Sopenharmony_ci WIIMOD_PRO_KEY_RIGHT, 159262306a36Sopenharmony_ci WIIMOD_PRO_KEY_UP, 159362306a36Sopenharmony_ci WIIMOD_PRO_KEY_DOWN, 159462306a36Sopenharmony_ci WIIMOD_PRO_KEY_TL, 159562306a36Sopenharmony_ci WIIMOD_PRO_KEY_TR, 159662306a36Sopenharmony_ci WIIMOD_PRO_KEY_ZL, 159762306a36Sopenharmony_ci WIIMOD_PRO_KEY_ZR, 159862306a36Sopenharmony_ci WIIMOD_PRO_KEY_THUMBL, 159962306a36Sopenharmony_ci WIIMOD_PRO_KEY_THUMBR, 160062306a36Sopenharmony_ci WIIMOD_PRO_KEY_NUM, 160162306a36Sopenharmony_ci}; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic const __u16 wiimod_pro_map[] = { 160462306a36Sopenharmony_ci BTN_EAST, /* WIIMOD_PRO_KEY_A */ 160562306a36Sopenharmony_ci BTN_SOUTH, /* WIIMOD_PRO_KEY_B */ 160662306a36Sopenharmony_ci BTN_NORTH, /* WIIMOD_PRO_KEY_X */ 160762306a36Sopenharmony_ci BTN_WEST, /* WIIMOD_PRO_KEY_Y */ 160862306a36Sopenharmony_ci BTN_START, /* WIIMOD_PRO_KEY_PLUS */ 160962306a36Sopenharmony_ci BTN_SELECT, /* WIIMOD_PRO_KEY_MINUS */ 161062306a36Sopenharmony_ci BTN_MODE, /* WIIMOD_PRO_KEY_HOME */ 161162306a36Sopenharmony_ci BTN_DPAD_LEFT, /* WIIMOD_PRO_KEY_LEFT */ 161262306a36Sopenharmony_ci BTN_DPAD_RIGHT, /* WIIMOD_PRO_KEY_RIGHT */ 161362306a36Sopenharmony_ci BTN_DPAD_UP, /* WIIMOD_PRO_KEY_UP */ 161462306a36Sopenharmony_ci BTN_DPAD_DOWN, /* WIIMOD_PRO_KEY_DOWN */ 161562306a36Sopenharmony_ci BTN_TL, /* WIIMOD_PRO_KEY_TL */ 161662306a36Sopenharmony_ci BTN_TR, /* WIIMOD_PRO_KEY_TR */ 161762306a36Sopenharmony_ci BTN_TL2, /* WIIMOD_PRO_KEY_ZL */ 161862306a36Sopenharmony_ci BTN_TR2, /* WIIMOD_PRO_KEY_ZR */ 161962306a36Sopenharmony_ci BTN_THUMBL, /* WIIMOD_PRO_KEY_THUMBL */ 162062306a36Sopenharmony_ci BTN_THUMBR, /* WIIMOD_PRO_KEY_THUMBR */ 162162306a36Sopenharmony_ci}; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cistatic void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci __s16 rx, ry, lx, ly; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 162862306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 162962306a36Sopenharmony_ci * 1 | LX <7:0> | 163062306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 163162306a36Sopenharmony_ci * 2 | 0 0 0 0 | LX <11:8> | 163262306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 163362306a36Sopenharmony_ci * 3 | RX <7:0> | 163462306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 163562306a36Sopenharmony_ci * 4 | 0 0 0 0 | RX <11:8> | 163662306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 163762306a36Sopenharmony_ci * 5 | LY <7:0> | 163862306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 163962306a36Sopenharmony_ci * 6 | 0 0 0 0 | LY <11:8> | 164062306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 164162306a36Sopenharmony_ci * 7 | RY <7:0> | 164262306a36Sopenharmony_ci * -----+-----------------------+-----------------------+ 164362306a36Sopenharmony_ci * 8 | 0 0 0 0 | RY <11:8> | 164462306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 164562306a36Sopenharmony_ci * 9 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | 164662306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 164762306a36Sopenharmony_ci * 10 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | 164862306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 164962306a36Sopenharmony_ci * 11 | 1 | BATTERY | USB |CHARG|LTHUM|RTHUM| 165062306a36Sopenharmony_ci * -----+-----+-----------------+-----------+-----+-----+ 165162306a36Sopenharmony_ci * All buttons are low-active (0 if pressed) 165262306a36Sopenharmony_ci * RX and RY are right analog stick 165362306a36Sopenharmony_ci * LX and LY are left analog stick 165462306a36Sopenharmony_ci * BLT is left trigger, BRT is right trigger. 165562306a36Sopenharmony_ci * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons 165662306a36Sopenharmony_ci * BZL is left Z button and BZR is right Z button 165762306a36Sopenharmony_ci * B-, BH, B+ are +, HOME and - buttons 165862306a36Sopenharmony_ci * BB, BY, BA, BX are A, B, X, Y buttons 165962306a36Sopenharmony_ci * 166062306a36Sopenharmony_ci * Bits marked as 0/1 are unknown and never changed during tests. 166162306a36Sopenharmony_ci * 166262306a36Sopenharmony_ci * Not entirely verified: 166362306a36Sopenharmony_ci * CHARG: 1 if uncharging, 0 if charging 166462306a36Sopenharmony_ci * USB: 1 if not connected, 0 if connected 166562306a36Sopenharmony_ci * BATTERY: battery capacity from 000 (empty) to 100 (full) 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci lx = (ext[0] & 0xff) | ((ext[1] & 0x0f) << 8); 166962306a36Sopenharmony_ci rx = (ext[2] & 0xff) | ((ext[3] & 0x0f) << 8); 167062306a36Sopenharmony_ci ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8); 167162306a36Sopenharmony_ci ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* zero-point offsets */ 167462306a36Sopenharmony_ci lx -= 0x800; 167562306a36Sopenharmony_ci ly = 0x800 - ly; 167662306a36Sopenharmony_ci rx -= 0x800; 167762306a36Sopenharmony_ci ry = 0x800 - ry; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci /* Trivial automatic calibration. We don't know any calibration data 168062306a36Sopenharmony_ci * in the EEPROM so we must use the first report to calibrate the 168162306a36Sopenharmony_ci * null-position of the analog sticks. Users can retrigger calibration 168262306a36Sopenharmony_ci * via sysfs, or set it explicitly. If data is off more than abs(500), 168362306a36Sopenharmony_ci * we skip calibration as the sticks are likely to be moved already. */ 168462306a36Sopenharmony_ci if (!(wdata->state.flags & WIIPROTO_FLAG_PRO_CALIB_DONE)) { 168562306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; 168662306a36Sopenharmony_ci if (abs(lx) < 500) 168762306a36Sopenharmony_ci wdata->state.calib_pro_sticks[0] = -lx; 168862306a36Sopenharmony_ci if (abs(ly) < 500) 168962306a36Sopenharmony_ci wdata->state.calib_pro_sticks[1] = -ly; 169062306a36Sopenharmony_ci if (abs(rx) < 500) 169162306a36Sopenharmony_ci wdata->state.calib_pro_sticks[2] = -rx; 169262306a36Sopenharmony_ci if (abs(ry) < 500) 169362306a36Sopenharmony_ci wdata->state.calib_pro_sticks[3] = -ry; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* apply calibration data */ 169762306a36Sopenharmony_ci lx += wdata->state.calib_pro_sticks[0]; 169862306a36Sopenharmony_ci ly += wdata->state.calib_pro_sticks[1]; 169962306a36Sopenharmony_ci rx += wdata->state.calib_pro_sticks[2]; 170062306a36Sopenharmony_ci ry += wdata->state.calib_pro_sticks[3]; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, lx); 170362306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, ly); 170462306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RX, rx); 170562306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_RY, ry); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 170862306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT], 170962306a36Sopenharmony_ci !(ext[8] & 0x80)); 171062306a36Sopenharmony_ci input_report_key(wdata->extension.input, 171162306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_DOWN], 171262306a36Sopenharmony_ci !(ext[8] & 0x40)); 171362306a36Sopenharmony_ci input_report_key(wdata->extension.input, 171462306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_TL], 171562306a36Sopenharmony_ci !(ext[8] & 0x20)); 171662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 171762306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_MINUS], 171862306a36Sopenharmony_ci !(ext[8] & 0x10)); 171962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 172062306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_HOME], 172162306a36Sopenharmony_ci !(ext[8] & 0x08)); 172262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 172362306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_PLUS], 172462306a36Sopenharmony_ci !(ext[8] & 0x04)); 172562306a36Sopenharmony_ci input_report_key(wdata->extension.input, 172662306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_TR], 172762306a36Sopenharmony_ci !(ext[8] & 0x02)); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 173062306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_ZL], 173162306a36Sopenharmony_ci !(ext[9] & 0x80)); 173262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 173362306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_B], 173462306a36Sopenharmony_ci !(ext[9] & 0x40)); 173562306a36Sopenharmony_ci input_report_key(wdata->extension.input, 173662306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_Y], 173762306a36Sopenharmony_ci !(ext[9] & 0x20)); 173862306a36Sopenharmony_ci input_report_key(wdata->extension.input, 173962306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_A], 174062306a36Sopenharmony_ci !(ext[9] & 0x10)); 174162306a36Sopenharmony_ci input_report_key(wdata->extension.input, 174262306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_X], 174362306a36Sopenharmony_ci !(ext[9] & 0x08)); 174462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 174562306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_ZR], 174662306a36Sopenharmony_ci !(ext[9] & 0x04)); 174762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 174862306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_LEFT], 174962306a36Sopenharmony_ci !(ext[9] & 0x02)); 175062306a36Sopenharmony_ci input_report_key(wdata->extension.input, 175162306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_UP], 175262306a36Sopenharmony_ci !(ext[9] & 0x01)); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 175562306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_THUMBL], 175662306a36Sopenharmony_ci !(ext[10] & 0x02)); 175762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 175862306a36Sopenharmony_ci wiimod_pro_map[WIIMOD_PRO_KEY_THUMBR], 175962306a36Sopenharmony_ci !(ext[10] & 0x01)); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci input_sync(wdata->extension.input); 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic int wiimod_pro_open(struct input_dev *dev) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 176762306a36Sopenharmony_ci unsigned long flags; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 177062306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 177162306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 177262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci return 0; 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_cistatic void wiimod_pro_close(struct input_dev *dev) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 178062306a36Sopenharmony_ci unsigned long flags; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 178362306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 178462306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 178562306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_cistatic int wiimod_pro_play(struct input_dev *dev, void *data, 178962306a36Sopenharmony_ci struct ff_effect *eff) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 179262306a36Sopenharmony_ci __u8 value; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci /* 179562306a36Sopenharmony_ci * The wiimote supports only a single rumble motor so if any magnitude 179662306a36Sopenharmony_ci * is set to non-zero then we start the rumble motor. If both are set to 179762306a36Sopenharmony_ci * zero, we stop the rumble motor. 179862306a36Sopenharmony_ci */ 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude) 180162306a36Sopenharmony_ci value = 1; 180262306a36Sopenharmony_ci else 180362306a36Sopenharmony_ci value = 0; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* Locking state.lock here might deadlock with input_event() calls. 180662306a36Sopenharmony_ci * schedule_work acts as barrier. Merging multiple changes is fine. */ 180762306a36Sopenharmony_ci wdata->state.cache_rumble = value; 180862306a36Sopenharmony_ci schedule_work(&wdata->rumble_worker); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci return 0; 181162306a36Sopenharmony_ci} 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_cistatic ssize_t wiimod_pro_calib_show(struct device *dev, 181462306a36Sopenharmony_ci struct device_attribute *attr, 181562306a36Sopenharmony_ci char *out) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 181862306a36Sopenharmony_ci int r; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci r = 0; 182162306a36Sopenharmony_ci r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[0]); 182262306a36Sopenharmony_ci r += sprintf(&out[r], "%+06hd ", wdata->state.calib_pro_sticks[1]); 182362306a36Sopenharmony_ci r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[2]); 182462306a36Sopenharmony_ci r += sprintf(&out[r], "%+06hd\n", wdata->state.calib_pro_sticks[3]); 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci return r; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic ssize_t wiimod_pro_calib_store(struct device *dev, 183062306a36Sopenharmony_ci struct device_attribute *attr, 183162306a36Sopenharmony_ci const char *buf, size_t count) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci struct wiimote_data *wdata = dev_to_wii(dev); 183462306a36Sopenharmony_ci int r; 183562306a36Sopenharmony_ci s16 x1, y1, x2, y2; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if (!strncmp(buf, "scan\n", 5)) { 183862306a36Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 183962306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; 184062306a36Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 184162306a36Sopenharmony_ci } else { 184262306a36Sopenharmony_ci r = sscanf(buf, "%hd:%hd %hd:%hd", &x1, &y1, &x2, &y2); 184362306a36Sopenharmony_ci if (r != 4) 184462306a36Sopenharmony_ci return -EINVAL; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci spin_lock_irq(&wdata->state.lock); 184762306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; 184862306a36Sopenharmony_ci spin_unlock_irq(&wdata->state.lock); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci wdata->state.calib_pro_sticks[0] = x1; 185162306a36Sopenharmony_ci wdata->state.calib_pro_sticks[1] = y1; 185262306a36Sopenharmony_ci wdata->state.calib_pro_sticks[2] = x2; 185362306a36Sopenharmony_ci wdata->state.calib_pro_sticks[3] = y2; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci return strnlen(buf, PAGE_SIZE); 185762306a36Sopenharmony_ci} 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistatic DEVICE_ATTR(pro_calib, S_IRUGO|S_IWUSR|S_IWGRP, wiimod_pro_calib_show, 186062306a36Sopenharmony_ci wiimod_pro_calib_store); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_cistatic int wiimod_pro_probe(const struct wiimod_ops *ops, 186362306a36Sopenharmony_ci struct wiimote_data *wdata) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci int ret, i; 186662306a36Sopenharmony_ci unsigned long flags; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); 186962306a36Sopenharmony_ci wdata->state.calib_pro_sticks[0] = 0; 187062306a36Sopenharmony_ci wdata->state.calib_pro_sticks[1] = 0; 187162306a36Sopenharmony_ci wdata->state.calib_pro_sticks[2] = 0; 187262306a36Sopenharmony_ci wdata->state.calib_pro_sticks[3] = 0; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 187562306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; 187662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 187962306a36Sopenharmony_ci if (!wdata->extension.input) 188062306a36Sopenharmony_ci return -ENOMEM; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci set_bit(FF_RUMBLE, wdata->extension.input->ffbit); 188362306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (input_ff_create_memless(wdata->extension.input, NULL, 188662306a36Sopenharmony_ci wiimod_pro_play)) { 188762306a36Sopenharmony_ci ret = -ENOMEM; 188862306a36Sopenharmony_ci goto err_free; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci ret = device_create_file(&wdata->hdev->dev, 189262306a36Sopenharmony_ci &dev_attr_pro_calib); 189362306a36Sopenharmony_ci if (ret) { 189462306a36Sopenharmony_ci hid_err(wdata->hdev, "cannot create sysfs attribute\n"); 189562306a36Sopenharmony_ci goto err_free; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci wdata->extension.input->open = wiimod_pro_open; 189962306a36Sopenharmony_ci wdata->extension.input->close = wiimod_pro_close; 190062306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 190162306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 190262306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 190362306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 190462306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 190562306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Pro Controller"; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 190862306a36Sopenharmony_ci for (i = 0; i < WIIMOD_PRO_KEY_NUM; ++i) 190962306a36Sopenharmony_ci set_bit(wiimod_pro_map[i], 191062306a36Sopenharmony_ci wdata->extension.input->keybit); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 191362306a36Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 191462306a36Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 191562306a36Sopenharmony_ci set_bit(ABS_RX, wdata->extension.input->absbit); 191662306a36Sopenharmony_ci set_bit(ABS_RY, wdata->extension.input->absbit); 191762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 191862306a36Sopenharmony_ci ABS_X, -0x400, 0x400, 4, 100); 191962306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 192062306a36Sopenharmony_ci ABS_Y, -0x400, 0x400, 4, 100); 192162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 192262306a36Sopenharmony_ci ABS_RX, -0x400, 0x400, 4, 100); 192362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 192462306a36Sopenharmony_ci ABS_RY, -0x400, 0x400, 4, 100); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 192762306a36Sopenharmony_ci if (ret) 192862306a36Sopenharmony_ci goto err_file; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci return 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cierr_file: 193362306a36Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 193462306a36Sopenharmony_ci &dev_attr_pro_calib); 193562306a36Sopenharmony_cierr_free: 193662306a36Sopenharmony_ci input_free_device(wdata->extension.input); 193762306a36Sopenharmony_ci wdata->extension.input = NULL; 193862306a36Sopenharmony_ci return ret; 193962306a36Sopenharmony_ci} 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_cistatic void wiimod_pro_remove(const struct wiimod_ops *ops, 194262306a36Sopenharmony_ci struct wiimote_data *wdata) 194362306a36Sopenharmony_ci{ 194462306a36Sopenharmony_ci unsigned long flags; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (!wdata->extension.input) 194762306a36Sopenharmony_ci return; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 195062306a36Sopenharmony_ci wdata->extension.input = NULL; 195162306a36Sopenharmony_ci cancel_work_sync(&wdata->rumble_worker); 195262306a36Sopenharmony_ci device_remove_file(&wdata->hdev->dev, 195362306a36Sopenharmony_ci &dev_attr_pro_calib); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 195662306a36Sopenharmony_ci wiiproto_req_rumble(wdata, 0); 195762306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 195862306a36Sopenharmony_ci} 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_pro = { 196162306a36Sopenharmony_ci .flags = WIIMOD_FLAG_EXT16, 196262306a36Sopenharmony_ci .arg = 0, 196362306a36Sopenharmony_ci .probe = wiimod_pro_probe, 196462306a36Sopenharmony_ci .remove = wiimod_pro_remove, 196562306a36Sopenharmony_ci .in_ext = wiimod_pro_in_ext, 196662306a36Sopenharmony_ci}; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci/* 196962306a36Sopenharmony_ci * Drums 197062306a36Sopenharmony_ci * Guitar-Hero, Rock-Band and other games came bundled with drums which can 197162306a36Sopenharmony_ci * be plugged as extension to a Wiimote. Drum-reports are still not entirely 197262306a36Sopenharmony_ci * figured out, but the most important information is known. 197362306a36Sopenharmony_ci * We create a separate device for drums and report all information via this 197462306a36Sopenharmony_ci * input device. 197562306a36Sopenharmony_ci */ 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_cistatic inline void wiimod_drums_report_pressure(struct wiimote_data *wdata, 197862306a36Sopenharmony_ci __u8 none, __u8 which, 197962306a36Sopenharmony_ci __u8 pressure, __u8 onoff, 198062306a36Sopenharmony_ci __u8 *store, __u16 code, 198162306a36Sopenharmony_ci __u8 which_code) 198262306a36Sopenharmony_ci{ 198362306a36Sopenharmony_ci static const __u8 default_pressure = 3; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci if (!none && which == which_code) { 198662306a36Sopenharmony_ci *store = pressure; 198762306a36Sopenharmony_ci input_report_abs(wdata->extension.input, code, *store); 198862306a36Sopenharmony_ci } else if (onoff != !!*store) { 198962306a36Sopenharmony_ci *store = onoff ? default_pressure : 0; 199062306a36Sopenharmony_ci input_report_abs(wdata->extension.input, code, *store); 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci} 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_cistatic void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci __u8 pressure, which, none, hhp, sx, sy; 199762306a36Sopenharmony_ci __u8 o, r, y, g, b, bass, bm, bp; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 200062306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 200162306a36Sopenharmony_ci * 1 | 0 | 0 | SX <5:0> | 200262306a36Sopenharmony_ci * 2 | 0 | 0 | SY <5:0> | 200362306a36Sopenharmony_ci * -----+-----+-----+-----------------------------+-----+ 200462306a36Sopenharmony_ci * 3 | HPP | NON | WHICH <5:1> | ? | 200562306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 200662306a36Sopenharmony_ci * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | 200762306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 200862306a36Sopenharmony_ci * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? | 200962306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 201062306a36Sopenharmony_ci * 6 | O | R | Y | G | B | BSS | 1 | 1 | 201162306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 201262306a36Sopenharmony_ci * All buttons are 0 if pressed 201362306a36Sopenharmony_ci * 201462306a36Sopenharmony_ci * With Motion+ enabled, the following bits will get invalid: 201562306a36Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 201662306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 201762306a36Sopenharmony_ci * 1 | 0 | 0 | SX <5:1> |XXXXX| 201862306a36Sopenharmony_ci * 2 | 0 | 0 | SY <5:1> |XXXXX| 201962306a36Sopenharmony_ci * -----+-----+-----+-----------------------------+-----+ 202062306a36Sopenharmony_ci * 3 | HPP | NON | WHICH <5:1> | ? | 202162306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 202262306a36Sopenharmony_ci * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | 202362306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 202462306a36Sopenharmony_ci * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX| 202562306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 202662306a36Sopenharmony_ci * 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX| 202762306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci pressure = 7 - (ext[3] >> 5); 203162306a36Sopenharmony_ci which = (ext[2] >> 1) & 0x1f; 203262306a36Sopenharmony_ci none = !!(ext[2] & 0x40); 203362306a36Sopenharmony_ci hhp = !(ext[2] & 0x80); 203462306a36Sopenharmony_ci sx = ext[0] & 0x3f; 203562306a36Sopenharmony_ci sy = ext[1] & 0x3f; 203662306a36Sopenharmony_ci o = !(ext[5] & 0x80); 203762306a36Sopenharmony_ci r = !(ext[5] & 0x40); 203862306a36Sopenharmony_ci y = !(ext[5] & 0x20); 203962306a36Sopenharmony_ci g = !(ext[5] & 0x10); 204062306a36Sopenharmony_ci b = !(ext[5] & 0x08); 204162306a36Sopenharmony_ci bass = !(ext[5] & 0x04); 204262306a36Sopenharmony_ci bm = !(ext[4] & 0x10); 204362306a36Sopenharmony_ci bp = !(ext[4] & 0x04); 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 204662306a36Sopenharmony_ci sx &= 0x3e; 204762306a36Sopenharmony_ci sy &= 0x3e; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 205162306a36Sopenharmony_ci o, &wdata->state.pressure_drums[0], 205262306a36Sopenharmony_ci ABS_HAT2Y, 0x0e); 205362306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 205462306a36Sopenharmony_ci r, &wdata->state.pressure_drums[1], 205562306a36Sopenharmony_ci ABS_HAT0X, 0x19); 205662306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 205762306a36Sopenharmony_ci y, &wdata->state.pressure_drums[2], 205862306a36Sopenharmony_ci ABS_HAT2X, 0x11); 205962306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 206062306a36Sopenharmony_ci g, &wdata->state.pressure_drums[3], 206162306a36Sopenharmony_ci ABS_HAT1X, 0x12); 206262306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, which, pressure, 206362306a36Sopenharmony_ci b, &wdata->state.pressure_drums[4], 206462306a36Sopenharmony_ci ABS_HAT0Y, 0x0f); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci /* Bass shares pressure with hi-hat (set via hhp) */ 206762306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure, 206862306a36Sopenharmony_ci bass, &wdata->state.pressure_drums[5], 206962306a36Sopenharmony_ci ABS_HAT3X, 0x1b); 207062306a36Sopenharmony_ci /* Hi-hat has no on/off values, just pressure. Force to off/0. */ 207162306a36Sopenharmony_ci wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure, 207262306a36Sopenharmony_ci 0, &wdata->state.pressure_drums[6], 207362306a36Sopenharmony_ci ABS_HAT3Y, 0x0e); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); 207662306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci input_report_key(wdata->extension.input, BTN_START, bp); 207962306a36Sopenharmony_ci input_report_key(wdata->extension.input, BTN_SELECT, bm); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci input_sync(wdata->extension.input); 208262306a36Sopenharmony_ci} 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_cistatic int wiimod_drums_open(struct input_dev *dev) 208562306a36Sopenharmony_ci{ 208662306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 208762306a36Sopenharmony_ci unsigned long flags; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 209062306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 209162306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 209262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci return 0; 209562306a36Sopenharmony_ci} 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_cistatic void wiimod_drums_close(struct input_dev *dev) 209862306a36Sopenharmony_ci{ 209962306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 210062306a36Sopenharmony_ci unsigned long flags; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 210362306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 210462306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 210562306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_cistatic int wiimod_drums_probe(const struct wiimod_ops *ops, 210962306a36Sopenharmony_ci struct wiimote_data *wdata) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci int ret; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 211462306a36Sopenharmony_ci if (!wdata->extension.input) 211562306a36Sopenharmony_ci return -ENOMEM; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 211862306a36Sopenharmony_ci wdata->extension.input->open = wiimod_drums_open; 211962306a36Sopenharmony_ci wdata->extension.input->close = wiimod_drums_close; 212062306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 212162306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 212262306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 212362306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 212462306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 212562306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Drums"; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 212862306a36Sopenharmony_ci set_bit(BTN_START, wdata->extension.input->keybit); 212962306a36Sopenharmony_ci set_bit(BTN_SELECT, wdata->extension.input->keybit); 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 213262306a36Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 213362306a36Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 213462306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 213562306a36Sopenharmony_ci set_bit(ABS_HAT0Y, wdata->extension.input->absbit); 213662306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 213762306a36Sopenharmony_ci set_bit(ABS_HAT2X, wdata->extension.input->absbit); 213862306a36Sopenharmony_ci set_bit(ABS_HAT2Y, wdata->extension.input->absbit); 213962306a36Sopenharmony_ci set_bit(ABS_HAT3X, wdata->extension.input->absbit); 214062306a36Sopenharmony_ci set_bit(ABS_HAT3Y, wdata->extension.input->absbit); 214162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 214262306a36Sopenharmony_ci ABS_X, -32, 31, 1, 1); 214362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 214462306a36Sopenharmony_ci ABS_Y, -32, 31, 1, 1); 214562306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 214662306a36Sopenharmony_ci ABS_HAT0X, 0, 7, 0, 0); 214762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 214862306a36Sopenharmony_ci ABS_HAT0Y, 0, 7, 0, 0); 214962306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 215062306a36Sopenharmony_ci ABS_HAT1X, 0, 7, 0, 0); 215162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 215262306a36Sopenharmony_ci ABS_HAT2X, 0, 7, 0, 0); 215362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 215462306a36Sopenharmony_ci ABS_HAT2Y, 0, 7, 0, 0); 215562306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 215662306a36Sopenharmony_ci ABS_HAT3X, 0, 7, 0, 0); 215762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 215862306a36Sopenharmony_ci ABS_HAT3Y, 0, 7, 0, 0); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 216162306a36Sopenharmony_ci if (ret) 216262306a36Sopenharmony_ci goto err_free; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci return 0; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_cierr_free: 216762306a36Sopenharmony_ci input_free_device(wdata->extension.input); 216862306a36Sopenharmony_ci wdata->extension.input = NULL; 216962306a36Sopenharmony_ci return ret; 217062306a36Sopenharmony_ci} 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_cistatic void wiimod_drums_remove(const struct wiimod_ops *ops, 217362306a36Sopenharmony_ci struct wiimote_data *wdata) 217462306a36Sopenharmony_ci{ 217562306a36Sopenharmony_ci if (!wdata->extension.input) 217662306a36Sopenharmony_ci return; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 217962306a36Sopenharmony_ci wdata->extension.input = NULL; 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_drums = { 218362306a36Sopenharmony_ci .flags = 0, 218462306a36Sopenharmony_ci .arg = 0, 218562306a36Sopenharmony_ci .probe = wiimod_drums_probe, 218662306a36Sopenharmony_ci .remove = wiimod_drums_remove, 218762306a36Sopenharmony_ci .in_ext = wiimod_drums_in_ext, 218862306a36Sopenharmony_ci}; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci/* 219162306a36Sopenharmony_ci * Guitar 219262306a36Sopenharmony_ci * Guitar-Hero, Rock-Band and other games came bundled with guitars which can 219362306a36Sopenharmony_ci * be plugged as extension to a Wiimote. 219462306a36Sopenharmony_ci * We create a separate device for guitars and report all information via this 219562306a36Sopenharmony_ci * input device. 219662306a36Sopenharmony_ci */ 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_cienum wiimod_guitar_keys { 219962306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_G, 220062306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_R, 220162306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_Y, 220262306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_B, 220362306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_O, 220462306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_UP, 220562306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_DOWN, 220662306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_PLUS, 220762306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_MINUS, 220862306a36Sopenharmony_ci WIIMOD_GUITAR_KEY_NUM, 220962306a36Sopenharmony_ci}; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic const __u16 wiimod_guitar_map[] = { 221262306a36Sopenharmony_ci BTN_1, /* WIIMOD_GUITAR_KEY_G */ 221362306a36Sopenharmony_ci BTN_2, /* WIIMOD_GUITAR_KEY_R */ 221462306a36Sopenharmony_ci BTN_3, /* WIIMOD_GUITAR_KEY_Y */ 221562306a36Sopenharmony_ci BTN_4, /* WIIMOD_GUITAR_KEY_B */ 221662306a36Sopenharmony_ci BTN_5, /* WIIMOD_GUITAR_KEY_O */ 221762306a36Sopenharmony_ci BTN_DPAD_UP, /* WIIMOD_GUITAR_KEY_UP */ 221862306a36Sopenharmony_ci BTN_DPAD_DOWN, /* WIIMOD_GUITAR_KEY_DOWN */ 221962306a36Sopenharmony_ci BTN_START, /* WIIMOD_GUITAR_KEY_PLUS */ 222062306a36Sopenharmony_ci BTN_SELECT, /* WIIMOD_GUITAR_KEY_MINUS */ 222162306a36Sopenharmony_ci}; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_cistatic void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 222862306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 222962306a36Sopenharmony_ci * 1 | 0 | 0 | SX <5:0> | 223062306a36Sopenharmony_ci * 2 | 0 | 0 | SY <5:0> | 223162306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 223262306a36Sopenharmony_ci * 3 | 0 | 0 | 0 | TB <4:0> | 223362306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 223462306a36Sopenharmony_ci * 4 | 0 | 0 | 0 | WB <4:0> | 223562306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 223662306a36Sopenharmony_ci * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 | 223762306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 223862306a36Sopenharmony_ci * 6 | BO | BR | BB | BG | BY | 1 | 1 | BU | 223962306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 224062306a36Sopenharmony_ci * All buttons are 0 if pressed 224162306a36Sopenharmony_ci * 224262306a36Sopenharmony_ci * With Motion+ enabled, it will look like this: 224362306a36Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 224462306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 224562306a36Sopenharmony_ci * 1 | 0 | 0 | SX <5:1> | BU | 224662306a36Sopenharmony_ci * 2 | 0 | 0 | SY <5:1> | 1 | 224762306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------+-----+ 224862306a36Sopenharmony_ci * 3 | 0 | 0 | 0 | TB <4:0> | 224962306a36Sopenharmony_ci * -----+-----+-----+-----+-----------------------------+ 225062306a36Sopenharmony_ci * 4 | 0 | 0 | 0 | WB <4:0> | 225162306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 225262306a36Sopenharmony_ci * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX| 225362306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 225462306a36Sopenharmony_ci * 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX| 225562306a36Sopenharmony_ci * -----+-----+-----+-----+-----+-----+-----+-----+-----+ 225662306a36Sopenharmony_ci */ 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci sx = ext[0] & 0x3f; 225962306a36Sopenharmony_ci sy = ext[1] & 0x3f; 226062306a36Sopenharmony_ci tb = ext[2] & 0x1f; 226162306a36Sopenharmony_ci wb = ext[3] & 0x1f; 226262306a36Sopenharmony_ci bd = !(ext[4] & 0x40); 226362306a36Sopenharmony_ci bm = !(ext[4] & 0x10); 226462306a36Sopenharmony_ci bp = !(ext[4] & 0x04); 226562306a36Sopenharmony_ci bo = !(ext[5] & 0x80); 226662306a36Sopenharmony_ci br = !(ext[5] & 0x40); 226762306a36Sopenharmony_ci bb = !(ext[5] & 0x20); 226862306a36Sopenharmony_ci bg = !(ext[5] & 0x10); 226962306a36Sopenharmony_ci by = !(ext[5] & 0x08); 227062306a36Sopenharmony_ci bu = !(ext[5] & 0x01); 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 227362306a36Sopenharmony_ci bu = !(ext[0] & 0x01); 227462306a36Sopenharmony_ci sx &= 0x3e; 227562306a36Sopenharmony_ci sy &= 0x3e; 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); 227962306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); 228062306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, tb); 228162306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, wb - 0x10); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci input_report_key(wdata->extension.input, 228462306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], 228562306a36Sopenharmony_ci bg); 228662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 228762306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], 228862306a36Sopenharmony_ci br); 228962306a36Sopenharmony_ci input_report_key(wdata->extension.input, 229062306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], 229162306a36Sopenharmony_ci by); 229262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 229362306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], 229462306a36Sopenharmony_ci bb); 229562306a36Sopenharmony_ci input_report_key(wdata->extension.input, 229662306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], 229762306a36Sopenharmony_ci bo); 229862306a36Sopenharmony_ci input_report_key(wdata->extension.input, 229962306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], 230062306a36Sopenharmony_ci bu); 230162306a36Sopenharmony_ci input_report_key(wdata->extension.input, 230262306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], 230362306a36Sopenharmony_ci bd); 230462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 230562306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], 230662306a36Sopenharmony_ci bp); 230762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 230862306a36Sopenharmony_ci wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], 230962306a36Sopenharmony_ci bm); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci input_sync(wdata->extension.input); 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cistatic int wiimod_guitar_open(struct input_dev *dev) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 231762306a36Sopenharmony_ci unsigned long flags; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 232062306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 232162306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 232262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci return 0; 232562306a36Sopenharmony_ci} 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_cistatic void wiimod_guitar_close(struct input_dev *dev) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 233062306a36Sopenharmony_ci unsigned long flags; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 233362306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 233462306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 233562306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 233662306a36Sopenharmony_ci} 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_cistatic int wiimod_guitar_probe(const struct wiimod_ops *ops, 233962306a36Sopenharmony_ci struct wiimote_data *wdata) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci int ret, i; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 234462306a36Sopenharmony_ci if (!wdata->extension.input) 234562306a36Sopenharmony_ci return -ENOMEM; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 234862306a36Sopenharmony_ci wdata->extension.input->open = wiimod_guitar_open; 234962306a36Sopenharmony_ci wdata->extension.input->close = wiimod_guitar_close; 235062306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 235162306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 235262306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 235362306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 235462306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 235562306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Guitar"; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 235862306a36Sopenharmony_ci for (i = 0; i < WIIMOD_GUITAR_KEY_NUM; ++i) 235962306a36Sopenharmony_ci set_bit(wiimod_guitar_map[i], 236062306a36Sopenharmony_ci wdata->extension.input->keybit); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 236362306a36Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 236462306a36Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 236562306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 236662306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 236762306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 236862306a36Sopenharmony_ci ABS_X, -32, 31, 1, 1); 236962306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 237062306a36Sopenharmony_ci ABS_Y, -32, 31, 1, 1); 237162306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 237262306a36Sopenharmony_ci ABS_HAT0X, 0, 0x1f, 1, 1); 237362306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 237462306a36Sopenharmony_ci ABS_HAT1X, 0, 0x0f, 1, 1); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 237762306a36Sopenharmony_ci if (ret) 237862306a36Sopenharmony_ci goto err_free; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci return 0; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cierr_free: 238362306a36Sopenharmony_ci input_free_device(wdata->extension.input); 238462306a36Sopenharmony_ci wdata->extension.input = NULL; 238562306a36Sopenharmony_ci return ret; 238662306a36Sopenharmony_ci} 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_cistatic void wiimod_guitar_remove(const struct wiimod_ops *ops, 238962306a36Sopenharmony_ci struct wiimote_data *wdata) 239062306a36Sopenharmony_ci{ 239162306a36Sopenharmony_ci if (!wdata->extension.input) 239262306a36Sopenharmony_ci return; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 239562306a36Sopenharmony_ci wdata->extension.input = NULL; 239662306a36Sopenharmony_ci} 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_guitar = { 239962306a36Sopenharmony_ci .flags = 0, 240062306a36Sopenharmony_ci .arg = 0, 240162306a36Sopenharmony_ci .probe = wiimod_guitar_probe, 240262306a36Sopenharmony_ci .remove = wiimod_guitar_remove, 240362306a36Sopenharmony_ci .in_ext = wiimod_guitar_in_ext, 240462306a36Sopenharmony_ci}; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci/* 240762306a36Sopenharmony_ci * Turntable 240862306a36Sopenharmony_ci * DJ Hero came with a Turntable Controller that was plugged in 240962306a36Sopenharmony_ci * as an extension. 241062306a36Sopenharmony_ci * We create a separate device for turntables and report all information via this 241162306a36Sopenharmony_ci * input device. 241262306a36Sopenharmony_ci*/ 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_cienum wiimod_turntable_keys { 241562306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_G_RIGHT, 241662306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_R_RIGHT, 241762306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_B_RIGHT, 241862306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_G_LEFT, 241962306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_R_LEFT, 242062306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_B_LEFT, 242162306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_EUPHORIA, 242262306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_PLUS, 242362306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_MINUS, 242462306a36Sopenharmony_ci WIIMOD_TURNTABLE_KEY_NUM 242562306a36Sopenharmony_ci}; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_cistatic const __u16 wiimod_turntable_map[] = { 242862306a36Sopenharmony_ci BTN_1, /* WIIMOD_TURNTABLE_KEY_G_RIGHT */ 242962306a36Sopenharmony_ci BTN_2, /* WIIMOD_TURNTABLE_KEY_R_RIGHT */ 243062306a36Sopenharmony_ci BTN_3, /* WIIMOD_TURNTABLE_KEY_B_RIGHT */ 243162306a36Sopenharmony_ci BTN_4, /* WIIMOD_TURNTABLE_KEY_G_LEFT */ 243262306a36Sopenharmony_ci BTN_5, /* WIIMOD_TURNTABLE_KEY_R_LEFT */ 243362306a36Sopenharmony_ci BTN_6, /* WIIMOD_TURNTABLE_KEY_B_LEFT */ 243462306a36Sopenharmony_ci BTN_7, /* WIIMOD_TURNTABLE_KEY_EUPHORIA */ 243562306a36Sopenharmony_ci BTN_START, /* WIIMOD_TURNTABLE_KEY_PLUS */ 243662306a36Sopenharmony_ci BTN_SELECT, /* WIIMOD_TURNTABLE_KEY_MINUS */ 243762306a36Sopenharmony_ci}; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_cistatic void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext) 244062306a36Sopenharmony_ci{ 244162306a36Sopenharmony_ci __u8 be, cs, sx, sy, ed, rtt, rbg, rbr, rbb, ltt, lbg, lbr, lbb, bp, bm; 244262306a36Sopenharmony_ci /* 244362306a36Sopenharmony_ci * Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 244462306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 244562306a36Sopenharmony_ci * 0 | RTT<4:3> | SX <5:0> | 244662306a36Sopenharmony_ci * 1 | RTT<2:1> | SY <5:0> | 244762306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 244862306a36Sopenharmony_ci * 2 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> | 244962306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 245062306a36Sopenharmony_ci * 3 | ED<2:0> | LTT<4:0> | 245162306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 245262306a36Sopenharmony_ci * 4 | 0 | 0 | LBR | B- | 0 | B+ | RBR | LTT<5> | 245362306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 245462306a36Sopenharmony_ci * 5 | LBB | 0 | RBG | BE | LBG | RBB | 0 | 0 | 245562306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 245662306a36Sopenharmony_ci * All pressed buttons are 0 245762306a36Sopenharmony_ci * 245862306a36Sopenharmony_ci * With Motion+ enabled, it will look like this: 245962306a36Sopenharmony_ci * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 246062306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 246162306a36Sopenharmony_ci * 1 | RTT<4:3> | SX <5:1> | 0 | 246262306a36Sopenharmony_ci * 2 | RTT<2:1> | SY <5:1> | 0 | 246362306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 246462306a36Sopenharmony_ci * 3 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> | 246562306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 246662306a36Sopenharmony_ci * 4 | ED<2:0> | LTT<4:0> | 246762306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 246862306a36Sopenharmony_ci * 5 | 0 | 0 | LBR | B- | 0 | B+ | RBR | XXXX | 246962306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 247062306a36Sopenharmony_ci * 6 | LBB | 0 | RBG | BE | LBG | RBB | XXXX | XXXX | 247162306a36Sopenharmony_ci *------+------+-----+-----+-----+-----+------+------+--------+ 247262306a36Sopenharmony_ci */ 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci be = !(ext[5] & 0x10); 247562306a36Sopenharmony_ci cs = ((ext[2] & 0x1e)); 247662306a36Sopenharmony_ci sx = ext[0] & 0x3f; 247762306a36Sopenharmony_ci sy = ext[1] & 0x3f; 247862306a36Sopenharmony_ci ed = (ext[3] & 0xe0) >> 5; 247962306a36Sopenharmony_ci rtt = ((ext[2] & 0x01) << 5 | (ext[0] & 0xc0) >> 3 | (ext[1] & 0xc0) >> 5 | ( ext[2] & 0x80 ) >> 7); 248062306a36Sopenharmony_ci ltt = ((ext[4] & 0x01) << 5 | (ext[3] & 0x1f)); 248162306a36Sopenharmony_ci rbg = !(ext[5] & 0x20); 248262306a36Sopenharmony_ci rbr = !(ext[4] & 0x02); 248362306a36Sopenharmony_ci rbb = !(ext[5] & 0x04); 248462306a36Sopenharmony_ci lbg = !(ext[5] & 0x08); 248562306a36Sopenharmony_ci lbb = !(ext[5] & 0x80); 248662306a36Sopenharmony_ci lbr = !(ext[4] & 0x20); 248762306a36Sopenharmony_ci bm = !(ext[4] & 0x10); 248862306a36Sopenharmony_ci bp = !(ext[4] & 0x04); 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { 249162306a36Sopenharmony_ci ltt = (ext[4] & 0x01) << 5; 249262306a36Sopenharmony_ci sx &= 0x3e; 249362306a36Sopenharmony_ci sy &= 0x3e; 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_X, sx); 249762306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_Y, sy); 249862306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT0X, rtt); 249962306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT1X, ltt); 250062306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT2X, cs); 250162306a36Sopenharmony_ci input_report_abs(wdata->extension.input, ABS_HAT3X, ed); 250262306a36Sopenharmony_ci input_report_key(wdata->extension.input, 250362306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_RIGHT], 250462306a36Sopenharmony_ci rbg); 250562306a36Sopenharmony_ci input_report_key(wdata->extension.input, 250662306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_RIGHT], 250762306a36Sopenharmony_ci rbr); 250862306a36Sopenharmony_ci input_report_key(wdata->extension.input, 250962306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_RIGHT], 251062306a36Sopenharmony_ci rbb); 251162306a36Sopenharmony_ci input_report_key(wdata->extension.input, 251262306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_LEFT], 251362306a36Sopenharmony_ci lbg); 251462306a36Sopenharmony_ci input_report_key(wdata->extension.input, 251562306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_LEFT], 251662306a36Sopenharmony_ci lbr); 251762306a36Sopenharmony_ci input_report_key(wdata->extension.input, 251862306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_LEFT], 251962306a36Sopenharmony_ci lbb); 252062306a36Sopenharmony_ci input_report_key(wdata->extension.input, 252162306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_EUPHORIA], 252262306a36Sopenharmony_ci be); 252362306a36Sopenharmony_ci input_report_key(wdata->extension.input, 252462306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_PLUS], 252562306a36Sopenharmony_ci bp); 252662306a36Sopenharmony_ci input_report_key(wdata->extension.input, 252762306a36Sopenharmony_ci wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_MINUS], 252862306a36Sopenharmony_ci bm); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci input_sync(wdata->extension.input); 253162306a36Sopenharmony_ci} 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_cistatic int wiimod_turntable_open(struct input_dev *dev) 253462306a36Sopenharmony_ci{ 253562306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 253662306a36Sopenharmony_ci unsigned long flags; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 253962306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; 254062306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 254162306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci return 0; 254462306a36Sopenharmony_ci} 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_cistatic void wiimod_turntable_close(struct input_dev *dev) 254762306a36Sopenharmony_ci{ 254862306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 254962306a36Sopenharmony_ci unsigned long flags; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 255262306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; 255362306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 255462306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 255562306a36Sopenharmony_ci} 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_cistatic int wiimod_turntable_probe(const struct wiimod_ops *ops, 255862306a36Sopenharmony_ci struct wiimote_data *wdata) 255962306a36Sopenharmony_ci{ 256062306a36Sopenharmony_ci int ret, i; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci wdata->extension.input = input_allocate_device(); 256362306a36Sopenharmony_ci if (!wdata->extension.input) 256462306a36Sopenharmony_ci return -ENOMEM; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci input_set_drvdata(wdata->extension.input, wdata); 256762306a36Sopenharmony_ci wdata->extension.input->open = wiimod_turntable_open; 256862306a36Sopenharmony_ci wdata->extension.input->close = wiimod_turntable_close; 256962306a36Sopenharmony_ci wdata->extension.input->dev.parent = &wdata->hdev->dev; 257062306a36Sopenharmony_ci wdata->extension.input->id.bustype = wdata->hdev->bus; 257162306a36Sopenharmony_ci wdata->extension.input->id.vendor = wdata->hdev->vendor; 257262306a36Sopenharmony_ci wdata->extension.input->id.product = wdata->hdev->product; 257362306a36Sopenharmony_ci wdata->extension.input->id.version = wdata->hdev->version; 257462306a36Sopenharmony_ci wdata->extension.input->name = WIIMOTE_NAME " Turntable"; 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci set_bit(EV_KEY, wdata->extension.input->evbit); 257762306a36Sopenharmony_ci for (i = 0; i < WIIMOD_TURNTABLE_KEY_NUM; ++i) 257862306a36Sopenharmony_ci set_bit(wiimod_turntable_map[i], 257962306a36Sopenharmony_ci wdata->extension.input->keybit); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci set_bit(EV_ABS, wdata->extension.input->evbit); 258262306a36Sopenharmony_ci set_bit(ABS_X, wdata->extension.input->absbit); 258362306a36Sopenharmony_ci set_bit(ABS_Y, wdata->extension.input->absbit); 258462306a36Sopenharmony_ci set_bit(ABS_HAT0X, wdata->extension.input->absbit); 258562306a36Sopenharmony_ci set_bit(ABS_HAT1X, wdata->extension.input->absbit); 258662306a36Sopenharmony_ci set_bit(ABS_HAT2X, wdata->extension.input->absbit); 258762306a36Sopenharmony_ci set_bit(ABS_HAT3X, wdata->extension.input->absbit); 258862306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 258962306a36Sopenharmony_ci ABS_X, 0, 63, 1, 0); 259062306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 259162306a36Sopenharmony_ci ABS_Y, 63, 0, 1, 0); 259262306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 259362306a36Sopenharmony_ci ABS_HAT0X, -8, 8, 0, 0); 259462306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 259562306a36Sopenharmony_ci ABS_HAT1X, -8, 8, 0, 0); 259662306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 259762306a36Sopenharmony_ci ABS_HAT2X, 0, 31, 1, 1); 259862306a36Sopenharmony_ci input_set_abs_params(wdata->extension.input, 259962306a36Sopenharmony_ci ABS_HAT3X, 0, 7, 0, 0); 260062306a36Sopenharmony_ci ret = input_register_device(wdata->extension.input); 260162306a36Sopenharmony_ci if (ret) 260262306a36Sopenharmony_ci goto err_free; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci return 0; 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_cierr_free: 260762306a36Sopenharmony_ci input_free_device(wdata->extension.input); 260862306a36Sopenharmony_ci wdata->extension.input = NULL; 260962306a36Sopenharmony_ci return ret; 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cistatic void wiimod_turntable_remove(const struct wiimod_ops *ops, 261362306a36Sopenharmony_ci struct wiimote_data *wdata) 261462306a36Sopenharmony_ci{ 261562306a36Sopenharmony_ci if (!wdata->extension.input) 261662306a36Sopenharmony_ci return; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci input_unregister_device(wdata->extension.input); 261962306a36Sopenharmony_ci wdata->extension.input = NULL; 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_turntable = { 262362306a36Sopenharmony_ci .flags = 0, 262462306a36Sopenharmony_ci .arg = 0, 262562306a36Sopenharmony_ci .probe = wiimod_turntable_probe, 262662306a36Sopenharmony_ci .remove = wiimod_turntable_remove, 262762306a36Sopenharmony_ci .in_ext = wiimod_turntable_in_ext, 262862306a36Sopenharmony_ci}; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci/* 263162306a36Sopenharmony_ci * Builtin Motion Plus 263262306a36Sopenharmony_ci * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which 263362306a36Sopenharmony_ci * disables polling for Motion-Plus. This should be set only for devices which 263462306a36Sopenharmony_ci * don't allow MP hotplugging. 263562306a36Sopenharmony_ci */ 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_cistatic int wiimod_builtin_mp_probe(const struct wiimod_ops *ops, 263862306a36Sopenharmony_ci struct wiimote_data *wdata) 263962306a36Sopenharmony_ci{ 264062306a36Sopenharmony_ci unsigned long flags; 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 264362306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP; 264462306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci return 0; 264762306a36Sopenharmony_ci} 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_cistatic void wiimod_builtin_mp_remove(const struct wiimod_ops *ops, 265062306a36Sopenharmony_ci struct wiimote_data *wdata) 265162306a36Sopenharmony_ci{ 265262306a36Sopenharmony_ci unsigned long flags; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 265562306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP; 265662306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 265762306a36Sopenharmony_ci} 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_builtin_mp = { 266062306a36Sopenharmony_ci .flags = 0, 266162306a36Sopenharmony_ci .arg = 0, 266262306a36Sopenharmony_ci .probe = wiimod_builtin_mp_probe, 266362306a36Sopenharmony_ci .remove = wiimod_builtin_mp_remove, 266462306a36Sopenharmony_ci}; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci/* 266762306a36Sopenharmony_ci * No Motion Plus 266862306a36Sopenharmony_ci * This module simply sets the WIIPROTO_FLAG_NO_MP protocol flag which 266962306a36Sopenharmony_ci * disables motion-plus. This is needed for devices that advertise this but we 267062306a36Sopenharmony_ci * don't know how to use it (or whether it is actually present). 267162306a36Sopenharmony_ci */ 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_cistatic int wiimod_no_mp_probe(const struct wiimod_ops *ops, 267462306a36Sopenharmony_ci struct wiimote_data *wdata) 267562306a36Sopenharmony_ci{ 267662306a36Sopenharmony_ci unsigned long flags; 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 267962306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_NO_MP; 268062306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci return 0; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic void wiimod_no_mp_remove(const struct wiimod_ops *ops, 268662306a36Sopenharmony_ci struct wiimote_data *wdata) 268762306a36Sopenharmony_ci{ 268862306a36Sopenharmony_ci unsigned long flags; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 269162306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_NO_MP; 269262306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 269362306a36Sopenharmony_ci} 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_no_mp = { 269662306a36Sopenharmony_ci .flags = 0, 269762306a36Sopenharmony_ci .arg = 0, 269862306a36Sopenharmony_ci .probe = wiimod_no_mp_probe, 269962306a36Sopenharmony_ci .remove = wiimod_no_mp_remove, 270062306a36Sopenharmony_ci}; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci/* 270362306a36Sopenharmony_ci * Motion Plus 270462306a36Sopenharmony_ci * The Motion Plus extension provides rotation sensors (gyro) as a small 270562306a36Sopenharmony_ci * extension device for Wii Remotes. Many devices have them built-in so 270662306a36Sopenharmony_ci * you cannot see them from the outside. 270762306a36Sopenharmony_ci * Motion Plus extensions are special because they are on a separate extension 270862306a36Sopenharmony_ci * port and allow other extensions to be used simultaneously. This is all 270962306a36Sopenharmony_ci * handled by the Wiimote Core so we don't have to deal with it. 271062306a36Sopenharmony_ci */ 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_cistatic void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext) 271362306a36Sopenharmony_ci{ 271462306a36Sopenharmony_ci __s32 x, y, z; 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci /* | 8 7 6 5 4 3 | 2 | 1 | 271762306a36Sopenharmony_ci * -----+------------------------------+-----+-----+ 271862306a36Sopenharmony_ci * 1 | Yaw Speed <7:0> | 271962306a36Sopenharmony_ci * 2 | Roll Speed <7:0> | 272062306a36Sopenharmony_ci * 3 | Pitch Speed <7:0> | 272162306a36Sopenharmony_ci * -----+------------------------------+-----+-----+ 272262306a36Sopenharmony_ci * 4 | Yaw Speed <13:8> | Yaw |Pitch| 272362306a36Sopenharmony_ci * -----+------------------------------+-----+-----+ 272462306a36Sopenharmony_ci * 5 | Roll Speed <13:8> |Roll | Ext | 272562306a36Sopenharmony_ci * -----+------------------------------+-----+-----+ 272662306a36Sopenharmony_ci * 6 | Pitch Speed <13:8> | 1 | 0 | 272762306a36Sopenharmony_ci * -----+------------------------------+-----+-----+ 272862306a36Sopenharmony_ci * The single bits Yaw, Roll, Pitch in the lower right corner specify 272962306a36Sopenharmony_ci * whether the wiimote is rotating fast (0) or slow (1). Speed for slow 273062306a36Sopenharmony_ci * roation is 8192/440 units / deg/s and for fast rotation 8192/2000 273162306a36Sopenharmony_ci * units / deg/s. To get a linear scale for fast rotation we multiply 273262306a36Sopenharmony_ci * by 2000/440 = ~4.5454 and scale both fast and slow by 9 to match the 273362306a36Sopenharmony_ci * previous scale reported by this driver. 273462306a36Sopenharmony_ci * This leaves a linear scale with 8192*9/440 (~167.564) units / deg/s. 273562306a36Sopenharmony_ci * If the wiimote is not rotating the sensor reports 2^13 = 8192. 273662306a36Sopenharmony_ci * Ext specifies whether an extension is connected to the motionp. 273762306a36Sopenharmony_ci * which is parsed by wiimote-core. 273862306a36Sopenharmony_ci */ 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci x = ext[0]; 274162306a36Sopenharmony_ci y = ext[1]; 274262306a36Sopenharmony_ci z = ext[2]; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci x |= (((__u16)ext[3]) << 6) & 0xff00; 274562306a36Sopenharmony_ci y |= (((__u16)ext[4]) << 6) & 0xff00; 274662306a36Sopenharmony_ci z |= (((__u16)ext[5]) << 6) & 0xff00; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci x -= 8192; 274962306a36Sopenharmony_ci y -= 8192; 275062306a36Sopenharmony_ci z -= 8192; 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci if (!(ext[3] & 0x02)) 275362306a36Sopenharmony_ci x = (x * 2000 * 9) / 440; 275462306a36Sopenharmony_ci else 275562306a36Sopenharmony_ci x *= 9; 275662306a36Sopenharmony_ci if (!(ext[4] & 0x02)) 275762306a36Sopenharmony_ci y = (y * 2000 * 9) / 440; 275862306a36Sopenharmony_ci else 275962306a36Sopenharmony_ci y *= 9; 276062306a36Sopenharmony_ci if (!(ext[3] & 0x01)) 276162306a36Sopenharmony_ci z = (z * 2000 * 9) / 440; 276262306a36Sopenharmony_ci else 276362306a36Sopenharmony_ci z *= 9; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci input_report_abs(wdata->mp, ABS_RX, x); 276662306a36Sopenharmony_ci input_report_abs(wdata->mp, ABS_RY, y); 276762306a36Sopenharmony_ci input_report_abs(wdata->mp, ABS_RZ, z); 276862306a36Sopenharmony_ci input_sync(wdata->mp); 276962306a36Sopenharmony_ci} 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_cistatic int wiimod_mp_open(struct input_dev *dev) 277262306a36Sopenharmony_ci{ 277362306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 277462306a36Sopenharmony_ci unsigned long flags; 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 277762306a36Sopenharmony_ci wdata->state.flags |= WIIPROTO_FLAG_MP_USED; 277862306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 277962306a36Sopenharmony_ci __wiimote_schedule(wdata); 278062306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci return 0; 278362306a36Sopenharmony_ci} 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_cistatic void wiimod_mp_close(struct input_dev *dev) 278662306a36Sopenharmony_ci{ 278762306a36Sopenharmony_ci struct wiimote_data *wdata = input_get_drvdata(dev); 278862306a36Sopenharmony_ci unsigned long flags; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci spin_lock_irqsave(&wdata->state.lock, flags); 279162306a36Sopenharmony_ci wdata->state.flags &= ~WIIPROTO_FLAG_MP_USED; 279262306a36Sopenharmony_ci wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 279362306a36Sopenharmony_ci __wiimote_schedule(wdata); 279462306a36Sopenharmony_ci spin_unlock_irqrestore(&wdata->state.lock, flags); 279562306a36Sopenharmony_ci} 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_cistatic int wiimod_mp_probe(const struct wiimod_ops *ops, 279862306a36Sopenharmony_ci struct wiimote_data *wdata) 279962306a36Sopenharmony_ci{ 280062306a36Sopenharmony_ci int ret; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci wdata->mp = input_allocate_device(); 280362306a36Sopenharmony_ci if (!wdata->mp) 280462306a36Sopenharmony_ci return -ENOMEM; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci input_set_drvdata(wdata->mp, wdata); 280762306a36Sopenharmony_ci wdata->mp->open = wiimod_mp_open; 280862306a36Sopenharmony_ci wdata->mp->close = wiimod_mp_close; 280962306a36Sopenharmony_ci wdata->mp->dev.parent = &wdata->hdev->dev; 281062306a36Sopenharmony_ci wdata->mp->id.bustype = wdata->hdev->bus; 281162306a36Sopenharmony_ci wdata->mp->id.vendor = wdata->hdev->vendor; 281262306a36Sopenharmony_ci wdata->mp->id.product = wdata->hdev->product; 281362306a36Sopenharmony_ci wdata->mp->id.version = wdata->hdev->version; 281462306a36Sopenharmony_ci wdata->mp->name = WIIMOTE_NAME " Motion Plus"; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci set_bit(EV_ABS, wdata->mp->evbit); 281762306a36Sopenharmony_ci set_bit(ABS_RX, wdata->mp->absbit); 281862306a36Sopenharmony_ci set_bit(ABS_RY, wdata->mp->absbit); 281962306a36Sopenharmony_ci set_bit(ABS_RZ, wdata->mp->absbit); 282062306a36Sopenharmony_ci input_set_abs_params(wdata->mp, 282162306a36Sopenharmony_ci ABS_RX, -16000, 16000, 4, 8); 282262306a36Sopenharmony_ci input_set_abs_params(wdata->mp, 282362306a36Sopenharmony_ci ABS_RY, -16000, 16000, 4, 8); 282462306a36Sopenharmony_ci input_set_abs_params(wdata->mp, 282562306a36Sopenharmony_ci ABS_RZ, -16000, 16000, 4, 8); 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci ret = input_register_device(wdata->mp); 282862306a36Sopenharmony_ci if (ret) 282962306a36Sopenharmony_ci goto err_free; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci return 0; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_cierr_free: 283462306a36Sopenharmony_ci input_free_device(wdata->mp); 283562306a36Sopenharmony_ci wdata->mp = NULL; 283662306a36Sopenharmony_ci return ret; 283762306a36Sopenharmony_ci} 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_cistatic void wiimod_mp_remove(const struct wiimod_ops *ops, 284062306a36Sopenharmony_ci struct wiimote_data *wdata) 284162306a36Sopenharmony_ci{ 284262306a36Sopenharmony_ci if (!wdata->mp) 284362306a36Sopenharmony_ci return; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci input_unregister_device(wdata->mp); 284662306a36Sopenharmony_ci wdata->mp = NULL; 284762306a36Sopenharmony_ci} 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ciconst struct wiimod_ops wiimod_mp = { 285062306a36Sopenharmony_ci .flags = 0, 285162306a36Sopenharmony_ci .arg = 0, 285262306a36Sopenharmony_ci .probe = wiimod_mp_probe, 285362306a36Sopenharmony_ci .remove = wiimod_mp_remove, 285462306a36Sopenharmony_ci .in_mp = wiimod_mp_in_mp, 285562306a36Sopenharmony_ci}; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci/* module table */ 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_cistatic const struct wiimod_ops wiimod_dummy; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ciconst struct wiimod_ops *wiimod_table[WIIMOD_NUM] = { 286262306a36Sopenharmony_ci [WIIMOD_KEYS] = &wiimod_keys, 286362306a36Sopenharmony_ci [WIIMOD_RUMBLE] = &wiimod_rumble, 286462306a36Sopenharmony_ci [WIIMOD_BATTERY] = &wiimod_battery, 286562306a36Sopenharmony_ci [WIIMOD_LED1] = &wiimod_leds[0], 286662306a36Sopenharmony_ci [WIIMOD_LED2] = &wiimod_leds[1], 286762306a36Sopenharmony_ci [WIIMOD_LED3] = &wiimod_leds[2], 286862306a36Sopenharmony_ci [WIIMOD_LED4] = &wiimod_leds[3], 286962306a36Sopenharmony_ci [WIIMOD_ACCEL] = &wiimod_accel, 287062306a36Sopenharmony_ci [WIIMOD_IR] = &wiimod_ir, 287162306a36Sopenharmony_ci [WIIMOD_BUILTIN_MP] = &wiimod_builtin_mp, 287262306a36Sopenharmony_ci [WIIMOD_NO_MP] = &wiimod_no_mp, 287362306a36Sopenharmony_ci}; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ciconst struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { 287662306a36Sopenharmony_ci [WIIMOTE_EXT_NONE] = &wiimod_dummy, 287762306a36Sopenharmony_ci [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy, 287862306a36Sopenharmony_ci [WIIMOTE_EXT_NUNCHUK] = &wiimod_nunchuk, 287962306a36Sopenharmony_ci [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic, 288062306a36Sopenharmony_ci [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, 288162306a36Sopenharmony_ci [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro, 288262306a36Sopenharmony_ci [WIIMOTE_EXT_DRUMS] = &wiimod_drums, 288362306a36Sopenharmony_ci [WIIMOTE_EXT_GUITAR] = &wiimod_guitar, 288462306a36Sopenharmony_ci [WIIMOTE_EXT_TURNTABLE] = &wiimod_turntable, 288562306a36Sopenharmony_ci}; 2886