1 /*
2  * Speakup kobject implementation
3  *
4  * Copyright (C) 2009 William Hubbs
5  *
6  * This code is based on kobject-example.c, which came with linux 2.6.x.
7  *
8  * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
9  * Copyright (C) 2007 Novell Inc.
10  *
11  * Released under the GPL version 2 only.
12  *
13  */
14 #include <linux/slab.h>		/* For kmalloc. */
15 #include <linux/kernel.h>
16 #include <linux/kobject.h>
17 #include <linux/string.h>
18 #include <linux/sysfs.h>
19 #include <linux/ctype.h>
20 
21 #include "speakup.h"
22 #include "spk_priv.h"
23 
24 /*
25  * This is called when a user reads the characters or chartab sys file.
26  */
chars_chartab_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)27 static ssize_t chars_chartab_show(struct kobject *kobj,
28 	struct kobj_attribute *attr, char *buf)
29 {
30 	int i;
31 	int len = 0;
32 	char *cp;
33 	char *buf_pointer = buf;
34 	size_t bufsize = PAGE_SIZE;
35 	unsigned long flags;
36 
37 	spk_lock(flags);
38 	*buf_pointer = '\0';
39 	for (i = 0; i < 256; i++) {
40 		if (bufsize <= 1)
41 			break;
42 		if (strcmp("characters", attr->attr.name) == 0) {
43 			len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
44 					i, characters[i]);
45 		} else {	/* show chartab entry */
46 			if (IS_TYPE(i, B_CTL))
47 				cp = "B_CTL";
48 			else if (IS_TYPE(i, WDLM))
49 				cp = "WDLM";
50 			else if (IS_TYPE(i, A_PUNC))
51 				cp = "A_PUNC";
52 			else if (IS_TYPE(i, PUNC))
53 				cp = "PUNC";
54 			else if (IS_TYPE(i, NUM))
55 				cp = "NUM";
56 			else if (IS_TYPE(i, A_CAP))
57 				cp = "A_CAP";
58 			else if (IS_TYPE(i, ALPHA))
59 				cp = "ALPHA";
60 			else if (IS_TYPE(i, B_CAPSYM))
61 				cp = "B_CAPSYM";
62 			else if (IS_TYPE(i, B_SYM))
63 				cp = "B_SYM";
64 			else
65 				cp = "0";
66 			len =
67 			    scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp);
68 		}
69 		bufsize -= len;
70 		buf_pointer += len;
71 	}
72 	spk_unlock(flags);
73 	return buf_pointer - buf;
74 }
75 
76 /*
77  * Print informational messages or warnings after updating
78  * character descriptions or chartab entries.
79  */
report_char_chartab_status(int reset,int received,int used,int rejected,int do_characters)80 static void report_char_chartab_status(int reset, int received, int used,
81 	int rejected, int do_characters)
82 {
83 	char *object_type[] = {
84 		"character class entries",
85 		"character descriptions",
86 	};
87 	int len;
88 	char buf[80];
89 
90 	if (reset) {
91 		pr_info("%s reset to defaults\n", object_type[do_characters]);
92 	} else if (received) {
93 		len = snprintf(buf, sizeof(buf),
94 				" updated %d of %d %s\n",
95 				used, received, object_type[do_characters]);
96 		if (rejected)
97 			snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
98 				 " with %d reject%s\n",
99 				 rejected, rejected > 1 ? "s" : "");
100 		printk(buf);
101 	}
102 }
103 
104 /*
105  * This is called when a user changes the characters or chartab parameters.
106  */
chars_chartab_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)107 static ssize_t chars_chartab_store(struct kobject *kobj,
108 	struct kobj_attribute *attr, const char *buf, size_t count)
109 {
110 	char *cp = (char *) buf;
111 	char *end = cp + count; /* the null at the end of the buffer */
112 	char *linefeed = NULL;
113 	char keyword[MAX_DESC_LEN + 1];
114 	char *outptr = NULL;	/* Will hold keyword or desc. */
115 	char *temp = NULL;
116 	char *desc = NULL;
117 	ssize_t retval = count;
118 	unsigned long flags;
119 	unsigned long index = 0;
120 	int charclass = 0;
121 	int received = 0;
122 	int used = 0;
123 	int rejected = 0;
124 	int reset = 0;
125 	int do_characters = !strcmp(attr->attr.name, "characters");
126 	size_t desc_length = 0;
127 	int i;
128 
129 	spk_lock(flags);
130 	while (cp < end) {
131 
132 		while ((cp < end) && (*cp == ' ' || *cp == '\t'))
133 			cp++;
134 
135 		if (cp == end)
136 			break;
137 		if ((*cp == '\n') || strchr("dDrR", *cp)) {
138 			reset = 1;
139 			break;
140 		}
141 		received++;
142 
143 		linefeed = strchr(cp, '\n');
144 		if (!linefeed) {
145 			rejected++;
146 			break;
147 		}
148 
149 		if (!isdigit(*cp)) {
150 			rejected++;
151 			cp = linefeed + 1;
152 			continue;
153 		}
154 
155 		index = simple_strtoul(cp, &temp, 10);
156 		if (index > 255) {
157 			rejected++;
158 			cp = linefeed + 1;
159 			continue;
160 		}
161 
162 		while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
163 			temp++;
164 
165 		desc_length = linefeed - temp;
166 		if (desc_length > MAX_DESC_LEN) {
167 			rejected++;
168 			cp = linefeed + 1;
169 			continue;
170 		}
171 		if (do_characters) {
172 			desc = kmalloc(desc_length + 1, GFP_ATOMIC);
173 			if (!desc) {
174 				retval = -ENOMEM;
175 				reset = 1;	/* just reset on error. */
176 				break;
177 			}
178 			outptr = desc;
179 		} else {
180 			outptr = keyword;
181 		}
182 
183 		for (i = 0; i < desc_length; i++)
184 			outptr[i] = temp[i];
185 		outptr[desc_length] = '\0';
186 
187 		if (do_characters) {
188 			if (characters[index] != default_chars[index])
189 				kfree(characters[index]);
190 			characters[index] = desc;
191 			used++;
192 		} else {
193 			charclass = chartab_get_value(keyword);
194 			if (charclass == 0) {
195 				rejected++;
196 				cp = linefeed + 1;
197 				continue;
198 			}
199 			if (charclass != spk_chartab[index]) {
200 				spk_chartab[index] = charclass;
201 				used++;
202 			}
203 		}
204 		cp = linefeed + 1;
205 	}
206 
207 	if (reset) {
208 		if (do_characters)
209 			reset_default_chars();
210 		else
211 			reset_default_chartab();
212 	}
213 
214 	spk_unlock(flags);
215 	report_char_chartab_status(reset, received, used, rejected,
216 		do_characters);
217 	return retval;
218 }
219 
220 /*
221  * This is called when a user reads the keymap parameter.
222  */
keymap_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)223 static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
224 	char *buf)
225 {
226 	char *cp = buf;
227 	int i;
228 	int n;
229 	int num_keys;
230 	int nstates;
231 	u_char *cp1;
232 	u_char ch;
233 	unsigned long flags;
234 	spk_lock(flags);
235 	cp1 = key_buf + SHIFT_TBL_SIZE;
236 	num_keys = (int)(*cp1);
237 	nstates = (int)cp1[1];
238 	cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
239 	cp1 += 2; /* now pointing at shift states */
240 	/* dump num_keys+1 as first row is shift states + flags,
241 	 * each subsequent row is key + states */
242 	for (n = 0; n <= num_keys; n++) {
243 		for (i = 0; i <= nstates; i++) {
244 			ch = *cp1++;
245 			cp += sprintf(cp, "%d,", (int)ch);
246 			*cp++ = (i < nstates) ? SPACE : '\n';
247 		}
248 	}
249 	cp += sprintf(cp, "0, %d\n", KEY_MAP_VER);
250 	spk_unlock(flags);
251 	return (int)(cp-buf);
252 }
253 
254 /*
255  * This is called when a user changes the keymap parameter.
256  */
keymap_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)257 static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
258 	const char *buf, size_t count)
259 {
260 	int i;
261 	ssize_t ret = count;
262 	char *in_buff = NULL;
263 	char *cp;
264 	u_char *cp1;
265 	unsigned long flags;
266 
267 	spk_lock(flags);
268 	in_buff = kmalloc(count + 1, GFP_ATOMIC);
269 	if (!in_buff) {
270 		spk_unlock(flags);
271 		return -ENOMEM;
272 	}
273 	memcpy(in_buff, buf, count + 1);
274 	if (strchr("dDrR", *in_buff)) {
275 		set_key_info(key_defaults, key_buf);
276 		pr_info("keymap set to default values\n");
277 		kfree(in_buff);
278 		spk_unlock(flags);
279 		return count;
280 	}
281 	if (in_buff[count - 1] == '\n')
282 		in_buff[count - 1] = '\0';
283 	cp = in_buff;
284 	cp1 = (u_char *)in_buff;
285 	for (i = 0; i < 3; i++) {
286 		cp = s2uchar(cp, cp1);
287 		cp1++;
288 	}
289 	i = (int)cp1[-2]+1;
290 	i *= (int)cp1[-1]+1;
291 	i += 2; /* 0 and last map ver */
292 	if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
293 			i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf)) {
294 		pr_warn("i %d %d %d %d\n", i,
295 				(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
296 		kfree(in_buff);
297 		spk_unlock(flags);
298 		return -EINVAL;
299 	}
300 	while (--i >= 0) {
301 		cp = s2uchar(cp, cp1);
302 		cp1++;
303 		if (!(*cp))
304 			break;
305 	}
306 	if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
307 		ret = -EINVAL;
308 		pr_warn("end %d %d %d %d\n", i,
309 				(int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
310 	} else {
311 		if (set_key_info(in_buff, key_buf)) {
312 			set_key_info(key_defaults, key_buf);
313 			ret = -EINVAL;
314 			pr_warn("set key failed\n");
315 		}
316 	}
317 	kfree(in_buff);
318 	spk_unlock(flags);
319 	return ret;
320 }
321 
322 /*
323  * This is called when a user changes the value of the silent parameter.
324  */
silent_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)325 static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
326 	const char *buf, size_t count)
327 {
328 	int len;
329 	struct vc_data *vc = vc_cons[fg_console].d;
330 	char ch = 0;
331 	char shut;
332 	unsigned long flags;
333 
334 	len = strlen(buf);
335 	if (len > 0 && len < 3) {
336 		ch = buf[0];
337 		if (ch == '\n')
338 			ch = '0';
339 	}
340 	if (ch < '0' || ch > '7') {
341 		pr_warn("silent value '%c' not in range (0,7)\n", ch);
342 		return -EINVAL;
343 	}
344 	spk_lock(flags);
345 	if (ch&2) {
346 		shut = 1;
347 		do_flush();
348 	} else {
349 		shut = 0;
350 	}
351 	if (ch&4)
352 		shut |= 0x40;
353 	if (ch&1)
354 		spk_shut_up |= shut;
355 	else
356 		spk_shut_up &= ~shut;
357 	spk_unlock(flags);
358 	return count;
359 }
360 
361 /*
362  * This is called when a user reads the synth setting.
363  */
synth_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)364 static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
365 	char *buf)
366 {
367 	int rv;
368 
369 	if (synth == NULL)
370 		rv = sprintf(buf, "%s\n", "none");
371 	else
372 		rv = sprintf(buf, "%s\n", synth->name);
373 	return rv;
374 }
375 
376 /*
377  * This is called when a user requests to change synthesizers.
378  */
synth_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)379 static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
380 	const char *buf, size_t count)
381 {
382 	int len;
383 	char new_synth_name[10];
384 
385 	len = strlen(buf);
386 	if (len < 2 || len > 9)
387 		return -EINVAL;
388 	strncpy(new_synth_name, buf, len);
389 	if (new_synth_name[len - 1] == '\n')
390 		len--;
391 	new_synth_name[len] = '\0';
392 	strlwr(new_synth_name);
393 	if ((synth != NULL) && (!strcmp(new_synth_name, synth->name))) {
394 		pr_warn("%s already in use\n", new_synth_name);
395 	} else if (synth_init(new_synth_name) != 0) {
396 		pr_warn("failed to init synth %s\n", new_synth_name);
397 		return -ENODEV;
398 	}
399 	return count;
400 }
401 
402 /*
403  * This is called when text is sent to the synth via the synth_direct file.
404  */
synth_direct_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)405 static ssize_t synth_direct_store(struct kobject *kobj,
406 	struct kobj_attribute *attr, const char *buf, size_t count)
407 {
408 	u_char tmp[256];
409 	int len;
410 	int bytes;
411 	const char *ptr = buf;
412 
413 	if (!synth)
414 		return -EPERM;
415 
416 	len = strlen(buf);
417 	while (len > 0) {
418 		bytes = min_t(size_t, len, 250);
419 		strncpy(tmp, ptr, bytes);
420 		tmp[bytes] = '\0';
421 		xlate(tmp);
422 		synth_printf("%s", tmp);
423 		ptr += bytes;
424 		len -= bytes;
425 	}
426 	return count;
427 }
428 
429 /*
430  * This function is called when a user reads the version.
431  */
version_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)432 static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
433 	char *buf)
434 {
435 	char *cp;
436 
437 	cp = buf;
438 	cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
439 	if (synth)
440 		cp += sprintf(cp, "%s synthesizer driver version %s\n",
441 		synth->name, synth->version);
442 	return cp - buf;
443 }
444 
445 /*
446  * This is called when a user reads the punctuation settings.
447  */
punc_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)448 static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
449 	char *buf)
450 {
451 	int i;
452 	char *cp = buf;
453 	struct st_var_header *p_header;
454 	struct punc_var_t *var;
455 	struct st_bits_data *pb;
456 	short mask;
457 	unsigned long flags;
458 
459 	p_header = var_header_by_name(attr->attr.name);
460 	if (p_header == NULL) {
461 		pr_warn("p_header is null, attr->attr.name is %s\n",
462 			attr->attr.name);
463 		return -EINVAL;
464 	}
465 
466 	var = get_punc_var(p_header->var_id);
467 	if (var == NULL) {
468 		pr_warn("var is null, p_header->var_id is %i\n",
469 				p_header->var_id);
470 		return -EINVAL;
471 	}
472 
473 	spk_lock(flags);
474 	pb = (struct st_bits_data *) &punc_info[var->value];
475 	mask = pb->mask;
476 	for (i = 33; i < 128; i++) {
477 		if (!(spk_chartab[i]&mask))
478 			continue;
479 		*cp++ = (char)i;
480 	}
481 	spk_unlock(flags);
482 	return cp-buf;
483 }
484 
485 /*
486  * This is called when a user changes the punctuation settings.
487  */
punc_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)488 static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
489 			 const char *buf, size_t count)
490 {
491 	int x;
492 	struct st_var_header *p_header;
493 	struct punc_var_t *var;
494 	char punc_buf[100];
495 	unsigned long flags;
496 
497 	x = strlen(buf);
498 	if (x < 1 || x > 99)
499 		return -EINVAL;
500 
501 	p_header = var_header_by_name(attr->attr.name);
502 	if (p_header == NULL) {
503 		pr_warn("p_header is null, attr->attr.name is %s\n",
504 			attr->attr.name);
505 		return -EINVAL;
506 	}
507 
508 	var = get_punc_var(p_header->var_id);
509 	if (var == NULL) {
510 		pr_warn("var is null, p_header->var_id is %i\n",
511 				p_header->var_id);
512 		return -EINVAL;
513 	}
514 
515 	strncpy(punc_buf, buf, x);
516 
517 	while (x && punc_buf[x - 1] == '\n')
518 		x--;
519 	punc_buf[x] = '\0';
520 
521 	spk_lock(flags);
522 
523 	if (*punc_buf == 'd' || *punc_buf == 'r')
524 		x = set_mask_bits(0, var->value, 3);
525 	else
526 		x = set_mask_bits(punc_buf, var->value, 3);
527 
528 	spk_unlock(flags);
529 	return count;
530 }
531 
532 /*
533  * This function is called when a user reads one of the variable parameters.
534  */
spk_var_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)535 ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
536 	char *buf)
537 {
538 	int rv = 0;
539 	struct st_var_header *param;
540 	struct var_t *var;
541 		char *cp1;
542 	char *cp;
543 	char ch;
544 	unsigned long flags;
545 
546 	param = var_header_by_name(attr->attr.name);
547 	if (param == NULL)
548 		return -EINVAL;
549 
550 	spk_lock(flags);
551 	var = (struct var_t *) param->data;
552 	switch (param->var_type) {
553 	case VAR_NUM:
554 	case VAR_TIME:
555 		if (var)
556 			rv = sprintf(buf, "%i\n", var->u.n.value);
557 		else
558 			rv = sprintf(buf, "0\n");
559 		break;
560 	case VAR_STRING:
561 		if (var) {
562 			cp1 = buf;
563 			*cp1++ = '"';
564 			for (cp = (char *)param->p_val; (ch = *cp); cp++) {
565 				if (ch >= ' ' && ch < '~')
566 					*cp1++ = ch;
567 				else
568 					cp1 += sprintf(cp1, "\\""x%02x", ch);
569 			}
570 			*cp1++ = '"';
571 			*cp1++ = '\n';
572 			*cp1 = '\0';
573 			rv = cp1-buf;
574 		} else {
575 			rv = sprintf(buf, "\"\"\n");
576 		}
577 		break;
578 	default:
579 		rv = sprintf(buf, "Bad parameter  %s, type %i\n",
580 			param->name, param->var_type);
581 		break;
582 	}
583 	spk_unlock(flags);
584 	return rv;
585 }
586 EXPORT_SYMBOL_GPL(spk_var_show);
587 
588 /*
589  * This function is called when a user echos a value to one of the
590  * variable parameters.
591  */
spk_var_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)592 ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
593 			 const char *buf, size_t count)
594 {
595 	struct st_var_header *param;
596 	int ret;
597 	int len;
598 	char *cp;
599 	struct var_t *var_data;
600 	int value;
601 	unsigned long flags;
602 
603 	param = var_header_by_name(attr->attr.name);
604 	if (param == NULL)
605 		return -EINVAL;
606 	if (param->data == NULL)
607 		return 0;
608 	ret = 0;
609 	cp = xlate((char *) buf);
610 
611 	spk_lock(flags);
612 	switch (param->var_type) {
613 	case VAR_NUM:
614 	case VAR_TIME:
615 		if (*cp == 'd' || *cp == 'r' || *cp == '\0')
616 			len = E_DEFAULT;
617 		else if (*cp == '+' || *cp == '-')
618 			len = E_INC;
619 		else
620 			len = E_SET;
621 		speakup_s2i(cp, &value);
622 		ret = set_num_var(value, param, len);
623 		if (ret == E_RANGE) {
624 			var_data = param->data;
625 			pr_warn("value for %s out of range, expect %d to %d\n",
626 				attr->attr.name,
627 				var_data->u.n.low, var_data->u.n.high);
628 		}
629 		break;
630 	case VAR_STRING:
631 		len = strlen(buf);
632 		if ((len >= 1) && (buf[len - 1] == '\n'))
633 			--len;
634 		if ((len >= 2) && (buf[0] == '"') && (buf[len - 1] == '"')) {
635 			++buf;
636 			len -= 2;
637 		}
638 		cp = (char *) buf;
639 		cp[len] = '\0';
640 		ret = set_string_var(buf, param, len);
641 		if (ret == E_TOOLONG)
642 			pr_warn("value too long for %s\n",
643 					attr->attr.name);
644 		break;
645 	default:
646 		pr_warn("%s unknown type %d\n",
647 			param->name, (int)param->var_type);
648 	break;
649 	}
650 	/*
651 	 * If voice was just changed, we might need to reset our default
652 	 * pitch and volume.
653 	 */
654 	if (strcmp(attr->attr.name, "voice") == 0) {
655 		if (synth && synth->default_pitch) {
656 			param = var_header_by_name("pitch");
657 			if (param)  {
658 				set_num_var(synth->default_pitch[value], param,
659 					E_NEW_DEFAULT);
660 				set_num_var(0, param, E_DEFAULT);
661 			}
662 		}
663 		if (synth && synth->default_vol) {
664 			param = var_header_by_name("vol");
665 			if (param)  {
666 				set_num_var(synth->default_vol[value], param,
667 					E_NEW_DEFAULT);
668 				set_num_var(0, param, E_DEFAULT);
669 			}
670 		}
671 	}
672 	spk_unlock(flags);
673 
674 	if (ret == SET_DEFAULT)
675 		pr_info("%s reset to default value\n", attr->attr.name);
676 	return count;
677 }
678 EXPORT_SYMBOL_GPL(spk_var_store);
679 
680 /*
681  * Functions for reading and writing lists of i18n messages.  Incomplete.
682  */
683 
message_show_helper(char * buf,enum msg_index_t first,enum msg_index_t last)684 static ssize_t message_show_helper(char *buf, enum msg_index_t first,
685 	enum msg_index_t last)
686 {
687 	size_t bufsize = PAGE_SIZE;
688 	char *buf_pointer = buf;
689 	int printed;
690 	enum msg_index_t cursor;
691 	int index = 0;
692 	*buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */
693 
694 	for (cursor = first; cursor <= last; cursor++, index++) {
695 		if (bufsize <= 1)
696 			break;
697 		printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
698 			index, msg_get(cursor));
699 		buf_pointer += printed;
700 		bufsize -= printed;
701 	}
702 
703 	return buf_pointer - buf;
704 }
705 
report_msg_status(int reset,int received,int used,int rejected,char * groupname)706 static void report_msg_status(int reset, int received, int used,
707 	int rejected, char *groupname)
708 {
709 	int len;
710 	char buf[160];
711 
712 	if (reset) {
713 		pr_info("i18n messages from group %s reset to defaults\n",
714 			groupname);
715 	} else if (received) {
716 		len = snprintf(buf, sizeof(buf),
717 			       " updated %d of %d i18n messages from group %s\n",
718 				       used, received, groupname);
719 		if (rejected)
720 			snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
721 				 " with %d reject%s\n",
722 				 rejected, rejected > 1 ? "s" : "");
723 		printk(buf);
724 	}
725 }
726 
message_store_helper(const char * buf,size_t count,struct msg_group_t * group)727 static ssize_t message_store_helper(const char *buf, size_t count,
728 	struct msg_group_t *group)
729 {
730 	char *cp = (char *) buf;
731 	char *end = cp + count;
732 	char *linefeed = NULL;
733 	char *temp = NULL;
734 	ssize_t msg_stored = 0;
735 	ssize_t retval = count;
736 	size_t desc_length = 0;
737 	unsigned long index = 0;
738 	int received = 0;
739 	int used = 0;
740 	int rejected = 0;
741 	int reset = 0;
742 	enum msg_index_t firstmessage = group->start;
743 	enum msg_index_t lastmessage = group->end;
744 	enum msg_index_t curmessage;
745 
746 	while (cp < end) {
747 
748 		while ((cp < end) && (*cp == ' ' || *cp == '\t'))
749 			cp++;
750 
751 		if (cp == end)
752 			break;
753 		if (strchr("dDrR", *cp)) {
754 			reset = 1;
755 			break;
756 		}
757 		received++;
758 
759 		linefeed = strchr(cp, '\n');
760 		if (!linefeed) {
761 			rejected++;
762 			break;
763 		}
764 
765 		if (!isdigit(*cp)) {
766 			rejected++;
767 			cp = linefeed + 1;
768 			continue;
769 		}
770 
771 		index = simple_strtoul(cp, &temp, 10);
772 
773 		while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
774 			temp++;
775 
776 		desc_length = linefeed - temp;
777 		curmessage = firstmessage + index;
778 
779 		/*
780 		 * Note the check (curmessage < firstmessage).  It is not
781 		 * redundant.  Suppose that the user gave us an index
782 		 * equal to ULONG_MAX - 1.  If firstmessage > 1, then
783 		 * firstmessage + index < firstmessage!
784 		 */
785 
786 		if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
787 			rejected++;
788 			cp = linefeed + 1;
789 			continue;
790 		}
791 
792 		msg_stored = msg_set(curmessage, temp, desc_length);
793 		if (msg_stored < 0) {
794 			retval = msg_stored;
795 			if (msg_stored == -ENOMEM)
796 				reset = 1;
797 			break;
798 		} else {
799 			used++;
800 		}
801 
802 		cp = linefeed + 1;
803 	}
804 
805 	if (reset)
806 		reset_msg_group(group);
807 
808 	report_msg_status(reset, received, used, rejected, group->name);
809 	return retval;
810 }
811 
message_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)812 static ssize_t message_show(struct kobject *kobj,
813 	struct kobj_attribute *attr, char *buf)
814 {
815 	ssize_t retval = 0;
816 	struct msg_group_t *group = find_msg_group(attr->attr.name);
817 	unsigned long flags;
818 
819 	BUG_ON(!group);
820 	spk_lock(flags);
821 	retval = message_show_helper(buf, group->start, group->end);
822 	spk_unlock(flags);
823 	return retval;
824 }
825 
message_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)826 static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
827 	const char *buf, size_t count)
828 {
829 	ssize_t retval = 0;
830 	struct msg_group_t *group = find_msg_group(attr->attr.name);
831 
832 	BUG_ON(!group);
833 	retval = message_store_helper(buf, count, group);
834 	return retval;
835 }
836 
837 /*
838  * Declare the attributes.
839  */
840 static struct kobj_attribute keymap_attribute =
841 	__ATTR(keymap, ROOT_W, keymap_show, keymap_store);
842 static struct kobj_attribute silent_attribute =
843 	__ATTR(silent, USER_W, NULL, silent_store);
844 static struct kobj_attribute synth_attribute =
845 	__ATTR(synth, USER_RW, synth_show, synth_store);
846 static struct kobj_attribute synth_direct_attribute =
847 	__ATTR(synth_direct, USER_W, NULL, synth_direct_store);
848 static struct kobj_attribute version_attribute =
849 	__ATTR_RO(version);
850 
851 static struct kobj_attribute delimiters_attribute =
852 	__ATTR(delimiters, USER_RW, punc_show, punc_store);
853 static struct kobj_attribute ex_num_attribute =
854 	__ATTR(ex_num, USER_RW, punc_show, punc_store);
855 static struct kobj_attribute punc_all_attribute =
856 	__ATTR(punc_all, USER_RW, punc_show, punc_store);
857 static struct kobj_attribute punc_most_attribute =
858 	__ATTR(punc_most, USER_RW, punc_show, punc_store);
859 static struct kobj_attribute punc_some_attribute =
860 	__ATTR(punc_some, USER_RW, punc_show, punc_store);
861 static struct kobj_attribute repeats_attribute =
862 	__ATTR(repeats, USER_RW, punc_show, punc_store);
863 
864 static struct kobj_attribute attrib_bleep_attribute =
865 	__ATTR(attrib_bleep, USER_RW, spk_var_show, spk_var_store);
866 static struct kobj_attribute bell_pos_attribute =
867 	__ATTR(bell_pos, USER_RW, spk_var_show, spk_var_store);
868 static struct kobj_attribute bleep_time_attribute =
869 	__ATTR(bleep_time, USER_RW, spk_var_show, spk_var_store);
870 static struct kobj_attribute bleeps_attribute =
871 	__ATTR(bleeps, USER_RW, spk_var_show, spk_var_store);
872 static struct kobj_attribute cursor_time_attribute =
873 	__ATTR(cursor_time, USER_RW, spk_var_show, spk_var_store);
874 static struct kobj_attribute key_echo_attribute =
875 	__ATTR(key_echo, USER_RW, spk_var_show, spk_var_store);
876 static struct kobj_attribute no_interrupt_attribute =
877 	__ATTR(no_interrupt, USER_RW, spk_var_show, spk_var_store);
878 static struct kobj_attribute punc_level_attribute =
879 	__ATTR(punc_level, USER_RW, spk_var_show, spk_var_store);
880 static struct kobj_attribute reading_punc_attribute =
881 	__ATTR(reading_punc, USER_RW, spk_var_show, spk_var_store);
882 static struct kobj_attribute say_control_attribute =
883 	__ATTR(say_control, USER_RW, spk_var_show, spk_var_store);
884 static struct kobj_attribute say_word_ctl_attribute =
885 	__ATTR(say_word_ctl, USER_RW, spk_var_show, spk_var_store);
886 static struct kobj_attribute spell_delay_attribute =
887 	__ATTR(spell_delay, USER_RW, spk_var_show, spk_var_store);
888 
889 /*
890  * These attributes are i18n related.
891  */
892 static struct kobj_attribute announcements_attribute =
893 	__ATTR(announcements, USER_RW, message_show, message_store);
894 static struct kobj_attribute characters_attribute =
895 	__ATTR(characters, USER_RW, chars_chartab_show, chars_chartab_store);
896 static struct kobj_attribute chartab_attribute =
897 	__ATTR(chartab, USER_RW, chars_chartab_show, chars_chartab_store);
898 static struct kobj_attribute ctl_keys_attribute =
899 	__ATTR(ctl_keys, USER_RW, message_show, message_store);
900 static struct kobj_attribute colors_attribute =
901 	__ATTR(colors, USER_RW, message_show, message_store);
902 static struct kobj_attribute formatted_attribute =
903 	__ATTR(formatted, USER_RW, message_show, message_store);
904 static struct kobj_attribute function_names_attribute =
905 	__ATTR(function_names, USER_RW, message_show, message_store);
906 static struct kobj_attribute key_names_attribute =
907 	__ATTR(key_names, USER_RW, message_show, message_store);
908 static struct kobj_attribute states_attribute =
909 	__ATTR(states, USER_RW, message_show, message_store);
910 
911 /*
912  * Create groups of attributes so that we can create and destroy them all
913  * at once.
914  */
915 static struct attribute *main_attrs[] = {
916 	&keymap_attribute.attr,
917 	&silent_attribute.attr,
918 	&synth_attribute.attr,
919 	&synth_direct_attribute.attr,
920 	&version_attribute.attr,
921 	&delimiters_attribute.attr,
922 	&ex_num_attribute.attr,
923 	&punc_all_attribute.attr,
924 	&punc_most_attribute.attr,
925 	&punc_some_attribute.attr,
926 	&repeats_attribute.attr,
927 	&attrib_bleep_attribute.attr,
928 	&bell_pos_attribute.attr,
929 	&bleep_time_attribute.attr,
930 	&bleeps_attribute.attr,
931 	&cursor_time_attribute.attr,
932 	&key_echo_attribute.attr,
933 	&no_interrupt_attribute.attr,
934 	&punc_level_attribute.attr,
935 	&reading_punc_attribute.attr,
936 	&say_control_attribute.attr,
937 	&say_word_ctl_attribute.attr,
938 	&spell_delay_attribute.attr,
939 	NULL,
940 };
941 
942 static struct attribute *i18n_attrs[] = {
943 	&announcements_attribute.attr,
944 	&characters_attribute.attr,
945 	&chartab_attribute.attr,
946 	&ctl_keys_attribute.attr,
947 	&colors_attribute.attr,
948 	&formatted_attribute.attr,
949 	&function_names_attribute.attr,
950 	&key_names_attribute.attr,
951 	&states_attribute.attr,
952 	NULL,
953 };
954 
955 /*
956  * An unnamed attribute group will put all of the attributes directly in
957  * the kobject directory.  If we specify a name, a subdirectory will be
958  * created for the attributes with the directory being the name of the
959  * attribute group.
960  */
961 static struct attribute_group main_attr_group = {
962 	.attrs = main_attrs,
963 };
964 
965 static struct attribute_group i18n_attr_group = {
966 	.attrs = i18n_attrs,
967 	.name = "i18n",
968 };
969 
970 static struct kobject *accessibility_kobj;
971 struct kobject *speakup_kobj;
972 
speakup_kobj_init(void)973 int speakup_kobj_init(void)
974 {
975 	int retval;
976 
977 	/*
978 	 * Create a simple kobject with the name of "accessibility",
979 	 * located under /sys/
980 	 *
981 	 * As this is a simple directory, no uevent will be sent to
982 	 * userspace.  That is why this function should not be used for
983 	 * any type of dynamic kobjects, where the name and number are
984 	 * not known ahead of time.
985 	 */
986 	accessibility_kobj = kobject_create_and_add("accessibility", NULL);
987 	if (!accessibility_kobj) {
988 		retval = -ENOMEM;
989 		goto out;
990 	}
991 
992 	speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
993 	if (!speakup_kobj) {
994 		retval = -ENOMEM;
995 		goto err_acc;
996 	}
997 
998 	/* Create the files associated with this kobject */
999 	retval = sysfs_create_group(speakup_kobj, &main_attr_group);
1000 	if (retval)
1001 		goto err_speakup;
1002 
1003 	retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
1004 	if (retval)
1005 		goto err_group;
1006 
1007 	goto out;
1008 
1009 err_group:
1010 	sysfs_remove_group(speakup_kobj, &main_attr_group);
1011 err_speakup:
1012 	kobject_put(speakup_kobj);
1013 err_acc:
1014 	kobject_put(accessibility_kobj);
1015 out:
1016 	return retval;
1017 }
1018 
speakup_kobj_exit(void)1019 void speakup_kobj_exit(void)
1020 {
1021 	sysfs_remove_group(speakup_kobj, &i18n_attr_group);
1022 	sysfs_remove_group(speakup_kobj, &main_attr_group);
1023 	kobject_put(speakup_kobj);
1024 	kobject_put(accessibility_kobj);
1025 }
1026