1 /* 2 * USB HID quirks support for Linux 3 * 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 * Copyright (c) 2006-2007 Jiri Kosina 8 * Copyright (c) 2007 Paul Walmsley 9 * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> 10 */ 11 12 /* 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the Free 15 * Software Foundation; either version 2 of the License, or (at your option) 16 * any later version. 17 */ 18 19 #include <linux/device.h> 20 #include <linux/hid.h> 21 #include <linux/module.h> 22 #include <linux/usb.h> 23 24 #include "hid-ids.h" 25 26 #define APPLE_RDESC_JIS 0x0001 27 #define APPLE_IGNORE_MOUSE 0x0002 28 #define APPLE_HAS_FN 0x0004 29 #define APPLE_HIDDEV 0x0008 30 #define APPLE_ISO_KEYBOARD 0x0010 31 #define APPLE_MIGHTYMOUSE 0x0020 32 #define APPLE_INVERT_HWHEEL 0x0040 33 #define APPLE_IGNORE_HIDINPUT 0x0080 34 #define APPLE_NUMLOCK_EMULATION 0x0100 35 36 #define APPLE_FLAG_FKEY 0x01 37 38 static unsigned int fnmode = 1; 39 module_param(fnmode, uint, 0644); 40 MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " 41 "[1] = fkeyslast, 2 = fkeysfirst)"); 42 43 struct apple_sc { 44 unsigned long quirks; 45 unsigned int fn_on; 46 DECLARE_BITMAP(pressed_fn, KEY_CNT); 47 DECLARE_BITMAP(pressed_numlock, KEY_CNT); 48 }; 49 50 struct apple_key_translation { 51 u16 from; 52 u16 to; 53 u8 flags; 54 }; 55 56 static const struct apple_key_translation apple_fn_keys[] = { 57 { KEY_BACKSPACE, KEY_DELETE }, 58 { KEY_ENTER, KEY_INSERT }, 59 { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, 60 { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, 61 { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, 62 { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, 63 { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, 64 { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, 65 { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, 66 { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, 67 { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, 68 { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, 69 { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, 70 { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, 71 { KEY_UP, KEY_PAGEUP }, 72 { KEY_DOWN, KEY_PAGEDOWN }, 73 { KEY_LEFT, KEY_HOME }, 74 { KEY_RIGHT, KEY_END }, 75 { } 76 }; 77 78 static const struct apple_key_translation powerbook_fn_keys[] = { 79 { KEY_BACKSPACE, KEY_DELETE }, 80 { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, 81 { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, 82 { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY }, 83 { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, 84 { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, 85 { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, 86 { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY }, 87 { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY }, 88 { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, 89 { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, 90 { KEY_UP, KEY_PAGEUP }, 91 { KEY_DOWN, KEY_PAGEDOWN }, 92 { KEY_LEFT, KEY_HOME }, 93 { KEY_RIGHT, KEY_END }, 94 { } 95 }; 96 97 static const struct apple_key_translation powerbook_numlock_keys[] = { 98 { KEY_J, KEY_KP1 }, 99 { KEY_K, KEY_KP2 }, 100 { KEY_L, KEY_KP3 }, 101 { KEY_U, KEY_KP4 }, 102 { KEY_I, KEY_KP5 }, 103 { KEY_O, KEY_KP6 }, 104 { KEY_7, KEY_KP7 }, 105 { KEY_8, KEY_KP8 }, 106 { KEY_9, KEY_KP9 }, 107 { KEY_M, KEY_KP0 }, 108 { KEY_DOT, KEY_KPDOT }, 109 { KEY_SLASH, KEY_KPPLUS }, 110 { KEY_SEMICOLON, KEY_KPMINUS }, 111 { KEY_P, KEY_KPASTERISK }, 112 { KEY_MINUS, KEY_KPEQUAL }, 113 { KEY_0, KEY_KPSLASH }, 114 { KEY_F6, KEY_NUMLOCK }, 115 { KEY_KPENTER, KEY_KPENTER }, 116 { KEY_BACKSPACE, KEY_BACKSPACE }, 117 { } 118 }; 119 120 static const struct apple_key_translation apple_iso_keyboard[] = { 121 { KEY_GRAVE, KEY_102ND }, 122 { KEY_102ND, KEY_GRAVE }, 123 { } 124 }; 125 126 static const struct apple_key_translation *apple_find_translation( 127 const struct apple_key_translation *table, u16 from) 128 { 129 const struct apple_key_translation *trans; 130 131 /* Look for the translation */ 132 for (trans = table; trans->from; trans++) 133 if (trans->from == from) 134 return trans; 135 136 return NULL; 137 } 138 139 static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, 140 struct hid_usage *usage, __s32 value) 141 { 142 struct apple_sc *asc = hid_get_drvdata(hid); 143 const struct apple_key_translation *trans; 144 145 if (usage->code == KEY_FN) { 146 asc->fn_on = !!value; 147 input_event(input, usage->type, usage->code, value); 148 return 1; 149 } 150 151 if (fnmode) { 152 int do_translate; 153 154 trans = apple_find_translation((hid->product < 0x21d || 155 hid->product >= 0x300) ? 156 powerbook_fn_keys : apple_fn_keys, 157 usage->code); 158 if (trans) { 159 if (test_bit(usage->code, asc->pressed_fn)) 160 do_translate = 1; 161 else if (trans->flags & APPLE_FLAG_FKEY) 162 do_translate = (fnmode == 2 && asc->fn_on) || 163 (fnmode == 1 && !asc->fn_on); 164 else 165 do_translate = asc->fn_on; 166 167 if (do_translate) { 168 if (value) 169 set_bit(usage->code, asc->pressed_fn); 170 else 171 clear_bit(usage->code, asc->pressed_fn); 172 173 input_event(input, usage->type, trans->to, 174 value); 175 176 return 1; 177 } 178 } 179 180 if (asc->quirks & APPLE_NUMLOCK_EMULATION && 181 (test_bit(usage->code, asc->pressed_numlock) || 182 test_bit(LED_NUML, input->led))) { 183 trans = apple_find_translation(powerbook_numlock_keys, 184 usage->code); 185 186 if (trans) { 187 if (value) 188 set_bit(usage->code, 189 asc->pressed_numlock); 190 else 191 clear_bit(usage->code, 192 asc->pressed_numlock); 193 194 input_event(input, usage->type, trans->to, 195 value); 196 } 197 198 return 1; 199 } 200 } 201 202 if (asc->quirks & APPLE_ISO_KEYBOARD) { 203 trans = apple_find_translation(apple_iso_keyboard, usage->code); 204 if (trans) { 205 input_event(input, usage->type, trans->to, value); 206 return 1; 207 } 208 } 209 210 return 0; 211 } 212 213 static int apple_event(struct hid_device *hdev, struct hid_field *field, 214 struct hid_usage *usage, __s32 value) 215 { 216 struct apple_sc *asc = hid_get_drvdata(hdev); 217 218 if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 219 !usage->type) 220 return 0; 221 222 if ((asc->quirks & APPLE_INVERT_HWHEEL) && 223 usage->code == REL_HWHEEL) { 224 input_event(field->hidinput->input, usage->type, usage->code, 225 -value); 226 return 1; 227 } 228 229 if ((asc->quirks & APPLE_HAS_FN) && 230 hidinput_apple_event(hdev, field->hidinput->input, 231 usage, value)) 232 return 1; 233 234 235 return 0; 236 } 237 238 /* 239 * MacBook JIS keyboard has wrong logical maximum 240 */ 241 static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, 242 unsigned int rsize) 243 { 244 struct apple_sc *asc = hid_get_drvdata(hdev); 245 246 if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 && 247 rdesc[53] == 0x65 && rdesc[59] == 0x65) { 248 dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report " 249 "descriptor\n"); 250 rdesc[53] = rdesc[59] = 0xe7; 251 } 252 } 253 254 static void apple_setup_input(struct input_dev *input) 255 { 256 const struct apple_key_translation *trans; 257 258 set_bit(KEY_NUMLOCK, input->keybit); 259 260 /* Enable all needed keys */ 261 for (trans = apple_fn_keys; trans->from; trans++) 262 set_bit(trans->to, input->keybit); 263 264 for (trans = powerbook_fn_keys; trans->from; trans++) 265 set_bit(trans->to, input->keybit); 266 267 for (trans = powerbook_numlock_keys; trans->from; trans++) 268 set_bit(trans->to, input->keybit); 269 270 for (trans = apple_iso_keyboard; trans->from; trans++) 271 set_bit(trans->to, input->keybit); 272 } 273 274 static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, 275 struct hid_field *field, struct hid_usage *usage, 276 unsigned long **bit, int *max) 277 { 278 if (usage->hid == (HID_UP_CUSTOM | 0x0003)) { 279 /* The fn key on Apple USB keyboards */ 280 set_bit(EV_REP, hi->input->evbit); 281 hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); 282 apple_setup_input(hi->input); 283 return 1; 284 } 285 286 /* we want the hid layer to go through standard path (set and ignore) */ 287 return 0; 288 } 289 290 static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi, 291 struct hid_field *field, struct hid_usage *usage, 292 unsigned long **bit, int *max) 293 { 294 struct apple_sc *asc = hid_get_drvdata(hdev); 295 296 if (asc->quirks & APPLE_MIGHTYMOUSE) { 297 if (usage->hid == HID_GD_Z) 298 hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL); 299 else if (usage->code == BTN_1) 300 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2); 301 else if (usage->code == BTN_2) 302 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1); 303 } 304 305 return 0; 306 } 307 308 static int apple_probe(struct hid_device *hdev, 309 const struct hid_device_id *id) 310 { 311 unsigned long quirks = id->driver_data; 312 struct apple_sc *asc; 313 unsigned int connect_mask = HID_CONNECT_DEFAULT; 314 int ret; 315 316 asc = kzalloc(sizeof(*asc), GFP_KERNEL); 317 if (asc == NULL) { 318 dev_err(&hdev->dev, "can't alloc apple descriptor\n"); 319 return -ENOMEM; 320 } 321 322 asc->quirks = quirks; 323 324 hid_set_drvdata(hdev, asc); 325 326 ret = hid_parse(hdev); 327 if (ret) { 328 dev_err(&hdev->dev, "parse failed\n"); 329 goto err_free; 330 } 331 332 if (quirks & APPLE_HIDDEV) 333 connect_mask |= HID_CONNECT_HIDDEV_FORCE; 334 if (quirks & APPLE_IGNORE_HIDINPUT) 335 connect_mask &= ~HID_CONNECT_HIDINPUT; 336 337 ret = hid_hw_start(hdev, connect_mask); 338 if (ret) { 339 dev_err(&hdev->dev, "hw start failed\n"); 340 goto err_free; 341 } 342 343 return 0; 344 err_free: 345 kfree(asc); 346 return ret; 347 } 348 349 static void apple_remove(struct hid_device *hdev) 350 { 351 hid_hw_stop(hdev); 352 kfree(hid_get_drvdata(hdev)); 353 } 354 355 static const struct hid_device_id apple_devices[] = { 356 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL), 357 .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, 358 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4), 359 .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, 360 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), 361 .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, 362 363 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI), 364 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 365 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO), 366 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 367 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI), 368 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 369 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO), 370 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 371 APPLE_ISO_KEYBOARD }, 372 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS), 373 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 374 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI), 375 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 376 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO), 377 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 378 APPLE_ISO_KEYBOARD }, 379 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS), 380 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 381 APPLE_RDESC_JIS }, 382 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI), 383 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 384 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO), 385 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 386 APPLE_ISO_KEYBOARD }, 387 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS), 388 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 389 APPLE_RDESC_JIS }, 390 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI), 391 .driver_data = APPLE_HAS_FN }, 392 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO), 393 .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, 394 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS), 395 .driver_data = APPLE_HAS_FN }, 396 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI), 397 .driver_data = APPLE_HAS_FN }, 398 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO), 399 .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, 400 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS), 401 .driver_data = APPLE_HAS_FN }, 402 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI), 403 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 404 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO), 405 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 406 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS), 407 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 408 APPLE_RDESC_JIS }, 409 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), 410 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 411 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO), 412 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 413 APPLE_ISO_KEYBOARD }, 414 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), 415 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 416 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), 417 .driver_data = APPLE_HAS_FN }, 418 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO), 419 .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, 420 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS), 421 .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, 422 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), 423 .driver_data = APPLE_HAS_FN }, 424 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), 425 .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, 426 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), 427 .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, 428 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), 429 .driver_data = APPLE_HAS_FN }, 430 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), 431 .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, 432 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), 433 .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, 434 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), 435 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 436 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), 437 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | 438 APPLE_ISO_KEYBOARD }, 439 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS), 440 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 441 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY), 442 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 443 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY), 444 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 445 446 { } 447 }; 448 MODULE_DEVICE_TABLE(hid, apple_devices); 449 450 static struct hid_driver apple_driver = { 451 .name = "apple", 452 .id_table = apple_devices, 453 .report_fixup = apple_report_fixup, 454 .probe = apple_probe, 455 .remove = apple_remove, 456 .event = apple_event, 457 .input_mapping = apple_input_mapping, 458 .input_mapped = apple_input_mapped, 459 }; 460 461 static int __init apple_init(void) 462 { 463 int ret; 464 465 ret = hid_register_driver(&apple_driver); 466 if (ret) 467 printk(KERN_ERR "can't register apple driver\n"); 468 469 return ret; 470 } 471 472 static void __exit apple_exit(void) 473 { 474 hid_unregister_driver(&apple_driver); 475 } 476 477 module_init(apple_init); 478 module_exit(apple_exit); 479 MODULE_LICENSE("GPL"); 480