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, 08 Jan 2010 20:49:46 +0000 [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
WARNING: multiple messages have this Message-ID (diff)
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: 47+ 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 16:23 ` Rick L. Vinyard Jr.
2010-01-07 16:23 ` Rick L. Vinyard Jr.
2010-01-07 19:35 ` Pavel Machek
2010-01-07 19:35 ` Pavel Machek
2010-01-07 21:20 ` Rick L. Vinyard, Jr.
2010-01-07 21:20 ` Rick L. Vinyard, Jr.
2010-01-08 2:32 ` Jaya Kumar
2010-01-08 2:32 ` Jaya Kumar
2010-01-08 2:32 ` Jaya Kumar
2010-01-08 5:26 ` Rick L. Vinyard, Jr.
2010-01-08 5:26 ` Rick L. Vinyard, Jr.
2010-01-08 5:26 ` Rick L. Vinyard, Jr.
2010-01-09 13:43 ` Jiri Kosina
2010-01-09 13:43 ` Jiri Kosina
2010-01-09 13:43 ` Jiri Kosina
2010-01-14 18:24 ` Rick L. Vinyard, Jr.
2010-01-14 18:24 ` Rick L. Vinyard, Jr.
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 20:50 ` Rick L. Vinyard, Jr.
2010-01-14 21:03 ` Pavel Machek
2010-01-14 21:03 ` Pavel Machek
2010-01-14 22:05 ` Jiri Kosina
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 8:30 ` Dmitry Torokhov
2010-01-08 16:36 ` Pavel Machek
2010-01-08 16:36 ` Pavel Machek
2010-01-08 16:50 ` Rick L. Vinyard, Jr.
2010-01-08 16:50 ` Rick L. Vinyard, Jr.
2010-01-08 17:04 ` Pavel Machek
2010-01-08 17:04 ` Pavel Machek
2010-01-08 17:13 ` Greg KH
2010-01-08 17:13 ` Greg KH
2010-01-08 17:20 ` Dmitry Torokhov
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 17:43 ` Rick L. Vinyard, Jr.
2010-01-08 17:43 ` Rick L. Vinyard, Jr.
2010-01-08 18:32 ` Rick L. Vinyard, Jr.
2010-01-08 18:32 ` Rick L. Vinyard, Jr.
2010-01-08 20:49 ` Dmitry Torokhov [this message]
2010-01-08 20:49 ` Dmitry Torokhov
[not found] ` <20100108204946.GA22950-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>
2010-01-08 22:27 ` Rick L. Vinyard, Jr.
2010-01-08 22:27 ` Rick L. Vinyard, Jr.
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.