diff --git a/Documentation/ABI/testing/sysfs-driver-hid-picolcd b/Documentation/ABI/testing/sysfs-driver-hid-picolcd index 14f52d70621..08579e7e1e8 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-picolcd +++ b/Documentation/ABI/testing/sysfs-driver-hid-picolcd @@ -8,12 +8,21 @@ Description: Make it possible to switch the PicoLCD device between LCD enclosed in brackets ('[' and ']') Writing: causes operation mode switch. Permitted values are - the non-active mode names listed when read, optionally followed - by a delay value expressed in ms. + the non-active mode names listed when read. Note: when switching mode the current PicoLCD HID device gets - disconnected and reconnects after above delay (default value - is 5 seconds though this default should not be relied on). + disconnected and reconnects after above delay (see attribute + operation_mode_delay for its value). + + +What: /sys/bus/usb/devices/-:./::./operation_mode_delay +Date: April 2010 +Contact: Bruno Prémont +Description: Delay PicoLCD waits before restarting in new mode when + operation_mode has changed. + + Reading/Writing: It is expressed in ms and permitted range is + 0..30000ms. What: /sys/bus/usb/devices/-:./::./fb_update_rate diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 6f71c60bf65..aa6f2e18d4a 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -177,6 +177,7 @@ struct picolcd_data { int addr_sz; #endif u8 version[2]; + unsigned short opmode_delay; /* input stuff */ u8 pressed_keys[2]; struct input_dev *input_keys; @@ -1270,8 +1271,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev, struct picolcd_data *data = dev_get_drvdata(dev); struct hid_report *report = NULL; size_t cnt = count; - int timeout = 5000; - unsigned u; + int timeout = data->opmode_delay; unsigned long flags; if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { @@ -1288,20 +1288,10 @@ static ssize_t picolcd_operation_mode_store(struct device *dev, if (!report) return -EINVAL; - while (cnt > 0 && (*buf == ' ' || *buf == '\t')) { - buf++; - cnt--; - } while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) cnt--; - if (cnt > 0) { - if (sscanf(buf, "%u", &u) != 1) - return -EINVAL; - if (u > 30000) - return -EINVAL; - else - timeout = u; - } + if (cnt != 0) + return -EINVAL; spin_lock_irqsave(&data->lock, flags); hid_set_field(report->field[0], 0, timeout & 0xff); @@ -1314,6 +1304,34 @@ static ssize_t picolcd_operation_mode_store(struct device *dev, static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show, picolcd_operation_mode_store); +/* + * The "operation_mode_delay" sysfs attribute + */ +static ssize_t picolcd_operation_mode_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct picolcd_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); +} + +static ssize_t picolcd_operation_mode_delay_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct picolcd_data *data = dev_get_drvdata(dev); + unsigned u; + if (sscanf(buf, "%u", &u) != 1) + return -EINVAL; + if (u > 30000) + return -EINVAL; + else + data->opmode_delay = u; + return count; +} + +static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show, + picolcd_operation_mode_delay_store); + #ifdef CONFIG_DEBUG_FS /* @@ -2409,6 +2427,7 @@ static int picolcd_probe(struct hid_device *hdev, spin_lock_init(&data->lock); mutex_init(&data->mutex); data->hdev = hdev; + data->opmode_delay = 5000; if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) data->status |= PICOLCD_BOOTLOADER; hid_set_drvdata(hdev, data); @@ -2436,24 +2455,32 @@ static int picolcd_probe(struct hid_device *hdev, goto err_cleanup_hid_hw; } - error = device_create_file(&hdev->dev, &dev_attr_operation_mode); + error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); if (error) { dev_err(&hdev->dev, "failed to create sysfs attributes\n"); goto err_cleanup_hid_ll; } + error = device_create_file(&hdev->dev, &dev_attr_operation_mode); + if (error) { + dev_err(&hdev->dev, "failed to create sysfs attributes\n"); + goto err_cleanup_sysfs1; + } + if (data->status & PICOLCD_BOOTLOADER) error = picolcd_probe_bootloader(hdev, data); else error = picolcd_probe_lcd(hdev, data); if (error) - goto err_cleanup_sysfs; + goto err_cleanup_sysfs2; dbg_hid(PICOLCD_NAME " activated and initialized\n"); return 0; -err_cleanup_sysfs: +err_cleanup_sysfs2: device_remove_file(&hdev->dev, &dev_attr_operation_mode); +err_cleanup_sysfs1: + device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); err_cleanup_hid_ll: hdev->ll_driver->close(hdev); err_cleanup_hid_hw: @@ -2478,6 +2505,7 @@ static void picolcd_remove(struct hid_device *hdev) picolcd_exit_devfs(data); device_remove_file(&hdev->dev, &dev_attr_operation_mode); + device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); hdev->ll_driver->close(hdev); hid_hw_stop(hdev); hid_set_drvdata(hdev, NULL);