@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
174
174
struct bigben_device {
175
175
struct hid_device * hid ;
176
176
struct hid_report * report ;
177
+ spinlock_t lock ;
177
178
bool removed ;
178
179
u8 led_state ; /* LED1 = 1 .. LED4 = 8 */
179
180
u8 right_motor_on ; /* right motor off/on 0/1 */
@@ -190,12 +191,27 @@ static void bigben_worker(struct work_struct *work)
190
191
struct bigben_device * bigben = container_of (work ,
191
192
struct bigben_device , worker );
192
193
struct hid_field * report_field = bigben -> report -> field [0 ];
194
+ bool do_work_led = false;
195
+ bool do_work_ff = false;
196
+ u8 * buf ;
197
+ u32 len ;
198
+ unsigned long flags ;
193
199
194
200
if (bigben -> removed || !report_field )
195
201
return ;
196
202
203
+ buf = hid_alloc_report_buf (bigben -> report , GFP_KERNEL );
204
+ if (!buf )
205
+ return ;
206
+
207
+ len = hid_report_len (bigben -> report );
208
+
209
+ /* LED work */
210
+ spin_lock_irqsave (& bigben -> lock , flags );
211
+
197
212
if (bigben -> work_led ) {
198
213
bigben -> work_led = false;
214
+ do_work_led = true;
199
215
report_field -> value [0 ] = 0x01 ; /* 1 = led message */
200
216
report_field -> value [1 ] = 0x08 ; /* reserved value, always 8 */
201
217
report_field -> value [2 ] = bigben -> led_state ;
@@ -204,11 +220,22 @@ static void bigben_worker(struct work_struct *work)
204
220
report_field -> value [5 ] = 0x00 ; /* padding */
205
221
report_field -> value [6 ] = 0x00 ; /* padding */
206
222
report_field -> value [7 ] = 0x00 ; /* padding */
207
- hid_hw_request (bigben -> hid , bigben -> report , HID_REQ_SET_REPORT );
223
+ hid_output_report (bigben -> report , buf );
224
+ }
225
+
226
+ spin_unlock_irqrestore (& bigben -> lock , flags );
227
+
228
+ if (do_work_led ) {
229
+ hid_hw_raw_request (bigben -> hid , bigben -> report -> id , buf , len ,
230
+ bigben -> report -> type , HID_REQ_SET_REPORT );
208
231
}
209
232
233
+ /* FF work */
234
+ spin_lock_irqsave (& bigben -> lock , flags );
235
+
210
236
if (bigben -> work_ff ) {
211
237
bigben -> work_ff = false;
238
+ do_work_ff = true;
212
239
report_field -> value [0 ] = 0x02 ; /* 2 = rumble effect message */
213
240
report_field -> value [1 ] = 0x08 ; /* reserved value, always 8 */
214
241
report_field -> value [2 ] = bigben -> right_motor_on ;
@@ -217,8 +244,17 @@ static void bigben_worker(struct work_struct *work)
217
244
report_field -> value [5 ] = 0x00 ; /* padding */
218
245
report_field -> value [6 ] = 0x00 ; /* padding */
219
246
report_field -> value [7 ] = 0x00 ; /* padding */
220
- hid_hw_request (bigben -> hid , bigben -> report , HID_REQ_SET_REPORT );
247
+ hid_output_report (bigben -> report , buf );
248
+ }
249
+
250
+ spin_unlock_irqrestore (& bigben -> lock , flags );
251
+
252
+ if (do_work_ff ) {
253
+ hid_hw_raw_request (bigben -> hid , bigben -> report -> id , buf , len ,
254
+ bigben -> report -> type , HID_REQ_SET_REPORT );
221
255
}
256
+
257
+ kfree (buf );
222
258
}
223
259
224
260
static int hid_bigben_play_effect (struct input_dev * dev , void * data ,
@@ -228,6 +264,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
228
264
struct bigben_device * bigben = hid_get_drvdata (hid );
229
265
u8 right_motor_on ;
230
266
u8 left_motor_force ;
267
+ unsigned long flags ;
231
268
232
269
if (!bigben ) {
233
270
hid_err (hid , "no device data\n" );
@@ -242,9 +279,12 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
242
279
243
280
if (right_motor_on != bigben -> right_motor_on ||
244
281
left_motor_force != bigben -> left_motor_force ) {
282
+ spin_lock_irqsave (& bigben -> lock , flags );
245
283
bigben -> right_motor_on = right_motor_on ;
246
284
bigben -> left_motor_force = left_motor_force ;
247
285
bigben -> work_ff = true;
286
+ spin_unlock_irqrestore (& bigben -> lock , flags );
287
+
248
288
schedule_work (& bigben -> worker );
249
289
}
250
290
@@ -259,6 +299,7 @@ static void bigben_set_led(struct led_classdev *led,
259
299
struct bigben_device * bigben = hid_get_drvdata (hid );
260
300
int n ;
261
301
bool work ;
302
+ unsigned long flags ;
262
303
263
304
if (!bigben ) {
264
305
hid_err (hid , "no device data\n" );
@@ -267,13 +308,15 @@ static void bigben_set_led(struct led_classdev *led,
267
308
268
309
for (n = 0 ; n < NUM_LEDS ; n ++ ) {
269
310
if (led == bigben -> leds [n ]) {
311
+ spin_lock_irqsave (& bigben -> lock , flags );
270
312
if (value == LED_OFF ) {
271
313
work = (bigben -> led_state & BIT (n ));
272
314
bigben -> led_state &= ~BIT (n );
273
315
} else {
274
316
work = !(bigben -> led_state & BIT (n ));
275
317
bigben -> led_state |= BIT (n );
276
318
}
319
+ spin_unlock_irqrestore (& bigben -> lock , flags );
277
320
278
321
if (work ) {
279
322
bigben -> work_led = true;
@@ -307,8 +350,12 @@ static enum led_brightness bigben_get_led(struct led_classdev *led)
307
350
static void bigben_remove (struct hid_device * hid )
308
351
{
309
352
struct bigben_device * bigben = hid_get_drvdata (hid );
353
+ unsigned long flags ;
310
354
355
+ spin_lock_irqsave (& bigben -> lock , flags );
311
356
bigben -> removed = true;
357
+ spin_unlock_irqrestore (& bigben -> lock , flags );
358
+
312
359
cancel_work_sync (& bigben -> worker );
313
360
hid_hw_stop (hid );
314
361
}
@@ -362,6 +409,7 @@ static int bigben_probe(struct hid_device *hid,
362
409
set_bit (FF_RUMBLE , hidinput -> input -> ffbit );
363
410
364
411
INIT_WORK (& bigben -> worker , bigben_worker );
412
+ spin_lock_init (& bigben -> lock );
365
413
366
414
error = input_ff_create_memless (hidinput -> input , NULL ,
367
415
hid_bigben_play_effect );
0 commit comments