mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-10 07:00:48 +00:00
HID: wiimote: convert LEDS to modules
Each of the 4 LEDs may be supported individually by devices. Therefore, we need one module for each device. To avoid code-duplication, we simply pass the LED ID as "arg" argument to the module loading code. This just moves the code over to wiimote-module. The semantics stay the same as before. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
dcf3923138
commit
6c5ae01805
@ -14,7 +14,6 @@
|
|||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/leds.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
@ -151,7 +150,7 @@ void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
|
|||||||
wiimote_queue(wdata, cmd, sizeof(cmd));
|
wiimote_queue(wdata, cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
|
void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
|
||||||
{
|
{
|
||||||
__u8 cmd[2];
|
__u8 cmd[2];
|
||||||
|
|
||||||
@ -529,54 +528,6 @@ unlock:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
|
|
||||||
{
|
|
||||||
struct wiimote_data *wdata;
|
|
||||||
struct device *dev = led_dev->dev->parent;
|
|
||||||
int i;
|
|
||||||
unsigned long flags;
|
|
||||||
bool value = false;
|
|
||||||
|
|
||||||
wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
|
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
if (wdata->leds[i] == led_dev) {
|
|
||||||
spin_lock_irqsave(&wdata->state.lock, flags);
|
|
||||||
value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
|
|
||||||
spin_unlock_irqrestore(&wdata->state.lock, flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value ? LED_FULL : LED_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wiimote_leds_set(struct led_classdev *led_dev,
|
|
||||||
enum led_brightness value)
|
|
||||||
{
|
|
||||||
struct wiimote_data *wdata;
|
|
||||||
struct device *dev = led_dev->dev->parent;
|
|
||||||
int i;
|
|
||||||
unsigned long flags;
|
|
||||||
__u8 state, flag;
|
|
||||||
|
|
||||||
wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
|
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
if (wdata->leds[i] == led_dev) {
|
|
||||||
flag = WIIPROTO_FLAG_LED(i + 1);
|
|
||||||
spin_lock_irqsave(&wdata->state.lock, flags);
|
|
||||||
state = wdata->state.flags;
|
|
||||||
if (value == LED_OFF)
|
|
||||||
wiiproto_req_leds(wdata, state & ~flag);
|
|
||||||
else
|
|
||||||
wiiproto_req_leds(wdata, state | flag);
|
|
||||||
spin_unlock_irqrestore(&wdata->state.lock, flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wiimote_accel_open(struct input_dev *dev)
|
static int wiimote_accel_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct wiimote_data *wdata = input_get_drvdata(dev);
|
struct wiimote_data *wdata = input_get_drvdata(dev);
|
||||||
@ -626,18 +577,30 @@ static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
|
|||||||
WIIMOD_KEYS,
|
WIIMOD_KEYS,
|
||||||
WIIMOD_RUMBLE,
|
WIIMOD_RUMBLE,
|
||||||
WIIMOD_BATTERY,
|
WIIMOD_BATTERY,
|
||||||
|
WIIMOD_LED1,
|
||||||
|
WIIMOD_LED2,
|
||||||
|
WIIMOD_LED3,
|
||||||
|
WIIMOD_LED4,
|
||||||
WIIMOD_NULL,
|
WIIMOD_NULL,
|
||||||
},
|
},
|
||||||
[WIIMOTE_DEV_GEN10] = (const __u8[]){
|
[WIIMOTE_DEV_GEN10] = (const __u8[]){
|
||||||
WIIMOD_KEYS,
|
WIIMOD_KEYS,
|
||||||
WIIMOD_RUMBLE,
|
WIIMOD_RUMBLE,
|
||||||
WIIMOD_BATTERY,
|
WIIMOD_BATTERY,
|
||||||
|
WIIMOD_LED1,
|
||||||
|
WIIMOD_LED2,
|
||||||
|
WIIMOD_LED3,
|
||||||
|
WIIMOD_LED4,
|
||||||
WIIMOD_NULL,
|
WIIMOD_NULL,
|
||||||
},
|
},
|
||||||
[WIIMOTE_DEV_GEN20] = (const __u8[]){
|
[WIIMOTE_DEV_GEN20] = (const __u8[]){
|
||||||
WIIMOD_KEYS,
|
WIIMOD_KEYS,
|
||||||
WIIMOD_RUMBLE,
|
WIIMOD_RUMBLE,
|
||||||
WIIMOD_BATTERY,
|
WIIMOD_BATTERY,
|
||||||
|
WIIMOD_LED1,
|
||||||
|
WIIMOD_LED2,
|
||||||
|
WIIMOD_LED3,
|
||||||
|
WIIMOD_LED4,
|
||||||
WIIMOD_NULL,
|
WIIMOD_NULL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1159,58 +1122,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wiimote_leds_destroy(struct wiimote_data *wdata)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct led_classdev *led;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
if (wdata->leds[i]) {
|
|
||||||
led = wdata->leds[i];
|
|
||||||
wdata->leds[i] = NULL;
|
|
||||||
led_classdev_unregister(led);
|
|
||||||
kfree(led);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wiimote_leds_create(struct wiimote_data *wdata)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
struct device *dev = &wdata->hdev->dev;
|
|
||||||
size_t namesz = strlen(dev_name(dev)) + 9;
|
|
||||||
struct led_classdev *led;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
|
|
||||||
if (!led) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
name = (void*)&led[1];
|
|
||||||
snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
|
|
||||||
led->name = name;
|
|
||||||
led->brightness = 0;
|
|
||||||
led->max_brightness = 1;
|
|
||||||
led->brightness_get = wiimote_leds_get;
|
|
||||||
led->brightness_set = wiimote_leds_set;
|
|
||||||
|
|
||||||
ret = led_classdev_register(dev, led);
|
|
||||||
if (ret) {
|
|
||||||
kfree(led);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
wdata->leds[i] = led;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
wiimote_leds_destroy(wdata);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
|
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
struct wiimote_data *wdata;
|
struct wiimote_data *wdata;
|
||||||
@ -1300,7 +1211,6 @@ static void wiimote_destroy(struct wiimote_data *wdata)
|
|||||||
{
|
{
|
||||||
wiidebug_deinit(wdata);
|
wiidebug_deinit(wdata);
|
||||||
wiiext_deinit(wdata);
|
wiiext_deinit(wdata);
|
||||||
wiimote_leds_destroy(wdata);
|
|
||||||
|
|
||||||
cancel_work_sync(&wdata->init_worker);
|
cancel_work_sync(&wdata->init_worker);
|
||||||
wiimote_modules_unload(wdata);
|
wiimote_modules_unload(wdata);
|
||||||
@ -1357,10 +1267,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
|
|||||||
goto err_ir;
|
goto err_ir;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wiimote_leds_create(wdata);
|
|
||||||
if (ret)
|
|
||||||
goto err_free;
|
|
||||||
|
|
||||||
ret = wiiext_init(wdata);
|
ret = wiiext_init(wdata);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
@ -1371,11 +1277,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
|
|||||||
|
|
||||||
hid_info(hdev, "New device registered\n");
|
hid_info(hdev, "New device registered\n");
|
||||||
|
|
||||||
/* by default set led1 after device initialization */
|
|
||||||
spin_lock_irq(&wdata->state.lock);
|
|
||||||
wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
|
|
||||||
spin_unlock_irq(&wdata->state.lock);
|
|
||||||
|
|
||||||
/* schedule device detection */
|
/* schedule device detection */
|
||||||
schedule_work(&wdata->init_worker);
|
schedule_work(&wdata->init_worker);
|
||||||
|
|
||||||
|
@ -268,10 +268,150 @@ static const struct wiimod_ops wiimod_battery = {
|
|||||||
.remove = wiimod_battery_remove,
|
.remove = wiimod_battery_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LED
|
||||||
|
* 0 to 4 player LEDs are supported by devices. The "arg" field of the
|
||||||
|
* wiimod_ops structure specifies which LED this module controls. This allows
|
||||||
|
* to register a limited number of LEDs.
|
||||||
|
* State is managed by wiimote core.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
|
||||||
|
{
|
||||||
|
struct wiimote_data *wdata;
|
||||||
|
struct device *dev = led_dev->dev->parent;
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
bool value = false;
|
||||||
|
|
||||||
|
wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if (wdata->leds[i] == led_dev) {
|
||||||
|
spin_lock_irqsave(&wdata->state.lock, flags);
|
||||||
|
value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
|
||||||
|
spin_unlock_irqrestore(&wdata->state.lock, flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value ? LED_FULL : LED_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wiimod_led_set(struct led_classdev *led_dev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
struct wiimote_data *wdata;
|
||||||
|
struct device *dev = led_dev->dev->parent;
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
__u8 state, flag;
|
||||||
|
|
||||||
|
wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if (wdata->leds[i] == led_dev) {
|
||||||
|
flag = WIIPROTO_FLAG_LED(i + 1);
|
||||||
|
spin_lock_irqsave(&wdata->state.lock, flags);
|
||||||
|
state = wdata->state.flags;
|
||||||
|
if (value == LED_OFF)
|
||||||
|
wiiproto_req_leds(wdata, state & ~flag);
|
||||||
|
else
|
||||||
|
wiiproto_req_leds(wdata, state | flag);
|
||||||
|
spin_unlock_irqrestore(&wdata->state.lock, flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wiimod_led_probe(const struct wiimod_ops *ops,
|
||||||
|
struct wiimote_data *wdata)
|
||||||
|
{
|
||||||
|
struct device *dev = &wdata->hdev->dev;
|
||||||
|
size_t namesz = strlen(dev_name(dev)) + 9;
|
||||||
|
struct led_classdev *led;
|
||||||
|
unsigned long flags;
|
||||||
|
char *name;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
|
||||||
|
if (!led)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
name = (void*)&led[1];
|
||||||
|
snprintf(name, namesz, "%s:blue:p%lu", dev_name(dev), ops->arg);
|
||||||
|
led->name = name;
|
||||||
|
led->brightness = 0;
|
||||||
|
led->max_brightness = 1;
|
||||||
|
led->brightness_get = wiimod_led_get;
|
||||||
|
led->brightness_set = wiimod_led_set;
|
||||||
|
|
||||||
|
wdata->leds[ops->arg] = led;
|
||||||
|
ret = led_classdev_register(dev, led);
|
||||||
|
if (ret)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
|
/* enable LED1 to stop initial LED-blinking */
|
||||||
|
if (ops->arg == 0) {
|
||||||
|
spin_lock_irqsave(&wdata->state.lock, flags);
|
||||||
|
wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
|
||||||
|
spin_unlock_irqrestore(&wdata->state.lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
wdata->leds[ops->arg] = NULL;
|
||||||
|
kfree(led);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wiimod_led_remove(const struct wiimod_ops *ops,
|
||||||
|
struct wiimote_data *wdata)
|
||||||
|
{
|
||||||
|
if (!wdata->leds[ops->arg])
|
||||||
|
return;
|
||||||
|
|
||||||
|
led_classdev_unregister(wdata->leds[ops->arg]);
|
||||||
|
kfree(wdata->leds[ops->arg]);
|
||||||
|
wdata->leds[ops->arg] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wiimod_ops wiimod_leds[4] = {
|
||||||
|
{
|
||||||
|
.flags = 0,
|
||||||
|
.arg = 0,
|
||||||
|
.probe = wiimod_led_probe,
|
||||||
|
.remove = wiimod_led_remove,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.flags = 0,
|
||||||
|
.arg = 1,
|
||||||
|
.probe = wiimod_led_probe,
|
||||||
|
.remove = wiimod_led_remove,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.flags = 0,
|
||||||
|
.arg = 2,
|
||||||
|
.probe = wiimod_led_probe,
|
||||||
|
.remove = wiimod_led_remove,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.flags = 0,
|
||||||
|
.arg = 3,
|
||||||
|
.probe = wiimod_led_probe,
|
||||||
|
.remove = wiimod_led_remove,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* module table */
|
/* module table */
|
||||||
|
|
||||||
const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
|
const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
|
||||||
[WIIMOD_KEYS] = &wiimod_keys,
|
[WIIMOD_KEYS] = &wiimod_keys,
|
||||||
[WIIMOD_RUMBLE] = &wiimod_rumble,
|
[WIIMOD_RUMBLE] = &wiimod_rumble,
|
||||||
[WIIMOD_BATTERY] = &wiimod_battery,
|
[WIIMOD_BATTERY] = &wiimod_battery,
|
||||||
|
[WIIMOD_LED1] = &wiimod_leds[0],
|
||||||
|
[WIIMOD_LED2] = &wiimod_leds[1],
|
||||||
|
[WIIMOD_LED3] = &wiimod_leds[2],
|
||||||
|
[WIIMOD_LED4] = &wiimod_leds[3],
|
||||||
};
|
};
|
||||||
|
@ -129,6 +129,10 @@ enum wiimod_module {
|
|||||||
WIIMOD_KEYS,
|
WIIMOD_KEYS,
|
||||||
WIIMOD_RUMBLE,
|
WIIMOD_RUMBLE,
|
||||||
WIIMOD_BATTERY,
|
WIIMOD_BATTERY,
|
||||||
|
WIIMOD_LED1,
|
||||||
|
WIIMOD_LED2,
|
||||||
|
WIIMOD_LED3,
|
||||||
|
WIIMOD_LED4,
|
||||||
WIIMOD_NUM,
|
WIIMOD_NUM,
|
||||||
WIIMOD_NULL = WIIMOD_NUM,
|
WIIMOD_NULL = WIIMOD_NUM,
|
||||||
};
|
};
|
||||||
@ -185,6 +189,7 @@ enum wiiproto_reqs {
|
|||||||
|
|
||||||
extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
|
extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
|
||||||
extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble);
|
extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble);
|
||||||
|
extern void wiiproto_req_leds(struct wiimote_data *wdata, int leds);
|
||||||
extern void wiiproto_req_status(struct wiimote_data *wdata);
|
extern void wiiproto_req_status(struct wiimote_data *wdata);
|
||||||
extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
|
extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
|
||||||
const __u8 *wmem, __u8 size);
|
const __u8 *wmem, __u8 size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user