From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: "Rick L. Vinyard, Jr." <rvinyard@cs.nmsu.edu>
Cc: linux-kernel@vger.kernel.org, felipe.balbi@nokia.com,
pavel@ucw.cz, jayakumar.lkml@gmail.com,
linux-fbdev@vger.kernel.org, krzysztof.h1@wp.pl,
akpm@linux-foundation.org, linux-usb@vger.kernel.org,
oliver@neukum.org, linux-input@vger.kernel.org, jkosina@suse.cz
Subject: Re: [PATCH] hid: Logitech G13 driver 0.0.3
Date: Fri, 8 Jan 2010 12:49:46 -0800 [thread overview]
Message-ID: <20100108204946.GA22950@core.coreip.homeip.net> (raw)
In-Reply-To: <174828e8a25d1e607eb91ab963396b2a.squirrel@intranet.cs.nmsu.edu>
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.
> >> +
> >> +static DEVICE_ATTR(keymap, 0666, g13_keymap_show, g13_keymap_store);
> >>
> >
> > No. Just use EVIOCSKEYCODE.
> >
>
> I'd really prefer to provide a sysfs interface as opposed to ioctls.
>
I really think we should stick to standard interfaces. For the reason
see above.
>
> >> +/*
> >> + * The "emit_msc_raw" attribute
> >> + */
> >> +static ssize_t g13_emit_msc_raw_show(struct device *dev,
> >> + struct device_attribute *attr,
> >> + char *buf)
> >> +{
> >> + struct g13_data *data = dev_get_drvdata(dev);
> >> +
> >> + if (data == NULL)
> >> + return -ENODATA;
> >> +
> >> + return sprintf(buf, "%u\n", data->emit_msc_raw);
> >> +}
> >> +
> >> +static ssize_t g13_set_emit_msc_raw(struct hid_device *hdev, unsigned
> >> k)
> >> +{
> >> + struct g13_data *data = hid_get_g13data(hdev);
> >> +
> >> + if (data == NULL)
> >> + return -ENODATA;
> >> +
> >> + data->emit_msc_raw = k;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static ssize_t g13_emit_msc_raw_store(struct device *dev,
> >> + struct device_attribute *attr,
> >> + const char *buf, size_t count)
> >> +{
> >> + struct hid_device *hdev;
> >> + int i;
> >> + unsigned k;
> >> + 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", &k);
> >> + if (i != 1) {
> >> + printk(KERN_ERR "unrecognized input: %s", buf);
> >> + return -1;
> >> + }
> >> +
> >> + set_result = g13_set_emit_msc_raw(hdev, k);
> >> +
> >> + if (set_result < 0)
> >> + return set_result;
> >> +
> >> + return count;
> >> +}
> >> +
> >> +static DEVICE_ATTR(emit_msc_raw, 0666,
> >> + g13_emit_msc_raw_show,
> >> + g13_emit_msc_raw_store);
> >> +
> >
> > I do no see the need for this attribute, simply emit MSC_RAW always.
> >
>
> Will do.
>
> >> +
> >> +/*
> >> + * The "keymap_switching" attribute
> >> + */
> >> +static ssize_t g13_keymap_switching_show(struct device *dev,
> >> + struct device_attribute *attr,
> >> + char *buf)
> >> +{
> >> + struct g13_data *data = dev_get_drvdata(dev);
> >> +
> >> + if (data == NULL)
> >> + return -ENODATA;
> >> +
> >> + return sprintf(buf, "%u\n", data->keymap_switching);
> >> +}
> >> +
> >> +static ssize_t g13_set_keymap_switching(struct hid_device *hdev,
> >> unsigned k)
> >> +{
> >> + struct g13_data *data = hid_get_g13data(hdev);
> >> +
> >> + if (data == NULL)
> >> + return -ENODATA;
> >> +
> >> + data->keymap_switching = k;
> >> +
> >> + if (data->keymap_switching)
> >> + g13_set_mled(hdev, 1<<(data->curkeymap));
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static ssize_t g13_keymap_switching_store(struct device *dev,
> >> + struct device_attribute *attr,
> >> + const char *buf, size_t count)
> >> +{
> >> + struct hid_device *hdev;
> >> + int i;
> >> + unsigned k;
> >> + 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", &k);
> >> + if (i != 1) {
> >> + printk(KERN_ERR "unrecognized input: %s", buf);
> >> + return -1;
> >> + }
> >> +
> >> + set_result = g13_set_keymap_switching(hdev, k);
> >> +
> >> + if (set_result < 0)
> >> + return set_result;
> >> +
> >> + return count;
> >> +}
> >> +
> >> +static DEVICE_ATTR(keymap_switching, 0666,
> >> + g13_keymap_switching_show,
> >> + g13_keymap_switching_store);
> >
> > Hmm, attributes that are changing device state are usually 0644.
> >
>
> Fixed.
>
> >> +
> >> +
> >> +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.
>
> >> +
> >> +/*
> >> + * 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.
...
> >> +
> >> + 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.
>
> >> +
> >> + 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.
Thanks.
--
Dmitry
next prev parent reply other threads:[~2010-01-08 20:49 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 [this message]
[not found] ` <20100108204946.GA22950-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>
2010-01-08 22:27 ` Rick L. Vinyard, Jr.
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=20100108204946.GA22950@core.coreip.homeip.net \
--to=dmitry.torokhov@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=felipe.balbi@nokia.com \
--cc=jayakumar.lkml@gmail.com \
--cc=jkosina@suse.cz \
--cc=krzysztof.h1@wp.pl \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=oliver@neukum.org \
--cc=pavel@ucw.cz \
--cc=rvinyard@cs.nmsu.edu \
/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).