static ssize_t keymap_store()

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;
}