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