diff options
author | Bruno Prémont <bonbons@linux-vserver.org> | 2012-08-19 13:32:54 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-09-05 05:48:07 -0400 |
commit | ae08e324146c89f1059e9d3c3898d0260a988795 (patch) | |
tree | cc7df091c897f3f97127f08ed19cd70cc2bf97eb /drivers/hid | |
parent | 16048709b2f6a7e721ac677f9a6741ac1c13ffd7 (diff) |
HID: picoLCD: Add support for CIR
Implement support for picoLCD's CIR header using RC_CORE for decoding
the IR event stream.
Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-picolcd.h | 5 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_cir.c | 95 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_core.c | 3 |
3 files changed, 98 insertions, 5 deletions
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h index dc4c795dea5..240eb1cd872 100644 --- a/drivers/hid/hid-picolcd.h +++ b/drivers/hid/hid-picolcd.h | |||
@@ -85,7 +85,9 @@ struct picolcd_data { | |||
85 | /* input stuff */ | 85 | /* input stuff */ |
86 | u8 pressed_keys[2]; | 86 | u8 pressed_keys[2]; |
87 | struct input_dev *input_keys; | 87 | struct input_dev *input_keys; |
88 | struct input_dev *input_cir; | 88 | #ifdef CONFIG_HID_PICOLCD_CIR |
89 | struct rc_dev *rc_dev; | ||
90 | #endif | ||
89 | unsigned short keycode[PICOLCD_KEYS]; | 91 | unsigned short keycode[PICOLCD_KEYS]; |
90 | 92 | ||
91 | #ifdef CONFIG_HID_PICOLCD_FB | 93 | #ifdef CONFIG_HID_PICOLCD_FB |
@@ -114,6 +116,7 @@ struct picolcd_data { | |||
114 | int status; | 116 | int status; |
115 | #define PICOLCD_BOOTLOADER 1 | 117 | #define PICOLCD_BOOTLOADER 1 |
116 | #define PICOLCD_FAILED 2 | 118 | #define PICOLCD_FAILED 2 |
119 | #define PICOLCD_CIR_SHUN 4 | ||
117 | }; | 120 | }; |
118 | 121 | ||
119 | #ifdef CONFIG_HID_PICOLCD_FB | 122 | #ifdef CONFIG_HID_PICOLCD_FB |
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index dc632c3cab3..14c5ce0e71b 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/completion.h> | 37 | #include <linux/completion.h> |
38 | #include <linux/uaccess.h> | 38 | #include <linux/uaccess.h> |
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <media/rc-core.h> | ||
40 | 41 | ||
41 | #include "hid-picolcd.h" | 42 | #include "hid-picolcd.h" |
42 | 43 | ||
@@ -44,18 +45,108 @@ | |||
44 | int picolcd_raw_cir(struct picolcd_data *data, | 45 | int picolcd_raw_cir(struct picolcd_data *data, |
45 | struct hid_report *report, u8 *raw_data, int size) | 46 | struct hid_report *report, u8 *raw_data, int size) |
46 | { | 47 | { |
47 | /* Need understanding of CIR data format to implement ... */ | 48 | unsigned long flags; |
49 | int i, w, sz; | ||
50 | DEFINE_IR_RAW_EVENT(rawir); | ||
51 | |||
52 | /* ignore if rc_dev is NULL or status is shunned */ | ||
53 | spin_lock_irqsave(&data->lock, flags); | ||
54 | if (data->rc_dev && (data->status & PICOLCD_CIR_SHUN)) { | ||
55 | spin_unlock_irqrestore(&data->lock, flags); | ||
56 | return 1; | ||
57 | } | ||
58 | spin_unlock_irqrestore(&data->lock, flags); | ||
59 | |||
60 | /* PicoLCD USB packets contain 16-bit intervals in network order, | ||
61 | * with value negated for pulse. Intervals are in microseconds. | ||
62 | * | ||
63 | * Note: some userspace LIRC code for PicoLCD says negated values | ||
64 | * for space - is it a matter of IR chip? (pulse for my TSOP2236) | ||
65 | * | ||
66 | * In addition, the first interval seems to be around 15000 + base | ||
67 | * interval for non-first report of IR data - thus the quirk below | ||
68 | * to get RC_CODE to understand Sony and JVC remotes I have at hand | ||
69 | */ | ||
70 | sz = size > 0 ? min((int)raw_data[0], size-1) : 0; | ||
71 | for (i = 0; i+1 < sz; i += 2) { | ||
72 | init_ir_raw_event(&rawir); | ||
73 | w = (raw_data[i] << 8) | (raw_data[i+1]); | ||
74 | rawir.pulse = !!(w & 0x8000); | ||
75 | rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w); | ||
76 | /* Quirk!! - see above */ | ||
77 | if (i == 0 && rawir.duration > 15000000) | ||
78 | rawir.duration -= 15000000; | ||
79 | ir_raw_event_store(data->rc_dev, &rawir); | ||
80 | } | ||
81 | ir_raw_event_handle(data->rc_dev); | ||
82 | |||
48 | return 1; | 83 | return 1; |
49 | } | 84 | } |
50 | 85 | ||
86 | static int picolcd_cir_open(struct rc_dev *dev) | ||
87 | { | ||
88 | struct picolcd_data *data = dev->priv; | ||
89 | unsigned long flags; | ||
90 | |||
91 | spin_lock_irqsave(&data->lock, flags); | ||
92 | data->status &= ~PICOLCD_CIR_SHUN; | ||
93 | spin_unlock_irqrestore(&data->lock, flags); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static void picolcd_cir_close(struct rc_dev *dev) | ||
98 | { | ||
99 | struct picolcd_data *data = dev->priv; | ||
100 | unsigned long flags; | ||
101 | |||
102 | spin_lock_irqsave(&data->lock, flags); | ||
103 | data->status |= PICOLCD_CIR_SHUN; | ||
104 | spin_unlock_irqrestore(&data->lock, flags); | ||
105 | } | ||
106 | |||
51 | /* initialize CIR input device */ | 107 | /* initialize CIR input device */ |
52 | int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | 108 | int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) |
53 | { | 109 | { |
54 | /* support not implemented yet */ | 110 | struct rc_dev *rdev; |
111 | int ret = 0; | ||
112 | |||
113 | rdev = rc_allocate_device(); | ||
114 | if (!rdev) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | rdev->priv = data; | ||
118 | rdev->driver_type = RC_DRIVER_IR_RAW; | ||
119 | rdev->allowed_protos = RC_TYPE_ALL; | ||
120 | rdev->open = picolcd_cir_open; | ||
121 | rdev->close = picolcd_cir_close; | ||
122 | rdev->input_name = data->hdev->name; | ||
123 | rdev->input_phys = data->hdev->phys; | ||
124 | rdev->input_id.bustype = data->hdev->bus; | ||
125 | rdev->input_id.vendor = data->hdev->vendor; | ||
126 | rdev->input_id.product = data->hdev->product; | ||
127 | rdev->input_id.version = data->hdev->version; | ||
128 | rdev->dev.parent = &data->hdev->dev; | ||
129 | rdev->driver_name = PICOLCD_NAME; | ||
130 | rdev->map_name = RC_MAP_RC6_MCE; | ||
131 | rdev->timeout = MS_TO_NS(100); | ||
132 | rdev->rx_resolution = US_TO_NS(1); | ||
133 | |||
134 | ret = rc_register_device(rdev); | ||
135 | if (ret) | ||
136 | goto err; | ||
137 | data->rc_dev = rdev; | ||
55 | return 0; | 138 | return 0; |
139 | |||
140 | err: | ||
141 | rc_free_device(rdev); | ||
142 | return ret; | ||
56 | } | 143 | } |
57 | 144 | ||
58 | void picolcd_exit_cir(struct picolcd_data *data) | 145 | void picolcd_exit_cir(struct picolcd_data *data) |
59 | { | 146 | { |
147 | struct rc_dev *rdev = data->rc_dev; | ||
148 | |||
149 | data->rc_dev = NULL; | ||
150 | rc_unregister_device(rdev); | ||
60 | } | 151 | } |
61 | 152 | ||
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index e4fe342e7aa..0d0c798e3ee 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c | |||
@@ -356,8 +356,7 @@ static int picolcd_raw_event(struct hid_device *hdev, | |||
356 | if (data->input_keys) | 356 | if (data->input_keys) |
357 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); | 357 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); |
358 | } else if (report->id == REPORT_IR_DATA) { | 358 | } else if (report->id == REPORT_IR_DATA) { |
359 | if (data->input_cir) | 359 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); |
360 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); | ||
361 | } else { | 360 | } else { |
362 | spin_lock_irqsave(&data->lock, flags); | 361 | spin_lock_irqsave(&data->lock, flags); |
363 | /* | 362 | /* |