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 int hid_pid_erase(struct input_dev *dev, int id) { struct hid_device *hid = dev->private; struct hid_ff_pid *pid = hid->ff_private; struct hid_field *field; unsigned long flags; int ret; if (!CHECK_OWNERSHIP(id, pid)) return -EACCES; /* Find report */ field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE, HID_OUTPUT_REPORT); if (!field) { dev_err(&hid->dev->dev, "couldn't find report\n"); return -EIO; } ret = hid_set_field(field, 0, pid->effects[id].device_id); if (ret) { dev_err(&hid->dev->dev, "couldn't set field\n"); return ret; } hid_submit_report(hid, field->report, USB_DIR_OUT); spin_lock_irqsave(&pid->lock, flags); hid_pid_ctrl_playback(hid, pid->effects + id, 0); pid->effects[id].flags = 0; spin_unlock_irqrestore(&pid->lock, flags); 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 logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { 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[8]; 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); 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]); usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT); return 0; }
static int uhid_hid_input(struct input_dev *input, unsigned int type, unsigned int code, int value) { struct hid_device *hid = input_get_drvdata(input); struct uhid_device *uhid = hid->driver_data; unsigned long flags; struct uhid_event *ev; struct hid_field *field; struct hid_report *report; int offset; ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return -ENOMEM; switch (type) { case EV_LED: offset = hidinput_find_field(hid, type, code, &field); if (offset == -1) { hid_warn(input, "event field not found\n"); kfree(ev); return -1; } hid_set_field(field, offset, value); report = field->report; ev->type = UHID_OUTPUT; ev->u.output.rtype = UHID_OUTPUT_REPORT; hid_output_report(report, ev->u.output.data); ev->u.output.size = ((report->size - 1) >> 3) + 1 + (report->id > 0); break; default: ev->type = UHID_OUTPUT_EV; ev->u.output_ev.type = type; ev->u.output_ev.code = code; ev->u.output_ev.value = value; } spin_lock_irqsave(&uhid->qlock, flags); uhid_queue(uhid, ev); spin_unlock_irqrestore(&uhid->qlock, flags); return 0; }
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 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; }
/* 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; }
/* 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; }