1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
4*4882a593Smuzhiyun * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * USB/RS232 I-Force joysticks and wheels.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <asm/unaligned.h>
10*4882a593Smuzhiyun #include "iforce.h"
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun static struct {
13*4882a593Smuzhiyun __s32 x;
14*4882a593Smuzhiyun __s32 y;
15*4882a593Smuzhiyun } iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun
iforce_dump_packet(struct iforce * iforce,char * msg,u16 cmd,unsigned char * data)18*4882a593Smuzhiyun void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun dev_dbg(iforce->dev->dev.parent, "%s %s cmd = %04x, data = %*ph\n",
21*4882a593Smuzhiyun __func__, msg, cmd, LO(cmd), data);
22*4882a593Smuzhiyun }
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun * Send a packet of bytes to the device
26*4882a593Smuzhiyun */
iforce_send_packet(struct iforce * iforce,u16 cmd,unsigned char * data)27*4882a593Smuzhiyun int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun /* Copy data to buffer */
30*4882a593Smuzhiyun int n = LO(cmd);
31*4882a593Smuzhiyun int c;
32*4882a593Smuzhiyun int empty;
33*4882a593Smuzhiyun int head, tail;
34*4882a593Smuzhiyun unsigned long flags;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun * Update head and tail of xmit buffer
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun spin_lock_irqsave(&iforce->xmit_lock, flags);
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun head = iforce->xmit.head;
42*4882a593Smuzhiyun tail = iforce->xmit.tail;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
46*4882a593Smuzhiyun dev_warn(&iforce->dev->dev,
47*4882a593Smuzhiyun "not enough space in xmit buffer to send new packet\n");
48*4882a593Smuzhiyun spin_unlock_irqrestore(&iforce->xmit_lock, flags);
49*4882a593Smuzhiyun return -1;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun empty = head == tail;
53*4882a593Smuzhiyun XMIT_INC(iforce->xmit.head, n+2);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun * Store packet in xmit buffer
57*4882a593Smuzhiyun */
58*4882a593Smuzhiyun iforce->xmit.buf[head] = HI(cmd);
59*4882a593Smuzhiyun XMIT_INC(head, 1);
60*4882a593Smuzhiyun iforce->xmit.buf[head] = LO(cmd);
61*4882a593Smuzhiyun XMIT_INC(head, 1);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
64*4882a593Smuzhiyun if (n < c) c=n;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun memcpy(&iforce->xmit.buf[head],
67*4882a593Smuzhiyun data,
68*4882a593Smuzhiyun c);
69*4882a593Smuzhiyun if (n != c) {
70*4882a593Smuzhiyun memcpy(&iforce->xmit.buf[0],
71*4882a593Smuzhiyun data + c,
72*4882a593Smuzhiyun n - c);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun XMIT_INC(head, n);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun spin_unlock_irqrestore(&iforce->xmit_lock, flags);
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * If necessary, start the transmission
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun if (empty)
81*4882a593Smuzhiyun iforce->xport_ops->xmit(iforce);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun EXPORT_SYMBOL(iforce_send_packet);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /* Start or stop an effect */
iforce_control_playback(struct iforce * iforce,u16 id,unsigned int value)88*4882a593Smuzhiyun int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun unsigned char data[3];
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun data[0] = LO(id);
93*4882a593Smuzhiyun data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
94*4882a593Smuzhiyun data[2] = LO(value);
95*4882a593Smuzhiyun return iforce_send_packet(iforce, FF_CMD_PLAY, data);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Mark an effect that was being updated as ready. That means it can be updated
99*4882a593Smuzhiyun * again */
mark_core_as_ready(struct iforce * iforce,unsigned short addr)100*4882a593Smuzhiyun static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun int i;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if (!iforce->dev->ff)
105*4882a593Smuzhiyun return 0;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun for (i = 0; i < iforce->dev->ff->max_effects; ++i) {
108*4882a593Smuzhiyun if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
109*4882a593Smuzhiyun (iforce->core_effects[i].mod1_chunk.start == addr ||
110*4882a593Smuzhiyun iforce->core_effects[i].mod2_chunk.start == addr)) {
111*4882a593Smuzhiyun clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags);
112*4882a593Smuzhiyun return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun dev_warn(&iforce->dev->dev, "unused effect %04x updated !!!\n", addr);
116*4882a593Smuzhiyun return -1;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
iforce_report_hats_buttons(struct iforce * iforce,u8 * data)119*4882a593Smuzhiyun static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun struct input_dev *dev = iforce->dev;
122*4882a593Smuzhiyun int i;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
125*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun for (i = 0; iforce->type->btn[i] >= 0; i++)
128*4882a593Smuzhiyun input_report_key(dev, iforce->type->btn[i],
129*4882a593Smuzhiyun data[(i >> 3) + 5] & (1 << (i & 7)));
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* If there are untouched bits left, interpret them as the second hat */
132*4882a593Smuzhiyun if (i <= 8) {
133*4882a593Smuzhiyun u8 btns = data[6];
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (test_bit(ABS_HAT1X, dev->absbit)) {
136*4882a593Smuzhiyun if (btns & BIT(3))
137*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1X, -1);
138*4882a593Smuzhiyun else if (btns & BIT(1))
139*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1X, 1);
140*4882a593Smuzhiyun else
141*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1X, 0);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (test_bit(ABS_HAT1Y, dev->absbit)) {
145*4882a593Smuzhiyun if (btns & BIT(0))
146*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1Y, -1);
147*4882a593Smuzhiyun else if (btns & BIT(2))
148*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1Y, 1);
149*4882a593Smuzhiyun else
150*4882a593Smuzhiyun input_report_abs(dev, ABS_HAT1Y, 0);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
iforce_process_packet(struct iforce * iforce,u8 packet_id,u8 * data,size_t len)155*4882a593Smuzhiyun void iforce_process_packet(struct iforce *iforce,
156*4882a593Smuzhiyun u8 packet_id, u8 *data, size_t len)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct input_dev *dev = iforce->dev;
159*4882a593Smuzhiyun int i, j;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun switch (packet_id) {
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun case 0x01: /* joystick position data */
164*4882a593Smuzhiyun input_report_abs(dev, ABS_X,
165*4882a593Smuzhiyun (__s16) get_unaligned_le16(data));
166*4882a593Smuzhiyun input_report_abs(dev, ABS_Y,
167*4882a593Smuzhiyun (__s16) get_unaligned_le16(data + 2));
168*4882a593Smuzhiyun input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
171*4882a593Smuzhiyun input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun iforce_report_hats_buttons(iforce, data);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun input_sync(dev);
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun case 0x03: /* wheel position data */
179*4882a593Smuzhiyun input_report_abs(dev, ABS_WHEEL,
180*4882a593Smuzhiyun (__s16) get_unaligned_le16(data));
181*4882a593Smuzhiyun input_report_abs(dev, ABS_GAS, 255 - data[2]);
182*4882a593Smuzhiyun input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun iforce_report_hats_buttons(iforce, data);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun input_sync(dev);
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun case 0x02: /* status report */
190*4882a593Smuzhiyun input_report_key(dev, BTN_DEAD, data[0] & 0x02);
191*4882a593Smuzhiyun input_sync(dev);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Check if an effect was just started or stopped */
194*4882a593Smuzhiyun i = data[1] & 0x7f;
195*4882a593Smuzhiyun if (data[1] & 0x80) {
196*4882a593Smuzhiyun if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
197*4882a593Smuzhiyun /* Report play event */
198*4882a593Smuzhiyun input_report_ff_status(dev, i, FF_STATUS_PLAYING);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
201*4882a593Smuzhiyun /* Report stop event */
202*4882a593Smuzhiyun input_report_ff_status(dev, i, FF_STATUS_STOPPED);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun for (j = 3; j < len; j += 2)
206*4882a593Smuzhiyun mark_core_as_ready(iforce, get_unaligned_le16(data + j));
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun EXPORT_SYMBOL(iforce_process_packet);
212