1 // SPDX-License-Identifier: GPL-2.0
3 * Speakup kobject implementation
5 * Copyright (C) 2009 William Hubbs
7 * This code is based on kobject-example.c, which came with linux 2.6.x.
9 * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
10 * Copyright (C) 2007 Novell Inc.
12 * Released under the GPL version 2 only.
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>
27 * This is called when a user reads the characters or chartab sys file.
29 static ssize_t
chars_chartab_show(struct kobject
*kobj
,
30 struct kobj_attribute
*attr
, char *buf
)
35 char *buf_pointer
= buf
;
36 size_t bufsize
= PAGE_SIZE
;
39 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
41 for (i
= 0; i
< 256; i
++) {
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
))
50 else if (IS_TYPE(i
, WDLM
))
52 else if (IS_TYPE(i
, A_PUNC
))
54 else if (IS_TYPE(i
, PUNC
))
56 else if (IS_TYPE(i
, NUM
))
58 else if (IS_TYPE(i
, A_CAP
))
60 else if (IS_TYPE(i
, ALPHA
))
62 else if (IS_TYPE(i
, B_CAPSYM
))
64 else if (IS_TYPE(i
, B_SYM
))
69 scnprintf(buf_pointer
, bufsize
, "%d\t%s\n", i
, cp
);
74 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
75 return buf_pointer
- buf
;
79 * Print informational messages or warnings after updating
80 * character descriptions or chartab entries.
82 static void report_char_chartab_status(int reset
, int received
, int used
,
83 int rejected
, int do_characters
)
85 static char const *object_type
[] = {
86 "character class entries",
87 "character descriptions",
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
]);
99 snprintf(buf
+ (len
- 1), sizeof(buf
) - (len
- 1),
100 " with %d reject%s\n",
101 rejected
, rejected
> 1 ? "s" : "");
107 * This is called when a user changes the characters or chartab parameters.
109 static ssize_t
chars_chartab_store(struct kobject
*kobj
,
110 struct kobj_attribute
*attr
,
111 const char *buf
, size_t count
)
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. */
120 ssize_t retval
= count
;
122 unsigned long index
= 0;
128 int do_characters
= !strcmp(attr
->attr
.name
, "characters");
129 size_t desc_length
= 0;
132 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
134 while ((cp
< end
) && (*cp
== ' ' || *cp
== '\t'))
139 if ((*cp
== '\n') || strchr("dDrR", *cp
)) {
145 linefeed
= strchr(cp
, '\n');
158 * Do not replace with kstrtoul:
159 * here we need temp to be updated
161 index
= simple_strtoul(cp
, &temp
, 10);
168 while ((temp
< linefeed
) && (*temp
== ' ' || *temp
== '\t'))
171 desc_length
= linefeed
- temp
;
172 if (desc_length
> MAX_DESC_LEN
) {
178 desc
= kmalloc(desc_length
+ 1, GFP_ATOMIC
);
181 reset
= 1; /* just reset on error. */
189 for (i
= 0; i
< desc_length
; i
++)
191 outptr
[desc_length
] = '\0';
194 if (spk_characters
[index
] != spk_default_chars
[index
])
195 kfree(spk_characters
[index
]);
196 spk_characters
[index
] = desc
;
199 charclass
= spk_chartab_get_value(keyword
);
200 if (charclass
== 0) {
205 if (charclass
!= spk_chartab
[index
]) {
206 spk_chartab
[index
] = charclass
;
215 spk_reset_default_chars();
217 spk_reset_default_chartab();
220 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
221 report_char_chartab_status(reset
, received
, used
, rejected
,
227 * This is called when a user reads the keymap parameter.
229 static ssize_t
keymap_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
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
250 for (n
= 0; n
<= num_keys
; n
++) {
251 for (i
= 0; i
<= nstates
; i
++) {
253 cp
+= sprintf(cp
, "%d,", (int)ch
);
254 *cp
++ = (i
< nstates
) ? SPACE
: '\n';
257 cp
+= sprintf(cp
, "0, %d\n", KEY_MAP_VER
);
258 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
259 return (int)(cp
- buf
);
263 * This is called when a user changes the keymap parameter.
265 static ssize_t
keymap_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
266 const char *buf
, size_t count
)
270 char *in_buff
= NULL
;
275 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
276 in_buff
= kmemdup(buf
, count
+ 1, GFP_ATOMIC
);
278 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
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");
285 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
288 if (in_buff
[count
- 1] == '\n')
289 in_buff
[count
- 1] = '\0';
291 cp1
= (u_char
*)in_buff
;
292 for (i
= 0; i
< 3; i
++) {
293 cp
= spk_s2uchar(cp
, cp1
);
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]);
304 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
308 cp
= spk_s2uchar(cp
, cp1
);
313 if (i
!= 0 || cp1
[-1] != KEY_MAP_VER
|| cp1
[-2] != 0) {
315 pr_warn("end %d %d %d %d\n", i
,
316 (int)cp1
[-3], (int)cp1
[-2], (int)cp1
[-1]);
318 if (spk_set_key_info(in_buff
, spk_key_buf
)) {
319 spk_set_key_info(spk_key_defaults
, spk_key_buf
);
321 pr_warn("set key failed\n");
325 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
330 * This is called when a user changes the value of the silent parameter.
332 static ssize_t
silent_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
333 const char *buf
, size_t count
)
336 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
342 if (len
> 0 && len
< 3) {
347 if (ch
< '0' || ch
> '7') {
348 pr_warn("silent value '%c' not in range (0,7)\n", ch
);
351 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
363 spk_shut_up
&= ~shut
;
364 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
369 * This is called when a user reads the synth setting.
371 static ssize_t
synth_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
377 rv
= sprintf(buf
, "%s\n", "none");
379 rv
= sprintf(buf
, "%s\n", synth
->name
);
384 * This is called when a user requests to change synthesizers.
386 static ssize_t
synth_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
387 const char *buf
, size_t count
)
390 char new_synth_name
[10];
393 if (len
< 2 || len
> 9)
395 memcpy(new_synth_name
, buf
, len
);
396 if (new_synth_name
[len
- 1] == '\n')
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
);
410 * This is called when text is sent to the synth via the synth_direct file.
412 static ssize_t
synth_direct_store(struct kobject
*kobj
,
413 struct kobj_attribute
*attr
,
414 const char *buf
, size_t count
)
422 unescaped
= kstrdup(buf
, GFP_KERNEL
);
426 string_unescape_any_inplace(unescaped
);
428 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
429 synth_write(unescaped
, strlen(unescaped
));
430 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
438 * This function is called when a user reads the version.
440 static ssize_t
version_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
446 cp
+= sprintf(cp
, "Speakup version %s\n", SPEAKUP_VERSION
);
448 cp
+= sprintf(cp
, "%s synthesizer driver version %s\n",
449 synth
->name
, synth
->version
);
454 * This is called when a user reads the punctuation settings.
456 static ssize_t
punc_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
461 struct st_var_header
*p_header
;
462 struct punc_var_t
*var
;
463 struct st_bits_data
*pb
;
467 p_header
= spk_var_header_by_name(attr
->attr
.name
);
469 pr_warn("p_header is null, attr->attr.name is %s\n",
474 var
= spk_get_punc_var(p_header
->var_id
);
476 pr_warn("var is null, p_header->var_id is %i\n",
481 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
482 pb
= (struct st_bits_data
*)&spk_punc_info
[var
->value
];
484 for (i
= 33; i
< 128; i
++) {
485 if (!(spk_chartab
[i
] & mask
))
489 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
494 * This is called when a user changes the punctuation settings.
496 static ssize_t
punc_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
497 const char *buf
, size_t count
)
500 struct st_var_header
*p_header
;
501 struct punc_var_t
*var
;
509 p_header
= spk_var_header_by_name(attr
->attr
.name
);
511 pr_warn("p_header is null, attr->attr.name is %s\n",
516 var
= spk_get_punc_var(p_header
->var_id
);
518 pr_warn("var is null, p_header->var_id is %i\n",
523 memcpy(punc_buf
, buf
, x
);
525 while (x
&& punc_buf
[x
- 1] == '\n')
529 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
531 if (*punc_buf
== 'd' || *punc_buf
== 'r')
532 x
= spk_set_mask_bits(NULL
, var
->value
, 3);
534 x
= spk_set_mask_bits(punc_buf
, var
->value
, 3);
536 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
541 * This function is called when a user reads one of the variable parameters.
543 ssize_t
spk_var_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
547 struct st_var_header
*param
;
554 param
= spk_var_header_by_name(attr
->attr
.name
);
558 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
559 var
= (struct var_t
*)param
->data
;
560 switch (param
->var_type
) {
564 rv
= sprintf(buf
, "%i\n", var
->u
.n
.value
);
566 rv
= sprintf(buf
, "0\n");
572 for (cp
= (char *)param
->p_val
; (ch
= *cp
); cp
++) {
573 if (ch
>= ' ' && ch
< '~')
576 cp1
+= sprintf(cp1
, "\\x%02x", ch
);
583 rv
= sprintf(buf
, "\"\"\n");
587 rv
= sprintf(buf
, "Bad parameter %s, type %i\n",
588 param
->name
, param
->var_type
);
591 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
594 EXPORT_SYMBOL_GPL(spk_var_show
);
597 * Used to reset either default_pitch or default_vol.
599 static inline void spk_reset_default_value(char *header_name
,
600 int *synth_default_value
, int idx
)
602 struct st_var_header
*param
;
604 if (synth
&& synth_default_value
) {
605 param
= spk_var_header_by_name(header_name
);
607 spk_set_num_var(synth_default_value
[idx
],
608 param
, E_NEW_DEFAULT
);
609 spk_set_num_var(0, param
, E_DEFAULT
);
610 pr_info("%s reset to default value\n", param
->name
);
616 * This function is called when a user echos a value to one of the
617 * variable parameters.
619 ssize_t
spk_var_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
620 const char *buf
, size_t count
)
622 struct st_var_header
*param
;
626 struct var_t
*var_data
;
630 param
= spk_var_header_by_name(attr
->attr
.name
);
637 string_unescape_any_inplace(cp
);
639 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
640 switch (param
->var_type
) {
643 if (*cp
== 'd' || *cp
== 'r' || *cp
== '\0')
645 else if (*cp
== '+' || *cp
== '-')
649 if (kstrtol(cp
, 10, &value
) == 0)
650 ret
= spk_set_num_var(value
, param
, len
);
652 pr_warn("overflow or parsing error has occurred");
653 if (ret
== -ERANGE
) {
654 var_data
= param
->data
;
655 pr_warn("value for %s out of range, expect %d to %d\n",
657 var_data
->u
.n
.low
, var_data
->u
.n
.high
);
661 * If voice was just changed, we might need to reset our default
664 if (param
->var_id
== VOICE
&& synth
&&
665 (ret
== 0 || ret
== -ERESTART
)) {
666 var_data
= param
->data
;
667 value
= var_data
->u
.n
.value
;
668 spk_reset_default_value("pitch", synth
->default_pitch
,
670 spk_reset_default_value("vol", synth
->default_vol
,
676 if ((len
>= 1) && (cp
[len
- 1] == '\n'))
678 if ((len
>= 2) && (cp
[0] == '"') && (cp
[len
- 1] == '"')) {
683 ret
= spk_set_string_var(cp
, param
, len
);
685 pr_warn("value too long for %s\n",
689 pr_warn("%s unknown type %d\n",
690 param
->name
, (int)param
->var_type
);
693 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
695 if (ret
== -ERESTART
)
696 pr_info("%s reset to default value\n", param
->name
);
699 EXPORT_SYMBOL_GPL(spk_var_store
);
702 * Functions for reading and writing lists of i18n messages. Incomplete.
705 static ssize_t
message_show_helper(char *buf
, enum msg_index_t first
,
706 enum msg_index_t last
)
708 size_t bufsize
= PAGE_SIZE
;
709 char *buf_pointer
= buf
;
711 enum msg_index_t cursor
;
713 *buf_pointer
= '\0'; /* buf_pointer always looking at a NUL byte. */
715 for (cursor
= first
; cursor
<= last
; cursor
++, index
++) {
718 printed
= scnprintf(buf_pointer
, bufsize
, "%d\t%s\n",
719 index
, spk_msg_get(cursor
));
720 buf_pointer
+= printed
;
724 return buf_pointer
- buf
;
727 static void report_msg_status(int reset
, int received
, int used
,
728 int rejected
, char *groupname
)
734 pr_info("i18n messages from group %s reset to defaults\n",
736 } else if (received
) {
737 len
= snprintf(buf
, sizeof(buf
),
738 " updated %d of %d i18n messages from group %s\n",
739 used
, received
, groupname
);
741 snprintf(buf
+ (len
- 1), sizeof(buf
) - (len
- 1),
742 " with %d reject%s\n",
743 rejected
, rejected
> 1 ? "s" : "");
748 static ssize_t
message_store_helper(const char *buf
, size_t count
,
749 struct msg_group_t
*group
)
751 char *cp
= (char *)buf
;
752 char *end
= cp
+ count
;
753 char *linefeed
= NULL
;
755 ssize_t msg_stored
= 0;
756 ssize_t retval
= count
;
757 size_t desc_length
= 0;
758 unsigned long index
= 0;
763 enum msg_index_t firstmessage
= group
->start
;
764 enum msg_index_t lastmessage
= group
->end
;
765 enum msg_index_t curmessage
;
768 while ((cp
< end
) && (*cp
== ' ' || *cp
== '\t'))
773 if (strchr("dDrR", *cp
)) {
779 linefeed
= strchr(cp
, '\n');
792 * Do not replace with kstrtoul:
793 * here we need temp to be updated
795 index
= simple_strtoul(cp
, &temp
, 10);
797 while ((temp
< linefeed
) && (*temp
== ' ' || *temp
== '\t'))
800 desc_length
= linefeed
- temp
;
801 curmessage
= firstmessage
+ index
;
804 * Note the check (curmessage < firstmessage). It is not
805 * redundant. Suppose that the user gave us an index
806 * equal to ULONG_MAX - 1. If firstmessage > 1, then
807 * firstmessage + index < firstmessage!
810 if ((curmessage
< firstmessage
) || (curmessage
> lastmessage
)) {
816 msg_stored
= spk_msg_set(curmessage
, temp
, desc_length
);
817 if (msg_stored
< 0) {
819 if (msg_stored
== -ENOMEM
)
830 spk_reset_msg_group(group
);
832 report_msg_status(reset
, received
, used
, rejected
, group
->name
);
836 static ssize_t
message_show(struct kobject
*kobj
,
837 struct kobj_attribute
*attr
, char *buf
)
840 struct msg_group_t
*group
= spk_find_msg_group(attr
->attr
.name
);
846 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
847 retval
= message_show_helper(buf
, group
->start
, group
->end
);
848 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
852 static ssize_t
message_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
853 const char *buf
, size_t count
)
855 struct msg_group_t
*group
= spk_find_msg_group(attr
->attr
.name
);
860 return message_store_helper(buf
, count
, group
);
864 * Declare the attributes.
866 static struct kobj_attribute keymap_attribute
=
868 static struct kobj_attribute silent_attribute
=
870 static struct kobj_attribute synth_attribute
=
872 static struct kobj_attribute synth_direct_attribute
=
873 __ATTR_WO(synth_direct
);
874 static struct kobj_attribute version_attribute
=
877 static struct kobj_attribute delimiters_attribute
=
878 __ATTR(delimiters
, 0644, punc_show
, punc_store
);
879 static struct kobj_attribute ex_num_attribute
=
880 __ATTR(ex_num
, 0644, punc_show
, punc_store
);
881 static struct kobj_attribute punc_all_attribute
=
882 __ATTR(punc_all
, 0644, punc_show
, punc_store
);
883 static struct kobj_attribute punc_most_attribute
=
884 __ATTR(punc_most
, 0644, punc_show
, punc_store
);
885 static struct kobj_attribute punc_some_attribute
=
886 __ATTR(punc_some
, 0644, punc_show
, punc_store
);
887 static struct kobj_attribute repeats_attribute
=
888 __ATTR(repeats
, 0644, punc_show
, punc_store
);
890 static struct kobj_attribute attrib_bleep_attribute
=
891 __ATTR(attrib_bleep
, 0644, spk_var_show
, spk_var_store
);
892 static struct kobj_attribute bell_pos_attribute
=
893 __ATTR(bell_pos
, 0644, spk_var_show
, spk_var_store
);
894 static struct kobj_attribute bleep_time_attribute
=
895 __ATTR(bleep_time
, 0644, spk_var_show
, spk_var_store
);
896 static struct kobj_attribute bleeps_attribute
=
897 __ATTR(bleeps
, 0644, spk_var_show
, spk_var_store
);
898 static struct kobj_attribute cursor_time_attribute
=
899 __ATTR(cursor_time
, 0644, spk_var_show
, spk_var_store
);
900 static struct kobj_attribute key_echo_attribute
=
901 __ATTR(key_echo
, 0644, spk_var_show
, spk_var_store
);
902 static struct kobj_attribute no_interrupt_attribute
=
903 __ATTR(no_interrupt
, 0644, spk_var_show
, spk_var_store
);
904 static struct kobj_attribute punc_level_attribute
=
905 __ATTR(punc_level
, 0644, spk_var_show
, spk_var_store
);
906 static struct kobj_attribute reading_punc_attribute
=
907 __ATTR(reading_punc
, 0644, spk_var_show
, spk_var_store
);
908 static struct kobj_attribute say_control_attribute
=
909 __ATTR(say_control
, 0644, spk_var_show
, spk_var_store
);
910 static struct kobj_attribute say_word_ctl_attribute
=
911 __ATTR(say_word_ctl
, 0644, spk_var_show
, spk_var_store
);
912 static struct kobj_attribute spell_delay_attribute
=
913 __ATTR(spell_delay
, 0644, spk_var_show
, spk_var_store
);
914 static struct kobj_attribute cur_phonetic_attribute
=
915 __ATTR(cur_phonetic
, 0644, spk_var_show
, spk_var_store
);
918 * These attributes are i18n related.
920 static struct kobj_attribute announcements_attribute
=
921 __ATTR(announcements
, 0644, message_show
, message_store
);
922 static struct kobj_attribute characters_attribute
=
923 __ATTR(characters
, 0644, chars_chartab_show
,
924 chars_chartab_store
);
925 static struct kobj_attribute chartab_attribute
=
926 __ATTR(chartab
, 0644, chars_chartab_show
,
927 chars_chartab_store
);
928 static struct kobj_attribute ctl_keys_attribute
=
929 __ATTR(ctl_keys
, 0644, message_show
, message_store
);
930 static struct kobj_attribute colors_attribute
=
931 __ATTR(colors
, 0644, message_show
, message_store
);
932 static struct kobj_attribute formatted_attribute
=
933 __ATTR(formatted
, 0644, message_show
, message_store
);
934 static struct kobj_attribute function_names_attribute
=
935 __ATTR(function_names
, 0644, message_show
, message_store
);
936 static struct kobj_attribute key_names_attribute
=
937 __ATTR(key_names
, 0644, message_show
, message_store
);
938 static struct kobj_attribute states_attribute
=
939 __ATTR(states
, 0644, message_show
, message_store
);
942 * Create groups of attributes so that we can create and destroy them all
945 static struct attribute
*main_attrs
[] = {
946 &keymap_attribute
.attr
,
947 &silent_attribute
.attr
,
948 &synth_attribute
.attr
,
949 &synth_direct_attribute
.attr
,
950 &version_attribute
.attr
,
951 &delimiters_attribute
.attr
,
952 &ex_num_attribute
.attr
,
953 &punc_all_attribute
.attr
,
954 &punc_most_attribute
.attr
,
955 &punc_some_attribute
.attr
,
956 &repeats_attribute
.attr
,
957 &attrib_bleep_attribute
.attr
,
958 &bell_pos_attribute
.attr
,
959 &bleep_time_attribute
.attr
,
960 &bleeps_attribute
.attr
,
961 &cursor_time_attribute
.attr
,
962 &key_echo_attribute
.attr
,
963 &no_interrupt_attribute
.attr
,
964 &punc_level_attribute
.attr
,
965 &reading_punc_attribute
.attr
,
966 &say_control_attribute
.attr
,
967 &say_word_ctl_attribute
.attr
,
968 &spell_delay_attribute
.attr
,
969 &cur_phonetic_attribute
.attr
,
973 static struct attribute
*i18n_attrs
[] = {
974 &announcements_attribute
.attr
,
975 &characters_attribute
.attr
,
976 &chartab_attribute
.attr
,
977 &ctl_keys_attribute
.attr
,
978 &colors_attribute
.attr
,
979 &formatted_attribute
.attr
,
980 &function_names_attribute
.attr
,
981 &key_names_attribute
.attr
,
982 &states_attribute
.attr
,
987 * An unnamed attribute group will put all of the attributes directly in
988 * the kobject directory. If we specify a name, a subdirectory will be
989 * created for the attributes with the directory being the name of the
992 static const struct attribute_group main_attr_group
= {
996 static const struct attribute_group i18n_attr_group
= {
1001 static struct kobject
*accessibility_kobj
;
1002 struct kobject
*speakup_kobj
;
1004 int speakup_kobj_init(void)
1009 * Create a simple kobject with the name of "accessibility",
1010 * located under /sys/
1012 * As this is a simple directory, no uevent will be sent to
1013 * userspace. That is why this function should not be used for
1014 * any type of dynamic kobjects, where the name and number are
1015 * not known ahead of time.
1017 accessibility_kobj
= kobject_create_and_add("accessibility", NULL
);
1018 if (!accessibility_kobj
) {
1023 speakup_kobj
= kobject_create_and_add("speakup", accessibility_kobj
);
1024 if (!speakup_kobj
) {
1029 /* Create the files associated with this kobject */
1030 retval
= sysfs_create_group(speakup_kobj
, &main_attr_group
);
1034 retval
= sysfs_create_group(speakup_kobj
, &i18n_attr_group
);
1041 sysfs_remove_group(speakup_kobj
, &main_attr_group
);
1043 kobject_put(speakup_kobj
);
1045 kobject_put(accessibility_kobj
);
1050 void speakup_kobj_exit(void)
1052 sysfs_remove_group(speakup_kobj
, &i18n_attr_group
);
1053 sysfs_remove_group(speakup_kobj
, &main_attr_group
);
1054 kobject_put(speakup_kobj
);
1055 kobject_put(accessibility_kobj
);