static void g19_led_bl_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { struct device *dev; struct hid_device *hdev; struct g19_data *data; /* 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); if (led_cdev == data->led_cdev[G19_LED_BL_R]) data->rgb[0] = value; else if (led_cdev == data->led_cdev[G19_LED_BL_G]) data->rgb[1] = value; else if (led_cdev == data->led_cdev[G19_LED_BL_B]) data->rgb[2] = value; g19_rgb_send(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 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; }