diff options
Diffstat (limited to 'drivers/media/IR/ir-keytable.c')
| -rw-r--r-- | drivers/media/IR/ir-keytable.c | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c new file mode 100644 index 000000000000..bff7a5356037 --- /dev/null +++ b/drivers/media/IR/ir-keytable.c | |||
| @@ -0,0 +1,485 @@ | |||
| 1 | /* ir-register.c - handle IR scancode->keycode tables | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation version 2 of the License. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | |||
| 16 | #include <linux/usb/input.h> | ||
| 17 | #include <media/ir-common.h> | ||
| 18 | |||
| 19 | #define IR_TAB_MIN_SIZE 32 | ||
| 20 | #define IR_TAB_MAX_SIZE 1024 | ||
| 21 | |||
| 22 | /** | ||
| 23 | * ir_seek_table() - returns the element order on the table | ||
| 24 | * @rc_tab: the ir_scancode_table with the keymap to be used | ||
| 25 | * @scancode: the scancode that we're seeking | ||
| 26 | * | ||
| 27 | * This routine is used by the input routines when a key is pressed at the | ||
| 28 | * IR. The scancode is received and needs to be converted into a keycode. | ||
| 29 | * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the | ||
| 30 | * corresponding keycode from the table. | ||
| 31 | */ | ||
| 32 | static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode) | ||
| 33 | { | ||
| 34 | int rc; | ||
| 35 | unsigned long flags; | ||
| 36 | struct ir_scancode *keymap = rc_tab->scan; | ||
| 37 | |||
| 38 | spin_lock_irqsave(&rc_tab->lock, flags); | ||
| 39 | |||
| 40 | /* FIXME: replace it by a binary search */ | ||
| 41 | |||
| 42 | for (rc = 0; rc < rc_tab->size; rc++) | ||
| 43 | if (keymap[rc].scancode == scancode) | ||
| 44 | goto exit; | ||
| 45 | |||
| 46 | /* Not found */ | ||
| 47 | rc = -EINVAL; | ||
| 48 | |||
| 49 | exit: | ||
| 50 | spin_unlock_irqrestore(&rc_tab->lock, flags); | ||
| 51 | return rc; | ||
| 52 | } | ||
| 53 | |||
| 54 | /** | ||
| 55 | * ir_roundup_tablesize() - gets an optimum value for the table size | ||
| 56 | * @n_elems: minimum number of entries to store keycodes | ||
| 57 | * | ||
| 58 | * This routine is used to choose the keycode table size. | ||
| 59 | * | ||
| 60 | * In order to have some empty space for new keycodes, | ||
| 61 | * and knowing in advance that kmalloc allocates only power of two | ||
| 62 | * segments, it optimizes the allocated space to have some spare space | ||
| 63 | * for those new keycodes by using the maximum number of entries that | ||
| 64 | * will be effectively be allocated by kmalloc. | ||
| 65 | * In order to reduce the quantity of table resizes, it has a minimum | ||
| 66 | * table size of IR_TAB_MIN_SIZE. | ||
| 67 | */ | ||
| 68 | int ir_roundup_tablesize(int n_elems) | ||
| 69 | { | ||
| 70 | size_t size; | ||
| 71 | |||
| 72 | if (n_elems < IR_TAB_MIN_SIZE) | ||
| 73 | n_elems = IR_TAB_MIN_SIZE; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * As kmalloc only allocates sizes of power of two, get as | ||
| 77 | * much entries as possible for the allocated memory segment | ||
| 78 | */ | ||
| 79 | size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode)); | ||
| 80 | n_elems = size / sizeof(struct ir_scancode); | ||
| 81 | |||
| 82 | return n_elems; | ||
| 83 | } | ||
| 84 | EXPORT_SYMBOL_GPL(ir_roundup_tablesize); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * ir_copy_table() - copies a keytable, discarding the unused entries | ||
| 88 | * @destin: destin table | ||
| 89 | * @origin: origin table | ||
| 90 | * | ||
| 91 | * Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED | ||
| 92 | */ | ||
| 93 | |||
| 94 | int ir_copy_table(struct ir_scancode_table *destin, | ||
| 95 | const struct ir_scancode_table *origin) | ||
| 96 | { | ||
| 97 | int i, j = 0; | ||
| 98 | |||
| 99 | for (i = 0; i < origin->size; i++) { | ||
| 100 | if (origin->scan[i].keycode == KEY_UNKNOWN || | ||
| 101 | origin->scan[i].keycode == KEY_RESERVED) | ||
| 102 | continue; | ||
| 103 | |||
| 104 | memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode)); | ||
| 105 | j++; | ||
| 106 | } | ||
| 107 | destin->size = j; | ||
| 108 | |||
| 109 | IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | EXPORT_SYMBOL_GPL(ir_copy_table); | ||
| 114 | |||
| 115 | /** | ||
| 116 | * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table | ||
| 117 | * @dev: the struct input_dev device descriptor | ||
| 118 | * @scancode: the desired scancode | ||
| 119 | * @keycode: the keycode to be retorned. | ||
| 120 | * | ||
| 121 | * This routine is used to handle evdev EVIOCGKEY ioctl. | ||
| 122 | * If the key is not found, returns -EINVAL, otherwise, returns 0. | ||
| 123 | */ | ||
| 124 | static int ir_getkeycode(struct input_dev *dev, | ||
| 125 | int scancode, int *keycode) | ||
| 126 | { | ||
| 127 | int elem; | ||
| 128 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); | ||
| 129 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
| 130 | |||
| 131 | elem = ir_seek_table(rc_tab, scancode); | ||
| 132 | if (elem >= 0) { | ||
| 133 | *keycode = rc_tab->scan[elem].keycode; | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Scancode not found and table can't be expanded | ||
| 139 | */ | ||
| 140 | if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE) | ||
| 141 | return -EINVAL; | ||
| 142 | |||
| 143 | /* | ||
| 144 | * If is there extra space, returns KEY_RESERVED, | ||
| 145 | * otherwise, input core won't let ir_setkeycode to work | ||
| 146 | */ | ||
| 147 | *keycode = KEY_RESERVED; | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * ir_is_resize_needed() - Check if the table needs rezise | ||
| 153 | * @table: keycode table that may need to resize | ||
| 154 | * @n_elems: minimum number of entries to store keycodes | ||
| 155 | * | ||
| 156 | * Considering that kmalloc uses power of two storage areas, this | ||
| 157 | * routine detects if the real alloced size will change. If not, it | ||
| 158 | * just returns without doing nothing. Otherwise, it will extend or | ||
| 159 | * reduce the table size to meet the new needs. | ||
| 160 | * | ||
| 161 | * It returns 0 if no resize is needed, 1 otherwise. | ||
| 162 | */ | ||
| 163 | static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems) | ||
| 164 | { | ||
| 165 | int cur_size = ir_roundup_tablesize(table->size); | ||
| 166 | int new_size = ir_roundup_tablesize(n_elems); | ||
| 167 | |||
| 168 | if (cur_size == new_size) | ||
| 169 | return 0; | ||
| 170 | |||
| 171 | /* Resize is needed */ | ||
| 172 | return 1; | ||
| 173 | } | ||
| 174 | |||
| 175 | /** | ||
| 176 | * ir_delete_key() - remove a keycode from the table | ||
| 177 | * @rc_tab: keycode table | ||
| 178 | * @elem: element to be removed | ||
| 179 | * | ||
| 180 | */ | ||
| 181 | static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem) | ||
| 182 | { | ||
| 183 | unsigned long flags = 0; | ||
| 184 | int newsize = rc_tab->size - 1; | ||
| 185 | int resize = ir_is_resize_needed(rc_tab, newsize); | ||
| 186 | struct ir_scancode *oldkeymap = rc_tab->scan; | ||
| 187 | struct ir_scancode *newkeymap; | ||
| 188 | |||
| 189 | if (resize) { | ||
| 190 | newkeymap = kzalloc(ir_roundup_tablesize(newsize) * | ||
| 191 | sizeof(*newkeymap), GFP_ATOMIC); | ||
| 192 | |||
| 193 | /* There's no memory for resize. Keep the old table */ | ||
| 194 | if (!newkeymap) | ||
| 195 | resize = 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (!resize) { | ||
| 199 | newkeymap = oldkeymap; | ||
| 200 | |||
| 201 | /* We'll modify the live table. Lock it */ | ||
| 202 | spin_lock_irqsave(&rc_tab->lock, flags); | ||
| 203 | } | ||
| 204 | |||
| 205 | /* | ||
| 206 | * Copy the elements before the one that will be deleted | ||
| 207 | * if (!resize), both oldkeymap and newkeymap points | ||
| 208 | * to the same place, so, there's no need to copy | ||
| 209 | */ | ||
| 210 | if (resize && elem > 0) | ||
| 211 | memcpy(newkeymap, oldkeymap, | ||
| 212 | elem * sizeof(*newkeymap)); | ||
| 213 | |||
| 214 | /* | ||
| 215 | * Copy the other elements overwriting the element to be removed | ||
| 216 | * This operation applies to both resize and non-resize case | ||
| 217 | */ | ||
| 218 | if (elem < newsize) | ||
| 219 | memcpy(&newkeymap[elem], &oldkeymap[elem + 1], | ||
| 220 | (newsize - elem) * sizeof(*newkeymap)); | ||
| 221 | |||
| 222 | if (resize) { | ||
| 223 | /* | ||
| 224 | * As the copy happened to a temporary table, only here | ||
| 225 | * it needs to lock while replacing the table pointers | ||
| 226 | * to use the new table | ||
| 227 | */ | ||
| 228 | spin_lock_irqsave(&rc_tab->lock, flags); | ||
| 229 | rc_tab->size = newsize; | ||
| 230 | rc_tab->scan = newkeymap; | ||
| 231 | spin_unlock_irqrestore(&rc_tab->lock, flags); | ||
| 232 | |||
| 233 | /* Frees the old keytable */ | ||
| 234 | kfree(oldkeymap); | ||
| 235 | } else { | ||
| 236 | rc_tab->size = newsize; | ||
| 237 | spin_unlock_irqrestore(&rc_tab->lock, flags); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * ir_insert_key() - insert a keycode at the table | ||
| 243 | * @rc_tab: keycode table | ||
| 244 | * @scancode: the desired scancode | ||
| 245 | * @keycode: the keycode to be retorned. | ||
| 246 | * | ||
| 247 | */ | ||
| 248 | static int ir_insert_key(struct ir_scancode_table *rc_tab, | ||
| 249 | int scancode, int keycode) | ||
| 250 | { | ||
| 251 | unsigned long flags; | ||
| 252 | int elem = rc_tab->size; | ||
| 253 | int newsize = rc_tab->size + 1; | ||
| 254 | int resize = ir_is_resize_needed(rc_tab, newsize); | ||
| 255 | struct ir_scancode *oldkeymap = rc_tab->scan; | ||
| 256 | struct ir_scancode *newkeymap; | ||
| 257 | |||
| 258 | if (resize) { | ||
| 259 | newkeymap = kzalloc(ir_roundup_tablesize(newsize) * | ||
| 260 | sizeof(*newkeymap), GFP_ATOMIC); | ||
| 261 | if (!newkeymap) | ||
| 262 | return -ENOMEM; | ||
| 263 | |||
| 264 | memcpy(newkeymap, oldkeymap, | ||
| 265 | rc_tab->size * sizeof(*newkeymap)); | ||
| 266 | } else | ||
| 267 | newkeymap = oldkeymap; | ||
| 268 | |||
| 269 | /* Stores the new code at the table */ | ||
| 270 | IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n", | ||
| 271 | rc_tab->size, scancode, keycode); | ||
| 272 | |||
| 273 | spin_lock_irqsave(&rc_tab->lock, flags); | ||
| 274 | rc_tab->size = newsize; | ||
| 275 | if (resize) { | ||
| 276 | rc_tab->scan = newkeymap; | ||
| 277 | kfree(oldkeymap); | ||
| 278 | } | ||
| 279 | newkeymap[elem].scancode = scancode; | ||
| 280 | newkeymap[elem].keycode = keycode; | ||
| 281 | spin_unlock_irqrestore(&rc_tab->lock, flags); | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | /** | ||
| 287 | * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table | ||
| 288 | * @dev: the struct input_dev device descriptor | ||
| 289 | * @scancode: the desired scancode | ||
| 290 | * @keycode: the keycode to be retorned. | ||
| 291 | * | ||
| 292 | * This routine is used to handle evdev EVIOCSKEY ioctl. | ||
| 293 | * There's one caveat here: how can we increase the size of the table? | ||
| 294 | * If the key is not found, returns -EINVAL, otherwise, returns 0. | ||
| 295 | */ | ||
| 296 | static int ir_setkeycode(struct input_dev *dev, | ||
| 297 | int scancode, int keycode) | ||
| 298 | { | ||
| 299 | int rc = 0; | ||
| 300 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); | ||
| 301 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
| 302 | struct ir_scancode *keymap = rc_tab->scan; | ||
| 303 | unsigned long flags; | ||
| 304 | |||
| 305 | /* | ||
| 306 | * Handle keycode table deletions | ||
| 307 | * | ||
| 308 | * If userspace is adding a KEY_UNKNOWN or KEY_RESERVED, | ||
| 309 | * deal as a trial to remove an existing scancode attribution | ||
| 310 | * if table become too big, reduce it to save space | ||
| 311 | */ | ||
| 312 | if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) { | ||
| 313 | rc = ir_seek_table(rc_tab, scancode); | ||
| 314 | if (rc < 0) | ||
| 315 | return 0; | ||
| 316 | |||
| 317 | IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode); | ||
| 318 | clear_bit(keymap[rc].keycode, dev->keybit); | ||
| 319 | ir_delete_key(rc_tab, rc); | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | /* | ||
| 325 | * Handle keycode replacements | ||
| 326 | * | ||
| 327 | * If the scancode exists, just replace by the new value | ||
| 328 | */ | ||
| 329 | rc = ir_seek_table(rc_tab, scancode); | ||
| 330 | if (rc >= 0) { | ||
| 331 | IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n", | ||
| 332 | rc, scancode, keycode); | ||
| 333 | |||
| 334 | clear_bit(keymap[rc].keycode, dev->keybit); | ||
| 335 | |||
| 336 | spin_lock_irqsave(&rc_tab->lock, flags); | ||
| 337 | keymap[rc].keycode = keycode; | ||
| 338 | spin_unlock_irqrestore(&rc_tab->lock, flags); | ||
| 339 | |||
| 340 | set_bit(keycode, dev->keybit); | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | /* | ||
| 346 | * Handle new scancode inserts | ||
| 347 | * | ||
| 348 | * reallocate table if needed and insert a new keycode | ||
| 349 | */ | ||
| 350 | |||
| 351 | /* Avoid growing the table indefinitely */ | ||
| 352 | if (rc_tab->size + 1 > IR_TAB_MAX_SIZE) | ||
| 353 | return -EINVAL; | ||
| 354 | |||
| 355 | rc = ir_insert_key(rc_tab, scancode, keycode); | ||
| 356 | if (rc < 0) | ||
| 357 | return rc; | ||
| 358 | set_bit(keycode, dev->keybit); | ||
| 359 | |||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** | ||
| 364 | * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode | ||
| 365 | * @input_dev: the struct input_dev descriptor of the device | ||
| 366 | * @scancode: the scancode that we're seeking | ||
| 367 | * | ||
| 368 | * This routine is used by the input routines when a key is pressed at the | ||
| 369 | * IR. The scancode is received and needs to be converted into a keycode. | ||
| 370 | * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the | ||
| 371 | * corresponding keycode from the table. | ||
| 372 | */ | ||
| 373 | u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) | ||
| 374 | { | ||
| 375 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); | ||
| 376 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
| 377 | struct ir_scancode *keymap = rc_tab->scan; | ||
| 378 | int elem; | ||
| 379 | |||
| 380 | elem = ir_seek_table(rc_tab, scancode); | ||
| 381 | if (elem >= 0) { | ||
| 382 | IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", | ||
| 383 | dev->name, scancode, keymap[elem].keycode); | ||
| 384 | |||
| 385 | return rc_tab->scan[elem].keycode; | ||
| 386 | } | ||
| 387 | |||
| 388 | printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n", | ||
| 389 | dev->name, scancode); | ||
| 390 | |||
| 391 | /* Reports userspace that an unknown keycode were got */ | ||
| 392 | return KEY_RESERVED; | ||
| 393 | } | ||
| 394 | EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); | ||
| 395 | |||
| 396 | /** | ||
| 397 | * ir_input_register() - sets the IR keycode table and add the handlers | ||
| 398 | * for keymap table get/set | ||
| 399 | * @input_dev: the struct input_dev descriptor of the device | ||
| 400 | * @rc_tab: the struct ir_scancode_table table of scancode/keymap | ||
| 401 | * | ||
| 402 | * This routine is used to initialize the input infrastructure to work with | ||
| 403 | * an IR. | ||
| 404 | * It should be called before registering the IR device. | ||
| 405 | */ | ||
| 406 | int ir_input_register(struct input_dev *input_dev, | ||
| 407 | struct ir_scancode_table *rc_tab) | ||
| 408 | { | ||
| 409 | struct ir_input_dev *ir_dev; | ||
| 410 | struct ir_scancode *keymap = rc_tab->scan; | ||
| 411 | int i, rc; | ||
| 412 | |||
| 413 | if (rc_tab->scan == NULL || !rc_tab->size) | ||
| 414 | return -EINVAL; | ||
| 415 | |||
| 416 | ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL); | ||
| 417 | if (!ir_dev) | ||
| 418 | return -ENOMEM; | ||
| 419 | |||
| 420 | spin_lock_init(&rc_tab->lock); | ||
| 421 | |||
| 422 | ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size); | ||
| 423 | ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size * | ||
| 424 | sizeof(struct ir_scancode), GFP_KERNEL); | ||
| 425 | if (!ir_dev->rc_tab.scan) | ||
| 426 | return -ENOMEM; | ||
| 427 | |||
| 428 | IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", | ||
| 429 | ir_dev->rc_tab.size, | ||
| 430 | ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan)); | ||
| 431 | |||
| 432 | ir_copy_table(&ir_dev->rc_tab, rc_tab); | ||
| 433 | |||
| 434 | /* set the bits for the keys */ | ||
| 435 | IR_dprintk(1, "key map size: %d\n", rc_tab->size); | ||
| 436 | for (i = 0; i < rc_tab->size; i++) { | ||
| 437 | IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n", | ||
| 438 | i, keymap[i].keycode); | ||
| 439 | set_bit(keymap[i].keycode, input_dev->keybit); | ||
| 440 | } | ||
| 441 | clear_bit(0, input_dev->keybit); | ||
| 442 | |||
| 443 | set_bit(EV_KEY, input_dev->evbit); | ||
| 444 | |||
| 445 | input_dev->getkeycode = ir_getkeycode; | ||
| 446 | input_dev->setkeycode = ir_setkeycode; | ||
| 447 | input_set_drvdata(input_dev, ir_dev); | ||
| 448 | |||
| 449 | rc = input_register_device(input_dev); | ||
| 450 | if (rc < 0) { | ||
| 451 | kfree(rc_tab->scan); | ||
| 452 | kfree(ir_dev); | ||
| 453 | input_set_drvdata(input_dev, NULL); | ||
| 454 | } | ||
| 455 | |||
| 456 | return rc; | ||
| 457 | } | ||
| 458 | EXPORT_SYMBOL_GPL(ir_input_register); | ||
| 459 | |||
| 460 | void ir_input_unregister(struct input_dev *dev) | ||
| 461 | { | ||
| 462 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); | ||
| 463 | struct ir_scancode_table *rc_tab; | ||
| 464 | |||
| 465 | if (!ir_dev) | ||
| 466 | return; | ||
| 467 | |||
| 468 | IR_dprintk(1, "Freed keycode table\n"); | ||
| 469 | |||
| 470 | rc_tab = &ir_dev->rc_tab; | ||
| 471 | rc_tab->size = 0; | ||
| 472 | kfree(rc_tab->scan); | ||
| 473 | rc_tab->scan = NULL; | ||
| 474 | |||
| 475 | kfree(ir_dev); | ||
| 476 | input_unregister_device(dev); | ||
| 477 | } | ||
| 478 | EXPORT_SYMBOL_GPL(ir_input_unregister); | ||
| 479 | |||
| 480 | int ir_core_debug; /* ir_debug level (0,1,2) */ | ||
| 481 | EXPORT_SYMBOL_GPL(ir_core_debug); | ||
| 482 | module_param_named(debug, ir_core_debug, int, 0644); | ||
| 483 | |||
| 484 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
| 485 | MODULE_LICENSE("GPL"); | ||
