On Thu, May 14, 2015 at 06:24:46PM -0300, Mauro Carvalho Chehab wrote:
>Em Mon, 06 Apr 2015 13:26:18 +0200
>David Härdeman <da...@hardeman.nu> escreveu:
>
>> Introduce a list of "kernel" ir protocols (e.g. "sony12" instead of "sony")
>> and extend the set-key command to ir-keytable to allow for a mapping of the
>> form "protocol:scancode=keycode" in addition to the old "scancode=keycode"
>> format. The code automatically falls back to the old behaviour if the
>> kernel doesn't support the new approach with protocols.
>> 
>> The read command is also updated to show the protocol information if the
>> kernel supports it.
>
>
>I applied patches 1 to 3 of this series, as they are not based on any
>new feature.
>
>This patch, however, needs to wait for the Kernel patch to be acked, and
>may be modified, depending on the review process.
>
>I'll mark it at patchwork as RFC. Please re-submit after we merge the
>Kernel changes.

Agreed :)

>
>Thanks,
>Mauro
>
>> 
>> Signed-off-by: David Härdeman <da...@hardeman.nu>
>> ---
>>  utils/keytable/keytable.c |  288 
>> ++++++++++++++++++++++++++++++++-------------
>>  1 file changed, 202 insertions(+), 86 deletions(-)
>> 
>> diff --git a/utils/keytable/keytable.c b/utils/keytable/keytable.c
>> index 63eea2e..fd50095 100644
>> --- a/utils/keytable/keytable.c
>> +++ b/utils/keytable/keytable.c
>> @@ -55,13 +55,22 @@ struct input_keymap_entry_v2 {
>>  #define EVIOCSKEYCODE_V2    _IOW('E', 0x04, struct input_keymap_entry_v2)
>>  #endif
>>  
>> -struct keytable_entry {
>> -    u_int32_t scancode;
>> -    u_int32_t keycode;
>> -    struct keytable_entry *next;
>> +struct rc_scancode {
>> +    u_int16_t protocol;
>> +    u_int16_t reserved[3];
>> +    u_int64_t scancode;
>>  };
>>  
>> -struct keytable_entry *keytable = NULL;
>> +struct rc_keymap_entry {
>> +    u_int8_t  flags;
>> +    u_int8_t  len;
>> +    u_int16_t index;
>> +    u_int32_t keycode;
>> +    union {
>> +            struct rc_scancode rc;
>> +            u_int8_t raw[32];
>> +    };
>> +};
>>  
>>  struct uevents {
>>      char            *key;
>> @@ -109,41 +118,76 @@ enum sysfs_protocols {
>>      SYSFS_INVALID           = 0,
>>  };
>>  
>> +enum kernel_protocol {
>> +    KERN_UNKNOWN            = 0,    /* Protocol not known */
>> +    KERN_OTHER              = 1,    /* Protocol known but proprietary */
>> +    KERN_LIRC               = 2,    /* Pass raw IR to lirc userspace */
>> +    KERN_RC5                = 3,    /* Philips RC5 protocol */
>> +    KERN_RC5X               = 4,    /* Philips RC5x protocol */
>> +    KERN_RC5_SZ             = 5,    /* StreamZap variant of RC5 */
>> +    KERN_JVC                = 6,    /* JVC protocol */
>> +    KERN_SONY12             = 7,    /* Sony 12 bit protocol */
>> +    KERN_SONY15             = 8,    /* Sony 15 bit protocol */
>> +    KERN_SONY20             = 9,    /* Sony 20 bit protocol */
>> +    KERN_NEC                = 10,   /* NEC protocol */
>> +    KERN_SANYO              = 11,   /* Sanyo protocol */
>> +    KERN_MCE_KBD            = 12,   /* RC6-ish MCE keyboard/mouse */
>> +    KERN_RC6_0              = 13,   /* Philips RC6-0-16 protocol */
>> +    KERN_RC6_6A_20          = 14,   /* Philips RC6-6A-20 protocol */
>> +    KERN_RC6_6A_24          = 15,   /* Philips RC6-6A-24 protocol */
>> +    KERN_RC6_6A_32          = 16,   /* Philips RC6-6A-32 protocol */
>> +    KERN_RC6_MCE            = 17,   /* MCE (Philips RC6-6A-32 subtype) 
>> protocol */
>> +    KERN_SHARP              = 18,   /* Sharp protocol */
>> +    KERN_XMP                = 19,   /* XMP protocol */
>> +    KERN_INVALID            = 31,   /* internal, no real protocol number */
>> +};
>> +
>>  struct protocol_map_entry {
>>      const char *name;
>>      const char *sysfs1_name;
>>      enum sysfs_protocols sysfs_protocol;
>> +    enum kernel_protocol kernel_protocol;
>>  };
>>  
>>  const struct protocol_map_entry protocol_map[] = {
>> -    { "unknown",    NULL,           SYSFS_UNKNOWN   },
>> -    { "other",      NULL,           SYSFS_OTHER     },
>> -    { "lirc",       NULL,           SYSFS_LIRC      },
>> -    { "rc-5",       "/rc5_decoder", SYSFS_RC5       },
>> -    { "rc5",        NULL,           SYSFS_RC5       },
>> -    { "rc-5x",      NULL,           SYSFS_INVALID   },
>> -    { "rc5x",       NULL,           SYSFS_INVALID   },
>> -    { "jvc",        "/jvc_decoder", SYSFS_JVC       },
>> -    { "sony",       "/sony_decoder",SYSFS_SONY      },
>> -    { "sony12",     NULL,           SYSFS_INVALID   },
>> -    { "sony15",     NULL,           SYSFS_INVALID   },
>> -    { "sony20",     NULL,           SYSFS_INVALID   },
>> -    { "nec",        "/nec_decoder", SYSFS_NEC       },
>> -    { "sanyo",      NULL,           SYSFS_SANYO     },
>> -    { "mce-kbd",    NULL,           SYSFS_MCE_KBD   },
>> -    { "mce_kbd",    NULL,           SYSFS_MCE_KBD   },
>> -    { "rc-6",       "/rc6_decoder", SYSFS_RC6       },
>> -    { "rc6",        NULL,           SYSFS_RC6       },
>> -    { "rc-6-0",     NULL,           SYSFS_INVALID   },
>> -    { "rc-6-6a-20", NULL,           SYSFS_INVALID   },
>> -    { "rc-6-6a-24", NULL,           SYSFS_INVALID   },
>> -    { "rc-6-6a-32", NULL,           SYSFS_INVALID   },
>> -    { "rc-6-mce",   NULL,           SYSFS_INVALID   },
>> -    { "sharp",      NULL,           SYSFS_SHARP     },
>> -    { "xmp",        "/xmp_decoder", SYSFS_XMP       },
>> -    { NULL,         NULL,           SYSFS_INVALID   },
>> +    { "unknown",    NULL,           SYSFS_UNKNOWN,  KERN_UNKNOWN    },
>> +    { "other",      NULL,           SYSFS_OTHER,    KERN_OTHER      },
>> +    { "lirc",       NULL,           SYSFS_LIRC,     KERN_LIRC       },
>> +    { "rc-5",       "/rc5_decoder", SYSFS_RC5,      KERN_RC5        },
>> +    { "rc5",        NULL,           SYSFS_RC5,      KERN_RC5        },
>> +    { "rc-5x",      NULL,           SYSFS_INVALID,  KERN_RC5X       },
>> +    { "rc5x",       NULL,           SYSFS_INVALID,  KERN_RC5X       },
>> +    { "jvc",        "/jvc_decoder", SYSFS_JVC,      KERN_JVC        },
>> +    { "sony",       "/sony_decoder",SYSFS_SONY,     KERN_INVALID    },
>> +    { "sony12",     NULL,           SYSFS_INVALID,  KERN_SONY12     },
>> +    { "sony15",     NULL,           SYSFS_INVALID,  KERN_SONY15     },
>> +    { "sony20",     NULL,           SYSFS_INVALID,  KERN_SONY20     },
>> +    { "nec",        "/nec_decoder", SYSFS_NEC,      KERN_NEC        },
>> +    { "sanyo",      NULL,           SYSFS_SANYO,    KERN_SANYO      },
>> +    { "mce-kbd",    NULL,           SYSFS_MCE_KBD,  KERN_MCE_KBD    },
>> +    { "mce_kbd",    NULL,           SYSFS_MCE_KBD,  KERN_MCE_KBD    },
>> +    { "rc-6",       "/rc6_decoder", SYSFS_RC6,      KERN_INVALID    },
>> +    { "rc6",        NULL,           SYSFS_RC6,      KERN_INVALID    },
>> +    { "rc-6-0",     NULL,           SYSFS_INVALID,  KERN_RC6_0      },
>> +    { "rc-6-6a-20", NULL,           SYSFS_INVALID,  KERN_RC6_6A_20  },
>> +    { "rc-6-6a-24", NULL,           SYSFS_INVALID,  KERN_RC6_6A_24  },
>> +    { "rc-6-6a-32", NULL,           SYSFS_INVALID,  KERN_RC6_6A_32  },
>> +    { "rc-6-mce",   NULL,           SYSFS_INVALID,  KERN_RC6_MCE    },
>> +    { "sharp",      NULL,           SYSFS_SHARP,    KERN_SHARP      },
>> +    { "xmp",        "/xmp_decoder", SYSFS_XMP,      KERN_XMP        },
>> +    { NULL,         NULL,           SYSFS_INVALID,  KERN_INVALID    },
>> +};
>> +
>> +struct keytable_entry {
>> +    u_int32_t scancode;
>> +    u_int32_t keycode;
>> +    enum kernel_protocol protocol;
>> +    struct keytable_entry *next;
>>  };
>>  
>> +struct keytable_entry *keytable = NULL;
>> +
>> +
>>  static enum sysfs_protocols parse_sysfs_protocol(const char *name, bool 
>> all_allowed)
>>  {
>>      const struct protocol_map_entry *pme;
>> @@ -162,6 +206,21 @@ static enum sysfs_protocols parse_sysfs_protocol(const 
>> char *name, bool all_allo
>>      return SYSFS_INVALID;
>>  }
>>  
>> +static enum kernel_protocol parse_kernel_protocol(const char *name)
>> +{
>> +    const struct protocol_map_entry *pme;
>> +
>> +    if (!name)
>> +            return KERN_INVALID;
>> +
>> +    for (pme = protocol_map; pme->name; pme++) {
>> +            if (!strcasecmp(name, pme->name))
>> +                    return pme->kernel_protocol;
>> +    }
>> +
>> +    return KERN_INVALID;
>> +}
>> +
>>  static void write_sysfs_protocols(enum sysfs_protocols protocols, FILE *fp, 
>> const char *fmt)
>>  {
>>      const struct protocol_map_entry *pme;
>> @@ -197,6 +256,7 @@ static const char doc[] = N_(
>>      "  SYSDEV   - the ir class as found at /sys/class/rc\n"
>>      "  TABLE    - a file with a set of scancode=keycode value pairs\n"
>>      "  SCANKEY  - a set of scancode1=keycode1,scancode2=keycode2.. value 
>> pairs\n"
>> +    "             or (experimentally) a list of 
>> protocol1:scancode1=keycode1,protocol2:scancode2=keycode2...triplets\n"
>>      "  PROTOCOL - protocol name (nec, rc-5, rc-6, jvc, sony, sanyo, 
>> rc-5-sz, lirc,\n"
>>      "                            sharp, mce_kbd, xmp, other, all) to be 
>> enabled\n"
>>      "  DELAY    - Delay before repeating a keystroke\n"
>> @@ -447,7 +507,6 @@ err_einval:
>>  static error_t parse_opt(int k, char *arg, struct argp_state *state)
>>  {
>>      char *p;
>> -    long key;
>>      int rc;
>>  
>>      switch (k) {
>> @@ -492,51 +551,69 @@ static error_t parse_opt(int k, char *arg, struct 
>> argp_state *state)
>>              break;
>>      }
>>      case 'k':
>> -            p = strtok(arg, ":=");
>> -            do {
>> +            for (p = strtok(arg, ",;"); p; p = strtok(NULL, ",;")) {
>> +                    char *protocol_str;
>> +                    enum kernel_protocol protocol = KERN_INVALID;
>> +                    long long int scancode;
>> +                    char *keycode_str;
>> +                    long keycode;
>>                      struct keytable_entry *ke;
>>  
>> -                    if (!p)
>> -                            goto err_inval;
>> -
>> -                    ke = calloc(1, sizeof(*ke));
>> -                    if (!ke) {
>> -                            perror(_("No memory!\n"));
>> -                            return ENOMEM;
>> +                    errno = 0;
>> +                    /* New format - protocol:scancode=keycode */
>> +                    if (sscanf(p, " %m[^:] : %lli = %ms", &protocol_str, 
>> &scancode, &keycode_str) != 3) {
>> +                           if (errno != 0) {
>> +                                   fprintf(stderr, _("sscanf failed!\n"));
>> +                                   return errno;
>> +                           }
>> +
>> +                           /* Old format - scancode=keycode */
>> +                           protocol_str = NULL;
>> +                           if (sscanf(p, " %lli = %ms", &scancode, 
>> &keycode_str) != 2) {
>> +                                   if (errno != 0) {
>> +                                           fprintf(stderr, _("sscanf 
>> failed!\n"));
>> +                                           return errno;
>> +                                   }
>> +                                   goto err_inval;
>> +                           }
>>                      }
>>  
>> -                    ke->scancode = strtoul(p, NULL, 0);
>> -                    if (errno) {
>> -                            free(ke);
>> -                            goto err_inval;
>> +                    keycode = parse_code(keycode_str);
>> +                    if (keycode == -1) {
>> +                            errno = 0;
>> +                            keycode = strtoul(keycode_str, NULL, 0);
>> +                            if (errno)
>> +                                    keycode = -1;
>>                      }
>> +                    free(keycode_str);
>>  
>> -                    p = strtok(NULL, ",;");
>> -                    if (!p) {
>> -                            free(ke);
>> -                            goto err_inval;
>> -                    }
>> +                    if (protocol_str) {
>> +                            protocol = parse_kernel_protocol(protocol_str);
>> +                            free(protocol_str);
>>  
>> -                    key = parse_code(p);
>> -                    if (key == -1) {
>> -                            key = strtol(p, NULL, 0);
>> -                            if (errno) {
>> -                                    free(ke);
>> +                            if (protocol == KERN_INVALID)
>>                                      goto err_inval;
>> -                            }
>>                      }
>>  
>> -                    ke->keycode = key;
>> +                    if (keycode == -1 || scancode < 0)
>> +                            goto err_inval;
>>  
>> -                    if (debug)
>> -                            fprintf(stderr, _("scancode 0x%04x=%u\n"),
>> -                                    ke->scancode, ke->keycode);
>> +                    ke = calloc(1, sizeof(*ke));
>> +                    if (!ke) {
>> +                            perror(_("No memory!\n"));
>> +                            return ENOMEM;
>> +                    }
>>  
>> +                    ke->scancode = scancode;
>> +                    ke->keycode = keycode;
>> +                    ke->protocol = protocol;
>>                      ke->next = keytable;
>>                      keytable = ke;
>>  
>> -                    p = strtok(NULL, ":=");
>> -            } while (p);
>> +                    if (debug)
>> +                            fprintf(stderr, _("scancode %i:0x%04x=%u\n"),
>> +                                    ke->protocol, ke->scancode, 
>> ke->keycode);
>> +            }
>>              break;
>>      case 'p':
>>              for (p = strtok(arg, ",;"); p; p = strtok(NULL, ",;")) {
>> @@ -579,21 +656,24 @@ static struct argp argp = {
>>      .doc = doc,
>>  };
>>  
>> -static void prtcode(int *codes)
>> +static void print_mapping(enum kernel_protocol protocol, unsigned scancode, 
>> unsigned keycode)
>>  {
>>      struct parse_event *p;
>>  
>> +    if (protocol != KERN_INVALID)
>> +            printf(_("protocol 0x%04x, "), protocol);
>> +
>>      for (p = key_events; p->name != NULL; p++) {
>> -            if (p->value == (unsigned)codes[1]) {
>> -                    printf(_("scancode 0x%04x = %s (0x%02x)\n"), codes[0], 
>> p->name, codes[1]);
>> +            if (p->value == keycode) {
>> +                    printf(_("scancode 0x%04x = %s (0x%02x)\n"), scancode, 
>> p->name, keycode);
>>                      return;
>>              }
>>      }
>>  
>> -    if (isprint (codes[1]))
>> -            printf(_("scancode 0x%04x = '%c' (0x%02x)\n"), codes[0], 
>> codes[1], codes[1]);
>> +    if (isprint(keycode))
>> +            printf(_("scancode 0x%04x = '%c' (0x%02x)\n"), scancode, 
>> keycode, keycode);
>>      else
>> -            printf(_("scancode 0x%04x = 0x%02x\n"), codes[0], codes[1]);
>> +            printf(_("scancode 0x%04x = 0x%02x\n"), scancode, keycode);
>>  }
>>  
>>  static void free_names(struct sysfs_names *names)
>> @@ -1201,12 +1281,30 @@ static int add_keys(int fd)
>>      int write_cnt = 0;
>>      struct keytable_entry *ke;
>>      unsigned codes[2];
>> +    struct rc_keymap_entry rke;
>>  
>>      for (ke = keytable; ke; ke = ke->next) {
>>              write_cnt++;
>>              if (debug)
>> -                    fprintf(stderr, "\t%04x=%04x\n",
>> -                            ke->scancode, ke->keycode);
>> +                    fprintf(stderr, "\t%u:%04x=%04x\n",
>> +                            ke->protocol, ke->scancode, ke->keycode);
>> +
>> +            if (ke->protocol != KERN_INVALID) {
>> +                    memset(&rke, '\0', sizeof(rke));
>> +                    rke.len = sizeof(rke.rc);
>> +                    rke.keycode = ke->keycode;
>> +                    rke.rc.protocol = ke->protocol;
>> +                    rke.rc.scancode = ke->scancode;
>> +
>> +                    if (debug)
>> +                            fprintf(stderr, _("Attempting new 
>> EVIOCSKEYCODE_V2 ioctl\n"));
>> +
>> +                    if (ioctl(fd, EVIOCSKEYCODE_V2, &rke) == 0)
>> +                            continue;
>> +
>> +                    if (debug)
>> +                            fprintf(stderr, _("New EVIOCSKEYCODE_V2 ioctl 
>> failed\n"));
>> +            }
>>  
>>              codes[0] = ke->scancode;
>>              codes[1] = ke->keycode;
>> @@ -1329,7 +1427,7 @@ static void display_table_v1(struct rc_device *rc_dev, 
>> int fd)
>>                      if (ioctl(fd, EVIOCGKEYCODE, codes) == -1)
>>                              perror("EVIOCGKEYCODE");
>>                      else if (codes[1] != KEY_RESERVED)
>> -                            prtcode(codes);
>> +                            print_mapping(KERN_INVALID, codes[0], codes[1]);
>>              }
>>      }
>>      display_proto(rc_dev);
>> @@ -1337,27 +1435,45 @@ static void display_table_v1(struct rc_device 
>> *rc_dev, int fd)
>>  
>>  static void display_table_v2(struct rc_device *rc_dev, int fd)
>>  {
>> +    struct input_keymap_entry_v2 ike;
>> +    struct rc_keymap_entry rke;
>> +    bool first = true, rke_supported = true;
>> +    u_int32_t scancode;
>>      int i;
>> -    struct input_keymap_entry_v2 entry;
>> -    int codes[2];
>>  
>> -    memset(&entry, '\0', sizeof(entry));
>> -    i = 0;
>> -    do {
>> -            entry.flags = KEYMAP_BY_INDEX;
>> -            entry.index = i;
>> -            entry.len = sizeof(u_int32_t);
>> +    for (i = 0; ; i++) {
>> +            if (first || rke_supported) {
>> +                    memset(&rke, '\0', sizeof(rke));
>> +                    rke.flags = KEYMAP_BY_INDEX;
>> +                    rke.index = i;
>> +                    rke.len = sizeof(rke.rc);
>>  
>> -            if (ioctl(fd, EVIOCGKEYCODE_V2, &entry) == -1)
>> +                    if (ioctl(fd, EVIOCGKEYCODE_V2, &rke) == -1) {
>> +                            if (first)
>> +                                    rke_supported = false;
>> +                            else
>> +                                    break;
>> +                    }
>> +
>> +                    first = false;
>> +                    if (rke_supported) {
>> +                            print_mapping(rke.rc.protocol, rke.rc.scancode, 
>> rke.keycode);
>> +                            continue;
>> +                    }
>> +            }
>> +
>> +            memset(&ike, '\0', sizeof(ike));
>> +            ike.flags = KEYMAP_BY_INDEX;
>> +            ike.index = i;
>> +            ike.len = sizeof(scancode);
>> +
>> +            if (ioctl(fd, EVIOCGKEYCODE_V2, &ike) == -1)
>>                      break;
>>  
>>              /* FIXME: Extend it to support scancodes > 32 bits */
>> -            memcpy(&codes[0], entry.scancode, sizeof(codes[0]));
>> -            codes[1] = entry.keycode;
>> -
>> -            prtcode(codes);
>> -            i++;
>> -    } while (1);
>> +            memcpy(&scancode, ike.scancode, sizeof(scancode));
>> +            print_mapping(KERN_INVALID, scancode, ike.keycode);
>> +    }
>>      display_proto(rc_dev);
>>  }
>>  
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
David Härdeman
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to