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