162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci#ifndef __HID_WIIMOTE_H 362306a36Sopenharmony_ci#define __HID_WIIMOTE_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * HID driver for Nintendo Wii / Wii U peripherals 762306a36Sopenharmony_ci * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/completion.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/hid.h> 1662306a36Sopenharmony_ci#include <linux/input.h> 1762306a36Sopenharmony_ci#include <linux/leds.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci#include <linux/power_supply.h> 2162306a36Sopenharmony_ci#include <linux/spinlock.h> 2262306a36Sopenharmony_ci#include <linux/timer.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define WIIMOTE_NAME "Nintendo Wii Remote" 2562306a36Sopenharmony_ci#define WIIMOTE_BUFSIZE 32 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define WIIPROTO_FLAG_LED1 0x01 2862306a36Sopenharmony_ci#define WIIPROTO_FLAG_LED2 0x02 2962306a36Sopenharmony_ci#define WIIPROTO_FLAG_LED3 0x04 3062306a36Sopenharmony_ci#define WIIPROTO_FLAG_LED4 0x08 3162306a36Sopenharmony_ci#define WIIPROTO_FLAG_RUMBLE 0x10 3262306a36Sopenharmony_ci#define WIIPROTO_FLAG_ACCEL 0x20 3362306a36Sopenharmony_ci#define WIIPROTO_FLAG_IR_BASIC 0x40 3462306a36Sopenharmony_ci#define WIIPROTO_FLAG_IR_EXT 0x80 3562306a36Sopenharmony_ci#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */ 3662306a36Sopenharmony_ci#define WIIPROTO_FLAG_EXT_PLUGGED 0x0100 3762306a36Sopenharmony_ci#define WIIPROTO_FLAG_EXT_USED 0x0200 3862306a36Sopenharmony_ci#define WIIPROTO_FLAG_EXT_ACTIVE 0x0400 3962306a36Sopenharmony_ci#define WIIPROTO_FLAG_MP_PLUGGED 0x0800 4062306a36Sopenharmony_ci#define WIIPROTO_FLAG_MP_USED 0x1000 4162306a36Sopenharmony_ci#define WIIPROTO_FLAG_MP_ACTIVE 0x2000 4262306a36Sopenharmony_ci#define WIIPROTO_FLAG_EXITING 0x4000 4362306a36Sopenharmony_ci#define WIIPROTO_FLAG_DRM_LOCKED 0x8000 4462306a36Sopenharmony_ci#define WIIPROTO_FLAG_BUILTIN_MP 0x010000 4562306a36Sopenharmony_ci#define WIIPROTO_FLAG_NO_MP 0x020000 4662306a36Sopenharmony_ci#define WIIPROTO_FLAG_PRO_CALIB_DONE 0x040000 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ 4962306a36Sopenharmony_ci WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) 5062306a36Sopenharmony_ci#define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \ 5162306a36Sopenharmony_ci WIIPROTO_FLAG_IR_FULL) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* return flag for led \num */ 5462306a36Sopenharmony_ci#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cienum wiiproto_keys { 5762306a36Sopenharmony_ci WIIPROTO_KEY_LEFT, 5862306a36Sopenharmony_ci WIIPROTO_KEY_RIGHT, 5962306a36Sopenharmony_ci WIIPROTO_KEY_UP, 6062306a36Sopenharmony_ci WIIPROTO_KEY_DOWN, 6162306a36Sopenharmony_ci WIIPROTO_KEY_PLUS, 6262306a36Sopenharmony_ci WIIPROTO_KEY_MINUS, 6362306a36Sopenharmony_ci WIIPROTO_KEY_ONE, 6462306a36Sopenharmony_ci WIIPROTO_KEY_TWO, 6562306a36Sopenharmony_ci WIIPROTO_KEY_A, 6662306a36Sopenharmony_ci WIIPROTO_KEY_B, 6762306a36Sopenharmony_ci WIIPROTO_KEY_HOME, 6862306a36Sopenharmony_ci WIIPROTO_KEY_COUNT 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cienum wiimote_devtype { 7262306a36Sopenharmony_ci WIIMOTE_DEV_PENDING, 7362306a36Sopenharmony_ci WIIMOTE_DEV_UNKNOWN, 7462306a36Sopenharmony_ci WIIMOTE_DEV_GENERIC, 7562306a36Sopenharmony_ci WIIMOTE_DEV_GEN10, 7662306a36Sopenharmony_ci WIIMOTE_DEV_GEN20, 7762306a36Sopenharmony_ci WIIMOTE_DEV_BALANCE_BOARD, 7862306a36Sopenharmony_ci WIIMOTE_DEV_PRO_CONTROLLER, 7962306a36Sopenharmony_ci WIIMOTE_DEV_NUM, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cienum wiimote_exttype { 8362306a36Sopenharmony_ci WIIMOTE_EXT_NONE, 8462306a36Sopenharmony_ci WIIMOTE_EXT_UNKNOWN, 8562306a36Sopenharmony_ci WIIMOTE_EXT_NUNCHUK, 8662306a36Sopenharmony_ci WIIMOTE_EXT_CLASSIC_CONTROLLER, 8762306a36Sopenharmony_ci WIIMOTE_EXT_BALANCE_BOARD, 8862306a36Sopenharmony_ci WIIMOTE_EXT_PRO_CONTROLLER, 8962306a36Sopenharmony_ci WIIMOTE_EXT_DRUMS, 9062306a36Sopenharmony_ci WIIMOTE_EXT_GUITAR, 9162306a36Sopenharmony_ci WIIMOTE_EXT_TURNTABLE, 9262306a36Sopenharmony_ci WIIMOTE_EXT_NUM, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cienum wiimote_mptype { 9662306a36Sopenharmony_ci WIIMOTE_MP_NONE, 9762306a36Sopenharmony_ci WIIMOTE_MP_UNKNOWN, 9862306a36Sopenharmony_ci WIIMOTE_MP_SINGLE, 9962306a36Sopenharmony_ci WIIMOTE_MP_PASSTHROUGH_NUNCHUK, 10062306a36Sopenharmony_ci WIIMOTE_MP_PASSTHROUGH_CLASSIC, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct wiimote_buf { 10462306a36Sopenharmony_ci __u8 data[HID_MAX_BUFFER_SIZE]; 10562306a36Sopenharmony_ci size_t size; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct wiimote_queue { 10962306a36Sopenharmony_ci spinlock_t lock; 11062306a36Sopenharmony_ci struct work_struct worker; 11162306a36Sopenharmony_ci __u8 head; 11262306a36Sopenharmony_ci __u8 tail; 11362306a36Sopenharmony_ci struct wiimote_buf outq[WIIMOTE_BUFSIZE]; 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistruct wiimote_state { 11762306a36Sopenharmony_ci spinlock_t lock; 11862306a36Sopenharmony_ci __u32 flags; 11962306a36Sopenharmony_ci __u8 accel_split[2]; 12062306a36Sopenharmony_ci __u8 drm; 12162306a36Sopenharmony_ci __u8 devtype; 12262306a36Sopenharmony_ci __u8 exttype; 12362306a36Sopenharmony_ci __u8 mp; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* synchronous cmd requests */ 12662306a36Sopenharmony_ci struct mutex sync; 12762306a36Sopenharmony_ci struct completion ready; 12862306a36Sopenharmony_ci int cmd; 12962306a36Sopenharmony_ci __u32 opt; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* results of synchronous requests */ 13262306a36Sopenharmony_ci __u8 cmd_battery; 13362306a36Sopenharmony_ci __u8 cmd_err; 13462306a36Sopenharmony_ci __u8 *cmd_read_buf; 13562306a36Sopenharmony_ci __u8 cmd_read_size; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* calibration/cache data */ 13862306a36Sopenharmony_ci __u16 calib_bboard[4][3]; 13962306a36Sopenharmony_ci __s16 calib_pro_sticks[4]; 14062306a36Sopenharmony_ci __u8 pressure_drums[7]; 14162306a36Sopenharmony_ci __u8 cache_rumble; 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct wiimote_data { 14562306a36Sopenharmony_ci struct hid_device *hdev; 14662306a36Sopenharmony_ci struct input_dev *input; 14762306a36Sopenharmony_ci struct work_struct rumble_worker; 14862306a36Sopenharmony_ci struct led_classdev *leds[4]; 14962306a36Sopenharmony_ci struct input_dev *accel; 15062306a36Sopenharmony_ci struct input_dev *ir; 15162306a36Sopenharmony_ci struct power_supply *battery; 15262306a36Sopenharmony_ci struct power_supply_desc battery_desc; 15362306a36Sopenharmony_ci struct input_dev *mp; 15462306a36Sopenharmony_ci struct timer_list timer; 15562306a36Sopenharmony_ci struct wiimote_debug *debug; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci union { 15862306a36Sopenharmony_ci struct input_dev *input; 15962306a36Sopenharmony_ci } extension; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci struct wiimote_queue queue; 16262306a36Sopenharmony_ci struct wiimote_state state; 16362306a36Sopenharmony_ci struct work_struct init_worker; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciextern bool wiimote_dpad_as_analog; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* wiimote modules */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cienum wiimod_module { 17162306a36Sopenharmony_ci WIIMOD_KEYS, 17262306a36Sopenharmony_ci WIIMOD_RUMBLE, 17362306a36Sopenharmony_ci WIIMOD_BATTERY, 17462306a36Sopenharmony_ci WIIMOD_LED1, 17562306a36Sopenharmony_ci WIIMOD_LED2, 17662306a36Sopenharmony_ci WIIMOD_LED3, 17762306a36Sopenharmony_ci WIIMOD_LED4, 17862306a36Sopenharmony_ci WIIMOD_ACCEL, 17962306a36Sopenharmony_ci WIIMOD_IR, 18062306a36Sopenharmony_ci WIIMOD_BUILTIN_MP, 18162306a36Sopenharmony_ci WIIMOD_NO_MP, 18262306a36Sopenharmony_ci WIIMOD_NUM, 18362306a36Sopenharmony_ci WIIMOD_NULL = WIIMOD_NUM, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define WIIMOD_FLAG_INPUT 0x0001 18762306a36Sopenharmony_ci#define WIIMOD_FLAG_EXT8 0x0002 18862306a36Sopenharmony_ci#define WIIMOD_FLAG_EXT16 0x0004 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistruct wiimod_ops { 19162306a36Sopenharmony_ci __u16 flags; 19262306a36Sopenharmony_ci unsigned long arg; 19362306a36Sopenharmony_ci int (*probe) (const struct wiimod_ops *ops, 19462306a36Sopenharmony_ci struct wiimote_data *wdata); 19562306a36Sopenharmony_ci void (*remove) (const struct wiimod_ops *ops, 19662306a36Sopenharmony_ci struct wiimote_data *wdata); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci void (*in_keys) (struct wiimote_data *wdata, const __u8 *keys); 19962306a36Sopenharmony_ci void (*in_accel) (struct wiimote_data *wdata, const __u8 *accel); 20062306a36Sopenharmony_ci void (*in_ir) (struct wiimote_data *wdata, const __u8 *ir, bool packed, 20162306a36Sopenharmony_ci unsigned int id); 20262306a36Sopenharmony_ci void (*in_mp) (struct wiimote_data *wdata, const __u8 *mp); 20362306a36Sopenharmony_ci void (*in_ext) (struct wiimote_data *wdata, const __u8 *ext); 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ciextern const struct wiimod_ops *wiimod_table[WIIMOD_NUM]; 20762306a36Sopenharmony_ciextern const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM]; 20862306a36Sopenharmony_ciextern const struct wiimod_ops wiimod_mp; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* wiimote requests */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cienum wiiproto_reqs { 21362306a36Sopenharmony_ci WIIPROTO_REQ_NULL = 0x0, 21462306a36Sopenharmony_ci WIIPROTO_REQ_RUMBLE = 0x10, 21562306a36Sopenharmony_ci WIIPROTO_REQ_LED = 0x11, 21662306a36Sopenharmony_ci WIIPROTO_REQ_DRM = 0x12, 21762306a36Sopenharmony_ci WIIPROTO_REQ_IR1 = 0x13, 21862306a36Sopenharmony_ci WIIPROTO_REQ_SREQ = 0x15, 21962306a36Sopenharmony_ci WIIPROTO_REQ_WMEM = 0x16, 22062306a36Sopenharmony_ci WIIPROTO_REQ_RMEM = 0x17, 22162306a36Sopenharmony_ci WIIPROTO_REQ_IR2 = 0x1a, 22262306a36Sopenharmony_ci WIIPROTO_REQ_STATUS = 0x20, 22362306a36Sopenharmony_ci WIIPROTO_REQ_DATA = 0x21, 22462306a36Sopenharmony_ci WIIPROTO_REQ_RETURN = 0x22, 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* DRM_K: BB*2 */ 22762306a36Sopenharmony_ci WIIPROTO_REQ_DRM_K = 0x30, 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* DRM_KA: BB*2 AA*3 */ 23062306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KA = 0x31, 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* DRM_KE: BB*2 EE*8 */ 23362306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KE = 0x32, 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* DRM_KAI: BB*2 AA*3 II*12 */ 23662306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KAI = 0x33, 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* DRM_KEE: BB*2 EE*19 */ 23962306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KEE = 0x34, 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* DRM_KAE: BB*2 AA*3 EE*16 */ 24262306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KAE = 0x35, 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* DRM_KIE: BB*2 II*10 EE*9 */ 24562306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KIE = 0x36, 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* DRM_KAIE: BB*2 AA*3 II*10 EE*6 */ 24862306a36Sopenharmony_ci WIIPROTO_REQ_DRM_KAIE = 0x37, 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* DRM_E: EE*21 */ 25162306a36Sopenharmony_ci WIIPROTO_REQ_DRM_E = 0x3d, 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* DRM_SKAI1: BB*2 AA*1 II*18 */ 25462306a36Sopenharmony_ci WIIPROTO_REQ_DRM_SKAI1 = 0x3e, 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* DRM_SKAI2: BB*2 AA*1 II*18 */ 25762306a36Sopenharmony_ci WIIPROTO_REQ_DRM_SKAI2 = 0x3f, 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci WIIPROTO_REQ_MAX 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define dev_to_wii(pdev) hid_get_drvdata(to_hid_device(pdev)) 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid __wiimote_schedule(struct wiimote_data *wdata); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciextern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm); 26762306a36Sopenharmony_ciextern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble); 26862306a36Sopenharmony_ciextern void wiiproto_req_leds(struct wiimote_data *wdata, int leds); 26962306a36Sopenharmony_ciextern void wiiproto_req_status(struct wiimote_data *wdata); 27062306a36Sopenharmony_ciextern void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel); 27162306a36Sopenharmony_ciextern void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags); 27262306a36Sopenharmony_ciextern void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags); 27362306a36Sopenharmony_ciextern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset, 27462306a36Sopenharmony_ci const __u8 *wmem, __u8 size); 27562306a36Sopenharmony_ciextern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, 27662306a36Sopenharmony_ci __u8 *rmem, __u8 size); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci#define wiiproto_req_rreg(wdata, os, sz) \ 27962306a36Sopenharmony_ci wiiproto_req_rmem((wdata), false, (os), (sz)) 28062306a36Sopenharmony_ci#define wiiproto_req_reeprom(wdata, os, sz) \ 28162306a36Sopenharmony_ci wiiproto_req_rmem((wdata), true, (os), (sz)) 28262306a36Sopenharmony_ciextern void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, 28362306a36Sopenharmony_ci __u32 offset, __u16 size); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciextern int wiidebug_init(struct wiimote_data *wdata); 28862306a36Sopenharmony_ciextern void wiidebug_deinit(struct wiimote_data *wdata); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#else 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic inline int wiidebug_init(void *u) { return 0; } 29362306a36Sopenharmony_cistatic inline void wiidebug_deinit(void *u) { } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci#endif 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* requires the state.lock spinlock to be held */ 29862306a36Sopenharmony_cistatic inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd, 29962306a36Sopenharmony_ci __u32 opt) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci return wdata->state.cmd == cmd && wdata->state.opt == opt; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci/* requires the state.lock spinlock to be held */ 30562306a36Sopenharmony_cistatic inline void wiimote_cmd_complete(struct wiimote_data *wdata) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci wdata->state.cmd = WIIPROTO_REQ_NULL; 30862306a36Sopenharmony_ci complete(&wdata->state.ready); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* requires the state.lock spinlock to be held */ 31262306a36Sopenharmony_cistatic inline void wiimote_cmd_abort(struct wiimote_data *wdata) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci /* Abort synchronous request by waking up the sleeping caller. But 31562306a36Sopenharmony_ci * reset the state.cmd field to an invalid value so no further event 31662306a36Sopenharmony_ci * handlers will work with it. */ 31762306a36Sopenharmony_ci wdata->state.cmd = WIIPROTO_REQ_MAX; 31862306a36Sopenharmony_ci complete(&wdata->state.ready); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic inline int wiimote_cmd_acquire(struct wiimote_data *wdata) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic inline void wiimote_cmd_acquire_noint(struct wiimote_data *wdata) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci mutex_lock(&wdata->state.sync); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* requires the state.lock spinlock to be held */ 33262306a36Sopenharmony_cistatic inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd, 33362306a36Sopenharmony_ci __u32 opt) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci reinit_completion(&wdata->state.ready); 33662306a36Sopenharmony_ci wdata->state.cmd = cmd; 33762306a36Sopenharmony_ci wdata->state.opt = opt; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline void wiimote_cmd_release(struct wiimote_data *wdata) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci mutex_unlock(&wdata->state.sync); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic inline int wiimote_cmd_wait(struct wiimote_data *wdata) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci int ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* The completion acts as implicit memory barrier so we can safely 35062306a36Sopenharmony_ci * assume that state.cmd is set on success/failure and isn't accessed 35162306a36Sopenharmony_ci * by any other thread, anymore. */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ); 35462306a36Sopenharmony_ci if (ret < 0) 35562306a36Sopenharmony_ci return -ERESTARTSYS; 35662306a36Sopenharmony_ci else if (ret == 0) 35762306a36Sopenharmony_ci return -EIO; 35862306a36Sopenharmony_ci else if (wdata->state.cmd != WIIPROTO_REQ_NULL) 35962306a36Sopenharmony_ci return -EIO; 36062306a36Sopenharmony_ci else 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic inline int wiimote_cmd_wait_noint(struct wiimote_data *wdata) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci unsigned long ret; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* no locking needed; see wiimote_cmd_wait() */ 36962306a36Sopenharmony_ci ret = wait_for_completion_timeout(&wdata->state.ready, HZ); 37062306a36Sopenharmony_ci if (!ret) 37162306a36Sopenharmony_ci return -EIO; 37262306a36Sopenharmony_ci else if (wdata->state.cmd != WIIPROTO_REQ_NULL) 37362306a36Sopenharmony_ci return -EIO; 37462306a36Sopenharmony_ci else 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci#endif 379