diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-11-14 20:38:05 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-11-14 20:38:05 -0500 |
| commit | 42249094f79422fbf5ed4b54eeb48ff096809b8f (patch) | |
| tree | 91e6850c8c7e8cc284cf8bb6363f8662f84011f4 /drivers/input/serio | |
| parent | 936816161978ca716a56c5e553c68f25972b1e3a (diff) | |
| parent | 2c027b7c48a888ab173ba45babb4525e278375d9 (diff) | |
Merge branch 'next' into for-linus
Merge first round of changes for 3.13 merge window.
Diffstat (limited to 'drivers/input/serio')
| -rw-r--r-- | drivers/input/serio/Kconfig | 17 | ||||
| -rw-r--r-- | drivers/input/serio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/serio/altera_ps2.c | 1 | ||||
| -rw-r--r-- | drivers/input/serio/hyperv-keyboard.c | 437 | ||||
| -rw-r--r-- | drivers/input/serio/i8042-x86ia64io.h | 2 | ||||
| -rw-r--r-- | drivers/input/serio/serio.c | 21 |
6 files changed, 465 insertions, 14 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 1e691a3a79cb..5a96acb667ea 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Input core configuration | 2 | # Input core configuration |
| 3 | # | 3 | # |
| 4 | config SERIO | 4 | config SERIO |
| 5 | tristate "Serial I/O support" if EXPERT || !X86 | 5 | tristate "Serial I/O support" |
| 6 | default y | 6 | default y |
| 7 | help | 7 | help |
| 8 | Say Yes here if you have any input device that uses serial I/O to | 8 | Say Yes here if you have any input device that uses serial I/O to |
| @@ -19,7 +19,7 @@ config SERIO | |||
| 19 | if SERIO | 19 | if SERIO |
| 20 | 20 | ||
| 21 | config SERIO_I8042 | 21 | config SERIO_I8042 |
| 22 | tristate "i8042 PC Keyboard controller" if EXPERT || !X86 | 22 | tristate "i8042 PC Keyboard controller" |
| 23 | default y | 23 | default y |
| 24 | depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ | 24 | depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ |
| 25 | (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390 && \ | 25 | (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390 && \ |
| @@ -170,7 +170,7 @@ config SERIO_MACEPS2 | |||
| 170 | module will be called maceps2. | 170 | module will be called maceps2. |
| 171 | 171 | ||
| 172 | config SERIO_LIBPS2 | 172 | config SERIO_LIBPS2 |
| 173 | tristate "PS/2 driver library" if EXPERT | 173 | tristate "PS/2 driver library" |
| 174 | depends on SERIO_I8042 || SERIO_I8042=n | 174 | depends on SERIO_I8042 || SERIO_I8042=n |
| 175 | help | 175 | help |
| 176 | Say Y here if you are using a driver for device connected | 176 | Say Y here if you are using a driver for device connected |
| @@ -239,7 +239,6 @@ config SERIO_PS2MULT | |||
| 239 | 239 | ||
| 240 | config SERIO_ARC_PS2 | 240 | config SERIO_ARC_PS2 |
| 241 | tristate "ARC PS/2 support" | 241 | tristate "ARC PS/2 support" |
| 242 | depends on GENERIC_HARDIRQS | ||
| 243 | help | 242 | help |
| 244 | Say Y here if you have an ARC FPGA platform with a PS/2 | 243 | Say Y here if you have an ARC FPGA platform with a PS/2 |
| 245 | controller in it. | 244 | controller in it. |
| @@ -267,4 +266,14 @@ config SERIO_OLPC_APSP | |||
| 267 | To compile this driver as a module, choose M here: the module will | 266 | To compile this driver as a module, choose M here: the module will |
| 268 | be called olpc_apsp. | 267 | be called olpc_apsp. |
| 269 | 268 | ||
| 269 | config HYPERV_KEYBOARD | ||
| 270 | tristate "Microsoft Synthetic Keyboard driver" | ||
| 271 | depends on HYPERV | ||
| 272 | default HYPERV | ||
| 273 | help | ||
| 274 | Select this option to enable the Hyper-V Keyboard driver. | ||
| 275 | |||
| 276 | To compile this driver as a module, choose M here: the module will | ||
| 277 | be called hyperv_keyboard. | ||
| 278 | |||
| 270 | endif | 279 | endif |
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 12298b1c0e71..815d874fe724 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile | |||
| @@ -28,3 +28,4 @@ obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o | |||
| 28 | obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o | 28 | obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o |
| 29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o | 29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o |
| 30 | obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o | 30 | obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o |
| 31 | obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o | ||
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index a0a2657e31ff..4777a73cd390 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c | |||
| @@ -176,6 +176,7 @@ static int altera_ps2_remove(struct platform_device *pdev) | |||
| 176 | #ifdef CONFIG_OF | 176 | #ifdef CONFIG_OF |
| 177 | static const struct of_device_id altera_ps2_match[] = { | 177 | static const struct of_device_id altera_ps2_match[] = { |
| 178 | { .compatible = "ALTR,ps2-1.0", }, | 178 | { .compatible = "ALTR,ps2-1.0", }, |
| 179 | { .compatible = "altr,ps2-1.0", }, | ||
| 179 | {}, | 180 | {}, |
| 180 | }; | 181 | }; |
| 181 | MODULE_DEVICE_TABLE(of, altera_ps2_match); | 182 | MODULE_DEVICE_TABLE(of, altera_ps2_match); |
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c new file mode 100644 index 000000000000..3a83c3c14b23 --- /dev/null +++ b/drivers/input/serio/hyperv-keyboard.c | |||
| @@ -0,0 +1,437 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013, Microsoft Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/completion.h> | ||
| 18 | #include <linux/hyperv.h> | ||
| 19 | #include <linux/serio.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Current version 1.0 | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | #define SYNTH_KBD_VERSION_MAJOR 1 | ||
| 27 | #define SYNTH_KBD_VERSION_MINOR 0 | ||
| 28 | #define SYNTH_KBD_VERSION (SYNTH_KBD_VERSION_MINOR | \ | ||
| 29 | (SYNTH_KBD_VERSION_MAJOR << 16)) | ||
| 30 | |||
| 31 | |||
| 32 | /* | ||
| 33 | * Message types in the synthetic input protocol | ||
| 34 | */ | ||
| 35 | enum synth_kbd_msg_type { | ||
| 36 | SYNTH_KBD_PROTOCOL_REQUEST = 1, | ||
| 37 | SYNTH_KBD_PROTOCOL_RESPONSE = 2, | ||
| 38 | SYNTH_KBD_EVENT = 3, | ||
| 39 | SYNTH_KBD_LED_INDICATORS = 4, | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Basic message structures. | ||
| 44 | */ | ||
| 45 | struct synth_kbd_msg_hdr { | ||
| 46 | __le32 type; | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct synth_kbd_msg { | ||
| 50 | struct synth_kbd_msg_hdr header; | ||
| 51 | char data[]; /* Enclosed message */ | ||
| 52 | }; | ||
| 53 | |||
| 54 | union synth_kbd_version { | ||
| 55 | __le32 version; | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Protocol messages | ||
| 60 | */ | ||
| 61 | struct synth_kbd_protocol_request { | ||
| 62 | struct synth_kbd_msg_hdr header; | ||
| 63 | union synth_kbd_version version_requested; | ||
| 64 | }; | ||
| 65 | |||
| 66 | #define PROTOCOL_ACCEPTED BIT(0) | ||
| 67 | struct synth_kbd_protocol_response { | ||
| 68 | struct synth_kbd_msg_hdr header; | ||
| 69 | __le32 proto_status; | ||
| 70 | }; | ||
| 71 | |||
| 72 | #define IS_UNICODE BIT(0) | ||
| 73 | #define IS_BREAK BIT(1) | ||
| 74 | #define IS_E0 BIT(2) | ||
| 75 | #define IS_E1 BIT(3) | ||
| 76 | struct synth_kbd_keystroke { | ||
| 77 | struct synth_kbd_msg_hdr header; | ||
| 78 | __le16 make_code; | ||
| 79 | __le16 reserved0; | ||
| 80 | __le32 info; /* Additional information */ | ||
| 81 | }; | ||
| 82 | |||
| 83 | |||
| 84 | #define HK_MAXIMUM_MESSAGE_SIZE 256 | ||
| 85 | |||
| 86 | #define KBD_VSC_SEND_RING_BUFFER_SIZE (10 * PAGE_SIZE) | ||
| 87 | #define KBD_VSC_RECV_RING_BUFFER_SIZE (10 * PAGE_SIZE) | ||
| 88 | |||
| 89 | #define XTKBD_EMUL0 0xe0 | ||
| 90 | #define XTKBD_EMUL1 0xe1 | ||
| 91 | #define XTKBD_RELEASE 0x80 | ||
| 92 | |||
| 93 | |||
| 94 | /* | ||
| 95 | * Represents a keyboard device | ||
| 96 | */ | ||
| 97 | struct hv_kbd_dev { | ||
| 98 | struct hv_device *hv_dev; | ||
| 99 | struct serio *hv_serio; | ||
| 100 | struct synth_kbd_protocol_request protocol_req; | ||
| 101 | struct synth_kbd_protocol_response protocol_resp; | ||
| 102 | /* Synchronize the request/response if needed */ | ||
| 103 | struct completion wait_event; | ||
| 104 | spinlock_t lock; /* protects 'started' field */ | ||
| 105 | bool started; | ||
| 106 | }; | ||
| 107 | |||
| 108 | static void hv_kbd_on_receive(struct hv_device *hv_dev, | ||
| 109 | struct synth_kbd_msg *msg, u32 msg_length) | ||
| 110 | { | ||
| 111 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | ||
| 112 | struct synth_kbd_keystroke *ks_msg; | ||
| 113 | unsigned long flags; | ||
| 114 | u32 msg_type = __le32_to_cpu(msg->header.type); | ||
| 115 | u32 info; | ||
| 116 | u16 scan_code; | ||
| 117 | |||
| 118 | switch (msg_type) { | ||
| 119 | case SYNTH_KBD_PROTOCOL_RESPONSE: | ||
| 120 | /* | ||
| 121 | * Validate the information provided by the host. | ||
| 122 | * If the host is giving us a bogus packet, | ||
| 123 | * drop the packet (hoping the problem | ||
| 124 | * goes away). | ||
| 125 | */ | ||
| 126 | if (msg_length < sizeof(struct synth_kbd_protocol_response)) { | ||
| 127 | dev_err(&hv_dev->device, | ||
| 128 | "Illegal protocol response packet (len: %d)\n", | ||
| 129 | msg_length); | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | |||
| 133 | memcpy(&kbd_dev->protocol_resp, msg, | ||
| 134 | sizeof(struct synth_kbd_protocol_response)); | ||
| 135 | complete(&kbd_dev->wait_event); | ||
| 136 | break; | ||
| 137 | |||
| 138 | case SYNTH_KBD_EVENT: | ||
| 139 | /* | ||
| 140 | * Validate the information provided by the host. | ||
| 141 | * If the host is giving us a bogus packet, | ||
| 142 | * drop the packet (hoping the problem | ||
| 143 | * goes away). | ||
| 144 | */ | ||
| 145 | if (msg_length < sizeof(struct synth_kbd_keystroke)) { | ||
| 146 | dev_err(&hv_dev->device, | ||
| 147 | "Illegal keyboard event packet (len: %d)\n", | ||
| 148 | msg_length); | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | |||
| 152 | ks_msg = (struct synth_kbd_keystroke *)msg; | ||
| 153 | info = __le32_to_cpu(ks_msg->info); | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Inject the information through the serio interrupt. | ||
| 157 | */ | ||
| 158 | spin_lock_irqsave(&kbd_dev->lock, flags); | ||
| 159 | if (kbd_dev->started) { | ||
| 160 | if (info & IS_E0) | ||
| 161 | serio_interrupt(kbd_dev->hv_serio, | ||
| 162 | XTKBD_EMUL0, 0); | ||
| 163 | |||
| 164 | scan_code = __le16_to_cpu(ks_msg->make_code); | ||
| 165 | if (info & IS_BREAK) | ||
| 166 | scan_code |= XTKBD_RELEASE; | ||
| 167 | |||
| 168 | serio_interrupt(kbd_dev->hv_serio, scan_code, 0); | ||
| 169 | } | ||
| 170 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | ||
| 171 | break; | ||
| 172 | |||
| 173 | default: | ||
| 174 | dev_err(&hv_dev->device, | ||
| 175 | "unhandled message type %d\n", msg_type); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | static void hv_kbd_handle_received_packet(struct hv_device *hv_dev, | ||
| 180 | struct vmpacket_descriptor *desc, | ||
| 181 | u32 bytes_recvd, | ||
| 182 | u64 req_id) | ||
| 183 | { | ||
| 184 | struct synth_kbd_msg *msg; | ||
| 185 | u32 msg_sz; | ||
| 186 | |||
| 187 | switch (desc->type) { | ||
| 188 | case VM_PKT_COMP: | ||
| 189 | break; | ||
| 190 | |||
| 191 | case VM_PKT_DATA_INBAND: | ||
| 192 | /* | ||
| 193 | * We have a packet that has "inband" data. The API used | ||
| 194 | * for retrieving the packet guarantees that the complete | ||
| 195 | * packet is read. So, minimally, we should be able to | ||
| 196 | * parse the payload header safely (assuming that the host | ||
| 197 | * can be trusted. Trusting the host seems to be a | ||
| 198 | * reasonable assumption because in a virtualized | ||
| 199 | * environment there is not whole lot you can do if you | ||
| 200 | * don't trust the host. | ||
| 201 | * | ||
| 202 | * Nonetheless, let us validate if the host can be trusted | ||
| 203 | * (in a trivial way). The interesting aspect of this | ||
| 204 | * validation is how do you recover if we discover that the | ||
| 205 | * host is not to be trusted? Simply dropping the packet, I | ||
| 206 | * don't think is an appropriate recovery. In the interest | ||
| 207 | * of failing fast, it may be better to crash the guest. | ||
| 208 | * For now, I will just drop the packet! | ||
| 209 | */ | ||
| 210 | |||
| 211 | msg_sz = bytes_recvd - (desc->offset8 << 3); | ||
| 212 | if (msg_sz <= sizeof(struct synth_kbd_msg_hdr)) { | ||
| 213 | /* | ||
| 214 | * Drop the packet and hope | ||
| 215 | * the problem magically goes away. | ||
| 216 | */ | ||
| 217 | dev_err(&hv_dev->device, | ||
| 218 | "Illegal packet (type: %d, tid: %llx, size: %d)\n", | ||
| 219 | desc->type, req_id, msg_sz); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | |||
| 223 | msg = (void *)desc + (desc->offset8 << 3); | ||
| 224 | hv_kbd_on_receive(hv_dev, msg, msg_sz); | ||
| 225 | break; | ||
| 226 | |||
| 227 | default: | ||
| 228 | dev_err(&hv_dev->device, | ||
| 229 | "unhandled packet type %d, tid %llx len %d\n", | ||
| 230 | desc->type, req_id, bytes_recvd); | ||
| 231 | break; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | static void hv_kbd_on_channel_callback(void *context) | ||
| 236 | { | ||
| 237 | struct hv_device *hv_dev = context; | ||
| 238 | void *buffer; | ||
| 239 | int bufferlen = 0x100; /* Start with sensible size */ | ||
| 240 | u32 bytes_recvd; | ||
| 241 | u64 req_id; | ||
| 242 | int error; | ||
| 243 | |||
| 244 | buffer = kmalloc(bufferlen, GFP_ATOMIC); | ||
| 245 | if (!buffer) | ||
| 246 | return; | ||
| 247 | |||
| 248 | while (1) { | ||
| 249 | error = vmbus_recvpacket_raw(hv_dev->channel, buffer, bufferlen, | ||
| 250 | &bytes_recvd, &req_id); | ||
| 251 | switch (error) { | ||
| 252 | case 0: | ||
| 253 | if (bytes_recvd == 0) { | ||
| 254 | kfree(buffer); | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | |||
| 258 | hv_kbd_handle_received_packet(hv_dev, buffer, | ||
| 259 | bytes_recvd, req_id); | ||
| 260 | break; | ||
| 261 | |||
| 262 | case -ENOBUFS: | ||
| 263 | kfree(buffer); | ||
| 264 | /* Handle large packet */ | ||
| 265 | bufferlen = bytes_recvd; | ||
| 266 | buffer = kmalloc(bytes_recvd, GFP_ATOMIC); | ||
| 267 | if (!buffer) | ||
| 268 | return; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev) | ||
| 275 | { | ||
| 276 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | ||
| 277 | struct synth_kbd_protocol_request *request; | ||
| 278 | struct synth_kbd_protocol_response *response; | ||
| 279 | u32 proto_status; | ||
| 280 | int error; | ||
| 281 | |||
| 282 | request = &kbd_dev->protocol_req; | ||
| 283 | memset(request, 0, sizeof(struct synth_kbd_protocol_request)); | ||
| 284 | request->header.type = __cpu_to_le32(SYNTH_KBD_PROTOCOL_REQUEST); | ||
| 285 | request->version_requested.version = __cpu_to_le32(SYNTH_KBD_VERSION); | ||
| 286 | |||
| 287 | error = vmbus_sendpacket(hv_dev->channel, request, | ||
| 288 | sizeof(struct synth_kbd_protocol_request), | ||
| 289 | (unsigned long)request, | ||
| 290 | VM_PKT_DATA_INBAND, | ||
| 291 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||
| 292 | if (error) | ||
| 293 | return error; | ||
| 294 | |||
| 295 | if (!wait_for_completion_timeout(&kbd_dev->wait_event, 10 * HZ)) | ||
| 296 | return -ETIMEDOUT; | ||
| 297 | |||
| 298 | response = &kbd_dev->protocol_resp; | ||
| 299 | proto_status = __le32_to_cpu(response->proto_status); | ||
| 300 | if (!(proto_status & PROTOCOL_ACCEPTED)) { | ||
| 301 | dev_err(&hv_dev->device, | ||
| 302 | "synth_kbd protocol request failed (version %d)\n", | ||
| 303 | SYNTH_KBD_VERSION); | ||
| 304 | return -ENODEV; | ||
| 305 | } | ||
| 306 | |||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int hv_kbd_start(struct serio *serio) | ||
| 311 | { | ||
| 312 | struct hv_kbd_dev *kbd_dev = serio->port_data; | ||
| 313 | unsigned long flags; | ||
| 314 | |||
| 315 | spin_lock_irqsave(&kbd_dev->lock, flags); | ||
| 316 | kbd_dev->started = true; | ||
| 317 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | ||
| 318 | |||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | |||
| 322 | static void hv_kbd_stop(struct serio *serio) | ||
| 323 | { | ||
| 324 | struct hv_kbd_dev *kbd_dev = serio->port_data; | ||
| 325 | unsigned long flags; | ||
| 326 | |||
| 327 | spin_lock_irqsave(&kbd_dev->lock, flags); | ||
| 328 | kbd_dev->started = false; | ||
| 329 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | ||
| 330 | } | ||
| 331 | |||
| 332 | static int hv_kbd_probe(struct hv_device *hv_dev, | ||
| 333 | const struct hv_vmbus_device_id *dev_id) | ||
| 334 | { | ||
| 335 | struct hv_kbd_dev *kbd_dev; | ||
| 336 | struct serio *hv_serio; | ||
| 337 | int error; | ||
| 338 | |||
| 339 | kbd_dev = kzalloc(sizeof(struct hv_kbd_dev), GFP_KERNEL); | ||
| 340 | hv_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | ||
| 341 | if (!kbd_dev || !hv_serio) { | ||
| 342 | error = -ENOMEM; | ||
| 343 | goto err_free_mem; | ||
| 344 | } | ||
| 345 | |||
| 346 | kbd_dev->hv_dev = hv_dev; | ||
| 347 | kbd_dev->hv_serio = hv_serio; | ||
| 348 | spin_lock_init(&kbd_dev->lock); | ||
| 349 | init_completion(&kbd_dev->wait_event); | ||
| 350 | hv_set_drvdata(hv_dev, kbd_dev); | ||
| 351 | |||
| 352 | hv_serio->dev.parent = &hv_dev->device; | ||
| 353 | hv_serio->id.type = SERIO_8042_XL; | ||
| 354 | hv_serio->port_data = kbd_dev; | ||
| 355 | strlcpy(hv_serio->name, dev_name(&hv_dev->device), | ||
| 356 | sizeof(hv_serio->name)); | ||
| 357 | strlcpy(hv_serio->phys, dev_name(&hv_dev->device), | ||
| 358 | sizeof(hv_serio->phys)); | ||
| 359 | |||
| 360 | hv_serio->start = hv_kbd_start; | ||
| 361 | hv_serio->stop = hv_kbd_stop; | ||
| 362 | |||
| 363 | error = vmbus_open(hv_dev->channel, | ||
| 364 | KBD_VSC_SEND_RING_BUFFER_SIZE, | ||
| 365 | KBD_VSC_RECV_RING_BUFFER_SIZE, | ||
| 366 | NULL, 0, | ||
| 367 | hv_kbd_on_channel_callback, | ||
| 368 | hv_dev); | ||
| 369 | if (error) | ||
| 370 | goto err_free_mem; | ||
| 371 | |||
| 372 | error = hv_kbd_connect_to_vsp(hv_dev); | ||
| 373 | if (error) | ||
| 374 | goto err_close_vmbus; | ||
| 375 | |||
| 376 | serio_register_port(kbd_dev->hv_serio); | ||
| 377 | return 0; | ||
| 378 | |||
| 379 | err_close_vmbus: | ||
| 380 | vmbus_close(hv_dev->channel); | ||
| 381 | err_free_mem: | ||
| 382 | kfree(hv_serio); | ||
| 383 | kfree(kbd_dev); | ||
| 384 | return error; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int hv_kbd_remove(struct hv_device *hv_dev) | ||
| 388 | { | ||
| 389 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | ||
| 390 | |||
| 391 | serio_unregister_port(kbd_dev->hv_serio); | ||
| 392 | vmbus_close(hv_dev->channel); | ||
| 393 | kfree(kbd_dev); | ||
| 394 | |||
| 395 | hv_set_drvdata(hv_dev, NULL); | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | |||
| 400 | /* | ||
| 401 | * Keyboard GUID | ||
| 402 | * {f912ad6d-2b17-48ea-bd65-f927a61c7684} | ||
| 403 | */ | ||
| 404 | #define HV_KBD_GUID \ | ||
| 405 | .guid = { \ | ||
| 406 | 0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \ | ||
| 407 | 0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \ | ||
| 408 | } | ||
| 409 | |||
| 410 | static const struct hv_vmbus_device_id id_table[] = { | ||
| 411 | /* Keyboard guid */ | ||
| 412 | { HV_KBD_GUID, }, | ||
| 413 | { }, | ||
| 414 | }; | ||
| 415 | |||
| 416 | MODULE_DEVICE_TABLE(vmbus, id_table); | ||
| 417 | |||
| 418 | static struct hv_driver hv_kbd_drv = { | ||
| 419 | .name = KBUILD_MODNAME, | ||
| 420 | .id_table = id_table, | ||
| 421 | .probe = hv_kbd_probe, | ||
| 422 | .remove = hv_kbd_remove, | ||
| 423 | }; | ||
| 424 | |||
| 425 | static int __init hv_kbd_init(void) | ||
| 426 | { | ||
| 427 | return vmbus_driver_register(&hv_kbd_drv); | ||
| 428 | } | ||
| 429 | |||
| 430 | static void __exit hv_kbd_exit(void) | ||
| 431 | { | ||
| 432 | vmbus_driver_unregister(&hv_kbd_drv); | ||
| 433 | } | ||
| 434 | |||
| 435 | MODULE_LICENSE("GPL"); | ||
| 436 | module_init(hv_kbd_init); | ||
| 437 | module_exit(hv_kbd_exit); | ||
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5f306f79da0c..0ec9abbe31fe 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
| @@ -765,6 +765,7 @@ static struct pnp_device_id pnp_kbd_devids[] = { | |||
| 765 | { .id = "CPQA0D7", .driver_data = 0 }, | 765 | { .id = "CPQA0D7", .driver_data = 0 }, |
| 766 | { .id = "", }, | 766 | { .id = "", }, |
| 767 | }; | 767 | }; |
| 768 | MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids); | ||
| 768 | 769 | ||
| 769 | static struct pnp_driver i8042_pnp_kbd_driver = { | 770 | static struct pnp_driver i8042_pnp_kbd_driver = { |
| 770 | .name = "i8042 kbd", | 771 | .name = "i8042 kbd", |
| @@ -786,6 +787,7 @@ static struct pnp_device_id pnp_aux_devids[] = { | |||
| 786 | { .id = "SYN0801", .driver_data = 0 }, | 787 | { .id = "SYN0801", .driver_data = 0 }, |
| 787 | { .id = "", }, | 788 | { .id = "", }, |
| 788 | }; | 789 | }; |
| 790 | MODULE_DEVICE_TABLE(pnp, pnp_aux_devids); | ||
| 789 | 791 | ||
| 790 | static struct pnp_driver i8042_pnp_aux_driver = { | 792 | static struct pnp_driver i8042_pnp_aux_driver = { |
| 791 | .name = "i8042 aux", | 793 | .name = "i8042 aux", |
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 25fc5971f426..2b56855c2c77 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
| @@ -732,19 +732,20 @@ EXPORT_SYMBOL(serio_unregister_child_port); | |||
| 732 | * Serio driver operations | 732 | * Serio driver operations |
| 733 | */ | 733 | */ |
| 734 | 734 | ||
| 735 | static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) | 735 | static ssize_t description_show(struct device_driver *drv, char *buf) |
| 736 | { | 736 | { |
| 737 | struct serio_driver *driver = to_serio_driver(drv); | 737 | struct serio_driver *driver = to_serio_driver(drv); |
| 738 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); | 738 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); |
| 739 | } | 739 | } |
| 740 | static DRIVER_ATTR_RO(description); | ||
| 740 | 741 | ||
| 741 | static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) | 742 | static ssize_t bind_mode_show(struct device_driver *drv, char *buf) |
| 742 | { | 743 | { |
| 743 | struct serio_driver *serio_drv = to_serio_driver(drv); | 744 | struct serio_driver *serio_drv = to_serio_driver(drv); |
| 744 | return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); | 745 | return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); |
| 745 | } | 746 | } |
| 746 | 747 | ||
| 747 | static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) | 748 | static ssize_t bind_mode_store(struct device_driver *drv, const char *buf, size_t count) |
| 748 | { | 749 | { |
| 749 | struct serio_driver *serio_drv = to_serio_driver(drv); | 750 | struct serio_driver *serio_drv = to_serio_driver(drv); |
| 750 | int retval; | 751 | int retval; |
| @@ -760,14 +761,14 @@ static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char | |||
| 760 | 761 | ||
| 761 | return retval; | 762 | return retval; |
| 762 | } | 763 | } |
| 764 | static DRIVER_ATTR_RW(bind_mode); | ||
| 763 | 765 | ||
| 764 | 766 | static struct attribute *serio_driver_attrs[] = { | |
| 765 | static struct driver_attribute serio_driver_attrs[] = { | 767 | &driver_attr_description.attr, |
| 766 | __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), | 768 | &driver_attr_bind_mode.attr, |
| 767 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, | 769 | NULL, |
| 768 | serio_driver_show_bind_mode, serio_driver_set_bind_mode), | ||
| 769 | __ATTR_NULL | ||
| 770 | }; | 770 | }; |
| 771 | ATTRIBUTE_GROUPS(serio_driver); | ||
| 771 | 772 | ||
| 772 | static int serio_driver_probe(struct device *dev) | 773 | static int serio_driver_probe(struct device *dev) |
| 773 | { | 774 | { |
| @@ -996,7 +997,7 @@ EXPORT_SYMBOL(serio_interrupt); | |||
| 996 | static struct bus_type serio_bus = { | 997 | static struct bus_type serio_bus = { |
| 997 | .name = "serio", | 998 | .name = "serio", |
| 998 | .dev_attrs = serio_device_attrs, | 999 | .dev_attrs = serio_device_attrs, |
| 999 | .drv_attrs = serio_driver_attrs, | 1000 | .drv_groups = serio_driver_groups, |
| 1000 | .match = serio_bus_match, | 1001 | .match = serio_bus_match, |
| 1001 | .uevent = serio_uevent, | 1002 | .uevent = serio_uevent, |
| 1002 | .probe = serio_driver_probe, | 1003 | .probe = serio_driver_probe, |
