* Dell Latitude E7440 - ALPS touchpad keeps having state reset
From: Allan Crooks @ 2014-01-27 15:23 UTC (permalink / raw)
To: linux-input
Hi,
I've reported the problem I'm having in more detail here:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1258837
In summary - I keep suffering from the mouse pointer jumping around
erratically, with the following messages output to syslog:
psmouse serio1: DualPoint TouchPad at isa0060/serio1/input0 lost sync at byte 1
psmouse serio1: DualPoint TouchPad at isa0060/serio1/input0 - driver resynced.
Other people have reported the same problem in that bug report.
Bisecting the kernel, the problem seems to have always been in place
as soon as the touchpad was correctly identified; according to xinput
- it's a "AlpsPS/2 ALPS DualPoint TouchPad". When it was being
identified as a generic PS/2 mouse, there's no problem (though of
course, there's also no touchpad functionality available either).
Is there anything I can do to help provide information to get this fixed?
Thanks,
Allan.
^ permalink raw reply
* [PATCH v2 2/2] HID: sony: Add output events for the multi-touch pad on the Dualshock 4.
From: Frank Praznik @ 2014-01-27 15:17 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, Frank Praznik
In-Reply-To: <1390835857-4523-1-git-send-email-frank.praznik@oh.rr.com>
Add output events for the multi-touch pad on the Dualshock 4.
The touchpad has a resolution of 1920x940 and is capable of 2 simultaneous
touches. A 'Type B' stateful slot protocol is implemented as defined in
Documentation/input/multi-touch-protocol.txt
Applications can use the touchpad data by processing the ABS_MT_SLOT,
ABS_MT_TRACKING_ID, ABS_MT_POSITION_X and ABS_MT_POSITION_Y events.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 04fd611..2bd3f13 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -32,6 +32,7 @@
#include <linux/leds.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
+#include <linux/input/mt.h>
#include "hid-ids.h"
@@ -643,7 +644,11 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
{
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
unsigned long flags;
+ int n, offset = 35;
__u8 cable_state, battery_capacity, battery_charging;
/* The lower 4 bits of byte 30 contain the battery level
@@ -669,6 +674,28 @@ static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
sc->battery_capacity = battery_capacity;
sc->battery_charging = battery_charging;
spin_unlock_irqrestore(&sc->lock, flags);
+
+ /* The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB.
+ * The first 7 bits of the first byte is a counter and bit 8 is a touch
+ * indicator that is 0 when pressed and 1 when not pressed.
+ * The next 3 bytes are two 12 bit touch coordinates, X and Y.
+ * The data for the second touch is in the same format and immediatly
+ * follows the data for the first.
+ */
+ for (n = 0; n < 2; n++) {
+ __u16 x, y;
+
+ x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8);
+ y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
+
+ input_mt_slot(input_dev, n);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+ !(rd[offset] >> 7));
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+ offset += 4;
+ }
}
static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -1200,6 +1227,26 @@ static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
return -EINVAL;
}
+static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
+ int w, int h)
+{
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ int ret;
+
+ ret = input_mt_init_slots(input_dev, touch_count, 0);
+ if (ret < 0) {
+ hid_err(sc->hdev, "Unable to initialize multi-touch slots\n");
+ return ret;
+ }
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0);
+
+ return 0;
+}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -1249,6 +1296,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
+ /* The Dualshock 4 touchpad supports 2 touches and has a
+ * resolution of 1920x940.
+ */
+ ret = sony_register_touchpad(sc, 2, 1920, 940);
+ if (ret < 0)
+ goto err_stop;
+
INIT_WORK(&sc->state_worker, dualshock4_state_worker);
} else {
ret = 0;
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 1/2] HID: sony: Add battery status reporting for the Sixaxis and Dualshock 4 controllers.
From: Frank Praznik @ 2014-01-27 15:17 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, Frank Praznik
Add battery status reporting for the Sixaxis and Dualshock 4 controllers.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
v2 of the patch fixes a small logic error where the battery_charging flag was
flipped on the Sixaxis.
The line: battery_charging = rd[30] & 0x01;
should be: battery_charging = !(rd[30] & 0x01);
since the low bit is 0 when charging and 1 when charging is complete.
drivers/hid/hid-sony.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 185 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 1235405..04fd611 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -30,6 +30,8 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/leds.h>
+#include <linux/power_supply.h>
+#include <linux/spinlock.h>
#include "hid-ids.h"
@@ -42,6 +44,7 @@
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_USB)
#define MAX_LEDS 4
@@ -487,18 +490,30 @@ static const unsigned int buzz_keymap[] = {
[20] = BTN_TRIGGER_HAPPY20,
};
+static enum power_supply_property sony_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_STATUS,
+};
+
struct sony_sc {
+ spinlock_t lock;
struct hid_device *hdev;
struct led_classdev *leds[MAX_LEDS];
struct hid_report *output_report;
unsigned long quirks;
struct work_struct state_worker;
+ struct power_supply battery;
#ifdef CONFIG_SONY_FF
__u8 left;
__u8 right;
#endif
+ __u8 cable_state;
+ __u8 battery_charging;
+ __u8 battery_capacity;
__u8 led_state[MAX_LEDS];
__u8 led_count;
};
@@ -599,6 +614,63 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
+ unsigned long flags;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /* The sixaxis is charging if the battery value is 0xee
+ * and it is fully charged if the value is 0xef.
+ * It does not report the actual level while charging so it
+ * is set to 100% while charging is in progress.
+ */
+ if (rd[30] >= 0xee) {
+ battery_capacity = 100;
+ battery_charging = rd[30] & 0x01;
+ } else {
+ battery_capacity = sixaxis_battery_capacity[rd[30]];
+ battery_charging = 0;
+ }
+ cable_state = (rd[31] >> 4) & 0x01;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ unsigned long flags;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /* The lower 4 bits of byte 30 contain the battery level
+ * and the 5th bit contains the USB cable state.
+ */
+ cable_state = (rd[30] >> 4) & 0x01;
+ battery_capacity = rd[30] & 0x0F;
+
+ /* On USB the Dualshock 4 battery level goes from 0 to 11.
+ * A battery level of 11 means fully charged.
+ */
+ if (cable_state && battery_capacity == 11)
+ battery_charging = 0;
+ else
+ battery_charging = 1;
+
+ if (battery_capacity > 10)
+ battery_capacity--;
+ battery_capacity *= 10;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+}
+
static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
__u8 *rd, int size)
{
@@ -613,6 +685,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
swap(rd[43], rd[44]);
swap(rd[45], rd[46]);
swap(rd[47], rd[48]);
+
+ sixaxis_parse_report(sc, rd, size);
+ } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 &&
+ size == 64) {
+ dualshock4_parse_report(sc, rd, size);
}
return 0;
@@ -1011,6 +1088,91 @@ static void sony_destroy_ff(struct hid_device *hdev)
}
#endif
+static int sony_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct sony_sc *sc = container_of(psy, struct sony_sc, battery);
+ unsigned long flags;
+ int ret = 0;
+ u8 battery_charging, battery_capacity, cable_state;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ battery_charging = sc->battery_charging;
+ battery_capacity = sc->battery_capacity;
+ cable_state = sc->cable_state;
+ spin_unlock_irqrestore(&sc->lock, flags);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ if (battery_charging)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ if (battery_capacity == 100 && cable_state)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int sony_battery_probe(struct sony_sc *sc)
+{
+ static atomic_t power_id_seq = ATOMIC_INIT(0);
+ unsigned long power_id;
+ struct hid_device *hdev = sc->hdev;
+ int ret;
+
+ power_id = (unsigned long)atomic_inc_return(&power_id_seq);
+
+ sc->battery.properties = sony_battery_props;
+ sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
+ sc->battery.get_property = sony_battery_get_property;
+ sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ sc->battery.use_for_apm = 0;
+ sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
+ power_id);
+ if (!sc->battery.name)
+ return -ENOMEM;
+
+ ret = power_supply_register(&hdev->dev, &sc->battery);
+ if (ret) {
+ hid_err(hdev, "Unable to register battery device\n");
+ goto err_free;
+ }
+
+ power_supply_powers(&sc->battery, &hdev->dev);
+ return 0;
+
+err_free:
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
+ return ret;
+}
+
+static void sony_battery_remove(struct sony_sc *sc)
+{
+ if (!sc->battery.name)
+ return;
+
+ power_supply_unregister(&sc->battery);
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
+}
+
static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
{
struct list_head *head, *list;
@@ -1101,14 +1263,31 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
}
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ ret = sony_battery_probe(sc);
+ if (ret < 0)
+ goto err_stop;
+
+ /* Open the device to receive reports with battery info */
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ hid_err(hdev, "hw open failed\n");
+ goto err_stop;
+ }
+ }
+
ret = sony_init_ff(hdev);
if (ret < 0)
- goto err_stop;
+ goto err_close;
return 0;
+err_close:
+ hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
+ if (sc->quirks & SONY_BATTERY_SUPPORT)
+ sony_battery_remove(sc);
hid_hw_stop(hdev);
return ret;
}
@@ -1120,6 +1299,11 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ hid_hw_close(hdev);
+ sony_battery_remove(sc);
+ }
+
sony_destroy_ff(hdev);
hid_hw_stop(hdev);
--
1.8.3.2
^ permalink raw reply related
* Re: [RFC][PATCH] Input: i8042 - fix PNP modaliases when both aux and kdb are enabled
From: Tom Gundersen @ 2014-01-27 14:57 UTC (permalink / raw)
To: linux-input@vger.kernel.org; +Cc: Tom Gundersen, Dmitry Torokhov
In-Reply-To: <1390770052-26499-1-git-send-email-teg@jklm.no>
On Sun, Jan 26, 2014 at 10:00 PM, Tom Gundersen <teg@jklm.no> wrote:
> Commit 78551277e4 exposed the PNP modaliases for the i8042 module. However,
> the aux entries overrode the kbd ones.
>
> Refactor the device_id lists to expose both the aux and the kbd modaliases.
>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Tom Gundersen <teg@jklm.no>
> ---
> Hi Dmitry,
>
> I don't know if there is a better way to do this, so sending as an RFC.
Please disregard this patch for now, I'll first try to get in a
generic fix to MODULE_DEVICE_TABLE().
Cheers,
Tom
> drivers/input/serio/i8042-x86ia64io.h | 67 ++++++++++++++++++++---------------
> 1 file changed, 39 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
> index 0ec9abb..dbc6958 100644
> --- a/drivers/input/serio/i8042-x86ia64io.h
> +++ b/drivers/input/serio/i8042-x86ia64io.h
> @@ -747,25 +747,27 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
> return 0;
> }
>
> -static struct pnp_device_id pnp_kbd_devids[] = {
> - { .id = "PNP0300", .driver_data = 0 },
> - { .id = "PNP0301", .driver_data = 0 },
> - { .id = "PNP0302", .driver_data = 0 },
> - { .id = "PNP0303", .driver_data = 0 },
> - { .id = "PNP0304", .driver_data = 0 },
> - { .id = "PNP0305", .driver_data = 0 },
> - { .id = "PNP0306", .driver_data = 0 },
> - { .id = "PNP0309", .driver_data = 0 },
> - { .id = "PNP030a", .driver_data = 0 },
> - { .id = "PNP030b", .driver_data = 0 },
> - { .id = "PNP0320", .driver_data = 0 },
> - { .id = "PNP0343", .driver_data = 0 },
> - { .id = "PNP0344", .driver_data = 0 },
> - { .id = "PNP0345", .driver_data = 0 },
> +#define KBD_DEVIDS \
> + { .id = "PNP0300", .driver_data = 0 }, \
> + { .id = "PNP0301", .driver_data = 0 }, \
> + { .id = "PNP0302", .driver_data = 0 }, \
> + { .id = "PNP0303", .driver_data = 0 }, \
> + { .id = "PNP0304", .driver_data = 0 }, \
> + { .id = "PNP0305", .driver_data = 0 }, \
> + { .id = "PNP0306", .driver_data = 0 }, \
> + { .id = "PNP0309", .driver_data = 0 }, \
> + { .id = "PNP030a", .driver_data = 0 }, \
> + { .id = "PNP030b", .driver_data = 0 }, \
> + { .id = "PNP0320", .driver_data = 0 }, \
> + { .id = "PNP0343", .driver_data = 0 }, \
> + { .id = "PNP0344", .driver_data = 0 }, \
> + { .id = "PNP0345", .driver_data = 0 }, \
> { .id = "CPQA0D7", .driver_data = 0 },
> +
> +static struct pnp_device_id pnp_kbd_devids[] = {
> + KBD_DEVIDS
> { .id = "", },
> };
> -MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids);
>
> static struct pnp_driver i8042_pnp_kbd_driver = {
> .name = "i8042 kbd",
> @@ -773,21 +775,23 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
> .probe = i8042_pnp_kbd_probe,
> };
>
> -static struct pnp_device_id pnp_aux_devids[] = {
> - { .id = "AUI0200", .driver_data = 0 },
> - { .id = "FJC6000", .driver_data = 0 },
> - { .id = "FJC6001", .driver_data = 0 },
> - { .id = "PNP0f03", .driver_data = 0 },
> - { .id = "PNP0f0b", .driver_data = 0 },
> - { .id = "PNP0f0e", .driver_data = 0 },
> - { .id = "PNP0f12", .driver_data = 0 },
> - { .id = "PNP0f13", .driver_data = 0 },
> - { .id = "PNP0f19", .driver_data = 0 },
> - { .id = "PNP0f1c", .driver_data = 0 },
> +#define AUX_DEVIDS \
> + { .id = "AUI0200", .driver_data = 0 }, \
> + { .id = "FJC6000", .driver_data = 0 }, \
> + { .id = "FJC6001", .driver_data = 0 }, \
> + { .id = "PNP0f03", .driver_data = 0 }, \
> + { .id = "PNP0f0b", .driver_data = 0 }, \
> + { .id = "PNP0f0e", .driver_data = 0 }, \
> + { .id = "PNP0f12", .driver_data = 0 }, \
> + { .id = "PNP0f13", .driver_data = 0 }, \
> + { .id = "PNP0f19", .driver_data = 0 }, \
> + { .id = "PNP0f1c", .driver_data = 0 }, \
> { .id = "SYN0801", .driver_data = 0 },
> +
> +static struct pnp_device_id pnp_aux_devids[] = {
> + AUX_DEVIDS
> { .id = "", },
> };
> -MODULE_DEVICE_TABLE(pnp, pnp_aux_devids);
>
> static struct pnp_driver i8042_pnp_aux_driver = {
> .name = "i8042 aux",
> @@ -795,6 +799,13 @@ static struct pnp_driver i8042_pnp_aux_driver = {
> .probe = i8042_pnp_aux_probe,
> };
>
> +static struct pnp_device_id pnp_kdb_aux_devids[] = {
> + KBD_DEVIDS
> + AUX_DEVIDS
> + { .id = "", },
> +};
> +MODULE_DEVICE_TABLE(pnp, pnp_kdb_aux_devids);
> +
> static void i8042_pnp_exit(void)
> {
> if (i8042_pnp_kbd_registered) {
> --
> 1.8.5.3
>
^ permalink raw reply
* Re: [PATCH] USB: input: gtco.c: fix usb_dev leak
From: Greg Kroah-Hartman @ 2014-01-27 13:17 UTC (permalink / raw)
To: Alexey Khoroshilov
Cc: Dmitry Torokhov, linux-input, linux-kernel, ldv-project
In-Reply-To: <52E63503.3060804@ispras.ru>
On Mon, Jan 27, 2014 at 02:29:23PM +0400, Alexey Khoroshilov wrote:
> On 27.01.2014 10:54, Dmitry Torokhov wrote:
> > Hi Alexey,
> >
> > On Mon, Jan 27, 2014 at 10:31:36AM +0400, Alexey Khoroshilov wrote:
> >> On 21.01.2014 23:59, Dmitry Torokhov wrote:
> >>> On Sun, Jan 19, 2014 at 03:24:26AM +0400, Alexey Khoroshilov wrote:
> >>>> There is usb_get_dev() in gtco_probe(), but there is no usb_put_dev()
> >>>> anywhere in the driver.
> >>>>
> >>>> The patch adds usb_get_dev() to failure handling code of gtco_probe()
> >>>> and to gtco_disconnect(().
> >>> Hmm, I think gtco should simply not use usb_get_dev() in the first
> >>> place.
> >>>
> >>> Thanks.
> >> Dear Dmitry,
> >>
> >> Could you please clarify why usb_get_dev() not needed here?
> >> We store reference to usb_dev in gtco structure, so we should refcount it.
> >> What is wrong in this reasoning?
> > The lifetime of gtco structure is already directly tied to lifetime of
> > usb_dev: when destroying usb_dev driver core will call remove() function
> > of currently bound driver (in our case gtco) which will destroy gtco
> > memory.
> >
> > Taking additional reference is not needed here.
> >
> > Hope this helps.
> Thank you, that helps a lot.
>
> By the way, usb_skeleton suggests to use usb_get_dev()/usb_put_dev()
> nevertheless.
>
> Greg, may be it makes sense to fix usb_skeleton as well?
Patches are always welcome.
^ permalink raw reply
* Re: [PATCH] USB: input: gtco.c: fix usb_dev leak
From: Alexey Khoroshilov @ 2014-01-27 10:29 UTC (permalink / raw)
To: Dmitry Torokhov, Greg Kroah-Hartman
Cc: linux-input, linux-kernel, ldv-project
In-Reply-To: <20140127065416.GA11945@core.coreip.homeip.net>
On 27.01.2014 10:54, Dmitry Torokhov wrote:
> Hi Alexey,
>
> On Mon, Jan 27, 2014 at 10:31:36AM +0400, Alexey Khoroshilov wrote:
>> On 21.01.2014 23:59, Dmitry Torokhov wrote:
>>> On Sun, Jan 19, 2014 at 03:24:26AM +0400, Alexey Khoroshilov wrote:
>>>> There is usb_get_dev() in gtco_probe(), but there is no usb_put_dev()
>>>> anywhere in the driver.
>>>>
>>>> The patch adds usb_get_dev() to failure handling code of gtco_probe()
>>>> and to gtco_disconnect(().
>>> Hmm, I think gtco should simply not use usb_get_dev() in the first
>>> place.
>>>
>>> Thanks.
>> Dear Dmitry,
>>
>> Could you please clarify why usb_get_dev() not needed here?
>> We store reference to usb_dev in gtco structure, so we should refcount it.
>> What is wrong in this reasoning?
> The lifetime of gtco structure is already directly tied to lifetime of
> usb_dev: when destroying usb_dev driver core will call remove() function
> of currently bound driver (in our case gtco) which will destroy gtco
> memory.
>
> Taking additional reference is not needed here.
>
> Hope this helps.
Thank you, that helps a lot.
By the way, usb_skeleton suggests to use usb_get_dev()/usb_put_dev()
nevertheless.
Greg, may be it makes sense to fix usb_skeleton as well?
--
Alexey
^ permalink raw reply
* Re: [PATCH] Input: i8042-io - Exclude mips platforms when allocating/deallocating IO regions.
From: Dmitry Torokhov @ 2014-01-27 6:56 UTC (permalink / raw)
To: Raghu Gandham
Cc: aaro.koskinen@iki.fi, linux-input@vger.kernel.org,
linux-mips@linux-mips.org, linux-kernel@vger.kernel.org
In-Reply-To: <E2EE47005FA75F44B80E1019FDD2EBBB6E38B06D@BADAG02.ba.imgtec.org>
On Mon, Jan 27, 2014 at 12:32:36AM +0000, Raghu Gandham wrote:
> Hi Dmitry,
>
> >
> > On Sat, Jan 25, 2014 at 11:01:54AM -0800, Raghu Gandham wrote:
> > > The standard IO regions are already reserved by the platform code on
> > > most MIPS devices(malta, cobalt, sni). The Commit
> > > 197a1e96c8be5b6005145af3a4c0e45e2d651444
> > > ("Input: i8042-io - fix up region handling on MIPS") introduced a bug
> > > on these MIPS platforms causing i8042 driver to fail when trying to reserve
> > IO ports.
> > > Prior to the above mentioned commit request_region is skipped on MIPS
> > > but release_region is called.
> > >
> > > This patch reverts commit 197a1e96c8be5b6005145af3a4c0e45e2d651444
> > and
> > > also avoids calling release_region for MIPS.
> >
> > The problem is that IO regions are reserved on _most_, but not _all_ devices.
> > MIPS should figure out what they want to do with i8042 registers and be
> > consistent on all devices.
>
> Please examine the attached patch which went upstream in April of 2004. Since then
> it had been a convention not to call request_region routine in i8042 for MIPS. The
> attached patch had a glitch that it guarded request_region in i8042-io.h but skipped
> guarding release_region in i8042-io.h. I believe that the issue Aaro saw was due to this
> glitch. Below is the error quoted in Aaro's commit message.
>
> [ 2.112000] Trying to free nonexistent resource <0000000000000060-000000000000006f>
>
> My patch reinstates the convention followed on MIPS devices along with fixing Aaro's issue.
I assume that Aaro did test his patch and on his box request_region()
succeeds. That would indicate that various MIPS sub-arches still not
settled on the topic.
Aaro?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] USB: input: gtco.c: fix usb_dev leak
From: Dmitry Torokhov @ 2014-01-27 6:54 UTC (permalink / raw)
To: Alexey Khoroshilov
Cc: Greg Kroah-Hartman, linux-input, linux-kernel, ldv-project
In-Reply-To: <52E5FD48.7040208@ispras.ru>
Hi Alexey,
On Mon, Jan 27, 2014 at 10:31:36AM +0400, Alexey Khoroshilov wrote:
> On 21.01.2014 23:59, Dmitry Torokhov wrote:
> > On Sun, Jan 19, 2014 at 03:24:26AM +0400, Alexey Khoroshilov wrote:
> >> There is usb_get_dev() in gtco_probe(), but there is no usb_put_dev()
> >> anywhere in the driver.
> >>
> >> The patch adds usb_get_dev() to failure handling code of gtco_probe()
> >> and to gtco_disconnect(().
> > Hmm, I think gtco should simply not use usb_get_dev() in the first
> > place.
> >
> > Thanks.
> Dear Dmitry,
>
> Could you please clarify why usb_get_dev() not needed here?
> We store reference to usb_dev in gtco structure, so we should refcount it.
> What is wrong in this reasoning?
The lifetime of gtco structure is already directly tied to lifetime of
usb_dev: when destroying usb_dev driver core will call remove() function
of currently bound driver (in our case gtco) which will destroy gtco
memory.
Taking additional reference is not needed here.
Hope this helps.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: synaptics-rmi4 - Count IRQs before creating functions; save F01 container.
From: Dmitry Torokhov @ 2014-01-27 6:36 UTC (permalink / raw)
To: Christopher Heiny
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Jean Delvare, Joerie de Gram, Linus Walleij,
Benjamin Tissoires
In-Reply-To: <1389390814-4063-1-git-send-email-cheiny@synaptics.com>
Hi Christopher,
On Fri, Jan 10, 2014 at 01:53:34PM -0800, Christopher Heiny wrote:
>
> err_free_data:
> + rmi_free_function_list(rmi_dev);
> + if (gpio_is_valid(pdata->attn_gpio))
> + gpio_free(pdata->attn_gpio);
> + devm_kfree(&rmi_dev->dev, data->irq_status);
> + devm_kfree(&rmi_dev->dev, data->current_irq_mask);
> + devm_kfree(&rmi_dev->dev, data->irq_mask_store);
> + devm_kfree(&rmi_dev->dev, data);
It is rarely makes sense to explicitly free devm-managed data. In
general I find that RMI code is very confused about when devm-managed
resources are released (they only released after failed probe or remove,
but we use devm_kzalloc to allocate function's interrupt masks during
device creation and they will get freed only when parent unbinds, etc).
Given that you mentioned firmware flash in the work and I expect we'll
be destroying and re-creating functions and other data structures at
will I think we should limit use of devm APIs so that lifetime
management is explicit and clear.
I tried adjusting the patch so that it works with the version of PDT
cleanup patch I posted a few minutes ago, please let me know what you
think.
Thanks.
--
Dmitry
Input: synaptics-rmi4 - count IRQs before creating functions
From: Christopher Heiny <cheiny@synaptics.com>
Because creating a function can trigger events that result in the IRQ related
storage being accessed, we need to count the IRQs and allocate their storage
before the functions are created, rather than counting them as the functions
are created and allocating them afterwards. Since we know the number of IRQs
already, we can allocate the mask at function creation time, rather than in
a post-creation loop. Also, the F01 function_container is needed elsewhere,
so we need to save it here.
In order to keep the IRQ count logic sane in bootloader mode, we move the
check for bootloader mode from F01 initialization to the IRQ counting routine.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/rmi4/rmi_driver.c | 250 +++++++++++++++++++++++----------------
drivers/input/rmi4/rmi_driver.h | 1
drivers/input/rmi4/rmi_f01.c | 9 -
3 files changed, 149 insertions(+), 111 deletions(-)
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index b9eb8a5..3362f58 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -184,6 +184,7 @@ static void rmi_free_function_list(struct rmi_device *rmi_dev)
list_for_each_entry_safe_reverse(fn, tmp,
&data->function_list, node) {
list_del(&fn->node);
+ kfree(fn->irq_mask);
rmi_unregister_function(fn);
}
}
@@ -256,21 +257,20 @@ static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
return 0;
}
-static void process_one_interrupt(struct rmi_function *fn,
- unsigned long *irq_status, struct rmi_driver_data *data)
+static void process_one_interrupt(struct rmi_driver_data *data,
+ struct rmi_function *fn)
{
struct rmi_function_handler *fh;
- DECLARE_BITMAP(irq_bits, data->num_of_irq_regs);
if (!fn || !fn->dev.driver)
return;
fh = to_rmi_function_handler(fn->dev.driver);
if (fn->irq_mask && fh->attention) {
- bitmap_and(irq_bits, irq_status, fn->irq_mask,
- data->irq_count);
- if (!bitmap_empty(irq_bits, data->irq_count))
- fh->attention(fn, irq_bits);
+ bitmap_and(data->fn_irq_bits, data->irq_status, fn->irq_mask,
+ data->irq_count);
+ if (!bitmap_empty(data->fn_irq_bits, data->irq_count))
+ fh->attention(fn, data->fn_irq_bits);
}
}
@@ -306,11 +306,9 @@ static int process_interrupt_requests(struct rmi_device *rmi_dev)
* recent kernels (say, 3.3 and higher), this should be switched to
* use irq_chip.
*/
- list_for_each_entry(entry, &data->function_list, node) {
+ list_for_each_entry(entry, &data->function_list, node)
if (entry->irq_mask)
- process_one_interrupt(entry, data->irq_status,
- data);
- }
+ process_one_interrupt(data, entry);
return 0;
}
@@ -469,12 +467,12 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
int rmi_driver_irq_get_mask(struct rmi_device *rmi_dev,
struct rmi_function *fn)
{
- int i;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int i;
/* call devm_kcalloc when it will be defined in kernel in future */
fn->irq_mask = devm_kzalloc(&rmi_dev->dev,
- BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
+ BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long),
GFP_KERNEL);
if (fn->irq_mask) {
@@ -604,7 +602,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
return error;
}
- mdelay(pdata->reset_delay_ms);
+ mdelay(pdata->reset_delay_ms ?: DEFAULT_RESET_DELAY_MS);
return RMI_SCAN_DONE;
}
@@ -613,6 +611,51 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
return pdt->page_start == 0 ? RMI_SCAN_CONTINUE : -ENODEV;
}
+/* Indicates that flash programming is enabled (bootloader mode). */
+#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
+
+/*
+ * Given the PDT entry for F01, read the device status register to determine
+ * if we're stuck in bootloader mode or not.
+ *
+ */
+static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
+ const struct pdt_entry *pdt)
+{
+ int error;
+ u8 device_status;
+
+ error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
+ &device_status);
+ if (error) {
+ dev_err(&rmi_dev->dev,
+ "Failed to read device status: %d\n", error);
+ return error;
+ }
+
+ return RMI_F01_STATUS_BOOTLOADER(device_status);
+}
+
+static int rmi_count_irqs(struct rmi_device *rmi_dev,
+ void *ctx, const struct pdt_entry *pdt)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int *irq_count = ctx;
+
+ *irq_count += pdt->interrupt_source_count;
+ if (pdt->function_number == 0x01) {
+ data->f01_bootloader_mode =
+ rmi_check_bootloader_mode(rmi_dev, pdt);
+ if (data->f01_bootloader_mode) {
+ dev_warn(&rmi_dev->dev,
+ "WARNING: RMI4 device is in bootloader mode!\n");
+ return RMI_SCAN_DONE;
+ }
+ }
+
+ return RMI_SCAN_CONTINUE;
+}
+
static int rmi_create_function(struct rmi_device *rmi_dev,
void *ctx, const struct pdt_entry *pdt)
{
@@ -621,6 +664,7 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
int *current_irq_count = ctx;
struct rmi_function *fn;
+ int i;
int error;
dev_dbg(dev, "Initializing F%02X for %s.\n",
@@ -634,53 +678,46 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
}
INIT_LIST_HEAD(&fn->node);
+ rmi_driver_copy_pdt_to_fd(pdt, &fn->fd);
fn->rmi_dev = rmi_dev;
- fn->num_of_irqs = pdt->interrupt_source_count;
+ fn->num_of_irqs = pdt->interrupt_source_count;
fn->irq_pos = *current_irq_count;
*current_irq_count += fn->num_of_irqs;
- rmi_driver_copy_pdt_to_fd(pdt, &fn->fd);
+ fn->irq_mask = kcalloc(BITS_TO_LONGS(data->irq_count),
+ sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!fn->irq_mask) {
+ dev_err(dev, "%s: Failed to create irq_mask for F%02X.\n",
+ __func__, pdt->function_number);
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ for (i = 0; i < fn->num_of_irqs; i++)
+ __set_bit(fn->irq_pos + i, fn->irq_mask);
error = rmi_register_function(fn);
if (error)
- goto err_free_mem;
+ goto err_free_irq_mask;
+
+ if (pdt->function_number == 0x01)
+ data->f01_container = fn;
list_add_tail(&fn->node, &data->function_list);
- return data->f01_bootloader_mode ? RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
+ return pdt->function_number == 0x01 && data->f01_bootloader_mode ?
+ RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
+err_free_irq_mask:
+ kfree(fn->irq_mask);
err_free_mem:
kfree(fn);
return error;
}
-static int rmi_create_functions(struct rmi_device *rmi_dev)
-{
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- int irq_count = 0;
- int retval;
-
- /*
- * XXX need to make sure we create F01 first...
- * XXX or do we? It might not be required in the updated structure.
- */
- retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
- if (retval < 0)
- return retval;
-
- /*
- * TODO: I think we need to count the IRQs before creating the
- * functions.
- */
- data->irq_count = irq_count;
- data->num_of_irq_regs = (irq_count + 7) / 8;
-
- return 0;
-}
-
-
#ifdef CONFIG_PM_SLEEP
static int rmi_driver_suspend(struct device *dev)
{
@@ -747,9 +784,9 @@ static SIMPLE_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend, rmi_driver_resume);
static int rmi_driver_remove(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
const struct rmi_device_platform_data *pdata =
to_rmi_platform_data(rmi_dev);
- const struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
disable_sensor(rmi_dev);
rmi_free_function_list(rmi_dev);
@@ -757,17 +794,22 @@ static int rmi_driver_remove(struct device *dev)
if (data->gpio_held)
gpio_free(pdata->attn_gpio);
+ kfree(data->irq_status);
+ kfree(data);
+
return 0;
}
static int rmi_driver_probe(struct device *dev)
{
struct rmi_driver *rmi_driver;
- struct rmi_driver_data *data = NULL;
- struct rmi_function *fn;
- struct rmi_device_platform_data *pdata;
- int retval = 0;
+ struct rmi_driver_data *data;
+ const struct rmi_device_platform_data *pdata;
struct rmi_device *rmi_dev;
+ size_t size;
+ void *irq_memory;
+ int irq_count;
+ int retval;
dev_dbg(dev, "%s: Starting probe.\n", __func__);
@@ -787,6 +829,7 @@ static int rmi_driver_probe(struct device *dev)
dev_err(dev, "%s: Failed to allocate driver data.\n", __func__);
return -ENOMEM;
}
+
INIT_LIST_HEAD(&data->function_list);
data->rmi_dev = rmi_dev;
dev_set_drvdata(&rmi_dev->dev, data);
@@ -813,80 +856,79 @@ static int rmi_driver_probe(struct device *dev)
* and leave the customer's device unusable. So we warn them, and
* continue processing.
*/
- if (!pdata->reset_delay_ms)
- pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
retval = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
- if (retval)
+ if (retval < 0)
dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
- retval = rmi_create_functions(rmi_dev);
+ retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, &data->pdt_props);
if (retval) {
- dev_err(dev, "PDT scan for %s failed with code %d.\n",
- pdata->sensor_name, retval);
- goto err_free_data;
+ /*
+ * We'll print out a warning and continue since failure to
+ * get the PDT properties is not a cause to fail.
+ */
+ dev_warn(dev, "Could not read PDT properties from %#06x: %d. Assuming 0x00.\n",
+ PDT_PROPERTIES_LOCATION, retval);
}
- if (!data->f01_container) {
- dev_err(dev, "missing F01 container!\n");
- retval = -EINVAL;
- goto err_free_data;
+ /*
+ * We need to count the IRQs and allocate their storage before scanning
+ * the PDT and creating the function entries, because adding a new
+ * function can trigger events that result in the IRQ related storage
+ * being accessed.
+ */
+ dev_dbg(dev, "Counting IRQs.\n");
+ irq_count = 0;
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+ if (retval < 0) {
+ dev_err(dev, "IRQ counting for %s failed with code %d.\n",
+ pdata->sensor_name, retval);
+ goto err_free_mem;
}
- list_for_each_entry(fn, &data->function_list, node) {
- retval = rmi_driver_irq_get_mask(rmi_dev, fn);
- if (retval < 0) {
- dev_err(dev, "%s: Failed to create irq_mask.\n",
- __func__);
- goto err_free_data;
- }
- }
+ data->irq_count = irq_count;
+ data->num_of_irq_regs = (data->irq_count + 7) / 8;
- retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, &data->pdt_props);
- if (retval < 0) {
- /*
- * we'll print out a warning and continue since
- * failure to get the PDT properties is not a cause to fail
- */
- dev_warn(dev, "Could not read PDT properties from %#06x. Assuming 0x00.\n",
- PDT_PROPERTIES_LOCATION);
+ mutex_init(&data->irq_mutex);
+
+ size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+ irq_memory = kzalloc(size * 4, GFP_KERNEL);
+ if (!irq_memory) {
+ dev_err(dev, "Failed to allocate memory for irq masks.\n");
+ goto err_free_mem;
}
- mutex_init(&data->irq_mutex);
- data->irq_status = devm_kzalloc(dev,
- BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
- GFP_KERNEL);
- if (!data->irq_status) {
- dev_err(dev, "Failed to allocate irq_status.\n");
- retval = -ENOMEM;
- goto err_free_data;
+ data->irq_status = irq_memory + size * 0;
+ data->fn_irq_bits = irq_memory + size * 1;
+ data->current_irq_mask = irq_memory + size * 2;
+ data->irq_mask_store = irq_memory + size * 3;
+
+ /*
+ * XXX need to make sure we create F01 first...
+ * XXX or do we? It might not be required in the updated structure.
+ */
+ irq_count = 0;
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+ if (retval < 0) {
+ dev_err(dev, "Function creation failed with code %d.\n",
+ retval);
+ goto err_destroy_functions;
}
- data->current_irq_mask = devm_kzalloc(dev,
- data->num_of_irq_regs,
- GFP_KERNEL);
- if (!data->current_irq_mask) {
- dev_err(dev, "Failed to allocate current_irq_mask.\n");
- retval = -ENOMEM;
- goto err_free_data;
+ if (!data->f01_container) {
+ dev_err(dev, "missing F01 container!\n");
+ retval = -EINVAL;
+ goto err_destroy_functions;
}
retval = rmi_read_block(rmi_dev,
- data->f01_container->fd.control_base_addr+1,
+ data->f01_container->fd.control_base_addr + 1,
data->current_irq_mask, data->num_of_irq_regs);
if (retval < 0) {
dev_err(dev, "%s: Failed to read current IRQ mask.\n",
__func__);
- goto err_free_data;
+ goto err_destroy_functions;
}
- data->irq_mask_store = devm_kzalloc(dev,
- BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
- GFP_KERNEL);
- if (!data->irq_mask_store) {
- dev_err(dev, "Failed to allocate mask store.\n");
- retval = -ENOMEM;
- goto err_free_data;
- }
if (IS_ENABLED(CONFIG_PM)) {
data->pm_data = pdata->pm_data;
data->pre_suspend = pdata->pre_suspend;
@@ -951,8 +993,12 @@ static int rmi_driver_probe(struct device *dev)
return 0;
- err_free_data:
- return retval;
+err_destroy_functions:
+ rmi_free_function_list(rmi_dev);
+ kfree(irq_memory);
+err_free_mem:
+ kfree(data);
+ return retval < 0 ? retval : 0;
}
struct rmi_driver rmi_physical_driver = {
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 9ecd31b..d071ff5 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -45,6 +45,7 @@ struct rmi_driver_data {
int num_of_irq_regs;
int irq_count;
unsigned long *irq_status;
+ unsigned long *fn_irq_bits;
unsigned long *current_irq_mask;
unsigned long *irq_mask_store;
bool irq_stored;
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index cf1081f..381ad60 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -59,8 +59,6 @@ struct f01_basic_properties {
/* Most recent device status event */
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
/* The device has lost its configuration for some reason. */
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
@@ -372,13 +370,6 @@ static int rmi_f01_initialize(struct rmi_function *fn)
goto error_exit;
}
- driver_data->f01_bootloader_mode =
- RMI_F01_STATUS_BOOTLOADER(data->device_status);
- if (driver_data->f01_bootloader_mode)
- dev_warn(&rmi_dev->dev,
- "WARNING: RMI4 device is in bootloader mode!\n");
-
-
if (RMI_F01_STATUS_UNCONFIGURED(data->device_status)) {
dev_err(&fn->dev,
"Device was reset during configuration process, status: %#02x!\n",
^ permalink raw reply related
* Re: [PATCH] USB: input: gtco.c: fix usb_dev leak
From: Alexey Khoroshilov @ 2014-01-27 6:31 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Greg Kroah-Hartman, linux-input, linux-kernel, ldv-project
In-Reply-To: <20140121195957.GB29615@core.coreip.homeip.net>
On 21.01.2014 23:59, Dmitry Torokhov wrote:
> On Sun, Jan 19, 2014 at 03:24:26AM +0400, Alexey Khoroshilov wrote:
>> There is usb_get_dev() in gtco_probe(), but there is no usb_put_dev()
>> anywhere in the driver.
>>
>> The patch adds usb_get_dev() to failure handling code of gtco_probe()
>> and to gtco_disconnect(().
> Hmm, I think gtco should simply not use usb_get_dev() in the first
> place.
>
> Thanks.
Dear Dmitry,
Could you please clarify why usb_get_dev() not needed here?
We store reference to usb_dev in gtco structure, so we should refcount it.
What is wrong in this reasoning?
Thanks,
Alexey
^ permalink raw reply
* Re: [PATCH v2] input synaptics-rmi4: PDT scan cleanup
From: Dmitry Torokhov @ 2014-01-27 6:30 UTC (permalink / raw)
To: Christopher Heiny
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Jean Delvare, Joerie de Gram, Linus Walleij,
Benjamin Tissoires
In-Reply-To: <1390438569-11395-1-git-send-email-cheiny@synaptics.com>
Hi Christopher,
On Wed, Jan 22, 2014 at 04:56:09PM -0800, Christopher Heiny wrote:
> Eliminates copy-paste code that handled scans of the Page Descriptor
> Table, replacing it with a single PDT scan routine that invokes a
> callback function. The scan routine is not static so that it can be
> used by the firmware update code (under development, not yet submitted).
>
> Symbols that no longer needed to be public were moved into rmi_driver.c.
>
> Updated the copyright dates and eliminate C++ style comments while we
> were at it.
>
> Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
I compared the 2 versions that you posted and I realized that losing
error codes from lower levels by reducing them to RMI_SCAN_ERROR is not
the best option, so I took your first patch as a basis and tried to
rework it a bit so that we:
- do not have special logic in generic scan routine regarding bootloader
mode, and
- do not leave with mutex locked in case of PDT read error.
I also added start page address to PDT structure so we do not have to
pass it around so much.
Please let me know if the patch below makes sense to you (only compile
tested, as always).
Thanks!
--
Dmitry
Input: input synaptics-rmi4 - PDT scan cleanup
From: Christopher Heiny <cheiny@synaptics.com>
Eliminates copy-paste code that handled scans of the Page Descriptor Table,
replacing it with a single PDT scan routine that invokes a callback function.
The scan routine is not static so that it can be used by the firmware update
code (under development, not yet submitted).
Updated the copyright dates while we were at it.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/rmi4/rmi_driver.c | 258 ++++++++++++++++++++-------------------
drivers/input/rmi4/rmi_driver.h | 3
2 files changed, 132 insertions(+), 129 deletions(-)
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index c01a6b8..b9eb8a5 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2013 Synaptics Incorporated
+ * Copyright (c) 2011-2014 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This driver provides the core support for a single RMI4-based device.
@@ -467,7 +467,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
* Construct a function's IRQ mask. This should be called once and stored.
*/
int rmi_driver_irq_get_mask(struct rmi_device *rmi_dev,
- struct rmi_function *fn) {
+ struct rmi_function *fn)
+{
int i;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
@@ -491,12 +492,13 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
int error;
error = rmi_read_block(rmi_dev, pdt_address, buf, RMI_PDT_ENTRY_SIZE);
- if (error < 0) {
+ if (error) {
dev_err(&rmi_dev->dev, "Read PDT entry at %#06x failed, code: %d.\n",
pdt_address, error);
return error;
}
+ entry->page_start = pdt_address / RMI4_PAGE_SIZE;
entry->query_base_addr = buf[0];
entry->command_base_addr = buf[1];
entry->control_base_addr = buf[2];
@@ -509,27 +511,115 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
}
EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
-static void rmi_driver_copy_pdt_to_fd(struct pdt_entry *pdt,
- struct rmi_function_descriptor *fd,
- u16 page_start)
+static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
+ struct rmi_function_descriptor *fd)
{
- fd->query_base_addr = pdt->query_base_addr + page_start;
- fd->command_base_addr = pdt->command_base_addr + page_start;
- fd->control_base_addr = pdt->control_base_addr + page_start;
- fd->data_base_addr = pdt->data_base_addr + page_start;
+ fd->query_base_addr = pdt->query_base_addr + pdt->page_start;
+ fd->command_base_addr = pdt->command_base_addr + pdt->page_start;
+ fd->control_base_addr = pdt->control_base_addr + pdt->page_start;
+ fd->data_base_addr = pdt->data_base_addr + pdt->page_start;
fd->function_number = pdt->function_number;
fd->interrupt_source_count = pdt->interrupt_source_count;
fd->function_version = pdt->function_version;
}
-static int create_function(struct rmi_device *rmi_dev,
- struct pdt_entry *pdt,
- int *current_irq_count,
- u16 page_start)
+#define RMI_SCAN_CONTINUE 0
+#define RMI_SCAN_DONE 1
+
+static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
+ int page,
+ void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev,
+ void *ctx,
+ const struct pdt_entry *entry))
+{
+ struct pdt_entry pdt_entry;
+ u16 page_start = RMI4_PAGE_SIZE * page;
+ u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
+ u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
+ u16 addr;
+ int error;
+ int retval;
+
+ for (addr = pdt_start; addr >= pdt_end; addr -= RMI_PDT_ENTRY_SIZE) {
+ error = rmi_read_pdt_entry(rmi_dev, &pdt_entry, addr);
+ if (error)
+ return error;
+
+ if (RMI4_END_OF_PDT(pdt_entry.function_number))
+ break;
+
+ dev_dbg(&rmi_dev->dev, "Found F%02X on page %#04x\n",
+ pdt_entry.function_number, page);
+
+ retval = callback(rmi_dev, ctx, &pdt_entry);
+ if (retval != RMI_SCAN_CONTINUE)
+ return retval;
+ }
+
+ return RMI_SCAN_CONTINUE;
+}
+
+static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev,
+ void *ctx,
+ const struct pdt_entry *entry))
+{
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int page;
+ int retval = RMI_SCAN_DONE;
+
+ /*
+ * TODO: With F01 and reflash as part of the core now, is this
+ * lock still required?
+ */
+ mutex_lock(&data->pdt_mutex);
+
+ for (page = 0; page <= RMI4_MAX_PAGE; page++) {
+ retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
+ if (retval != RMI_SCAN_CONTINUE)
+ break;
+ }
+
+ mutex_unlock(&data->pdt_mutex);
+
+ return retval < 0 ? retval : 0;
+}
+
+static int rmi_initial_reset(struct rmi_device *rmi_dev,
+ void *ctx, const struct pdt_entry *pdt)
+{
+ int error;
+
+ if (pdt->function_number == 0x01) {
+ u16 cmd_addr = pdt->page_start + pdt->command_base_addr;
+ u8 cmd_buf = RMI_DEVICE_RESET_CMD;
+ const struct rmi_device_platform_data *pdata =
+ to_rmi_platform_data(rmi_dev);
+
+ error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
+ if (error) {
+ dev_err(&rmi_dev->dev,
+ "Initial reset failed. Code = %d.\n", error);
+ return error;
+ }
+
+ mdelay(pdata->reset_delay_ms);
+
+ return RMI_SCAN_DONE;
+ }
+
+ /* F01 should always be on page 0. If we don't find it there, fail. */
+ return pdt->page_start == 0 ? RMI_SCAN_CONTINUE : -ENODEV;
+}
+
+static int rmi_create_function(struct rmi_device *rmi_dev,
+ void *ctx, const struct pdt_entry *pdt)
{
struct device *dev = &rmi_dev->dev;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
+ int *current_irq_count = ctx;
struct rmi_function *fn;
int error;
@@ -551,7 +641,7 @@ static int create_function(struct rmi_device *rmi_dev,
fn->irq_pos = *current_irq_count;
*current_irq_count += fn->num_of_irqs;
- rmi_driver_copy_pdt_to_fd(pdt, &fn->fd, page_start);
+ rmi_driver_copy_pdt_to_fd(pdt, &fn->fd);
error = rmi_register_function(fn);
if (error)
@@ -559,131 +649,38 @@ static int create_function(struct rmi_device *rmi_dev,
list_add_tail(&fn->node, &data->function_list);
- return 0;
+ return data->f01_bootloader_mode ? RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
err_free_mem:
kfree(fn);
return error;
}
-/*
- * Scan the PDT for F01 so we can force a reset before anything else
- * is done. This forces the sensor into a known state, and also
- * forces application of any pending updates from reflashing the
- * firmware or configuration.
- *
- * We have to do this before actually building the PDT because the reflash
- * updates (if any) might cause various registers to move around.
- */
-static int rmi_initial_reset(struct rmi_device *rmi_dev)
+static int rmi_create_functions(struct rmi_device *rmi_dev)
{
- struct pdt_entry pdt_entry;
- int page;
- struct device *dev = &rmi_dev->dev;
- bool done = false;
- bool has_f01 = false;
- int i;
- int retval;
- const struct rmi_device_platform_data *pdata =
- to_rmi_platform_data(rmi_dev);
-
- dev_dbg(dev, "Initial reset.\n");
-
- for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
- u16 page_start = RMI4_PAGE_SIZE * page;
- u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
- u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
-
- done = true;
- for (i = pdt_start; i >= pdt_end; i -= RMI_PDT_ENTRY_SIZE) {
- retval = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
- if (retval < 0)
- return retval;
-
- if (RMI4_END_OF_PDT(pdt_entry.function_number))
- break;
- done = false;
-
- if (pdt_entry.function_number == 0x01) {
- u16 cmd_addr = page_start +
- pdt_entry.command_base_addr;
- u8 cmd_buf = RMI_DEVICE_RESET_CMD;
- retval = rmi_write_block(rmi_dev, cmd_addr,
- &cmd_buf, 1);
- if (retval < 0) {
- dev_err(dev, "Initial reset failed. Code = %d.\n",
- retval);
- return retval;
- }
- mdelay(pdata->reset_delay_ms);
- done = true;
- has_f01 = true;
- break;
- }
- }
- }
-
- if (!has_f01) {
- dev_warn(dev, "WARNING: Failed to find F01 for initial reset.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int rmi_scan_pdt(struct rmi_device *rmi_dev)
-{
- struct rmi_driver_data *data;
- struct pdt_entry pdt_entry;
- int page;
- struct device *dev = &rmi_dev->dev;
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int irq_count = 0;
- bool done = false;
- int i;
int retval;
- dev_dbg(dev, "Scanning PDT...\n");
-
- data = dev_get_drvdata(&rmi_dev->dev);
- mutex_lock(&data->pdt_mutex);
-
- for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
- u16 page_start = RMI4_PAGE_SIZE * page;
- u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
- u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
-
- done = true;
- for (i = pdt_start; i >= pdt_end; i -= RMI_PDT_ENTRY_SIZE) {
- retval = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
- if (retval < 0)
- goto error_exit;
-
- if (RMI4_END_OF_PDT(pdt_entry.function_number))
- break;
-
- dev_dbg(dev, "Found F%02X on page %#04x\n",
- pdt_entry.function_number, page);
- done = false;
-
- // XXX need to make sure we create F01 first...
- retval = create_function(rmi_dev,
- &pdt_entry, &irq_count, page_start);
+ /*
+ * XXX need to make sure we create F01 first...
+ * XXX or do we? It might not be required in the updated structure.
+ */
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+ if (retval < 0)
+ return retval;
- if (retval)
- goto error_exit;
- }
- done = done || data->f01_bootloader_mode;
- }
+ /*
+ * TODO: I think we need to count the IRQs before creating the
+ * functions.
+ */
data->irq_count = irq_count;
data->num_of_irq_regs = (irq_count + 7) / 8;
- dev_dbg(dev, "%s: Done with PDT scan.\n", __func__);
- retval = 0;
-error_exit:
- mutex_unlock(&data->pdt_mutex);
- return retval;
+ return 0;
}
+
#ifdef CONFIG_PM_SLEEP
static int rmi_driver_suspend(struct device *dev)
{
@@ -797,10 +794,15 @@ static int rmi_driver_probe(struct device *dev)
/*
* Right before a warm boot, the sensor might be in some unusual state,
- * such as F54 diagnostics, or F34 bootloader mode. In order to clear
- * the sensor to a known state, we issue a initial reset to clear any
+ * such as F54 diagnostics, or F34 bootloader mode after a firmware
+ * or configuration update. In order to clear the sensor to a known
+ * state and/or apply any updates, we issue a initial reset to clear any
* previous settings and force it into normal operation.
*
+ * We have to do this before actually building the PDT because
+ * the reflash updates (if any) might cause various registers to move
+ * around.
+ *
* For a number of reasons, this initial reset may fail to return
* within the specified time, but we'll still be able to bring up the
* driver normally after that failure. This occurs most commonly in
@@ -813,11 +815,11 @@ static int rmi_driver_probe(struct device *dev)
*/
if (!pdata->reset_delay_ms)
pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
- retval = rmi_initial_reset(rmi_dev);
+ retval = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
if (retval)
dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
- retval = rmi_scan_pdt(rmi_dev);
+ retval = rmi_create_functions(rmi_dev);
if (retval) {
dev_err(dev, "PDT scan for %s failed with code %d.\n",
pdata->sensor_name, retval);
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 4f44a54..9ecd31b 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2013 Synaptics Incorporated
+ * Copyright (c) 2011-2014 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
@@ -94,6 +94,7 @@ struct rmi_driver_data {
#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
struct pdt_entry {
+ u16 page_start;
u8 query_base_addr;
u8 command_base_addr;
u8 control_base_addr;
^ permalink raw reply related
* [PATCH] input: pxa27x-keypad: bug fix of getting scan code
From: Chao Xie @ 2014-01-27 4:41 UTC (permalink / raw)
To: linux-input, dmitry.torokhov, linux-arm-kernel, xiechao.mail; +Cc: Chao Xie
From: Chao Xie <chao.xie@marvell.com>
The rows of pxa27x-keypad used by each boards are not fixed.
So in the driver, it will get the rows from DT and register
the keymap as:
matrix_keypad_build_keymap(keymap_data, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
But the scan code is gotten as
MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
It is not correct. Fix it as
MATRIX_SCAN_CODE(row, col, keypad->row_shift);
row_shift is calculated from pdata->matrix_key_rows.
Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
drivers/input/keyboard/pxa27x_keypad.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index d8241ba..8da3eb0 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -113,6 +113,7 @@ struct pxa27x_keypad {
/* state row bits of each column scan */
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
+ uint32_t row_shift;
uint32_t direct_key_state;
unsigned int direct_key_mask;
@@ -139,6 +140,7 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
pdata->matrix_key_rows = rows;
pdata->matrix_key_cols = cols;
+ keypad->row_shift = get_count_order(pdata->matrix_key_cols);
error = matrix_keypad_build_keymap(NULL, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
@@ -359,6 +361,7 @@ static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
if (error)
return error;
+ keypad->row_shift = get_count_order(pdata->matrix_key_cols);
/*
* The keycodes may not only include matrix keys but also the direct
* or rotary keys.
@@ -467,7 +470,8 @@ scan:
if ((bits_changed & (1 << row)) == 0)
continue;
- code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad->keycodes[code],
new_state[col] & (1 << row));
--
1.8.3.2
^ permalink raw reply related
* RE: [PATCH] Input: i8042-io - Exclude mips platforms when allocating/deallocating IO regions.
From: Raghu Gandham @ 2014-01-27 0:32 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: aaro.koskinen@iki.fi, linux-input@vger.kernel.org,
linux-mips@linux-mips.org, linux-kernel@vger.kernel.org
In-Reply-To: <20140126214952.GD18840@core.coreip.homeip.net>
[-- Attachment #1: Type: text/plain, Size: 1480 bytes --]
Hi Dmitry,
>
> On Sat, Jan 25, 2014 at 11:01:54AM -0800, Raghu Gandham wrote:
> > The standard IO regions are already reserved by the platform code on
> > most MIPS devices(malta, cobalt, sni). The Commit
> > 197a1e96c8be5b6005145af3a4c0e45e2d651444
> > ("Input: i8042-io - fix up region handling on MIPS") introduced a bug
> > on these MIPS platforms causing i8042 driver to fail when trying to reserve
> IO ports.
> > Prior to the above mentioned commit request_region is skipped on MIPS
> > but release_region is called.
> >
> > This patch reverts commit 197a1e96c8be5b6005145af3a4c0e45e2d651444
> and
> > also avoids calling release_region for MIPS.
>
> The problem is that IO regions are reserved on _most_, but not _all_ devices.
> MIPS should figure out what they want to do with i8042 registers and be
> consistent on all devices.
Please examine the attached patch which went upstream in April of 2004. Since then
it had been a convention not to call request_region routine in i8042 for MIPS. The
attached patch had a glitch that it guarded request_region in i8042-io.h but skipped
guarding release_region in i8042-io.h. I believe that the issue Aaro saw was due to this
glitch. Below is the error quoted in Aaro's commit message.
[ 2.112000] Trying to free nonexistent resource <0000000000000060-000000000000006f>
My patch reinstates the convention followed on MIPS devices along with fixing Aaro's issue.
Thanks,
Raghu
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 10823 bytes --]
commit 2b7058b32c3f1706a80d54b06ad238f3c0bd09e9
Author: Andrew Morton <akpm@osdl.org>
Date: Wed Apr 21 23:37:12 2004 -0700
[PATCH] Merge missing MIPS i8042 bits
From: Ralf Baechle <ralf@linux-mips.org>
- Add HPC3 PS/2 driver bits for SGI IP22 aka Indy
- Add Mace PS/2 driver bits for SGI IP32 aka O2
- Add R4030 PS/2 driver bits for Jazz family
- Don't register I/O ports where we're using the I/O port memory window
to access the i8042 registers
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 10a54dd..cacd1f2 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -130,3 +130,13 @@ config SERIO_PCIPS2
To compile this driver as a module, choose M here: the
module will be called pcips2.
+
+config SERIO_MACEPS2
+ tristate "SGI O2 MACE PS/2 controller"
+ depends on SGI_IP32 && SERIO
+ help
+ Say Y here if you have SGI O2 workstation and want to use its
+ PS/2 ports.
+
+ To compile this driver as a module, choose M here: the
+ module will be called maceps2.
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 2eb86eb..a47dec2 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
+obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 6b434f8..9b36485 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -69,7 +69,7 @@ static inline int i8042_platform_init(void)
* On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes.
*/
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -1;
#endif
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
new file mode 100644
index 0000000..863b9c9
--- /dev/null
+++ b/drivers/input/serio/i8042-ip22io.h
@@ -0,0 +1,76 @@
+#ifndef _I8042_IP22_H
+#define _I8042_IP22_H
+
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/ip22.h>
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * Names.
+ */
+
+#define I8042_KBD_PHYS_DESC "hpc3ps2/serio0"
+#define I8042_AUX_PHYS_DESC "hpc3ps2/serio1"
+#define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d"
+
+/*
+ * IRQs.
+ */
+
+#define I8042_KBD_IRQ SGI_KEYBD_IRQ
+#define I8042_AUX_IRQ SGI_KEYBD_IRQ
+
+/*
+ * Register numbers.
+ */
+
+#define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command)
+#define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command)
+#define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data)
+
+static inline int i8042_read_data(void)
+{
+ return sgioc->kbdmouse.data;
+}
+
+static inline int i8042_read_status(void)
+{
+ return sgioc->kbdmouse.command;
+}
+
+static inline void i8042_write_data(int val)
+{
+ sgioc->kbdmouse.data = val;
+}
+
+static inline void i8042_write_command(int val)
+{
+ sgioc->kbdmouse.command = val;
+}
+
+static inline int i8042_platform_init(void)
+{
+#if 0
+ /* XXX sgi_kh is a virtual address */
+ if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042"))
+ return 1;
+#endif
+
+ i8042_reset = 1;
+
+ return 0;
+}
+
+static inline void i8042_platform_exit(void)
+{
+#if 0
+ release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb));
+#endif
+}
+
+#endif /* _I8042_IP22_H */
diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h
new file mode 100644
index 0000000..5c20ab1
--- /dev/null
+++ b/drivers/input/serio/i8042-jazzio.h
@@ -0,0 +1,69 @@
+#ifndef _I8042_JAZZ_H
+#define _I8042_JAZZ_H
+
+#include <asm/jazz.h>
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * Names.
+ */
+
+#define I8042_KBD_PHYS_DESC "R4030/serio0"
+#define I8042_AUX_PHYS_DESC "R4030/serio1"
+#define I8042_MUX_PHYS_DESC "R4030/serio%d"
+
+/*
+ * IRQs.
+ */
+
+#define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ
+#define I8042_AUX_IRQ JAZZ_MOUSE_IRQ
+
+#define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command)
+#define I8042_STATUS_REG ((unsigned long)&jazz_kh->command)
+#define I8042_DATA_REG ((unsigned long)&jazz_kh->data)
+
+static inline int i8042_read_data(void)
+{
+ return jazz_kh->data;
+}
+
+static inline int i8042_read_status(void)
+{
+ return jazz_kh->command;
+}
+
+static inline void i8042_write_data(int val)
+{
+ jazz_kh->data = val;
+}
+
+static inline void i8042_write_command(int val)
+{
+ jazz_kh->command = val;
+}
+
+static inline int i8042_platform_init(void)
+{
+#if 0
+ /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */
+ if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042"))
+ return 1;
+#endif
+
+ return 0;
+}
+
+static inline void i8042_platform_exit(void)
+{
+#if 0
+ release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2);
+#endif
+}
+
+#endif /* _I8042_JAZZ_H */
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index 3d59eb2..f0f6374 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -1,6 +1,8 @@
#ifndef _I8042_H
#define _I8042_H
+#include <linux/config.h>
+
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
@@ -13,7 +15,11 @@
* Arch-dependent inline functions and defines.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_MIPS_JAZZ)
+#include "i8042-jazzio.h"
+#elif defined(CONFIG_SGI_IP22)
+#include "i8042-ip22io.h"
+#elif defined(CONFIG_PPC)
#include "i8042-ppcio.h"
#elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)
#include "i8042-sparcio.h"
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
new file mode 100644
index 0000000..c7db1de
--- /dev/null
+++ b/drivers/input/serio/maceps2.c
@@ -0,0 +1,160 @@
+/*
+ * SGI O2 MACE PS2 controller driver for linux
+ *
+ * Copyright (C) 2002 Vivien Chappelier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+
+MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org");
+MODULE_DESCRIPTION("SGI O2 MACE PS2 controller driver");
+MODULE_LICENSE("GPL");
+
+#define MACE_PS2_TIMEOUT 10000 /* in 50us unit */
+
+#define PS2_STATUS_CLOCK_SIGNAL BIT(0) /* external clock signal */
+#define PS2_STATUS_CLOCK_INHIBIT BIT(1) /* clken output signal */
+#define PS2_STATUS_TX_INPROGRESS BIT(2) /* transmission in progress */
+#define PS2_STATUS_TX_EMPTY BIT(3) /* empty transmit buffer */
+#define PS2_STATUS_RX_FULL BIT(4) /* full receive buffer */
+#define PS2_STATUS_RX_INPROGRESS BIT(5) /* reception in progress */
+#define PS2_STATUS_ERROR_PARITY BIT(6) /* parity error */
+#define PS2_STATUS_ERROR_FRAMING BIT(7) /* framing error */
+
+#define PS2_CONTROL_TX_CLOCK_DISABLE BIT(0) /* inhibit clock signal after TX */
+#define PS2_CONTROL_TX_ENABLE BIT(1) /* transmit enable */
+#define PS2_CONTROL_TX_INT_ENABLE BIT(2) /* enable transmit interrupt */
+#define PS2_CONTROL_RX_INT_ENABLE BIT(3) /* enable receive interrupt */
+#define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */
+#define PS2_CONTROL_RESET BIT(5) /* reset */
+
+
+struct maceps2_data {
+ struct mace_ps2port *port;
+ int irq;
+};
+
+static int maceps2_write(struct serio *dev, unsigned char val)
+{
+ struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port;
+ unsigned int timeout = MACE_PS2_TIMEOUT;
+
+ do {
+ if (mace_read(port->status) & PS2_STATUS_TX_EMPTY) {
+ mace_write(val, port->tx);
+ return 0;
+ }
+ udelay(50);
+ } while (timeout--);
+
+ return -1;
+}
+
+static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct serio *dev = dev_id;
+ struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port;
+ unsigned int byte;
+
+ if (mace_read(port->status) & PS2_STATUS_RX_FULL) {
+ byte = mace_read(port->rx);
+ serio_interrupt(dev, byte & 0xff, 0, regs);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int maceps2_open(struct serio *dev)
+{
+ struct maceps2_data *data = (struct maceps2_data *)dev->driver;
+
+ if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) {
+ printk(KERN_ERR "Could not allocate PS/2 IRQ\n");
+ return -EBUSY;
+ }
+
+ /* Reset port */
+ mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET,
+ data->port->control);
+ udelay(100);
+
+ /* Enable interrupts */
+ mace_write(PS2_CONTROL_RX_CLOCK_ENABLE | PS2_CONTROL_TX_ENABLE |
+ PS2_CONTROL_RX_INT_ENABLE, data->port->control);
+
+ return 0;
+}
+
+static void maceps2_close(struct serio *dev)
+{
+ struct maceps2_data *data = (struct maceps2_data *)dev->driver;
+
+ mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET,
+ data->port->control);
+ udelay(100);
+ free_irq(data->irq, dev);
+}
+
+static struct maceps2_data port0_data, port1_data;
+
+static struct serio maceps2_port0 =
+{
+ .type = SERIO_8042,
+ .open = maceps2_open,
+ .close = maceps2_close,
+ .write = maceps2_write,
+ .name = "MACE PS/2 port0",
+ .phys = "mace/serio0",
+ .driver = &port0_data,
+};
+
+static struct serio maceps2_port1 =
+{
+ .type = SERIO_8042,
+ .open = maceps2_open,
+ .close = maceps2_close,
+ .write = maceps2_write,
+ .name = "MACE PS/2 port1",
+ .phys = "mace/serio1",
+ .driver = &port1_data,
+};
+
+static int __init maceps2_init(void)
+{
+ port0_data.port = &mace->perif.ps2.keyb;
+ port0_data.irq = MACEISA_KEYB_IRQ;
+ port1_data.port = &mace->perif.ps2.mouse;
+ port1_data.irq = MACEISA_MOUSE_IRQ;
+ serio_register_port(&maceps2_port0);
+ serio_register_port(&maceps2_port1);
+
+ return 0;
+}
+
+static void __exit maceps2_exit(void)
+{
+ serio_unregister_port(&maceps2_port0);
+ serio_unregister_port(&maceps2_port1);
+}
+
+module_init(maceps2_init);
+module_exit(maceps2_exit);
^ permalink raw reply related
* Kind Regards
From: Abdul Nasser @ 2014-01-26 21:30 UTC (permalink / raw)
To: Recipients
Greetings,
My name is Abdul Nasser Sokariah and I am writing you from Syria, I choose to contact you directly as I need a reliable person to trust who can help me handle my huge deposit with a vault company in EUROPE, and based on my present situation in Syria, I need you urgently to take possession of everything and further modalities/directives will follow.Please reply to my private Email: nasserabdul190@yahoo.com
I wait for your response.
Yours truly,
Abdul Nasser Sokariah
^ permalink raw reply
* Kind Regards
From: Abdul Nasser @ 2014-01-26 21:51 UTC (permalink / raw)
To: Recipients
Greetings,
My name is Abdul Nasser Sokariah and I am writing you from Syria, I choose to contact you directly as I need a reliable person to trust who can help me handle my huge deposit with a vault company in EUROPE, and based on my present situation in Syria, I need you urgently to take possession of everything and further modalities/directives will follow.Please reply to my private Email: nasserabdul190@yahoo.com
I wait for your response.
Yours truly,
Abdul Nasser Sokariah
^ permalink raw reply
* Kind Regards
From: Abdul Nasser @ 2014-01-26 22:31 UTC (permalink / raw)
To: Recipients
Greetings,
My name is Abdul Nasser Sokariah and I am writing you from Syria, I choose to contact you directly as I need a reliable person to trust who can help me handle my huge deposit with a vault company in EUROPE, and based on my present situation in Syria, I need you urgently to take possession of everything and further modalities/directives will follow.Please reply to my private Email: nasserabdul190@yahoo.com
I wait for your response.
Yours truly,
Abdul Nasser Sokariah
^ permalink raw reply
* [PATCH] Input: xpad - do not map the DPAD to buttons with xbox 360 wireless controllers
From: Petr Šebor @ 2014-01-26 23:21 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input
Having the DPAD mapped to buttons makes the wireless gamepad behave
differently from the wired counterpart. Given the MAP_DPAD_TO_BUTTONS
flag is typically used for dance pads, this was probably added by
a mistake. Not specifying the flag makes the controller's hat switch
behave as expected.
Signed-off-by: Petr Sebor <petr@scssoft.com>
---
drivers/input/joystick/xpad.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/joystick/xpad.c
b/drivers/input/joystick/xpad.c
index 603fe0d..a433636 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -121,8 +121,8 @@ static const struct xpad_device {
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
- { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)",
MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
- { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS,
XTYPE_XBOX360W },
+ { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", 0,
XTYPE_XBOX360W },
+ { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", 0, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH] Input: i8042-io - Exclude mips platforms when allocating/deallocating IO regions.
From: Dmitry Torokhov @ 2014-01-26 21:49 UTC (permalink / raw)
To: Raghu Gandham; +Cc: aaro.koskinen, linux-input, linux-mips, linux-kernel
In-Reply-To: <1390676514-30880-1-git-send-email-raghu.gandham@imgtec.com>
Hi Raghu,
On Sat, Jan 25, 2014 at 11:01:54AM -0800, Raghu Gandham wrote:
> The standard IO regions are already reserved by the platform code on most MIPS
> devices(malta, cobalt, sni). The Commit 197a1e96c8be5b6005145af3a4c0e45e2d651444
> ("Input: i8042-io - fix up region handling on MIPS") introduced a bug on these
> MIPS platforms causing i8042 driver to fail when trying to reserve IO ports.
> Prior to the above mentioned commit request_region is skipped on MIPS but
> release_region is called.
>
> This patch reverts commit 197a1e96c8be5b6005145af3a4c0e45e2d651444 and also
> avoids calling release_region for MIPS.
The problem is that IO regions are reserved on _most_, but not _all_
devices. MIPS should figure out what they want to do with i8042
registers and be consistent on all devices.
I do not want to apply this patch because it will be breaking devices
using the other configuration.
Thanks.
--
Dmitry
^ permalink raw reply
* [RFC][PATCH] Input: i8042 - fix PNP modaliases when both aux and kdb are enabled
From: Tom Gundersen @ 2014-01-26 21:00 UTC (permalink / raw)
To: linux-input; +Cc: Tom Gundersen, Dmitry Torokhov
Commit 78551277e4 exposed the PNP modaliases for the i8042 module. However,
the aux entries overrode the kbd ones.
Refactor the device_id lists to expose both the aux and the kbd modaliases.
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Tom Gundersen <teg@jklm.no>
---
Hi Dmitry,
I don't know if there is a better way to do this, so sending as an RFC.
Cheers,
Tom
drivers/input/serio/i8042-x86ia64io.h | 67 ++++++++++++++++++++---------------
1 file changed, 39 insertions(+), 28 deletions(-)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 0ec9abb..dbc6958 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -747,25 +747,27 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
return 0;
}
-static struct pnp_device_id pnp_kbd_devids[] = {
- { .id = "PNP0300", .driver_data = 0 },
- { .id = "PNP0301", .driver_data = 0 },
- { .id = "PNP0302", .driver_data = 0 },
- { .id = "PNP0303", .driver_data = 0 },
- { .id = "PNP0304", .driver_data = 0 },
- { .id = "PNP0305", .driver_data = 0 },
- { .id = "PNP0306", .driver_data = 0 },
- { .id = "PNP0309", .driver_data = 0 },
- { .id = "PNP030a", .driver_data = 0 },
- { .id = "PNP030b", .driver_data = 0 },
- { .id = "PNP0320", .driver_data = 0 },
- { .id = "PNP0343", .driver_data = 0 },
- { .id = "PNP0344", .driver_data = 0 },
- { .id = "PNP0345", .driver_data = 0 },
+#define KBD_DEVIDS \
+ { .id = "PNP0300", .driver_data = 0 }, \
+ { .id = "PNP0301", .driver_data = 0 }, \
+ { .id = "PNP0302", .driver_data = 0 }, \
+ { .id = "PNP0303", .driver_data = 0 }, \
+ { .id = "PNP0304", .driver_data = 0 }, \
+ { .id = "PNP0305", .driver_data = 0 }, \
+ { .id = "PNP0306", .driver_data = 0 }, \
+ { .id = "PNP0309", .driver_data = 0 }, \
+ { .id = "PNP030a", .driver_data = 0 }, \
+ { .id = "PNP030b", .driver_data = 0 }, \
+ { .id = "PNP0320", .driver_data = 0 }, \
+ { .id = "PNP0343", .driver_data = 0 }, \
+ { .id = "PNP0344", .driver_data = 0 }, \
+ { .id = "PNP0345", .driver_data = 0 }, \
{ .id = "CPQA0D7", .driver_data = 0 },
+
+static struct pnp_device_id pnp_kbd_devids[] = {
+ KBD_DEVIDS
{ .id = "", },
};
-MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids);
static struct pnp_driver i8042_pnp_kbd_driver = {
.name = "i8042 kbd",
@@ -773,21 +775,23 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
.probe = i8042_pnp_kbd_probe,
};
-static struct pnp_device_id pnp_aux_devids[] = {
- { .id = "AUI0200", .driver_data = 0 },
- { .id = "FJC6000", .driver_data = 0 },
- { .id = "FJC6001", .driver_data = 0 },
- { .id = "PNP0f03", .driver_data = 0 },
- { .id = "PNP0f0b", .driver_data = 0 },
- { .id = "PNP0f0e", .driver_data = 0 },
- { .id = "PNP0f12", .driver_data = 0 },
- { .id = "PNP0f13", .driver_data = 0 },
- { .id = "PNP0f19", .driver_data = 0 },
- { .id = "PNP0f1c", .driver_data = 0 },
+#define AUX_DEVIDS \
+ { .id = "AUI0200", .driver_data = 0 }, \
+ { .id = "FJC6000", .driver_data = 0 }, \
+ { .id = "FJC6001", .driver_data = 0 }, \
+ { .id = "PNP0f03", .driver_data = 0 }, \
+ { .id = "PNP0f0b", .driver_data = 0 }, \
+ { .id = "PNP0f0e", .driver_data = 0 }, \
+ { .id = "PNP0f12", .driver_data = 0 }, \
+ { .id = "PNP0f13", .driver_data = 0 }, \
+ { .id = "PNP0f19", .driver_data = 0 }, \
+ { .id = "PNP0f1c", .driver_data = 0 }, \
{ .id = "SYN0801", .driver_data = 0 },
+
+static struct pnp_device_id pnp_aux_devids[] = {
+ AUX_DEVIDS
{ .id = "", },
};
-MODULE_DEVICE_TABLE(pnp, pnp_aux_devids);
static struct pnp_driver i8042_pnp_aux_driver = {
.name = "i8042 aux",
@@ -795,6 +799,13 @@ static struct pnp_driver i8042_pnp_aux_driver = {
.probe = i8042_pnp_aux_probe,
};
+static struct pnp_device_id pnp_kdb_aux_devids[] = {
+ KBD_DEVIDS
+ AUX_DEVIDS
+ { .id = "", },
+};
+MODULE_DEVICE_TABLE(pnp, pnp_kdb_aux_devids);
+
static void i8042_pnp_exit(void)
{
if (i8042_pnp_kbd_registered) {
--
1.8.5.3
^ permalink raw reply related
* [PATCH] Input: i8042-io - Exclude mips platforms when allocating/deallocating IO regions.
From: Raghu Gandham @ 2014-01-25 19:01 UTC (permalink / raw)
To: dmitry.torokhov, aaro.koskinen, linux-input, linux-mips,
linux-kernel
Cc: Raghu Gandham
The standard IO regions are already reserved by the platform code on most MIPS
devices(malta, cobalt, sni). The Commit 197a1e96c8be5b6005145af3a4c0e45e2d651444
("Input: i8042-io - fix up region handling on MIPS") introduced a bug on these
MIPS platforms causing i8042 driver to fail when trying to reserve IO ports.
Prior to the above mentioned commit request_region is skipped on MIPS but
release_region is called.
This patch reverts commit 197a1e96c8be5b6005145af3a4c0e45e2d651444 and also
avoids calling release_region for MIPS.
Signed-off-by: Raghu Gandham <raghu.gandham@imgtec.com>
Reviewed-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
drivers/input/serio/i8042-io.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index a5eed2a..a09bb72 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -76,7 +76,7 @@ static inline int i8042_platform_init(void)
if (check_legacy_ioport(I8042_DATA_REG))
return -ENODEV;
#endif
-#if !defined(__sh__) && !defined(__alpha__)
+#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -EBUSY;
#endif
@@ -87,7 +87,7 @@ static inline int i8042_platform_init(void)
static inline void i8042_platform_exit(void)
{
-#if !defined(__sh__) && !defined(__alpha__)
+#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__)
release_region(I8042_DATA_REG, 16);
#endif
}
--
1.8.5.2
^ permalink raw reply related
* I HAVE A PROPOSAL FOR YOU!
From: YUNG KIM @ 2014-01-25 17:31 UTC (permalink / raw)
Hello,
The Project is about the exportation of 100,000 barrels of Light Crude
Oil daily out from Iraq to Turkey through my client's company in Iraq
at the rate of $92.00 per barrel. This amount to $9,200,000 daily. I ask
for your support as a foreigner to handle this business project with my
client and you are not expected to invest in Iraq
If yes, let me know and we will discuss this project proper.
Kim.
Email: kyu.kim@shqiptar.eu
^ permalink raw reply
* Messenger from Administrator
From: Webmail Admin @ 2014-01-25 8:46 UTC (permalink / raw)
Our records indicate that your E-mail® Account could not be automatically updated with our F-Secure R-HTK4S new(2014) version anti-spam/anti-virus/anti-spyware. Please click this link below to update manually
http://contactme.com/52e0fe1e021de90002006bd6
We Are Sorry For Any Inconvenience.
Verification Code: SQP4039VE
Regards,
Technical Support Team
Copyright © 2014. All Rights Reserved
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2/2] HID: sony: Add output events for the multi-touch pad on the Dualshock 4.
From: Frank Praznik @ 2014-01-25 3:27 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, Frank Praznik
In-Reply-To: <1390620421-11365-1-git-send-email-frank.praznik@oh.rr.com>
Add output events for the multi-touch pad on the Dualshock 4.
The touchpad has a resolution of 1920x940 and is capable of 2 simultaneous
touches. A 'Type B' stateful slot protocol is implemented as defined in
Documentation/input/multi-touch-protocol.txt
Applications can use the touchpad data by processing the ABS_MT_SLOT,
ABS_MT_TRACKING_ID, ABS_MT_POSITION_X and ABS_MT_POSITION_Y events.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 04fd611..2bd3f13 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -32,6 +32,7 @@
#include <linux/leds.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
+#include <linux/input/mt.h>
#include "hid-ids.h"
@@ -643,7 +644,11 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
{
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
unsigned long flags;
+ int n, offset = 35;
__u8 cable_state, battery_capacity, battery_charging;
/* The lower 4 bits of byte 30 contain the battery level
@@ -669,6 +674,28 @@ static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
sc->battery_capacity = battery_capacity;
sc->battery_charging = battery_charging;
spin_unlock_irqrestore(&sc->lock, flags);
+
+ /* The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB.
+ * The first 7 bits of the first byte is a counter and bit 8 is a touch
+ * indicator that is 0 when pressed and 1 when not pressed.
+ * The next 3 bytes are two 12 bit touch coordinates, X and Y.
+ * The data for the second touch is in the same format and immediatly
+ * follows the data for the first.
+ */
+ for (n = 0; n < 2; n++) {
+ __u16 x, y;
+
+ x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8);
+ y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
+
+ input_mt_slot(input_dev, n);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+ !(rd[offset] >> 7));
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+ offset += 4;
+ }
}
static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -1200,6 +1227,26 @@ static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
return -EINVAL;
}
+static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
+ int w, int h)
+{
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ int ret;
+
+ ret = input_mt_init_slots(input_dev, touch_count, 0);
+ if (ret < 0) {
+ hid_err(sc->hdev, "Unable to initialize multi-touch slots\n");
+ return ret;
+ }
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0);
+
+ return 0;
+}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -1249,6 +1296,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
+ /* The Dualshock 4 touchpad supports 2 touches and has a
+ * resolution of 1920x940.
+ */
+ ret = sony_register_touchpad(sc, 2, 1920, 940);
+ if (ret < 0)
+ goto err_stop;
+
INIT_WORK(&sc->state_worker, dualshock4_state_worker);
} else {
ret = 0;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/2] HID: sony: Add battery status reporting for the Sixaxis and Dualshock 4 controllers.
From: Frank Praznik @ 2014-01-25 3:27 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, Frank Praznik
Add battery status reporting for the Sixaxis and Dualshock 4 controllers.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 185 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 1235405..04fd611 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -30,6 +30,8 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/leds.h>
+#include <linux/power_supply.h>
+#include <linux/spinlock.h>
#include "hid-ids.h"
@@ -42,6 +44,7 @@
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_USB)
#define MAX_LEDS 4
@@ -487,18 +490,30 @@ static const unsigned int buzz_keymap[] = {
[20] = BTN_TRIGGER_HAPPY20,
};
+static enum power_supply_property sony_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_STATUS,
+};
+
struct sony_sc {
+ spinlock_t lock;
struct hid_device *hdev;
struct led_classdev *leds[MAX_LEDS];
struct hid_report *output_report;
unsigned long quirks;
struct work_struct state_worker;
+ struct power_supply battery;
#ifdef CONFIG_SONY_FF
__u8 left;
__u8 right;
#endif
+ __u8 cable_state;
+ __u8 battery_charging;
+ __u8 battery_capacity;
__u8 led_state[MAX_LEDS];
__u8 led_count;
};
@@ -599,6 +614,63 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
+ unsigned long flags;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /* The sixaxis is charging if the battery value is 0xee
+ * and it is fully charged if the value is 0xef.
+ * It does not report the actual level while charging so it
+ * is set to 100% while charging is in progress.
+ */
+ if (rd[30] >= 0xee) {
+ battery_capacity = 100;
+ battery_charging = rd[30] & 0x01;
+ } else {
+ battery_capacity = sixaxis_battery_capacity[rd[30]];
+ battery_charging = 0;
+ }
+ cable_state = (rd[31] >> 4) & 0x01;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ unsigned long flags;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /* The lower 4 bits of byte 30 contain the battery level
+ * and the 5th bit contains the USB cable state.
+ */
+ cable_state = (rd[30] >> 4) & 0x01;
+ battery_capacity = rd[30] & 0x0F;
+
+ /* On USB the Dualshock 4 battery level goes from 0 to 11.
+ * A battery level of 11 means fully charged.
+ */
+ if (cable_state && battery_capacity == 11)
+ battery_charging = 0;
+ else
+ battery_charging = 1;
+
+ if (battery_capacity > 10)
+ battery_capacity--;
+ battery_capacity *= 10;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+}
+
static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
__u8 *rd, int size)
{
@@ -613,6 +685,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
swap(rd[43], rd[44]);
swap(rd[45], rd[46]);
swap(rd[47], rd[48]);
+
+ sixaxis_parse_report(sc, rd, size);
+ } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 &&
+ size == 64) {
+ dualshock4_parse_report(sc, rd, size);
}
return 0;
@@ -1011,6 +1088,91 @@ static void sony_destroy_ff(struct hid_device *hdev)
}
#endif
+static int sony_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct sony_sc *sc = container_of(psy, struct sony_sc, battery);
+ unsigned long flags;
+ int ret = 0;
+ u8 battery_charging, battery_capacity, cable_state;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ battery_charging = sc->battery_charging;
+ battery_capacity = sc->battery_capacity;
+ cable_state = sc->cable_state;
+ spin_unlock_irqrestore(&sc->lock, flags);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ if (battery_charging)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ if (battery_capacity == 100 && cable_state)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int sony_battery_probe(struct sony_sc *sc)
+{
+ static atomic_t power_id_seq = ATOMIC_INIT(0);
+ unsigned long power_id;
+ struct hid_device *hdev = sc->hdev;
+ int ret;
+
+ power_id = (unsigned long)atomic_inc_return(&power_id_seq);
+
+ sc->battery.properties = sony_battery_props;
+ sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
+ sc->battery.get_property = sony_battery_get_property;
+ sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ sc->battery.use_for_apm = 0;
+ sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
+ power_id);
+ if (!sc->battery.name)
+ return -ENOMEM;
+
+ ret = power_supply_register(&hdev->dev, &sc->battery);
+ if (ret) {
+ hid_err(hdev, "Unable to register battery device\n");
+ goto err_free;
+ }
+
+ power_supply_powers(&sc->battery, &hdev->dev);
+ return 0;
+
+err_free:
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
+ return ret;
+}
+
+static void sony_battery_remove(struct sony_sc *sc)
+{
+ if (!sc->battery.name)
+ return;
+
+ power_supply_unregister(&sc->battery);
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
+}
+
static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
{
struct list_head *head, *list;
@@ -1101,14 +1263,31 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
}
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ ret = sony_battery_probe(sc);
+ if (ret < 0)
+ goto err_stop;
+
+ /* Open the device to receive reports with battery info */
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ hid_err(hdev, "hw open failed\n");
+ goto err_stop;
+ }
+ }
+
ret = sony_init_ff(hdev);
if (ret < 0)
- goto err_stop;
+ goto err_close;
return 0;
+err_close:
+ hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
+ if (sc->quirks & SONY_BATTERY_SUPPORT)
+ sony_battery_remove(sc);
hid_hw_stop(hdev);
return ret;
}
@@ -1120,6 +1299,11 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ hid_hw_close(hdev);
+ sony_battery_remove(sc);
+ }
+
sony_destroy_ff(hdev);
hid_hw_stop(hdev);
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH 00/15] Input: synaptics-rmi4 - cleanup and add DT support
From: Courtney Cavin @ 2014-01-25 1:08 UTC (permalink / raw)
To: Christopher Heiny; +Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
In-Reply-To: <52E2F62B.80101@synaptics.com>
On Sat, Jan 25, 2014 at 12:24:27AM +0100, Christopher Heiny wrote:
> On 01/23/2014 04:00 PM, Courtney Cavin wrote:
> > This is an attempt to get this driver closer to being in an upstream-able form.
> > In the process, this drops legacy callback methods for managing power and GPIO
> > configuration, in favor of the already existing frameworks. Most of this
> > series is cleanup, but there are a few intermixed bug fixes to make it all
> > work.
>
> Hi Courtney!
>
> Thanks for the extensive patches. There's a great deal of cool stuff in
> there that we're really happy to see (as in "buy Courtney a beer! No,
> make it two beers!" levels of happy). We really want to get the driver
> upstream, and your improvements will help a lot. The device tree work
> looks to be particularly helpful.
>
Thanks. Glad to help!
> Unfortunately some of your cleanup is too aggressive, and winds up
> breaking code outside of the current patch submissions. The current
> patch codebase is significantly reduced in size in order to be more
> manageable, but there's a non-trivial amount of production code outside
> that codebase that depends on things like the current GPIO/IRQ handling,
> the debugfs infrastructure, platform suspend/resume, and so on. This
> code will be submitted after the core of the driver is upstreamed.
> Tearing out the supporting code now and then putting it all back later
> just makes more work for all concerned.
I can definitely understand that some of your production code must
manage older kernels and alternative features. The problem I see here is
that the driver will never get upstreamed with the GPIO/IRQ handling and
unused variables in the first place. It is unnecessary in mainline, and
therefore should not exist in mainline. I am not the maintainer though,
so... Dmitry should probably chime in on this.
>
> Additionally, some of your changes are redundant to, or in conflict
> with, patches submitted over the past few weeks. Have you been
> following that series and discussions relating to them? It would
> probably be more efficient for you to offer comments on those patches,
> rather than submitting conflicting work.
>
I did not see any specific logical conflicts other than saving the F01
container, which was needed for testing, and was independent of IRQ
counting. Other than that, there should only need to be rebasing
one-way or the other. I am simply basing my patches off of what exists
in the tree, which prevents awkward patch-series dependencies.
I did look at your patches, but didn't comment because I had nothing to
say. I'll be sure to participate in patch discussions if I have
something to add.
... and after double checking, I just noticed that 1/15 conflicts
with your PDT scan cleanup, as we both have C++ comment style cleanup.
Whoops.
> We'll be going over the new feature and bug fix parts of this patch
> series, and will send comments in the next couple of workdays.
>
> Thanks,
> Chris
>
I'm looking forward to some comments.
-Courtney
> >
> > This patch series is based off of the synaptics-rmi4 branch merged into
> > Linus' 3.13. A tree is available at [1].
> >
> > This was tested on Synaptics TM2281-001 & TM2282-001.
> >
> > [1] http://github.com/courtc/linux.git
> > tag for-input/synaptics-rmi4
> >
> > Courtney Cavin (15):
> > Input: synaptics-rmi4 - fix checkpatch.pl, sparse and GCC warnings
> > Input: synaptics-rmi4 - don't kfree devm_ alloced memory
> > Input: synaptics-rmi4 - don't free devices directly
> > Input: synaptics-rmi4 - remove sensor name from platform data
> > Input: synaptics-rmi4 - remove gpio handling and polling
> > Input: synaptics-rmi4 - remove platform suspend callbacks
> > Input: synaptics-rmi4 - remove remaining debugfs code
> > Input: synaptics-rmi4 - cleanup platform data
> > Input: synaptics-rmi4 - remove unused defines and variables
> > Input: synaptics-rmi4 - add devicetree support
> > Input: synaptics-rmi4 - add regulator support
> > Input: synaptics-rmi4 - don't immediately set page on probe
> > Input: synaptics-rmi4 - properly set F01 container on PDT scan
> > Input: synaptics-rmi4 - ensure we have IRQs before reading status
> > Input: synaptics-rmi4 - correct RMI4 spec url
> >
> > Documentation/devicetree/bindings/input/rmi4.txt | 117 +++++
> > .../devicetree/bindings/vendor-prefixes.txt | 1 +
> > drivers/input/rmi4/Kconfig | 1 -
> > drivers/input/rmi4/rmi_bus.c | 131 +-----
> > drivers/input/rmi4/rmi_bus.h | 18 +-
> > drivers/input/rmi4/rmi_driver.c | 321 +++++--------
> > drivers/input/rmi4/rmi_driver.h | 33 +-
> > drivers/input/rmi4/rmi_f01.c | 163 ++++---
> > drivers/input/rmi4/rmi_f11.c | 523 ++++++---------------
> > drivers/input/rmi4/rmi_i2c.c | 55 +--
> > include/linux/rmi.h | 219 ++-------
> > 11 files changed, 551 insertions(+), 1031 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/input/rmi4.txt
> >
>
>
> --
>
> Christopher Heiny
> Senior Staff Firmware Engineer
> Synaptics Incorporated
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox