示例#1
0
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);
}
示例#2
0
/* 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);
}
示例#3
0
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);
}
示例#4
0
文件: hid-g19.c 项目: tanktarta/lg4l
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;
}
示例#5
0
文件: hid-g19.c 项目: tanktarta/lg4l
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;
}
示例#6
0
文件: hid-g19.c 项目: tanktarta/lg4l
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);
}
示例#7
0
文件: hid-g19.c 项目: tanktarta/lg4l
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;
}
示例#8
0
文件: hid-g19.c 项目: tanktarta/lg4l
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;
}