linux_dsm_epyc7002/drivers/hid/hid-wiimote-modules.c

180 lines
5.7 KiB
C
Raw Normal View History

/*
* Device Modules for Nintendo Wii / Wii U HID Driver
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
/*
* Wiimote Modules
* Nintendo devices provide different peripherals and many new devices lack
* initial features like the IR camera. Therefore, each peripheral device is
* implemented as an independent module and we probe on each device only the
* modules for the hardware that really is available.
*
* Module registration is sequential. Unregistration is done in reverse order.
* After device detection, the needed modules are loaded. Users can trigger
* re-detection which causes all modules to be unloaded and then reload the
* modules for the new detected device.
*
* wdata->input is a shared input device. It is always initialized prior to
* module registration. If at least one registered module is marked as
* WIIMOD_FLAG_INPUT, then the input device will get registered after all
* modules were registered.
* Please note that it is unregistered _before_ the "remove" callbacks are
* called. This guarantees that no input interaction is done, anymore. However,
* the wiimote core keeps a reference to the input device so it is freed only
* after all modules were removed. It is safe to send events to unregistered
* input devices.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/spinlock.h>
#include "hid-wiimote.h"
/*
* Keys
* The initial Wii Remote provided a bunch of buttons that are reported as
* part of the core protocol. Many later devices dropped these and report
* invalid data in the core button reports. Load this only on devices which
* correctly send button reports.
* It uses the shared input device.
*/
static const __u16 wiimod_keys_map[] = {
KEY_LEFT, /* WIIPROTO_KEY_LEFT */
KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */
KEY_UP, /* WIIPROTO_KEY_UP */
KEY_DOWN, /* WIIPROTO_KEY_DOWN */
KEY_NEXT, /* WIIPROTO_KEY_PLUS */
KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */
BTN_1, /* WIIPROTO_KEY_ONE */
BTN_2, /* WIIPROTO_KEY_TWO */
BTN_A, /* WIIPROTO_KEY_A */
BTN_B, /* WIIPROTO_KEY_B */
BTN_MODE, /* WIIPROTO_KEY_HOME */
};
static void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys)
{
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT],
!!(keys[0] & 0x01));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT],
!!(keys[0] & 0x02));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN],
!!(keys[0] & 0x04));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP],
!!(keys[0] & 0x08));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS],
!!(keys[0] & 0x10));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO],
!!(keys[1] & 0x01));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE],
!!(keys[1] & 0x02));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B],
!!(keys[1] & 0x04));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A],
!!(keys[1] & 0x08));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS],
!!(keys[1] & 0x10));
input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME],
!!(keys[1] & 0x80));
input_sync(wdata->input);
}
static int wiimod_keys_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
unsigned int i;
set_bit(EV_KEY, wdata->input->evbit);
for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
set_bit(wiimod_keys_map[i], wdata->input->keybit);
return 0;
}
static const struct wiimod_ops wiimod_keys = {
.flags = WIIMOD_FLAG_INPUT,
.arg = 0,
.probe = wiimod_keys_probe,
.remove = NULL,
.in_keys = wiimod_keys_in_keys,
};
/*
* Rumble
* Nearly all devices provide a rumble feature. A small motor for
* force-feedback effects. We provide an FF_RUMBLE memless ff device on the
* shared input device if this module is loaded.
* The rumble motor is controlled via a flag on almost every output report so
* the wiimote core handles the rumble flag. But if a device doesn't provide
* the rumble motor, this flag shouldn't be set.
*/
static int wiimod_rumble_play(struct input_dev *dev, void *data,
struct ff_effect *eff)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
__u8 value;
unsigned long flags;
/*
* The wiimote supports only a single rumble motor so if any magnitude
* is set to non-zero then we start the rumble motor. If both are set to
* zero, we stop the rumble motor.
*/
if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
value = 1;
else
value = 0;
spin_lock_irqsave(&wdata->state.lock, flags);
wiiproto_req_rumble(wdata, value);
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
static int wiimod_rumble_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
set_bit(FF_RUMBLE, wdata->input->ffbit);
if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
return -ENOMEM;
return 0;
}
static void wiimod_rumble_remove(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wiiproto_req_rumble(wdata, 0);
spin_unlock_irqrestore(&wdata->state.lock, flags);
}
static const struct wiimod_ops wiimod_rumble = {
.flags = WIIMOD_FLAG_INPUT,
.arg = 0,
.probe = wiimod_rumble_probe,
.remove = wiimod_rumble_remove,
};
/* module table */
const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
[WIIMOD_KEYS] = &wiimod_keys,
[WIIMOD_RUMBLE] = &wiimod_rumble,
};