in speakup/kobjects.c [265:327]
static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
int i;
ssize_t ret = count;
char *in_buff = NULL;
char *cp;
u_char *cp1;
unsigned long flags;
spin_lock_irqsave(&speakup_info.spinlock, flags);
in_buff = kmemdup(buf, count + 1, GFP_ATOMIC);
if (!in_buff) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
return -ENOMEM;
}
if (strchr("dDrR", *in_buff)) {
spk_set_key_info(spk_key_defaults, spk_key_buf);
pr_info("keymap set to default values\n");
kfree(in_buff);
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
return count;
}
if (in_buff[count - 1] == '\n')
in_buff[count - 1] = '\0';
cp = in_buff;
cp1 = (u_char *)in_buff;
for (i = 0; i < 3; i++) {
cp = spk_s2uchar(cp, cp1);
cp1++;
}
i = (int)cp1[-2] + 1;
i *= (int)cp1[-1] + 1;
i += 2; /* 0 and last map ver */
if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
i + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
pr_warn("i %d %d %d %d\n", i,
(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
kfree(in_buff);
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
return -EINVAL;
}
while (--i >= 0) {
cp = spk_s2uchar(cp, cp1);
cp1++;
if (!(*cp))
break;
}
if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
ret = -EINVAL;
pr_warn("end %d %d %d %d\n", i,
(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
} else {
if (spk_set_key_info(in_buff, spk_key_buf)) {
spk_set_key_info(spk_key_defaults, spk_key_buf);
ret = -EINVAL;
pr_warn("set key failed\n");
}
}
kfree(in_buff);
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
return ret;
}