linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Rick L. Vinyard, Jr." <rvinyard-qcTL/1vZYtiVc3sceRu5cw@public.gmane.org>
To: Dmitry Torokhov
	<dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org,
	pavel-+ZI9xUNit7I@public.gmane.org,
	jayakumar.lkml-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	krzysztof.h1-5tc4TXWwyLM@public.gmane.org,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org,
	linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	jkosina-AlSwsSmVLrQ@public.gmane.org
Subject: Re: [PATCH] hid: Logitech G13 driver 0.0.3
Date: Fri, 8 Jan 2010 15:27:04 -0700	[thread overview]
Message-ID: <00a07c3325a5a8a7f746ecc118cc0a66.squirrel@intranet.cs.nmsu.edu> (raw)
In-Reply-To: <20100108204946.GA22950-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>

Dmitry Torokhov wrote:
> On Fri, Jan 08, 2010 at 11:32:29AM -0700, Rick L. Vinyard, Jr. wrote:
>> Dmitry Torokhov wrote:
>> > Hi Rick,
>> >
>> > On Thu, Jan 07, 2010 at 09:23:24AM -0700, Rick L. Vinyard Jr. wrote:
>> >> +
>> >> +static int g13_input_setkeycode(struct input_dev *dev,
>> >> +				int scancode,
>> >> +				int keycode)
>> >> +{
>> >> +	int old_keycode;
>> >> +	int i;
>> >> +	struct g13_data *data = input_get_g13data(dev);
>> >> +
>> >> +	if (data == NULL)
>> >> +		return -EINVAL;
>> >> +
>> >> +	if (scancode >= dev->keycodemax)
>> >> +		return -EINVAL;
>> >> +
>> >> +	if (!dev->keycodesize)
>> >> +		return -EINVAL;
>> >> +
>> >> +	if (dev->keycodesize < sizeof(keycode) &&
>> >> +	    (keycode >> (dev->keycodesize * 8)))
>> >> +		return -EINVAL;
>> >> +
>> >> +	write_lock(&data->lock);
>> >> +
>> >> +	old_keycode = data->keycode[scancode];
>> >> +	data->keycode[scancode] = keycode;
>> >> +
>> >> +	clear_bit(old_keycode, dev->keybit);
>> >> +	set_bit(keycode, dev->keybit);
>> >> +
>> >> +	for (i = 0; i < dev->keycodemax; i++) {
>> >> +		if (data->keycode[i] == old_keycode) {
>> >> +			set_bit(old_keycode, dev->keybit);
>> >> +			break; /* Setting the bit twice is useless, so break */
>> >> +		}
>> >> +	}
>> >> +
>> >> +	write_unlock(&data->lock);
>> >> +
>> >> +	return 0;
>> >> +}
>> >> +
>> >> +static int g13_input_getkeycode(struct input_dev *dev,
>> >> +				int scancode,
>> >> +				int *keycode)
>> >> +{
>> >> +	struct g13_data *data = input_get_g13data(dev);
>> >> +
>> >> +	if (!dev->keycodesize)
>> >> +		return -EINVAL;
>> >> +
>> >> +	if (scancode >= dev->keycodemax)
>> >> +		return -EINVAL;
>> >> +
>> >> +	read_lock(&data->lock);
>> >> +
>> >> +	*keycode = data->keycode[scancode];
>> >> +
>> >> +	read_unlock(&data->lock);
>> >> +
>> >> +	return 0;
>> >> +}
>> >
>> > Default input core methods should cover this, no?
>> >
>>
>> I couldn't find this exposed from input core through sysfs anywhere.
>> From
>> userspace I could access it from an ioctl, but I'd prefer to allow
>> userspace to do everything from libsysfs rather than a mixture of
>> libsysfs
>> and ioctls.
>>
>> I did make sure the ioctls are still supported by providing functions to
>> input_dev->setkeycode and input_dev->getkeycode.
>>
>
> Unfortunately the input core does more stuff after driver-specific
> routines
> get called. And I am planning to add device rebinding upong keymap
> change and more stuff.
>

What if I use input_set_keycode()? That way I bypass the ioctl but stay
within the input core standard interface.

>> >> +
>> >> +
>> >> +static ssize_t g13_name_show(struct device *dev,
>> >> +			     struct device_attribute *attr,
>> >> +			     char *buf)
>> >> +{
>> >> +	struct g13_data *data = dev_get_drvdata(dev);
>> >> +	int result;
>> >> +
>> >> +	if (data == NULL)
>> >> +		return -ENODATA;
>> >> +
>> >> +	if (data->name == NULL) {
>> >> +		buf[0] = 0x00;
>> >> +		return 1;
>> >> +	}
>> >> +
>> >> +	read_lock(&data->lock);
>> >> +	result = sprintf(buf, "%s", data->name);
>> >> +	read_unlock(&data->lock);
>> >> +
>> >> +	return result;
>> >> +}
>> >> +
>> >> +static ssize_t g13_name_store(struct device *dev,
>> >> +			      struct device_attribute *attr,
>> >> +			      const char *buf, size_t count)
>> >> +{
>> >> +	struct g13_data *data = dev_get_drvdata(dev);
>> >> +	size_t limit = count;
>> >> +	char *end;
>> >> +
>> >> +	if (data == NULL)
>> >> +		return -ENODATA;
>> >> +
>> >> +	write_lock(&data->lock);
>> >> +
>> >> +	if (data->name != NULL) {
>> >> +		kfree(data->name);
>> >> +		data->name = NULL;
>> >> +	}
>> >> +
>> >> +	end = strpbrk(buf, "\n\r");
>> >> +	if (end != NULL)
>> >> +		limit = end - buf;
>> >> +
>> >> +	if (end != buf) {
>> >> +
>> >> +		if (limit > 100)
>> >> +			limit = 100;
>> >> +
>> >> +		data->name = kzalloc(limit+1, GFP_KERNEL);
>> >> +
>> >> +		strncpy(data->name, buf, limit);
>> >> +	}
>> >> +
>> >> +	write_unlock(&data->lock);
>> >> +
>> >> +	return count;
>> >> +}
>> >> +
>> >> +static DEVICE_ATTR(name, 0666, g13_name_show, g13_name_store);
>> >
>> > What this attribute is for?
>> >
>>
>> To provide a mnemonic identifier for the device that can be shared
>> across
>> applications. It also allows a userspace application to lookup a device
>> by
>> name through sysfs.
>
> To set it you need to identify sysfs path fisrt. Once you've identified
> sysfs path you can simply use it in other apps. So I do not see the need
> for the name.
>

>From an app I use it like this (g13_device is a typedef of struct
udev_device):

g13_device* g13_device_new_from_name( const char * find ) {
  g13_list_entry* devices;
  g13_list_entry *list_entry;
  g13_device* device;
  char* name;

  devices = g13_enumerate_scan_devices_get_list_entry( NULL );

  g13_list_entry_foreach( list_entry, devices ) {
    device = g13_device_new_from_list_entry( list_entry );
    if ( device == NULL ) continue;
    name = g13_device_get_name( device );
    if ( name==NULL || find==NULL || strcmp( name,find )==0 ) {
      g13_device_free_name( name );
      return device;
    }
    g13_device_free_name( name );
    g13_device_unref( device );
  }

  return NULL;
}

Then, an app can be executed by the user with something like:

[ ~]$ g13-set-backlight --name left 255 0 0
[ ~]$ g13-set-backlight --name right 0 255 0

After popt arg processing g13-set-backlight is as simple as:

  device = g13_device_new_from_name(name);
  if ( device != NULL )
  {
    g13_device_set_rgb( device, r, g, b );
    g13_device_unref(device);
  }


>>
>> >> +
>> >> +/*
>> >> + * The "rgb" attribute
>> >> + * red green blue
>> >> + * each with values 0 - 255 (black - full intensity)
>> >> + */
>> >> +static ssize_t g13_rgb_show(struct device *dev,
>> >> +			    struct device_attribute *attr,
>> >> +			    char *buf)
>> >> +{
>> >> +	unsigned r, g, b;
>> >> +	struct g13_data *data = dev_get_drvdata(dev);
>> >> +
>> >> +	if (data == NULL)
>> >> +		return -ENODATA;
>> >> +
>> >> +	r = data->rgb[0];
>> >> +	g = data->rgb[1];
>> >> +	b = data->rgb[2];
>> >> +
>> >> +	return sprintf(buf, "%u %u %u\n", r, g, b);
>> >> +}
>> >> +
>> >> +static ssize_t g13_set_rgb(struct hid_device *hdev,
>> >> +			   unsigned r, unsigned g, unsigned b)
>> >> +{
>> >> +	struct g13_data *data = hid_get_g13data(hdev);
>> >> +
>> >> +	if (data == NULL || data->backlight_report == NULL)
>> >> +		return -ENODATA;
>> >> +
>> >> +	data->backlight_report->field[0]->value[0] = r;
>> >> +	data->backlight_report->field[0]->value[1] = g;
>> >> +	data->backlight_report->field[0]->value[2] = b;
>> >> +	data->backlight_report->field[0]->value[3] = 0x00;
>> >> +
>> >> +	usbhid_submit_report(hdev, data->backlight_report, USB_DIR_OUT);
>> >> +
>> >> +	data->rgb[0] = r;
>> >> +	data->rgb[1] = g;
>> >> +	data->rgb[2] = b;
>> >> +
>> >> +	return 0;
>> >> +}
>> >> +
>> >> +static ssize_t g13_rgb_store(struct device *dev,
>> >> +			     struct device_attribute *attr,
>> >> +			     const char *buf, size_t count)
>> >> +{
>> >> +	struct hid_device *hdev;
>> >> +	int i;
>> >> +	unsigned r;
>> >> +	unsigned g;
>> >> +	unsigned b;
>> >> +	ssize_t set_result;
>> >> +
>> >> +	/* Get the hid associated with the device */
>> >> +	hdev = container_of(dev, struct hid_device, dev);
>> >> +
>> >> +	/* If we have an invalid pointer we'll return ENODATA */
>> >> +	if (hdev == NULL || &(hdev->dev) != dev)
>> >> +		return -ENODATA;
>> >> +
>> >> +	i = sscanf(buf, "%u %u %u", &r, &g, &b);
>> >> +	if (i != 3) {
>> >> +		printk(KERN_ERR "unrecognized input: %s", buf);
>> >> +		return -1;
>> >> +	}
>> >> +
>> >> +	set_result = g13_set_rgb(hdev, r, g, b);
>> >> +
>> >> +	if (set_result < 0)
>> >> +		return set_result;
>> >> +
>> >> +	return count;
>> >> +}
>> >> +
>> >> +static DEVICE_ATTR(rgb, 0666, g13_rgb_show, g13_rgb_store);
>> >> +
>> >> +/*
>> >> + * Create a group of attributes so that we can create and destroy
>> them
>> >> all
>> >> + * at once.
>> >> + */
>> >> +static struct attribute *g13_attrs[] = {
>> >> +	&dev_attr_name.attr,
>> >> +	&dev_attr_rgb.attr,
>> >> +	&dev_attr_mled.attr,
>> >> +	&dev_attr_keymap_index.attr,
>> >> +	&dev_attr_emit_msc_raw.attr,
>> >> +	&dev_attr_keymap_switching.attr,
>> >> +	&dev_attr_keymap.attr,
>> >> +	&dev_attr_fb_update_rate.attr,
>> >> +	&dev_attr_fb_node.attr,
>> >> +	NULL,	 /* need to NULL terminate the list of attributes */
>> >> +};
>> >> +
>> >> +/*
>> >> + * An unnamed attribute group will put all of the attributes
>> directly
>> >> in
>> >> + * the kobject directory.  If we specify a name, a subdirectory will
>> be
>> >> + * created for the attributes with the directory being the name of
>> the
>> >> + * attribute group.
>> >> + */
>> >> +static struct attribute_group g13_attr_group = {
>> >> +	.attrs = g13_attrs,
>> >> +};
>> >> +
>> >> +static struct fb_deferred_io g13_fb_defio = {
>> >> +	.delay = HZ / G13FB_UPDATE_RATE_DEFAULT,
>> >> +	.deferred_io = g13_fb_deferred_io,
>> >> +};
>> >> +
>> >> +static void g13_raw_event_process_input(struct hid_device *hdev,
>> >> +					struct g13_data *g13data,
>> >> +     u8 *raw_data)
>> >> +{
>> >> +	struct input_dev *idev = g13data->input_dev;
>> >> +	unsigned int code;
>> >> +	int value;
>> >> +	int i;
>> >> +	int mask;
>> >> +	int offset;
>> >> +	u8 val;
>> >> +
>> >> +	g13data->ready2 = 1;
>> >> +
>> >> +	if (idev == NULL)
>> >> +		return;
>> >> +
>> >> +	if (g13data->curkeymap < 3)
>> >> +		offset = G13_KEYS * g13data->curkeymap;
>> >> +	else
>> >> +		offset = 0;
>> >> +
>> >> +	for (i = 0, mask = 0x01; i < 8; i++, mask <<= 1) {
>> >> +		/* Keys G1 through G8 */
>> >> +		code = g13data->keycode[i+offset];
>> >> +		value = raw_data[3] & mask;
>> >> +		if (g13data->keycode[i] != KEY_RESERVED)
>> >> +			input_report_key(idev, code, value);
>> >> +		input_event(idev, EV_MSC, MSC_SCAN, i);
>> >
>> > That means these MSC_SCAN events are emitted _always_. Not sure if
>> that
>> > is too useful. If you were to detect the state change and emit
>> MSC_SCAN
>> > for changed keys, that would be better.
>> >
>>
>> I couldn't find anything that really explained the purpose of MSC_SCAN.
>> Can I use it just to report scancodes?
>
> Yes, it purpose if to report scancode or it's equivalent of pressed key.
>
>>
>> In particular can I selectively emit MSC_SCAN when I only want to report
>> specific events such as an unmapped key or a special key such as the
>> backlight or one of the M* keys?
>
> You could, but then users would not really know what scancode to use to
> remap already mapped key. The problem with your approach that userspace
> will get 10 MSC_SCAN before getting KEY_* event. Not terribly useful.
>
> ...
>

I'll change it to only emit MSC_SCAN when a key with no mapping or when an
M* key has a state change.

That will allow me to simplify the MSC_RAW as well.

>> >> +
>> >> +	dbg_hid("Found all reports\n");
>> >> +
>> >> +	for (i = 0; i < 20; i++) {
>> >> +		if (data->ready && data->ready2)
>> >> +			break;
>> >> +		mdelay(10);
>> >> +	}
>> >
>> > Consider using completion?
>> >
>>
>> I'm not sure what you mean.
>
> Look at wait_for_completion() and wait_completion_timeout() functions.
> These are proper APIs to wait for completion of a certain task instead
> of busily (or sleepily) spinning.
>

That sounds much better. That will allow me to extend the initialization
time a bit as well... probably 500ms or so.

>>
>> >> +
>> >> +	if (!(data->ready && data->ready2))
>> >> +		printk(KERN_ERR "G13 hasn't responded yet, forging ahead with
>> >> initialization\n");
>> >> +	else
>> >> +		dbg_hid("G13 initialized\n");
>> >> +
>> >> +	/*
>> >> +	 * Set the initial color and load the linux logo
>> >> +	 * We're going to ignore the error values. If there is an error at
>> >> this
>> >> +	 * point we'll forge ahead.
>> >> +	 */
>> >> +
>> >> +	dbg_hid("Set default color\n");
>> >> +
>> >> +	error = g13_set_rgb(hdev, G13_DEFAULT_RED, G13_DEFAULT_GREEN,
>> >> G13_DEFAULT_BLUE);
>> >
>> > And...?
>> >
>>
>> I had an error message before, but took it out. Missed taking out the
>> "error =" since at this point we'll just forge ahead.
>>
>> Although failing to set the backlight color at this point could indicate
>> some I/O issue it's not critical enough to fail driver initialization.
>>
>
> Then dev_warn() is your friend.
>

Excellent.

Thanks again,

---

Rick


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

      parent reply	other threads:[~2010-01-08 22:27 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-07 16:23 [PATCH] hid: Logitech G13 driver 0.0.3 Rick L. Vinyard Jr.
2010-01-07 19:35 ` Pavel Machek
2010-01-07 21:20   ` Rick L. Vinyard, Jr.
2010-01-08  2:32 ` Jaya Kumar
2010-01-08  5:26   ` Rick L. Vinyard, Jr.
2010-01-09 13:43     ` Jiri Kosina
2010-01-14 18:24       ` Rick L. Vinyard, Jr.
2010-01-14 20:50         ` Best way to post Logitech G13 driver 0.0.4? Rick L. Vinyard, Jr.
2010-01-14 21:03           ` Pavel Machek
2010-01-14 22:05           ` Jiri Kosina
2010-01-08  8:30 ` [PATCH] hid: Logitech G13 driver 0.0.3 Dmitry Torokhov
2010-01-08 16:36   ` Pavel Machek
2010-01-08 16:50     ` Rick L. Vinyard, Jr.
2010-01-08 17:04       ` Pavel Machek
2010-01-08 17:13         ` Greg KH
2010-01-08 17:20           ` Dmitry Torokhov
     [not found]             ` <201001080920.51979.dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2010-01-08 17:43               ` Rick L. Vinyard, Jr.
2010-01-08 18:32   ` Rick L. Vinyard, Jr.
2010-01-08 20:49     ` Dmitry Torokhov
     [not found]       ` <20100108204946.GA22950-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>
2010-01-08 22:27         ` Rick L. Vinyard, Jr. [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=00a07c3325a5a8a7f746ecc118cc0a66.squirrel@intranet.cs.nmsu.edu \
    --to=rvinyard-qctl/1vzytivc3sceru5cw@public.gmane.org \
    --cc=akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org \
    --cc=dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org \
    --cc=jayakumar.lkml-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=jkosina-AlSwsSmVLrQ@public.gmane.org \
    --cc=krzysztof.h1-5tc4TXWwyLM@public.gmane.org \
    --cc=linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org \
    --cc=pavel-+ZI9xUNit7I@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).