Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
kobjects.c
Go to the documentation of this file.
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 <[email protected]>
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  */
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  */
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  */
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)
210  else
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  */
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  */
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 = kmemdup(buf, count + 1, GFP_ATOMIC);
269  if (!in_buff) {
270  spk_unlock(flags);
271  return -ENOMEM;
272  }
273  if (strchr("dDrR", *in_buff)) {
275  pr_info("keymap set to default values\n");
276  kfree(in_buff);
277  spk_unlock(flags);
278  return count;
279  }
280  if (in_buff[count - 1] == '\n')
281  in_buff[count - 1] = '\0';
282  cp = in_buff;
283  cp1 = (u_char *)in_buff;
284  for (i = 0; i < 3; i++) {
285  cp = s2uchar(cp, cp1);
286  cp1++;
287  }
288  i = (int)cp1[-2]+1;
289  i *= (int)cp1[-1]+1;
290  i += 2; /* 0 and last map ver */
291  if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
292  i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf)) {
293  pr_warn("i %d %d %d %d\n", i,
294  (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
295  kfree(in_buff);
296  spk_unlock(flags);
297  return -EINVAL;
298  }
299  while (--i >= 0) {
300  cp = s2uchar(cp, cp1);
301  cp1++;
302  if (!(*cp))
303  break;
304  }
305  if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
306  ret = -EINVAL;
307  pr_warn("end %d %d %d %d\n", i,
308  (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
309  } else {
310  if (set_key_info(in_buff, key_buf)) {
312  ret = -EINVAL;
313  pr_warn("set key failed\n");
314  }
315  }
316  kfree(in_buff);
317  spk_unlock(flags);
318  return ret;
319 }
320 
321 /*
322  * This is called when a user changes the value of the silent parameter.
323  */
324 static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
325  const char *buf, size_t count)
326 {
327  int len;
328  struct vc_data *vc = vc_cons[fg_console].d;
329  char ch = 0;
330  char shut;
331  unsigned long flags;
332 
333  len = strlen(buf);
334  if (len > 0 && len < 3) {
335  ch = buf[0];
336  if (ch == '\n')
337  ch = '0';
338  }
339  if (ch < '0' || ch > '7') {
340  pr_warn("silent value '%c' not in range (0,7)\n", ch);
341  return -EINVAL;
342  }
343  spk_lock(flags);
344  if (ch&2) {
345  shut = 1;
346  do_flush();
347  } else {
348  shut = 0;
349  }
350  if (ch&4)
351  shut |= 0x40;
352  if (ch&1)
353  spk_shut_up |= shut;
354  else
355  spk_shut_up &= ~shut;
356  spk_unlock(flags);
357  return count;
358 }
359 
360 /*
361  * This is called when a user reads the synth setting.
362  */
363 static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
364  char *buf)
365 {
366  int rv;
367 
368  if (synth == NULL)
369  rv = sprintf(buf, "%s\n", "none");
370  else
371  rv = sprintf(buf, "%s\n", synth->name);
372  return rv;
373 }
374 
375 /*
376  * This is called when a user requests to change synthesizers.
377  */
378 static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
379  const char *buf, size_t count)
380 {
381  int len;
382  char new_synth_name[10];
383 
384  len = strlen(buf);
385  if (len < 2 || len > 9)
386  return -EINVAL;
387  strncpy(new_synth_name, buf, len);
388  if (new_synth_name[len - 1] == '\n')
389  len--;
390  new_synth_name[len] = '\0';
391  strlwr(new_synth_name);
392  if ((synth != NULL) && (!strcmp(new_synth_name, synth->name))) {
393  pr_warn("%s already in use\n", new_synth_name);
394  } else if (synth_init(new_synth_name) != 0) {
395  pr_warn("failed to init synth %s\n", new_synth_name);
396  return -ENODEV;
397  }
398  return count;
399 }
400 
401 /*
402  * This is called when text is sent to the synth via the synth_direct file.
403  */
404 static ssize_t synth_direct_store(struct kobject *kobj,
405  struct kobj_attribute *attr, const char *buf, size_t count)
406 {
407  u_char tmp[256];
408  int len;
409  int bytes;
410  const char *ptr = buf;
411 
412  if (!synth)
413  return -EPERM;
414 
415  len = strlen(buf);
416  while (len > 0) {
417  bytes = min_t(size_t, len, 250);
418  strncpy(tmp, ptr, bytes);
419  tmp[bytes] = '\0';
420  xlate(tmp);
421  synth_printf("%s", tmp);
422  ptr += bytes;
423  len -= bytes;
424  }
425  return count;
426 }
427 
428 /*
429  * This function is called when a user reads the version.
430  */
431 static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
432  char *buf)
433 {
434  char *cp;
435 
436  cp = buf;
437  cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
438  if (synth)
439  cp += sprintf(cp, "%s synthesizer driver version %s\n",
440  synth->name, synth->version);
441  return cp - buf;
442 }
443 
444 /*
445  * This is called when a user reads the punctuation settings.
446  */
447 static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
448  char *buf)
449 {
450  int i;
451  char *cp = buf;
452  struct st_var_header *p_header;
453  struct punc_var_t *var;
454  struct st_bits_data *pb;
455  short mask;
456  unsigned long flags;
457 
458  p_header = var_header_by_name(attr->attr.name);
459  if (p_header == NULL) {
460  pr_warn("p_header is null, attr->attr.name is %s\n",
461  attr->attr.name);
462  return -EINVAL;
463  }
464 
465  var = get_punc_var(p_header->var_id);
466  if (var == NULL) {
467  pr_warn("var is null, p_header->var_id is %i\n",
468  p_header->var_id);
469  return -EINVAL;
470  }
471 
472  spk_lock(flags);
473  pb = (struct st_bits_data *) &punc_info[var->value];
474  mask = pb->mask;
475  for (i = 33; i < 128; i++) {
476  if (!(spk_chartab[i]&mask))
477  continue;
478  *cp++ = (char)i;
479  }
480  spk_unlock(flags);
481  return cp-buf;
482 }
483 
484 /*
485  * This is called when a user changes the punctuation settings.
486  */
487 static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
488  const char *buf, size_t count)
489 {
490  int x;
491  struct st_var_header *p_header;
492  struct punc_var_t *var;
493  char punc_buf[100];
494  unsigned long flags;
495 
496  x = strlen(buf);
497  if (x < 1 || x > 99)
498  return -EINVAL;
499 
500  p_header = var_header_by_name(attr->attr.name);
501  if (p_header == NULL) {
502  pr_warn("p_header is null, attr->attr.name is %s\n",
503  attr->attr.name);
504  return -EINVAL;
505  }
506 
507  var = get_punc_var(p_header->var_id);
508  if (var == NULL) {
509  pr_warn("var is null, p_header->var_id is %i\n",
510  p_header->var_id);
511  return -EINVAL;
512  }
513 
514  strncpy(punc_buf, buf, x);
515 
516  while (x && punc_buf[x - 1] == '\n')
517  x--;
518  punc_buf[x] = '\0';
519 
520  spk_lock(flags);
521 
522  if (*punc_buf == 'd' || *punc_buf == 'r')
523  x = set_mask_bits(0, var->value, 3);
524  else
525  x = set_mask_bits(punc_buf, var->value, 3);
526 
527  spk_unlock(flags);
528  return count;
529 }
530 
531 /*
532  * This function is called when a user reads one of the variable parameters.
533  */
534 ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
535  char *buf)
536 {
537  int rv = 0;
538  struct st_var_header *param;
539  struct var_t *var;
540  char *cp1;
541  char *cp;
542  char ch;
543  unsigned long flags;
544 
545  param = var_header_by_name(attr->attr.name);
546  if (param == NULL)
547  return -EINVAL;
548 
549  spk_lock(flags);
550  var = (struct var_t *) param->data;
551  switch (param->var_type) {
552  case VAR_NUM:
553  case VAR_TIME:
554  if (var)
555  rv = sprintf(buf, "%i\n", var->u.n.value);
556  else
557  rv = sprintf(buf, "0\n");
558  break;
559  case VAR_STRING:
560  if (var) {
561  cp1 = buf;
562  *cp1++ = '"';
563  for (cp = (char *)param->p_val; (ch = *cp); cp++) {
564  if (ch >= ' ' && ch < '~')
565  *cp1++ = ch;
566  else
567  cp1 += sprintf(cp1, "\\""x%02x", ch);
568  }
569  *cp1++ = '"';
570  *cp1++ = '\n';
571  *cp1 = '\0';
572  rv = cp1-buf;
573  } else {
574  rv = sprintf(buf, "\"\"\n");
575  }
576  break;
577  default:
578  rv = sprintf(buf, "Bad parameter %s, type %i\n",
579  param->name, param->var_type);
580  break;
581  }
582  spk_unlock(flags);
583  return rv;
584 }
586 
587 /*
588  * This function is called when a user echos a value to one of the
589  * variable parameters.
590  */
591 ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
592  const char *buf, size_t count)
593 {
594  struct st_var_header *param;
595  int ret;
596  int len;
597  char *cp;
598  struct var_t *var_data;
599  int value;
600  unsigned long flags;
601 
602  param = var_header_by_name(attr->attr.name);
603  if (param == NULL)
604  return -EINVAL;
605  if (param->data == NULL)
606  return 0;
607  ret = 0;
608  cp = xlate((char *) buf);
609 
610  spk_lock(flags);
611  switch (param->var_type) {
612  case VAR_NUM:
613  case VAR_TIME:
614  if (*cp == 'd' || *cp == 'r' || *cp == '\0')
615  len = E_DEFAULT;
616  else if (*cp == '+' || *cp == '-')
617  len = E_INC;
618  else
619  len = E_SET;
620  speakup_s2i(cp, &value);
621  ret = set_num_var(value, param, len);
622  if (ret == E_RANGE) {
623  var_data = param->data;
624  pr_warn("value for %s out of range, expect %d to %d\n",
625  attr->attr.name,
626  var_data->u.n.low, var_data->u.n.high);
627  }
628  break;
629  case VAR_STRING:
630  len = strlen(buf);
631  if ((len >= 1) && (buf[len - 1] == '\n'))
632  --len;
633  if ((len >= 2) && (buf[0] == '"') && (buf[len - 1] == '"')) {
634  ++buf;
635  len -= 2;
636  }
637  cp = (char *) buf;
638  cp[len] = '\0';
639  ret = set_string_var(buf, param, len);
640  if (ret == E_TOOLONG)
641  pr_warn("value too long for %s\n",
642  attr->attr.name);
643  break;
644  default:
645  pr_warn("%s unknown type %d\n",
646  param->name, (int)param->var_type);
647  break;
648  }
649  /*
650  * If voice was just changed, we might need to reset our default
651  * pitch and volume.
652  */
653  if (strcmp(attr->attr.name, "voice") == 0) {
654  if (synth && synth->default_pitch) {
655  param = var_header_by_name("pitch");
656  if (param) {
657  set_num_var(synth->default_pitch[value], param,
658  E_NEW_DEFAULT);
659  set_num_var(0, param, E_DEFAULT);
660  }
661  }
662  if (synth && synth->default_vol) {
663  param = var_header_by_name("vol");
664  if (param) {
665  set_num_var(synth->default_vol[value], param,
666  E_NEW_DEFAULT);
667  set_num_var(0, param, E_DEFAULT);
668  }
669  }
670  }
671  spk_unlock(flags);
672 
673  if (ret == SET_DEFAULT)
674  pr_info("%s reset to default value\n", attr->attr.name);
675  return count;
676 }
678 
679 /*
680  * Functions for reading and writing lists of i18n messages. Incomplete.
681  */
682 
683 static ssize_t message_show_helper(char *buf, enum msg_index_t first,
684  enum msg_index_t last)
685 {
686  size_t bufsize = PAGE_SIZE;
687  char *buf_pointer = buf;
688  int printed;
689  enum msg_index_t cursor;
690  int index = 0;
691  *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */
692 
693  for (cursor = first; cursor <= last; cursor++, index++) {
694  if (bufsize <= 1)
695  break;
696  printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
697  index, msg_get(cursor));
698  buf_pointer += printed;
699  bufsize -= printed;
700  }
701 
702  return buf_pointer - buf;
703 }
704 
705 static void report_msg_status(int reset, int received, int used,
706  int rejected, char *groupname)
707 {
708  int len;
709  char buf[160];
710 
711  if (reset) {
712  pr_info("i18n messages from group %s reset to defaults\n",
713  groupname);
714  } else if (received) {
715  len = snprintf(buf, sizeof(buf),
716  " updated %d of %d i18n messages from group %s\n",
717  used, received, groupname);
718  if (rejected)
719  snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
720  " with %d reject%s\n",
721  rejected, rejected > 1 ? "s" : "");
722  printk(buf);
723  }
724 }
725 
726 static ssize_t message_store_helper(const char *buf, size_t count,
727  struct msg_group_t *group)
728 {
729  char *cp = (char *) buf;
730  char *end = cp + count;
731  char *linefeed = NULL;
732  char *temp = NULL;
733  ssize_t msg_stored = 0;
734  ssize_t retval = count;
735  size_t desc_length = 0;
736  unsigned long index = 0;
737  int received = 0;
738  int used = 0;
739  int rejected = 0;
740  int reset = 0;
741  enum msg_index_t firstmessage = group->start;
742  enum msg_index_t lastmessage = group->end;
743  enum msg_index_t curmessage;
744 
745  while (cp < end) {
746 
747  while ((cp < end) && (*cp == ' ' || *cp == '\t'))
748  cp++;
749 
750  if (cp == end)
751  break;
752  if (strchr("dDrR", *cp)) {
753  reset = 1;
754  break;
755  }
756  received++;
757 
758  linefeed = strchr(cp, '\n');
759  if (!linefeed) {
760  rejected++;
761  break;
762  }
763 
764  if (!isdigit(*cp)) {
765  rejected++;
766  cp = linefeed + 1;
767  continue;
768  }
769 
770  index = simple_strtoul(cp, &temp, 10);
771 
772  while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
773  temp++;
774 
775  desc_length = linefeed - temp;
776  curmessage = firstmessage + index;
777 
778  /*
779  * Note the check (curmessage < firstmessage). It is not
780  * redundant. Suppose that the user gave us an index
781  * equal to ULONG_MAX - 1. If firstmessage > 1, then
782  * firstmessage + index < firstmessage!
783  */
784 
785  if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
786  rejected++;
787  cp = linefeed + 1;
788  continue;
789  }
790 
791  msg_stored = msg_set(curmessage, temp, desc_length);
792  if (msg_stored < 0) {
793  retval = msg_stored;
794  if (msg_stored == -ENOMEM)
795  reset = 1;
796  break;
797  } else {
798  used++;
799  }
800 
801  cp = linefeed + 1;
802  }
803 
804  if (reset)
805  reset_msg_group(group);
806 
807  report_msg_status(reset, received, used, rejected, group->name);
808  return retval;
809 }
810 
811 static ssize_t message_show(struct kobject *kobj,
812  struct kobj_attribute *attr, char *buf)
813 {
814  ssize_t retval = 0;
815  struct msg_group_t *group = find_msg_group(attr->attr.name);
816  unsigned long flags;
817 
818  BUG_ON(!group);
819  spk_lock(flags);
820  retval = message_show_helper(buf, group->start, group->end);
821  spk_unlock(flags);
822  return retval;
823 }
824 
825 static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
826  const char *buf, size_t count)
827 {
828  ssize_t retval = 0;
829  struct msg_group_t *group = find_msg_group(attr->attr.name);
830 
831  BUG_ON(!group);
832  retval = message_store_helper(buf, count, group);
833  return retval;
834 }
835 
836 /*
837  * Declare the attributes.
838  */
839 static struct kobj_attribute keymap_attribute =
840  __ATTR(keymap, ROOT_W, keymap_show, keymap_store);
841 static struct kobj_attribute silent_attribute =
842  __ATTR(silent, USER_W, NULL, silent_store);
843 static struct kobj_attribute synth_attribute =
844  __ATTR(synth, USER_RW, synth_show, synth_store);
845 static struct kobj_attribute synth_direct_attribute =
846  __ATTR(synth_direct, USER_W, NULL, synth_direct_store);
847 static struct kobj_attribute version_attribute =
849 
850 static struct kobj_attribute delimiters_attribute =
851  __ATTR(delimiters, USER_RW, punc_show, punc_store);
852 static struct kobj_attribute ex_num_attribute =
853  __ATTR(ex_num, USER_RW, punc_show, punc_store);
854 static struct kobj_attribute punc_all_attribute =
855  __ATTR(punc_all, USER_RW, punc_show, punc_store);
856 static struct kobj_attribute punc_most_attribute =
857  __ATTR(punc_most, USER_RW, punc_show, punc_store);
858 static struct kobj_attribute punc_some_attribute =
859  __ATTR(punc_some, USER_RW, punc_show, punc_store);
860 static struct kobj_attribute repeats_attribute =
861  __ATTR(repeats, USER_RW, punc_show, punc_store);
862 
863 static struct kobj_attribute attrib_bleep_attribute =
865 static struct kobj_attribute bell_pos_attribute =
867 static struct kobj_attribute bleep_time_attribute =
869 static struct kobj_attribute bleeps_attribute =
871 static struct kobj_attribute cursor_time_attribute =
872  __ATTR(cursor_time, USER_RW, spk_var_show, spk_var_store);
873 static struct kobj_attribute key_echo_attribute =
875 static struct kobj_attribute no_interrupt_attribute =
876  __ATTR(no_interrupt, USER_RW, spk_var_show, spk_var_store);
877 static struct kobj_attribute punc_level_attribute =
879 static struct kobj_attribute reading_punc_attribute =
881 static struct kobj_attribute say_control_attribute =
882  __ATTR(say_control, USER_RW, spk_var_show, spk_var_store);
883 static struct kobj_attribute say_word_ctl_attribute =
885 static struct kobj_attribute spell_delay_attribute =
887 
888 /*
889  * These attributes are i18n related.
890  */
891 static struct kobj_attribute announcements_attribute =
892  __ATTR(announcements, USER_RW, message_show, message_store);
893 static struct kobj_attribute characters_attribute =
894  __ATTR(characters, USER_RW, chars_chartab_show, chars_chartab_store);
895 static struct kobj_attribute chartab_attribute =
896  __ATTR(chartab, USER_RW, chars_chartab_show, chars_chartab_store);
897 static struct kobj_attribute ctl_keys_attribute =
898  __ATTR(ctl_keys, USER_RW, message_show, message_store);
899 static struct kobj_attribute colors_attribute =
900  __ATTR(colors, USER_RW, message_show, message_store);
901 static struct kobj_attribute formatted_attribute =
902  __ATTR(formatted, USER_RW, message_show, message_store);
903 static struct kobj_attribute function_names_attribute =
904  __ATTR(function_names, USER_RW, message_show, message_store);
905 static struct kobj_attribute key_names_attribute =
906  __ATTR(key_names, USER_RW, message_show, message_store);
907 static struct kobj_attribute states_attribute =
908  __ATTR(states, USER_RW, message_show, message_store);
909 
910 /*
911  * Create groups of attributes so that we can create and destroy them all
912  * at once.
913  */
914 static struct attribute *main_attrs[] = {
915  &keymap_attribute.attr,
916  &silent_attribute.attr,
917  &synth_attribute.attr,
918  &synth_direct_attribute.attr,
919  &version_attribute.attr,
920  &delimiters_attribute.attr,
921  &ex_num_attribute.attr,
922  &punc_all_attribute.attr,
923  &punc_most_attribute.attr,
924  &punc_some_attribute.attr,
925  &repeats_attribute.attr,
926  &attrib_bleep_attribute.attr,
927  &bell_pos_attribute.attr,
928  &bleep_time_attribute.attr,
929  &bleeps_attribute.attr,
930  &cursor_time_attribute.attr,
931  &key_echo_attribute.attr,
932  &no_interrupt_attribute.attr,
933  &punc_level_attribute.attr,
934  &reading_punc_attribute.attr,
935  &say_control_attribute.attr,
936  &say_word_ctl_attribute.attr,
937  &spell_delay_attribute.attr,
938  NULL,
939 };
940 
941 static struct attribute *i18n_attrs[] = {
942  &announcements_attribute.attr,
943  &characters_attribute.attr,
944  &chartab_attribute.attr,
945  &ctl_keys_attribute.attr,
946  &colors_attribute.attr,
947  &formatted_attribute.attr,
948  &function_names_attribute.attr,
949  &key_names_attribute.attr,
950  &states_attribute.attr,
951  NULL,
952 };
953 
954 /*
955  * An unnamed attribute group will put all of the attributes directly in
956  * the kobject directory. If we specify a name, a subdirectory will be
957  * created for the attributes with the directory being the name of the
958  * attribute group.
959  */
960 static struct attribute_group main_attr_group = {
961  .attrs = main_attrs,
962 };
963 
964 static struct attribute_group i18n_attr_group = {
965  .attrs = i18n_attrs,
966  .name = "i18n",
967 };
968 
969 static struct kobject *accessibility_kobj;
971 
973 {
974  int retval;
975 
976  /*
977  * Create a simple kobject with the name of "accessibility",
978  * located under /sys/
979  *
980  * As this is a simple directory, no uevent will be sent to
981  * userspace. That is why this function should not be used for
982  * any type of dynamic kobjects, where the name and number are
983  * not known ahead of time.
984  */
985  accessibility_kobj = kobject_create_and_add("accessibility", NULL);
986  if (!accessibility_kobj) {
987  retval = -ENOMEM;
988  goto out;
989  }
990 
991  speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
992  if (!speakup_kobj) {
993  retval = -ENOMEM;
994  goto err_acc;
995  }
996 
997  /* Create the files associated with this kobject */
998  retval = sysfs_create_group(speakup_kobj, &main_attr_group);
999  if (retval)
1000  goto err_speakup;
1001 
1002  retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
1003  if (retval)
1004  goto err_group;
1005 
1006  goto out;
1007 
1008 err_group:
1009  sysfs_remove_group(speakup_kobj, &main_attr_group);
1010 err_speakup:
1011  kobject_put(speakup_kobj);
1012 err_acc:
1013  kobject_put(accessibility_kobj);
1014 out:
1015  return retval;
1016 }
1017 
1019 {
1020  sysfs_remove_group(speakup_kobj, &i18n_attr_group);
1021  sysfs_remove_group(speakup_kobj, &main_attr_group);
1022  kobject_put(speakup_kobj);
1023  kobject_put(accessibility_kobj);
1024 }