/** * ir_locate_scancode() - set a keycode in the scancode->keycode table * @ir_dev: the struct ir_input_dev device descriptor * @rc_tab: scancode table to be searched * @scancode: the desired scancode * @resize: controls whether we allowed to resize the table to * accomodate not yet present scancodes * @return: index of the mapping containing scancode in question * or -1U in case of failure. * * This routine is used to locate given scancode in ir_scancode_table. * If scancode is not yet present the routine will allocate a new slot * for it. */ static unsigned int ir_establish_scancode(struct ir_input_dev *ir_dev, struct ir_scancode_table *rc_tab, unsigned int scancode, bool resize) { unsigned int i; /* * Unfortunately, some hardware-based IR decoders don't provide * all bits for the complete IR code. In general, they provide only * the command part of the IR code. Yet, as it is possible to replace * the provided IR with another one, it is needed to allow loading * IR tables from other remotes. So, */ if (ir_dev->props && ir_dev->props->scanmask) scancode &= ir_dev->props->scanmask; /* First check if we already have a mapping for this ir command */ for (i = 0; i < rc_tab->len; i++) { if (rc_tab->scan[i].scancode == scancode) return i; /* Keytable is sorted from lowest to highest scancode */ if (rc_tab->scan[i].scancode >= scancode) break; } /* No previous mapping found, we might need to grow the table */ if (rc_tab->size == rc_tab->len) { if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC)) return -1U; } /* i is the proper index to insert our new keycode */ if (i < rc_tab->len) memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i], (rc_tab->len - i) * sizeof(struct ir_scancode)); rc_tab->scan[i].scancode = scancode; rc_tab->scan[i].keycode = KEY_RESERVED; rc_tab->len++; return i; }
/** * ir_update_mapping() - set a keycode in the scancode->keycode table * @dev: the struct input_dev device descriptor * @rc_tab: scancode table to be adjusted * @index: index of the mapping that needs to be updated * @keycode: the desired keycode * @return: previous keycode assigned to the mapping * * This routine is used to update scancode->keycopde mapping at given * position. */ static unsigned int ir_update_mapping(struct input_dev *dev, struct ir_scancode_table *rc_tab, unsigned int index, unsigned int new_keycode) { int old_keycode = rc_tab->scan[index].keycode; int i; /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", index, rc_tab->scan[index].scancode); rc_tab->len--; memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1], (rc_tab->len - index) * sizeof(struct ir_scancode)); } else { IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n", index, old_keycode == KEY_RESERVED ? "New" : "Replacing", rc_tab->scan[index].scancode, new_keycode); rc_tab->scan[index].keycode = new_keycode; __set_bit(new_keycode, dev->keybit); } if (old_keycode != KEY_RESERVED) { /* A previous mapping was updated... */ __clear_bit(old_keycode, dev->keybit); /* ... but another scancode might use the same keycode */ for (i = 0; i < rc_tab->len; i++) { if (rc_tab->scan[i].keycode == old_keycode) { __set_bit(old_keycode, dev->keybit); break; } } /* Possibly shrink the keytable, failure is not a problem */ ir_resize_table(rc_tab, GFP_ATOMIC); } return old_keycode; }
/** * ir_do_setkeycode() - internal function to set a keycode in the * scancode->keycode table * @dev: the struct input_dev device descriptor * @rc_tab: the struct ir_scancode_table to set the keycode in * @scancode: the scancode for the ir command * @keycode: the keycode for the ir command * @resize: whether the keytable may be shrunk * @return: -EINVAL if the keycode could not be inserted, otherwise zero. * * This routine is used internally to manipulate the scancode->keycode table. * The caller has to hold @rc_tab->lock. */ static int ir_do_setkeycode(struct input_dev *dev, struct ir_scancode_table *rc_tab, unsigned scancode, unsigned keycode, bool resize) { unsigned int i; int old_keycode = KEY_RESERVED; struct ir_input_dev *ir_dev = input_get_drvdata(dev); /* * Unfortunately, some hardware-based IR decoders don't provide * all bits for the complete IR code. In general, they provide only * the command part of the IR code. Yet, as it is possible to replace * the provided IR with another one, it is needed to allow loading * IR tables from other remotes. So, */ if (ir_dev->props && ir_dev->props->scanmask) { scancode &= ir_dev->props->scanmask; } /* First check if we already have a mapping for this ir command */ for (i = 0; i < rc_tab->len; i++) { /* Keytable is sorted from lowest to highest scancode */ if (rc_tab->scan[i].scancode > scancode) break; else if (rc_tab->scan[i].scancode < scancode) continue; old_keycode = rc_tab->scan[i].keycode; rc_tab->scan[i].keycode = keycode; /* Did the user wish to remove the mapping? */ if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) { IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", i, scancode); rc_tab->len--; memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1], (rc_tab->len - i) * sizeof(struct ir_scancode)); } /* Possibly shrink the keytable, failure is not a problem */ ir_resize_table(rc_tab); break; } if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) { /* No previous mapping found, we might need to grow the table */ if (resize && ir_resize_table(rc_tab)) return -ENOMEM; IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n", i, scancode, keycode); /* i is the proper index to insert our new keycode */ memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i], (rc_tab->len - i) * sizeof(struct ir_scancode)); rc_tab->scan[i].scancode = scancode; rc_tab->scan[i].keycode = keycode; rc_tab->len++; set_bit(keycode, dev->keybit); } else { IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n", i, scancode, keycode); /* A previous mapping was updated... */ clear_bit(old_keycode, dev->keybit); /* ...but another scancode might use the same keycode */ for (i = 0; i < rc_tab->len; i++) { if (rc_tab->scan[i].keycode == old_keycode) { set_bit(old_keycode, dev->keybit); break; } } } return 0; }