static void g19_led_set(struct led_classdev *led_cdev, enum led_brightness value, int led_num) { struct device *dev; struct hid_device *hdev; struct g19_data *g19data; u8 mask; /* Get the device associated with the led */ dev = led_cdev->dev->parent; /* Get the hid associated with the device */ hdev = container_of(dev, struct hid_device, dev); /* Get the underlying data value */ g19data = hid_get_g19data(hdev); mask = 0x80>>led_num; if (value) g19data->led |= mask; else g19data->led &= ~mask; g19_led_send(hdev); }
/* change leds when the keymap was changed */ static void g19_notify_keymap_switched(struct gcommon_data * gdata, unsigned int index) { struct g19_data *g19data = gdata->data; g19data->led = 1 << index; g19_led_send(gdata->hdev); }
static void g19_post_reset_start(struct hid_device *hdev) { unsigned long irq_flags; struct gcommon_data *gdata = hid_get_gdata(hdev); spin_lock_irqsave(&gdata->lock, irq_flags); g19_rgb_send(hdev); g19_led_send(hdev); spin_unlock_irqrestore(&gdata->lock, irq_flags); }
static ssize_t g19_set_keymap_switching(struct hid_device *hdev, unsigned k) { struct g19_data *data = hid_get_g19data(hdev); data->keymap_switching = k; if (data->keymap_switching) { data->led = 1 << data->curkeymap; g19_led_send(hdev); } return 0; }
static ssize_t g19_set_keymap_index(struct hid_device *hdev, unsigned k) { int scancode; int offset_old; int offset_new; int keycode_old; int keycode_new; struct g19_data *data = hid_get_g19data(hdev); struct input_dev *idev = data->input_dev; if (k > 2) return -EINVAL; /* * Release all the pressed keys unless the new keymap has the same key * in the same scancode position. * * Also, clear the scancode state unless the new keymap has the same * key in the same scancode position. * * This allows a keycode mapped to the same scancode in two different * keymaps to remain pressed without a key up code when the keymap is * switched. */ offset_old = G19_KEYS * data->curkeymap; offset_new = G19_KEYS * k; for (scancode = 0; scancode < G19_KEYS; scancode++) { keycode_old = data->keycode[offset_old+scancode]; keycode_new = data->keycode[offset_new+scancode]; if (keycode_old != keycode_new) { if (keycode_old != KEY_RESERVED) input_report_key(idev, keycode_old, 0); data->scancode_state[scancode] = 0; } } data->curkeymap = k; if (data->keymap_switching) { data->led = 1 << k; g19_led_send(hdev); } return 0; }
static int g19_input_get_keycode(struct input_dev * dev, unsigned int scancode, unsigned int * keycode) { int retval; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) struct input_keymap_entry ke = { .flags = 0, .len = sizeof(scancode), .index = scancode, .scancode = { scancode }, }; retval = input_get_keycode(dev, &ke); *keycode = ke.keycode; #else retval = input_get_keycode(dev, scancode, keycode); #endif return retval; } static void g19_led_send(struct hid_device *hdev) { struct g19_data *data = hid_get_g19data(hdev); data->led_report->field[0]->value[0] = data->led&0xFF; usbhid_submit_report(hdev, data->led_report, USB_DIR_OUT); } static void g19_screen_bl_send(struct hid_device *hdev) { struct usb_interface *intf; struct usb_device *usb_dev; struct g19_data *data = hid_get_g19data(hdev); unsigned int pipe; int i = 0; unsigned char cp[9]; cp[0] = data->screen_bl; cp[1] = 0xe2; cp[2] = 0x12; cp[3] = 0x00; cp[4] = 0x8c; cp[5] = 0x11; cp[6] = 0x00; cp[7] = 0x10; cp[8] = 0x00; intf = to_usb_interface(hdev->dev.parent); usb_dev = interface_to_usbdev(intf); pipe = usb_sndctrlpipe(usb_dev, 0x00); i = usb_control_msg(usb_dev, pipe, 0x0a, USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 0, 0, cp, sizeof(cp), 1 * HZ); if (i < 0) { dev_warn(&hdev->dev, G19_NAME " error setting LCD backlight level %d\n", i); } } static void g19_rgb_send(struct hid_device *hdev) { struct g19_data *data = hid_get_g19data(hdev); data->backlight_report->field[0]->value[0] = data->rgb[0]; data->backlight_report->field[0]->value[1] = data->rgb[1]; data->backlight_report->field[0]->value[2] = data->rgb[2]; usbhid_submit_report(hdev, data->backlight_report, USB_DIR_OUT); } static void g19_led_set(struct led_classdev *led_cdev, enum led_brightness value, int led_num) { struct device *dev; struct hid_device *hdev; struct g19_data *data; u8 mask; /* Get the device associated with the led */ dev = led_cdev->dev->parent; /* Get the hid associated with the device */ hdev = container_of(dev, struct hid_device, dev); /* Get the underlying data value */ data = hid_get_g19data(hdev); mask = 0x80>>led_num; if (value) data->led |= mask; else data->led &= ~mask; g19_led_send(hdev); } static void g19_led_m1_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { g19_led_set(led_cdev, value, G19_LED_M1); }
static int g19_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long irq_flags; int error; struct g19_data *data; 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 */ data = kzalloc(sizeof(struct g19_data), GFP_KERNEL); if (data == NULL) { dev_err(&hdev->dev, "can't allocate space for Logitech G19 device attributes\n"); error = -ENOMEM; goto err_no_cleanup; } spin_lock_init(&data->lock); init_completion(&data->ready); data->hdev = hdev; data->ep1_urb = usb_alloc_urb(0, GFP_KERNEL); if (data->ep1_urb == NULL) { dev_err(&hdev->dev, G19_NAME ": ERROR: can't alloc ep1 urb stuff\n"); error = -ENOMEM; goto err_cleanup_data; } hid_set_drvdata(hdev, data); 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_ep1_urb; } /* Set up the input device for the key I/O */ data->input_dev = input_allocate_device(); if (data->input_dev == NULL) { dev_err(&hdev->dev, G19_NAME " error initializing the input device"); error = -ENOMEM; goto err_cleanup_ep1_urb; } input_set_drvdata(data->input_dev, hdev); data->input_dev->name = G19_NAME; data->input_dev->phys = hdev->phys; data->input_dev->uniq = hdev->uniq; data->input_dev->id.bustype = hdev->bus; data->input_dev->id.vendor = hdev->vendor; data->input_dev->id.product = hdev->product; data->input_dev->id.version = hdev->version; data->input_dev->dev.parent = hdev->dev.parent; data->input_dev->keycode = data->keycode; data->input_dev->keycodemax = G19_KEYMAP_SIZE; data->input_dev->keycodesize = sizeof(int); data->input_dev->setkeycode = g19_input_setkeycode; data->input_dev->getkeycode = g19_input_getkeycode; input_set_capability(data->input_dev, EV_KEY, KEY_UNKNOWN); data->input_dev->evbit[0] |= BIT_MASK(EV_REP); g19_initialize_keymap(data); error = input_register_device(data->input_dev); if (error) { dev_err(&hdev->dev, G19_NAME " error registering the input device"); error = -EINVAL; goto err_cleanup_input_dev; } 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: data->feature_report_4 = report; break; case 0x05: data->led_report = report; break; case 0x06: data->start_input_report = report; break; case 0x07: data->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++) { data->led_cdev[i] = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); if (data->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*/ *(data->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; } data->led_cdev[i]->name = led_name; } for (i = 0; i < LED_COUNT; i++) { led_num = i; error = led_classdev_register(&hdev->dev, data->led_cdev[i]); if (error < 0) { dev_err(&hdev->dev, G19_NAME " error registering led %d", i); error = -EINVAL; goto err_cleanup_registered_leds; } } data->gfb_data = gfb_probe(hdev, GFB_PANEL_TYPE_320_240_16); if (data->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_registered_leds; } /* * Wait here for stage 1 (substages 1-3) to complete */ wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->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 */ data->ready_stages = G19_READY_STAGE_1; } init_completion(&data->ready); data->ready_stages |= G19_READY_SUBSTAGE_4; spin_unlock_irqrestore(&data->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); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->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 */ data->ready_stages = G19_READY_STAGE_2; } init_completion(&data->ready); data->ready_stages |= G19_READY_SUBSTAGE_6; spin_unlock_irqrestore(&data->lock, irq_flags); /* * Clear the LEDs */ g19_led_send(hdev); data->rgb[0] = G19_DEFAULT_RED; data->rgb[1] = G19_DEFAULT_GREEN; data->rgb[2] = G19_DEFAULT_BLUE; g19_rgb_send(hdev); data->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); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); usbhid_submit_report(hdev, data->start_input_report, USB_DIR_IN); wait_for_completion_timeout(&data->ready, HZ); /* Protect data->ready_stages before checking whether we're ready to proceed */ spin_lock_irqsave(&data->lock, irq_flags); if (data->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 */ data->ready_stages = G19_READY_STAGE_3; } else { dbg_hid(G19_NAME " stage 3 complete\n"); } spin_unlock_irqrestore(&data->lock, irq_flags); g19_set_keymap_switching(hdev, 1); g19_ep1_read(hdev); dbg_hid("G19 activated and initialized\n"); /* Everything went well */ return 0; err_cleanup_registered_leds: for (i = 0; i < led_num; i++) led_classdev_unregister(data->led_cdev[i]); err_cleanup_led_structs: for (i = 0; i < LED_COUNT; i++) { if (data->led_cdev[i] != NULL) { if (data->led_cdev[i]->name != NULL) kfree(data->led_cdev[i]->name); kfree(data->led_cdev[i]); } } err_cleanup_input_dev_reg: input_unregister_device(data->input_dev); err_cleanup_input_dev: input_free_device(data->input_dev); err_cleanup_ep1_urb: usb_free_urb(data->ep1_urb); err_cleanup_data: /* Make sure we clean up the allocated data structure */ kfree(data); err_no_cleanup: hid_set_drvdata(hdev, NULL); return error; }
static int g19_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { unsigned long irq_flags; /* * On initialization receive a 258 byte message with * data = 6 0 255 255 255 255 255 255 255 255 ... */ struct g19_data *data; data = dev_get_drvdata(&hdev->dev); spin_lock_irqsave(&data->lock, irq_flags); if (unlikely(data->need_reset)) { g19_rgb_send(hdev); g19_led_send(hdev); data->need_reset = 0; spin_unlock_irqrestore(&data->lock, irq_flags); return 1; } if (unlikely(data->ready_stages != G19_READY_STAGE_3)) { switch (report->id) { case 6: if (!(data->ready_stages & G19_READY_SUBSTAGE_1)) data->ready_stages |= G19_READY_SUBSTAGE_1; else if (data->ready_stages & G19_READY_SUBSTAGE_4 && !(data->ready_stages & G19_READY_SUBSTAGE_5) ) data->ready_stages |= G19_READY_SUBSTAGE_5; else if (data->ready_stages & G19_READY_SUBSTAGE_6 && raw_data[1] >= 0x80) data->ready_stages |= G19_READY_SUBSTAGE_7; break; case 1: if (!(data->ready_stages & G19_READY_SUBSTAGE_2)) data->ready_stages |= G19_READY_SUBSTAGE_2; else data->ready_stages |= G19_READY_SUBSTAGE_3; break; } if (data->ready_stages == G19_READY_STAGE_1 || data->ready_stages == G19_READY_STAGE_2 || data->ready_stages == G19_READY_STAGE_3) complete_all(&data->ready); spin_unlock_irqrestore(&data->lock, irq_flags); return 1; } spin_unlock_irqrestore(&data->lock, irq_flags); if (likely(report->id == 2)) { g19_raw_event_process_input(hdev, data, raw_data); return 1; } return 0; }