static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { /* Sent by the input layer to handle leds and Force Feedback */ struct hid_device *dj_hiddev = input_get_drvdata(dev); struct dj_device *dj_dev = dj_hiddev->driver_data; struct dj_receiver_dev *djrcv_dev = dev_get_drvdata(dj_hiddev->dev.parent); struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev; struct hid_report_enum *output_report_enum; struct hid_field *field; struct hid_report *report; unsigned char *data; int offset; dbg_hid("%s: %s, type:%d | code:%d | value:%d\n", __func__, dev->phys, type, code, value); if (type != EV_LED) return -1; offset = hidinput_find_field(dj_hiddev, type, code, &field); if (offset == -1) { dev_warn(&dev->dev, "event field not found\n"); return -1; } hid_set_field(field, offset, value); data = hid_alloc_report_buf(field->report, GFP_KERNEL); if (!data) { dev_warn(&dev->dev, "failed to allocate report buf memory\n"); return -1; } hid_output_report(field->report, &data[0]); output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT]; report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; hid_set_field(report->field[0], 0, dj_dev->device_index); hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS); hid_set_field(report->field[0], 2, data[1]); hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT); kfree(data); return 0; }
static void send_finalize_report(struct gcore_data *gdata) { struct g19_data *g19data = gdata->data; struct hid_device *hdev = gdata->hdev; unsigned long irq_flags; /* * Send the finalize report, then follow with the input report to * trigger report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_FINALIZE); hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); wait_for_completion_timeout(&g19data->ready, HZ); /* Protect data->ready_stages */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_3) { dev_warn(&hdev->dev, "%s hasn't completed stage 3 yet, forging ahead with initialization\n", gdata->name); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_3; } else { dbg_hid("%s stage 3 complete\n", gdata->name); } spin_unlock_irqrestore(&gdata->lock, irq_flags); }
/* Send a given tile to PicoLCD */ static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap, int chip, int tile) { struct hid_report *report1, *report2; unsigned long flags; u8 *tdata; int i; report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, data->hdev); if (!report1 || report1->maxfield != 1) return -ENODEV; report2 = picolcd_out_report(REPORT_LCD_DATA, data->hdev); if (!report2 || report2->maxfield != 1) return -ENODEV; spin_lock_irqsave(&data->lock, flags); if ((data->status & PICOLCD_FAILED)) { spin_unlock_irqrestore(&data->lock, flags); return -ENODEV; } hid_set_field(report1->field[0], 0, chip << 2); hid_set_field(report1->field[0], 1, 0x02); hid_set_field(report1->field[0], 2, 0x00); hid_set_field(report1->field[0], 3, 0x00); hid_set_field(report1->field[0], 4, 0xb8 | tile); hid_set_field(report1->field[0], 5, 0x00); hid_set_field(report1->field[0], 6, 0x00); hid_set_field(report1->field[0], 7, 0x40); hid_set_field(report1->field[0], 8, 0x00); hid_set_field(report1->field[0], 9, 0x00); hid_set_field(report1->field[0], 10, 32); hid_set_field(report2->field[0], 0, (chip << 2) | 0x01); hid_set_field(report2->field[0], 1, 0x00); hid_set_field(report2->field[0], 2, 0x00); hid_set_field(report2->field[0], 3, 32); tdata = vbitmap + (tile * 4 + chip) * 64; for (i = 0; i < 64; i++) if (i < 32) hid_set_field(report1->field[0], 11 + i, tdata[i]); else hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); hid_hw_request(data->hdev, report1, HID_REQ_SET_REPORT); hid_hw_request(data->hdev, report2, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); return 0; }
static void g19_feature_report_4_send(struct hid_device *hdev, int which) { struct g19_data *g19data = hid_get_g19data(hdev); if (which == G19_REPORT_4_INIT) { g19data->feature_report_4->field[0]->value[0] = 0x02; g19data->feature_report_4->field[0]->value[1] = 0x00; g19data->feature_report_4->field[0]->value[2] = 0x00; g19data->feature_report_4->field[0]->value[3] = 0x00; } else if (which == G19_REPORT_4_FINALIZE) { g19data->feature_report_4->field[0]->value[0] = 0x02; g19data->feature_report_4->field[0]->value[1] = 0x80; g19data->feature_report_4->field[0]->value[2] = 0x00; g19data->feature_report_4->field[0]->value[3] = 0xFF; } else { return; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) hid_hw_request(hdev, g19data->feature_report_4, HID_REQ_SET_REPORT); #else usbhid_submit_report(hdev, g19data->feature_report_4, USB_DIR_OUT); #endif }
static int zpff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct zpff_device *zpff = data; int left, right; /* * The following is specified the other way around in the Zeroplus * datasheet but the order below is correct for the XFX Executioner; * however it is possible that the XFX Executioner is an exception */ left = effect->u.rumble.strong_magnitude; right = effect->u.rumble.weak_magnitude; dbg_hid("called with 0x%04x 0x%04x\n", left, right); left = left * 0x7f / 0xffff; right = right * 0x7f / 0xffff; zpff->report->field[2]->value[0] = left; zpff->report->field[3]->value[0] = right; dbg_hid("running with 0x%02x 0x%02x\n", left, right); hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT); return 0; }
static ssize_t picolcd_operation_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct picolcd_data *data = dev_get_drvdata(dev); struct hid_report *report = NULL; size_t cnt = count; int timeout = data->opmode_delay; unsigned long flags; if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { if (data->status & PICOLCD_BOOTLOADER) report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); buf += 3; cnt -= 3; } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) { if (!(data->status & PICOLCD_BOOTLOADER)) report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); buf += 10; cnt -= 10; } if (!report) return -EINVAL; while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) cnt--; if (cnt != 0) return -EINVAL; spin_lock_irqsave(&data->lock, flags); hid_set_field(report->field[0], 0, timeout & 0xff); hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); return count; }
/* * Reset our device and wait for answer to VERSION request */ int picolcd_reset(struct hid_device *hdev) { struct picolcd_data *data = hid_get_drvdata(hdev); struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev); unsigned long flags; int error; if (!data || !report || report->maxfield != 1) return -ENODEV; spin_lock_irqsave(&data->lock, flags); if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) data->status |= PICOLCD_BOOTLOADER; /* perform the reset */ hid_set_field(report->field[0], 0, 1); if (data->status & PICOLCD_FAILED) { spin_unlock_irqrestore(&data->lock, flags); return -ENODEV; } hid_hw_request(hdev, report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); error = picolcd_check_version(hdev); if (error) return error; picolcd_resume_lcd(data); picolcd_resume_backlight(data); picolcd_fb_refresh(data); picolcd_leds_set(data); return 0; }
static int play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct lg2ff_device *lg2ff = data; int weak, strong; strong = effect->u.rumble.strong_magnitude; weak = effect->u.rumble.weak_magnitude; if (weak || strong) { weak = weak * 0xff / 0xffff; strong = strong * 0xff / 0xffff; lg2ff->report->field[0]->value[0] = 0x51; lg2ff->report->field[0]->value[2] = weak; lg2ff->report->field[0]->value[4] = strong; } else { lg2ff->report->field[0]->value[0] = 0xf3; lg2ff->report->field[0]->value[2] = 0x00; lg2ff->report->field[0]->value[4] = 0x00; } hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT); return 0; }
static void g19_led_mbtns_send(struct hid_device *hdev) { struct g19_data *g19data = hid_get_g19data(hdev); g19data->led_report->field[0]->value[0] = g19data->led_mbtns & 0xFF; hid_hw_request(hdev, g19data->led_report, HID_REQ_SET_REPORT); }
static void g510_led_send(struct hid_device *hdev, u8 msg, u8 value1, u8 value2) { struct g510_data *g510data = hid_get_g510data(hdev); g510data->led_report->field[0]->value[0] = msg; g510data->led_report->field[0]->value[1] = value1; g510data->led_report->field[0]->value[2] = value2; hid_hw_request(hdev, g510data->led_report, HID_REQ_SET_REPORT); }
static int drff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct drff_device *drff = data; int strong, weak; strong = effect->u.rumble.strong_magnitude; weak = effect->u.rumble.weak_magnitude; dbg_hid("called with 0x%04x 0x%04x", strong, weak); if (strong || weak) { strong = strong * 0xff / 0xffff; weak = weak * 0xff / 0xffff; /* While reverse engineering this device, I found that when this value is set, it causes the strong rumble to function at a near maximum speed, so we'll bypass it. */ if (weak == 0x0a) weak = 0x0b; drff->report->field[0]->value[0] = 0x51; drff->report->field[0]->value[1] = 0x00; drff->report->field[0]->value[2] = weak; drff->report->field[0]->value[4] = strong; hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); drff->report->field[0]->value[0] = 0xfa; drff->report->field[0]->value[1] = 0xfe; } else { drff->report->field[0]->value[0] = 0xf3; drff->report->field[0]->value[1] = 0x00; } drff->report->field[0]->value[2] = 0x00; drff->report->field[0]->value[4] = 0x00; dbg_hid("running with 0x%02x 0x%02x", strong, weak); hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); return 0; }
static int drff_init(struct hid_device *hid) { struct drff_device *drff; struct hid_report *report; struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev = hidinput->input; int error; if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 1) { hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 7) { hid_err(hid, "not enough values in the field\n"); return -ENODEV; } drff = kzalloc(sizeof(struct drff_device), GFP_KERNEL); if (!drff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, drff, drff_play); if (error) { kfree(drff); return error; } drff->report = report; drff->report->field[0]->value[0] = 0xf3; drff->report->field[0]->value[1] = 0x00; drff->report->field[0]->value[2] = 0x00; drff->report->field[0]->value[3] = 0x00; drff->report->field[0]->value[4] = 0x00; drff->report->field[0]->value[5] = 0x00; drff->report->field[0]->value[6] = 0x00; hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT); hid_info(hid, "Force Feedback for DragonRise Inc. " "game controllers by Richard Walmsley <*****@*****.**>\n"); return 0; }
static void g19_led_bl_send(struct hid_device *hdev) { struct g19_data *g19data = hid_get_g19data(hdev); struct hid_field *field0 = g19data->backlight_report->field[0]; field0->value[0] = g19data->backlight_rgb[0]; field0->value[1] = g19data->backlight_rgb[1]; field0->value[2] = g19data->backlight_rgb[2]; hid_hw_request(hdev, g19data->backlight_report, HID_REQ_SET_REPORT); }
static int emsff_init(struct hid_device *hid) { struct emsff_device *emsff; struct hid_report *report; struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev = hidinput->input; int error; if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 1) { hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 7) { hid_err(hid, "not enough values in the field\n"); return -ENODEV; } emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL); if (!emsff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, emsff, emsff_play); if (error) { kfree(emsff); return error; } emsff->report = report; emsff->report->field[0]->value[0] = 0x01; emsff->report->field[0]->value[1] = 0x00; emsff->report->field[0]->value[2] = 0x00; emsff->report->field[0]->value[3] = 0x00; emsff->report->field[0]->value[4] = 0x00; emsff->report->field[0]->value[5] = 0x00; emsff->report->field[0]->value[6] = 0x00; hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT); hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <*****@*****.**>\n"); return 0; }
static int tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct tmff_device *tmff = data; struct hid_field *ff_field = tmff->ff_field; int x, y; int left, right; /* Rumbling */ switch (effect->type) { case FF_CONSTANT: x = tmff_scale_s8(effect->u.ramp.start_level, ff_field->logical_minimum, ff_field->logical_maximum); y = tmff_scale_s8(effect->u.ramp.end_level, ff_field->logical_minimum, ff_field->logical_maximum); dbg_hid("(x, y)=(%04x, %04x)\n", x, y); ff_field->value[0] = x; ff_field->value[1] = y; hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT); break; case FF_RUMBLE: left = tmff_scale_u16(effect->u.rumble.weak_magnitude, ff_field->logical_minimum, ff_field->logical_maximum); right = tmff_scale_u16(effect->u.rumble.strong_magnitude, ff_field->logical_minimum, ff_field->logical_maximum); dbg_hid("(left,right)=(%08x, %08x)\n", left, right); ff_field->value[0] = left; ff_field->value[1] = right; hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT); break; } return 0; }
static void g19_led_send(struct hid_device *hdev) { struct g19_data *g19data = hid_get_g19data(hdev); g19data->led_report->field[0]->value[0] = g19data->led&0xFF; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) hid_hw_request(hdev, g19data->led_report, HID_REQ_SET_REPORT); #else usbhid_submit_report(hdev, g19data->led_report, USB_DIR_OUT); #endif }
static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) { struct picolcd_data *data = lcd_get_data(ldev); struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); unsigned long flags; if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) return -ENODEV; data->lcd_contrast = contrast & 0x0ff; spin_lock_irqsave(&data->lock, flags); hid_set_field(report->field[0], 0, data->lcd_contrast); if (!(data->status & PICOLCD_FAILED)) hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); return 0; }
static int zpff_init(struct hid_device *hid) { struct zpff_device *zpff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev = hidinput->input; int error; if (list_empty(report_list)) { hid_err(hid, "no output report found\n"); return -ENODEV; } report = list_entry(report_list->next, struct hid_report, list); if (report->maxfield < 4) { hid_err(hid, "not enough fields in report\n"); return -ENODEV; } zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); if (!zpff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, zpff, zpff_play); if (error) { kfree(zpff); return error; } zpff->report = report; zpff->report->field[0]->value[0] = 0x00; zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT); hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <*****@*****.**>\n"); return 0; }
static void buzz_set_leds(struct hid_device *hdev, int leds) { struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); __s32 *value = report->field[0]->value; value[0] = 0x00; value[1] = (leds & 1) ? 0xff : 0x00; value[2] = (leds & 2) ? 0xff : 0x00; value[3] = (leds & 4) ? 0xff : 0x00; value[4] = (leds & 8) ? 0xff : 0x00; value[5] = 0x00; value[6] = 0x00; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); }
static void wait_ready(struct gcore_data *gdata) { struct g19_data *g19data = gdata->data; struct hid_device *hdev = gdata->hdev; unsigned long irq_flags; dbg_hid("Waiting for G19 to activate\n"); /* Wait here for stage 1 (substages 1-3) to complete */ wait_for_completion_timeout(&g19data->ready, HZ); /* Protect data->ready_stages */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_1) { dev_warn(&hdev->dev, "%s hasn't completed stage 1 yet, forging ahead with initialization\n", gdata->name); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_1; } init_completion(&g19data->ready); g19data->ready_stages |= G19_READY_SUBSTAGE_4; spin_unlock_irqrestore(&gdata->lock, irq_flags); /* * Send the init report, then follow with the input report to trigger * report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_INIT); hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); wait_for_completion_timeout(&g19data->ready, HZ); /* Protect g19data->ready_stages */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_2) { dev_warn(&hdev->dev, "%s hasn't completed stage 2 yet, forging ahead with initialization\n", gdata->name); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_2; } init_completion(&g19data->ready); g19data->ready_stages |= G19_READY_SUBSTAGE_6; spin_unlock_irqrestore(&gdata->lock, irq_flags); }
static int picolcd_set_brightness(struct backlight_device *bdev) { struct picolcd_data *data = bl_get_data(bdev); struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); unsigned long flags; if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) return -ENODEV; data->lcd_brightness = bdev->props.brightness & 0x0ff; data->lcd_power = bdev->props.power; spin_lock_irqsave(&data->lock, flags); hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); if (!(data->status & PICOLCD_FAILED)) hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); return 0; }
static int lenovo_features_set_tpkbd(struct hid_device *hdev) { struct hid_report *report; struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08; report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20; report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40; report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver report->field[2]->value[0] = data_pointer->sensitivity; report->field[3]->value[0] = data_pointer->press_speed; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); return 0; }
/* Submit a report and wait for a reply from device - if device fades away * or does not respond in time, return NULL */ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, int report_id, const u8 *raw_data, int size) { struct picolcd_data *data = hid_get_drvdata(hdev); struct picolcd_pending *work; struct hid_report *report = picolcd_out_report(report_id, hdev); unsigned long flags; int i, j, k; if (!report || !data) return NULL; if (data->status & PICOLCD_FAILED) return NULL; work = kzalloc(sizeof(*work), GFP_KERNEL); if (!work) return NULL; init_completion(&work->ready); work->out_report = report; work->in_report = NULL; work->raw_size = 0; mutex_lock(&data->mutex); spin_lock_irqsave(&data->lock, flags); for (i = k = 0; i < report->maxfield; i++) for (j = 0; j < report->field[i]->report_count; j++) { hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0); k++; } if (data->status & PICOLCD_FAILED) { kfree(work); work = NULL; } else { data->pending = work; hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&data->lock, flags); wait_for_completion_interruptible_timeout(&work->ready, HZ*2); spin_lock_irqsave(&data->lock, flags); data->pending = NULL; } spin_unlock_irqrestore(&data->lock, flags); mutex_unlock(&data->mutex); return work; }
static void g15v2_feature_report_4_send(struct hid_device *hdev, int which) { struct g15v2_data *gdata = hid_get_g15data(hdev); if (which == G15V2_REPORT_4_INIT) { gdata->feature_report_4->field[0]->value[0] = 0x02; gdata->feature_report_4->field[0]->value[1] = 0x00; gdata->feature_report_4->field[0]->value[2] = 0x00; gdata->feature_report_4->field[0]->value[3] = 0x00; } else if (which == G15V2_REPORT_4_FINALIZE) { gdata->feature_report_4->field[0]->value[0] = 0x02; gdata->feature_report_4->field[0]->value[1] = 0x80; gdata->feature_report_4->field[0]->value[2] = 0x00; gdata->feature_report_4->field[0]->value[3] = 0xFF; } else { return; } hid_hw_request(hdev, gdata->feature_report_4, HID_REQ_SET_REPORT); }
int lg2ff_init(struct hid_device *hid) { struct lg2ff_device *lg2ff; struct hid_report *report; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; int error; /* Check that the report looks ok */ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); if (!report) return -ENODEV; lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); if (!lg2ff) return -ENOMEM; set_bit(FF_RUMBLE, dev->ffbit); error = input_ff_create_memless(dev, lg2ff, play_effect); if (error) { kfree(lg2ff); return error; } lg2ff->report = report; report->field[0]->value[0] = 0xf3; report->field[0]->value[1] = 0x00; report->field[0]->value[2] = 0x00; report->field[0]->value[3] = 0x00; report->field[0]->value[4] = 0x00; report->field[0]->value[5] = 0x00; report->field[0]->value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); hid_info(hid, "Force feedback for Logitech variant 2 rumble devices by Anssi Hannula <*****@*****.**>\n"); return 0; }
static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev, enum led_brightness value) { struct device *dev = led_cdev->dev->parent; struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); struct hid_report *report; int led_nr = 0; if (led_cdev == &data_pointer->led_micmute) led_nr = 1; if (value == LED_OFF) data_pointer->led_state &= ~(1 << led_nr); else data_pointer->led_state |= 1 << led_nr; report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); }
static int emsff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct emsff_device *emsff = data; int weak, strong; weak = effect->u.rumble.weak_magnitude; strong = effect->u.rumble.strong_magnitude; dbg_hid("called with 0x%04x 0x%04x\n", strong, weak); weak = weak * 0xff / 0xffff; strong = strong * 0xff / 0xffff; emsff->report->field[0]->value[1] = weak; emsff->report->field[0]->value[2] = strong; dbg_hid("running with 0x%02x 0x%02x\n", strong, weak); hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT); return 0; }
static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report) { struct hid_device *hdev = djrcv_dev->hdev; struct hid_report *report; struct hid_report_enum *output_report_enum; u8 *data = (u8 *)(&dj_report->device_index); unsigned int i; output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; if (!report) { dev_err(&hdev->dev, "%s: unable to find dj report\n", __func__); return -ENODEV; } for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++) report->field[0]->value[i] = data[i]; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); return 0; }
static int g19_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long irq_flags; int error; struct gcommon_data *gdata; struct g19_data *g19data; int i; int led_num; struct usb_interface *intf; struct usb_device *usbdev; struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; struct hid_report *report; char *led_name; dev_dbg(&hdev->dev, "Logitech G19 HID hardware probe..."); /* Get the usb device to send the start report on */ intf = to_usb_interface(hdev->dev.parent); usbdev = interface_to_usbdev(intf); /* * Let's allocate the g19 data structure, set some reasonable * defaults, and associate it with the device */ gdata = kzalloc(sizeof(struct gcommon_data), GFP_KERNEL); if (gdata == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G19 device attributes\n"); error = -ENOMEM; goto err_no_cleanup; } g19data = kzalloc(sizeof(struct g19_data), GFP_KERNEL); if (g19data == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G19 device attributes\n"); error = -ENOMEM; goto err_cleanup_gdata; } gdata->data = g19data; spin_lock_init(&gdata->lock); init_completion(&g19data->ready); gdata->hdev = hdev; g19data->ep1_urb = usb_alloc_urb(0, GFP_KERNEL); if (g19data->ep1_urb == NULL) { dev_err(&hdev->dev, G19_NAME ": ERROR: can't alloc ep1 urb stuff\n"); error = -ENOMEM; goto err_cleanup_g19data; } hid_set_drvdata(hdev, gdata); dbg_hid("Preparing to parse " G19_NAME " hid reports\n"); /* Parse the device reports and start it up */ error = hid_parse(hdev); if (error) { dev_err(&hdev->dev, G19_NAME " device report parse failed\n"); error = -EINVAL; goto err_cleanup_ep1_urb; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDINPUT_FORCE); if (error) { dev_err(&hdev->dev, G19_NAME " hardware start failed\n"); error = -EINVAL; goto err_cleanup_ep1_urb; } dbg_hid(G19_NAME " claimed: %d\n", hdev->claimed); error = hdev->ll_driver->open(hdev); if (error) { dev_err(&hdev->dev, G19_NAME " failed to open input interrupt pipe for key and joystick events\n"); error = -EINVAL; goto err_cleanup_hw_start; } /* Set up the input device for the key I/O */ gdata->input_dev = input_allocate_device(); if (gdata->input_dev == NULL) { dev_err(&hdev->dev, G19_NAME " error initializing the input device"); error = -ENOMEM; goto err_cleanup_hw_start; } input_set_drvdata(gdata->input_dev, gdata); gdata->input_dev->name = G19_NAME; gdata->input_dev->phys = hdev->phys; gdata->input_dev->uniq = hdev->uniq; gdata->input_dev->id.bustype = hdev->bus; gdata->input_dev->id.vendor = hdev->vendor; gdata->input_dev->id.product = hdev->product; gdata->input_dev->id.version = hdev->version; gdata->input_dev->dev.parent = hdev->dev.parent; gdata->input_dev->keycode = gdata->input_data.keycode; gdata->input_dev->keycodemax = G19_KEYMAP_SIZE; gdata->input_dev->keycodesize = sizeof(unsigned int); gdata->input_dev->setkeycode = ginput_setkeycode; gdata->input_dev->getkeycode = ginput_getkeycode; input_set_capability(gdata->input_dev, EV_KEY, KEY_UNKNOWN); gdata->input_dev->evbit[0] |= BIT_MASK(EV_REP); gdata->input_data.notify_keymap_switched = g19_notify_keymap_switched; error = ginput_alloc(gdata, G19_KEYS); if (error) { dev_err(&hdev->dev, G19_NAME " error allocating memory for the input device"); goto err_cleanup_input_dev; } g19_initialize_keymap(gdata); error = input_register_device(gdata->input_dev); if (error) { dev_err(&hdev->dev, G19_NAME " error registering the input device"); error = -EINVAL; goto err_cleanup_input_dev_data; } if (list_empty(feature_report_list)) { dev_err(&hdev->dev, "no feature report found\n"); error = -ENODEV; goto err_cleanup_input_dev_reg; } dbg_hid(G19_NAME " feature report found\n"); list_for_each_entry(report, feature_report_list, list) { switch (report->id) { case 0x04: g19data->feature_report_4 = report; break; case 0x05: g19data->led_report = report; break; case 0x06: g19data->start_input_report = report; break; case 0x07: g19data->backlight_report = report; break; default: break; } dbg_hid(G19_NAME " Feature report: id=%u type=%u size=%u maxfield=%u report_count=%u\n", report->id, report->type, report->size, report->maxfield, report->field[0]->report_count); } dbg_hid("Found all reports\n"); /* Create the LED structures */ for (i = 0; i < LED_COUNT; i++) { g19data->led_cdev[i] = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); if (g19data->led_cdev[i] == NULL) { dev_err(&hdev->dev, G19_NAME " error allocating memory for led %d", i); error = -ENOMEM; goto err_cleanup_led_structs; } /* Set the accessor functions by copying from template*/ *(g19data->led_cdev[i]) = g19_led_cdevs[i]; /* * Allocate memory for the LED name * * Since led_classdev->name is a const char* we'll use an * intermediate until the name is formatted with sprintf(). */ led_name = kzalloc(sizeof(char)*20, GFP_KERNEL); if (led_name == NULL) { dev_err(&hdev->dev, G19_NAME " error allocating memory for led %d name", i); error = -ENOMEM; goto err_cleanup_led_structs; } switch (i) { case G19_LED_M1: case G19_LED_M2: case G19_LED_M3: sprintf(led_name, "g19_%d:orange:m%d", hdev->minor, i+1); break; case G19_LED_MR: sprintf(led_name, "g19_%d:red:mr", hdev->minor); break; case G19_LED_BL_R: sprintf(led_name, "g19_%d:red:bl", hdev->minor); break; case G19_LED_BL_G: sprintf(led_name, "g19_%d:green:bl", hdev->minor); break; case G19_LED_BL_B: sprintf(led_name, "g19_%d:blue:bl", hdev->minor); break; case G19_LED_BL_SCREEN: sprintf(led_name, "g19_%d:white:screen", hdev->minor); break; } g19data->led_cdev[i]->name = led_name; } for (i = 0; i < LED_COUNT; i++) { led_num = i; error = led_classdev_register(&hdev->dev, g19data->led_cdev[i]); if (error < 0) { dev_err(&hdev->dev, G19_NAME " error registering led %d", i); error = -EINVAL; goto err_cleanup_registered_leds; } } gdata->gfb_data = gfb_probe(hdev, GFB_PANEL_TYPE_320_240_16); if (gdata->gfb_data == NULL) { dev_err(&hdev->dev, G19_NAME " error registering framebuffer\n"); goto err_cleanup_registered_leds; } dbg_hid("Waiting for G19 to activate\n"); /* Add the sysfs attributes */ error = sysfs_create_group(&(hdev->dev.kobj), &g19_attr_group); if (error) { dev_err(&hdev->dev, G19_NAME " failed to create sysfs group attributes\n"); goto err_cleanup_gfb; } /* * Wait here for stage 1 (substages 1-3) to complete */ wait_for_completion_timeout(&g19data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_1) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 1 yet, forging ahead with initialization\n"); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_1; } init_completion(&g19data->ready); g19data->ready_stages |= G19_READY_SUBSTAGE_4; spin_unlock_irqrestore(&gdata->lock, irq_flags); /* * Send the init report, then follow with the input report to trigger * report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_INIT); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); #else usbhid_submit_report(hdev, g19data->start_input_report, USB_DIR_IN); #endif wait_for_completion_timeout(&g19data->ready, HZ); /* Protect g19data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_2) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 2 yet, forging ahead with initialization\n"); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_2; } init_completion(&g19data->ready); g19data->ready_stages |= G19_READY_SUBSTAGE_6; spin_unlock_irqrestore(&gdata->lock, irq_flags); /* * Clear the LEDs */ g19_led_send(hdev); g19data->rgb[0] = G19_DEFAULT_RED; g19data->rgb[1] = G19_DEFAULT_GREEN; g19data->rgb[2] = G19_DEFAULT_BLUE; g19_rgb_send(hdev); g19data->screen_bl = G19_DEFAULT_BRIGHTNESS; g19_screen_bl_send(hdev); /* * Send the finalize report, then follow with the input report to trigger * report 6 and wait for us to get a response. */ g19_feature_report_4_send(hdev, G19_REPORT_4_FINALIZE); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); hid_hw_request(hdev, g19data->start_input_report, HID_REQ_GET_REPORT); #else usbhid_submit_report(hdev, g19data->start_input_report, USB_DIR_IN); usbhid_submit_report(hdev, g19data->start_input_report, USB_DIR_IN); #endif wait_for_completion_timeout(&g19data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&gdata->lock, irq_flags); if (g19data->ready_stages != G19_READY_STAGE_3) { dev_warn(&hdev->dev, G19_NAME " hasn't completed stage 3 yet, forging ahead with initialization\n"); /* Force the stage */ g19data->ready_stages = G19_READY_STAGE_3; } else { dbg_hid(G19_NAME " stage 3 complete\n"); } spin_unlock_irqrestore(&gdata->lock, irq_flags); ginput_set_keymap_switching(gdata, 1); g19_ep1_read(hdev); dbg_hid("G19 activated and initialized\n"); /* Everything went well */ return 0; err_cleanup_gfb: gfb_remove(gdata->gfb_data); err_cleanup_registered_leds: for (i = 0; i < led_num; i++) led_classdev_unregister(g19data->led_cdev[i]); err_cleanup_led_structs: for (i = 0; i < LED_COUNT; i++) { if (g19data->led_cdev[i] != NULL) { if (g19data->led_cdev[i]->name != NULL) kfree(g19data->led_cdev[i]->name); kfree(g19data->led_cdev[i]); } } err_cleanup_input_dev_reg: input_unregister_device(gdata->input_dev); err_cleanup_input_dev_data: ginput_free(gdata); err_cleanup_input_dev: input_free_device(gdata->input_dev); err_cleanup_hw_start: hid_hw_stop(hdev); err_cleanup_ep1_urb: usb_free_urb(g19data->ep1_urb); err_cleanup_g19data: kfree(g19data); err_cleanup_gdata: kfree(gdata); err_no_cleanup: hid_set_drvdata(hdev, NULL); return error; }