2 * Speakup kobject implementation
4 * Copyright (C) 2009 William Hubbs
6 * This code is based on kobject-example.c, which came with linux 2.6.x.
8 * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
9 * Copyright (C) 2007 Novell Inc.
11 * Released under the GPL version 2 only.
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>
25 * This is called when a user reads the characters or chartab sys file.
27 static ssize_t
chars_chartab_show(struct kobject
*kobj
,
28 struct kobj_attribute
*attr
, char *buf
)
33 char *buf_pointer
= buf
;
34 size_t bufsize
= PAGE_SIZE
;
39 for (i
= 0; i
< 256; i
++) {
42 if (strcmp("characters", attr
->attr
.name
) == 0) {
43 len
= scnprintf(buf_pointer
, bufsize
, "%d\t%s\n",
45 } else { /* show chartab entry */
46 if (IS_TYPE(i
, B_CTL
))
48 else if (IS_TYPE(i
, WDLM
))
50 else if (IS_TYPE(i
, A_PUNC
))
52 else if (IS_TYPE(i
, PUNC
))
54 else if (IS_TYPE(i
, NUM
))
56 else if (IS_TYPE(i
, A_CAP
))
58 else if (IS_TYPE(i
, ALPHA
))
60 else if (IS_TYPE(i
, B_CAPSYM
))
62 else if (IS_TYPE(i
, B_SYM
))
67 scnprintf(buf_pointer
, bufsize
, "%d\t%s\n", i
, cp
);
73 return buf_pointer
- buf
;
77 * Print informational messages or warnings after updating
78 * character descriptions or chartab entries.
80 static void report_char_chartab_status(int reset
, int received
, int used
,
81 int rejected
, int do_characters
)
83 char *object_type
[] = {
84 "character class entries",
85 "character descriptions",
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
]);
97 snprintf(buf
+ (len
- 1), sizeof(buf
) - (len
- 1),
98 " with %d reject%s\n",
99 rejected
, rejected
> 1 ? "s" : "");
105 * This is called when a user changes the characters or chartab parameters.
107 static ssize_t
chars_chartab_store(struct kobject
*kobj
,
108 struct kobj_attribute
*attr
, const char *buf
, size_t count
)
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. */
117 ssize_t retval
= count
;
119 unsigned long index
= 0;
125 int do_characters
= !strcmp(attr
->attr
.name
, "characters");
126 size_t desc_length
= 0;
132 while ((cp
< end
) && (*cp
== ' ' || *cp
== '\t'))
137 if ((*cp
== '\n') || strchr("dDrR", *cp
)) {
143 linefeed
= strchr(cp
, '\n');
149 if (! isdigit(*cp
)) {
155 index
= simple_strtoul(cp
, &temp
, 10);
162 while ((temp
< linefeed
) && (*temp
== ' ' || *temp
== '\t'))
165 desc_length
= linefeed
- temp
;
166 if (desc_length
> MAX_DESC_LEN
) {
172 desc
= kmalloc(desc_length
+ 1, GFP_ATOMIC
);
175 reset
= 1; /* just reset on error. */
183 for (i
= 0; i
< desc_length
; i
++)
185 outptr
[desc_length
] = '\0';
188 if (characters
[index
] != default_chars
[index
])
189 kfree(characters
[index
]);
190 characters
[index
] = desc
;
193 charclass
= chartab_get_value(keyword
);
194 if (charclass
== 0) {
199 if (charclass
!= spk_chartab
[index
]) {
200 spk_chartab
[index
] = charclass
;
209 reset_default_chars();
211 reset_default_chartab();
215 report_char_chartab_status(reset
, received
, used
, rejected
, do_characters
);
220 * This is called when a user reads the keymap parameter.
222 static ssize_t
keymap_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
234 cp1
= key_buf
+ SHIFT_TBL_SIZE
;
235 num_keys
= (int)(*cp1
);
236 nstates
= (int)cp1
[1];
237 cp
+= sprintf(cp
, "%d, %d, %d,\n", KEY_MAP_VER
, num_keys
, nstates
);
238 cp1
+= 2; /* now pointing at shift states */
239 /* dump num_keys+1 as first row is shift states + flags,
240 each subsequent row is key + states */
241 for (n
= 0; n
<= num_keys
; n
++) {
242 for (i
= 0; i
<= nstates
; i
++) {
244 cp
+= sprintf(cp
, "%d,", (int)ch
);
245 *cp
++ = (i
< nstates
) ? SPACE
: '\n';
248 cp
+= sprintf(cp
, "0, %d\n", KEY_MAP_VER
);
250 return (int)(cp
-buf
);
254 * This is called when a user changes the keymap parameter.
256 static ssize_t
keymap_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
257 const char *buf
, size_t count
)
261 char *in_buff
= NULL
;
267 in_buff
= kmalloc(count
+ 1, GFP_ATOMIC
);
272 memcpy(in_buff
, buf
, count
+ 1);
273 if (strchr("dDrR", *in_buff
)) {
274 set_key_info(key_defaults
, key_buf
);
275 pr_info("keymap set to default values\n");
280 if (in_buff
[count
- 1] == '\n')
281 in_buff
[count
- 1] = '\0';
283 cp1
= (u_char
*)in_buff
;
284 for (i
= 0; i
< 3; i
++) {
285 cp
= s2uchar(cp
, cp1
);
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]);
300 cp
= s2uchar(cp
, cp1
);
305 if (i
!= 0 || cp1
[-1] != KEY_MAP_VER
|| cp1
[-2] != 0) {
307 pr_warn("end %d %d %d %d\n", i
,
308 (int)cp1
[-3], (int)cp1
[-2], (int)cp1
[-1]);
310 if (set_key_info(in_buff
, key_buf
)) {
311 set_key_info(key_defaults
, key_buf
);
313 pr_warn("set key failed\n");
322 * This is called when a user changes the value of the silent parameter.
324 static ssize_t
silent_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
325 const char *buf
, size_t count
)
328 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
334 if (len
> 0 || len
< 3) {
339 if (ch
< '0' || ch
> '7') {
340 pr_warn("silent value '%c' not in range (0,7)\n", ch
);
355 spk_shut_up
&= ~shut
;
361 * This is called when a user reads the synth setting.
363 static ssize_t
synth_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
369 rv
= sprintf(buf
, "%s\n", "none");
371 rv
= sprintf(buf
, "%s\n", synth
->name
);
376 * This is called when a user requests to change synthesizers.
378 static ssize_t
synth_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
379 const char *buf
, size_t count
)
382 char new_synth_name
[10];
385 if (len
< 2 || len
> 9)
387 strncpy(new_synth_name
, buf
, len
);
388 if (new_synth_name
[len
- 1] == '\n')
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
);
402 * This is called when text is sent to the synth via the synth_direct file.
404 static ssize_t
synth_direct_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
405 const char *buf
, size_t count
)
410 const char *ptr
= buf
;
417 bytes
= min_t(size_t, len
, 250);
418 strncpy(tmp
, ptr
, bytes
);
421 synth_printf("%s", tmp
);
429 * This function is called when a user reads the version.
431 static ssize_t
version_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
437 cp
+= sprintf(cp
, "Speakup version %s\n", SPEAKUP_VERSION
);
439 cp
+= sprintf(cp
, "%s synthesizer driver version %s\n",
440 synth
->name
, synth
->version
);
445 * This is called when a user reads the punctuation settings.
447 static ssize_t
punc_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
452 struct st_var_header
*p_header
;
453 struct punc_var_t
*var
;
454 struct st_bits_data
*pb
;
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", attr
->attr
.name
);
464 var
= get_punc_var(p_header
->var_id
);
466 pr_warn("var is null, p_header->var_id is %i\n",
472 pb
= (struct st_bits_data
*) &punc_info
[var
->value
];
474 for (i
= 33; i
< 128; i
++) {
475 if (!(spk_chartab
[i
]&mask
))
484 * This is called when a user changes the punctuation settings.
486 static ssize_t
punc_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
487 const char *buf
, size_t count
)
490 struct st_var_header
*p_header
;
491 struct punc_var_t
*var
;
499 p_header
= var_header_by_name(attr
->attr
.name
);
500 if (p_header
== NULL
) {
501 pr_warn("p_header is null, attr->attr.name is %s\n", attr
->attr
.name
);
505 var
= get_punc_var(p_header
->var_id
);
507 pr_warn("var is null, p_header->var_id is %i\n",
512 strncpy(punc_buf
, buf
, x
);
514 while (x
&& punc_buf
[x
- 1] == '\n')
520 if (*punc_buf
== 'd' || *punc_buf
== 'r')
521 x
= set_mask_bits(0, var
->value
, 3);
523 x
= set_mask_bits(punc_buf
, var
->value
, 3);
530 * This function is called when a user reads one of the variable parameters.
532 ssize_t
spk_var_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
536 struct st_var_header
*param
;
543 param
= var_header_by_name(attr
->attr
.name
);
548 var
= (struct var_t
*) param
->data
;
549 switch (param
->var_type
) {
553 rv
= sprintf(buf
, "%i\n", var
->u
.n
.value
);
555 rv
= sprintf(buf
, "0\n");
561 for (cp
= (char *)param
->p_val
; (ch
= *cp
); cp
++) {
562 if (ch
>= ' ' && ch
< '~')
565 cp1
+= sprintf(cp1
, "\\""x%02x", ch
);
572 rv
= sprintf(buf
, "\"\"\n");
576 rv
= sprintf(buf
, "Bad parameter %s, type %i\n",
577 param
->name
, param
->var_type
);
583 EXPORT_SYMBOL_GPL(spk_var_show
);
586 * This function is called when a user echos a value to one of the
587 * variable parameters.
589 ssize_t
spk_var_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
590 const char *buf
, size_t count
)
592 struct st_var_header
*param
;
596 struct var_t
*var_data
;
600 param
= var_header_by_name(attr
->attr
.name
);
603 if (param
->data
== NULL
)
606 cp
= xlate((char *) buf
);
609 switch (param
->var_type
) {
612 if (*cp
== 'd' || *cp
== 'r' || *cp
== '\0')
614 else if (*cp
== '+' || *cp
== '-')
618 speakup_s2i(cp
, &value
);
619 ret
= set_num_var(value
, param
, len
);
620 if (ret
== E_RANGE
) {
621 var_data
= param
->data
;
622 pr_warn("value for %s out of range, expect %d to %d\n",
624 var_data
->u
.n
.low
, var_data
->u
.n
.high
);
629 if ((len
>= 1) && (buf
[len
- 1] == '\n'))
631 if ((len
>= 2) && (buf
[0] == '"') && (buf
[len
- 1] == '"')) {
637 ret
= set_string_var(buf
, param
, len
);
638 if (ret
== E_TOOLONG
)
639 pr_warn("value too long for %s\n",
643 pr_warn("%s unknown type %d\n",
644 param
->name
, (int)param
->var_type
);
648 * If voice was just changed, we might need to reset our default
651 if (strcmp(attr
->attr
.name
, "voice") == 0) {
652 if (synth
&& synth
->default_pitch
) {
653 param
= var_header_by_name("pitch");
655 set_num_var(synth
->default_pitch
[value
], param
, E_NEW_DEFAULT
);
656 set_num_var(0, param
, E_DEFAULT
);
659 if (synth
&& synth
->default_vol
) {
660 param
= var_header_by_name("vol");
662 set_num_var(synth
->default_vol
[value
], param
, E_NEW_DEFAULT
);
663 set_num_var(0, param
, E_DEFAULT
);
669 if (ret
== SET_DEFAULT
)
670 pr_info("%s reset to default value\n", attr
->attr
.name
);
673 EXPORT_SYMBOL_GPL(spk_var_store
);
676 * Functions for reading and writing lists of i18n messages. Incomplete.
679 static ssize_t
message_show_helper(char *buf
, enum msg_index_t first
,
680 enum msg_index_t last
)
682 size_t bufsize
= PAGE_SIZE
;
683 char *buf_pointer
= buf
;
685 enum msg_index_t cursor
;
687 *buf_pointer
= '\0'; /* buf_pointer always looking at a NUL byte. */
689 for (cursor
= first
; cursor
<= last
; cursor
++, index
++) {
692 printed
= scnprintf(buf_pointer
, bufsize
, "%d\t%s\n",
693 index
, msg_get(cursor
));
694 buf_pointer
+= printed
;
698 return buf_pointer
- buf
;
701 static void report_msg_status(int reset
, int received
, int used
,
702 int rejected
, char *groupname
)
708 pr_info("i18n messages from group %s reset to defaults\n",
710 } else if (received
) {
711 len
= snprintf(buf
, sizeof(buf
),
712 " updated %d of %d i18n messages from group %s\n",
713 used
, received
, groupname
);
715 snprintf(buf
+ (len
- 1), sizeof(buf
) - (len
- 1),
716 " with %d reject%s\n",
717 rejected
, rejected
> 1 ? "s" : "");
722 static ssize_t
message_store_helper(const char *buf
, size_t count
,
723 struct msg_group_t
*group
)
725 char *cp
= (char *) buf
;
726 char *end
= cp
+ count
;
727 char *linefeed
= NULL
;
729 ssize_t msg_stored
= 0;
730 ssize_t retval
= count
;
731 size_t desc_length
= 0;
732 unsigned long index
= 0;
737 enum msg_index_t firstmessage
= group
->start
;
738 enum msg_index_t lastmessage
= group
->end
;
739 enum msg_index_t curmessage
;
743 while ((cp
< end
) && (*cp
== ' ' || *cp
== '\t'))
748 if (strchr("dDrR", *cp
)) {
754 linefeed
= strchr(cp
, '\n');
760 if (! isdigit(*cp
)) {
766 index
= simple_strtoul(cp
, &temp
, 10);
768 while ((temp
< linefeed
) && (*temp
== ' ' || *temp
== '\t'))
771 desc_length
= linefeed
- temp
;
772 curmessage
= firstmessage
+ index
;
775 * Note the check (curmessage < firstmessage). It is not
776 * redundant. Suppose that the user gave us an index
777 * equal to ULONG_MAX - 1. If firstmessage > 1, then
778 * firstmessage + index < firstmessage!
781 if ((curmessage
< firstmessage
) || (curmessage
> lastmessage
)) {
787 msg_stored
= msg_set(curmessage
, temp
, desc_length
);
788 if (msg_stored
< 0) {
790 if (msg_stored
== -ENOMEM
)
801 reset_msg_group(group
);
803 report_msg_status(reset
, received
, used
, rejected
, group
->name
);
807 static ssize_t
message_show(struct kobject
*kobj
,
808 struct kobj_attribute
*attr
, char *buf
)
811 struct msg_group_t
*group
= find_msg_group(attr
->attr
.name
);
816 retval
= message_show_helper(buf
, group
->start
, group
->end
);
821 static ssize_t
message_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
822 const char *buf
, size_t count
)
825 struct msg_group_t
*group
= find_msg_group(attr
->attr
.name
);
828 retval
= message_store_helper(buf
, count
, group
);
833 * Declare the attributes.
835 static struct kobj_attribute keymap_attribute
=
836 __ATTR(keymap
, ROOT_W
, keymap_show
, keymap_store
);
837 static struct kobj_attribute silent_attribute
=
838 __ATTR(silent
, USER_W
, NULL
, silent_store
);
839 static struct kobj_attribute synth_attribute
=
840 __ATTR(synth
, USER_RW
, synth_show
, synth_store
);
841 static struct kobj_attribute synth_direct_attribute
=
842 __ATTR(synth_direct
, USER_W
, NULL
, synth_direct_store
);
843 static struct kobj_attribute version_attribute
=
846 static struct kobj_attribute delimiters_attribute
=
847 __ATTR(delimiters
, USER_RW
, punc_show
, punc_store
);
848 static struct kobj_attribute ex_num_attribute
=
849 __ATTR(ex_num
, USER_RW
, punc_show
, punc_store
);
850 static struct kobj_attribute punc_all_attribute
=
851 __ATTR(punc_all
, USER_RW
, punc_show
, punc_store
);
852 static struct kobj_attribute punc_most_attribute
=
853 __ATTR(punc_most
, USER_RW
, punc_show
, punc_store
);
854 static struct kobj_attribute punc_some_attribute
=
855 __ATTR(punc_some
, USER_RW
, punc_show
, punc_store
);
856 static struct kobj_attribute repeats_attribute
=
857 __ATTR(repeats
, USER_RW
, punc_show
, punc_store
);
859 static struct kobj_attribute attrib_bleep_attribute
=
860 __ATTR(attrib_bleep
, USER_RW
, spk_var_show
, spk_var_store
);
861 static struct kobj_attribute bell_pos_attribute
=
862 __ATTR(bell_pos
, USER_RW
, spk_var_show
, spk_var_store
);
863 static struct kobj_attribute bleep_time_attribute
=
864 __ATTR(bleep_time
, USER_RW
, spk_var_show
, spk_var_store
);
865 static struct kobj_attribute bleeps_attribute
=
866 __ATTR(bleeps
, USER_RW
, spk_var_show
, spk_var_store
);
867 static struct kobj_attribute cursor_time_attribute
=
868 __ATTR(cursor_time
, USER_RW
, spk_var_show
, spk_var_store
);
869 static struct kobj_attribute key_echo_attribute
=
870 __ATTR(key_echo
, USER_RW
, spk_var_show
, spk_var_store
);
871 static struct kobj_attribute no_interrupt_attribute
=
872 __ATTR(no_interrupt
, USER_RW
, spk_var_show
, spk_var_store
);
873 static struct kobj_attribute punc_level_attribute
=
874 __ATTR(punc_level
, USER_RW
, spk_var_show
, spk_var_store
);
875 static struct kobj_attribute reading_punc_attribute
=
876 __ATTR(reading_punc
, USER_RW
, spk_var_show
, spk_var_store
);
877 static struct kobj_attribute say_control_attribute
=
878 __ATTR(say_control
, USER_RW
, spk_var_show
, spk_var_store
);
879 static struct kobj_attribute say_word_ctl_attribute
=
880 __ATTR(say_word_ctl
, USER_RW
, spk_var_show
, spk_var_store
);
881 static struct kobj_attribute spell_delay_attribute
=
882 __ATTR(spell_delay
, USER_RW
, spk_var_show
, spk_var_store
);
885 * These attributes are i18n related.
887 static struct kobj_attribute announcements_attribute
=
888 __ATTR(announcements
, USER_RW
, message_show
, message_store
);
889 static struct kobj_attribute characters_attribute
=
890 __ATTR(characters
, USER_RW
, chars_chartab_show
, chars_chartab_store
);
891 static struct kobj_attribute chartab_attribute
=
892 __ATTR(chartab
, USER_RW
, chars_chartab_show
, chars_chartab_store
);
893 static struct kobj_attribute ctl_keys_attribute
=
894 __ATTR(ctl_keys
, USER_RW
, message_show
, message_store
);
895 static struct kobj_attribute colors_attribute
=
896 __ATTR(colors
, USER_RW
, message_show
, message_store
);
897 static struct kobj_attribute formatted_attribute
=
898 __ATTR(formatted
, USER_RW
, message_show
, message_store
);
899 static struct kobj_attribute function_names_attribute
=
900 __ATTR(function_names
, USER_RW
, message_show
, message_store
);
901 static struct kobj_attribute key_names_attribute
=
902 __ATTR(key_names
, USER_RW
, message_show
, message_store
);
903 static struct kobj_attribute states_attribute
=
904 __ATTR(states
, USER_RW
, message_show
, message_store
);
907 * Create groups of attributes so that we can create and destroy them all
910 static struct attribute
*main_attrs
[] = {
911 &keymap_attribute
.attr
,
912 &silent_attribute
.attr
,
913 &synth_attribute
.attr
,
914 &synth_direct_attribute
.attr
,
915 &version_attribute
.attr
,
916 &delimiters_attribute
.attr
,
917 &ex_num_attribute
.attr
,
918 &punc_all_attribute
.attr
,
919 &punc_most_attribute
.attr
,
920 &punc_some_attribute
.attr
,
921 &repeats_attribute
.attr
,
922 &attrib_bleep_attribute
.attr
,
923 &bell_pos_attribute
.attr
,
924 &bleep_time_attribute
.attr
,
925 &bleeps_attribute
.attr
,
926 &cursor_time_attribute
.attr
,
927 &key_echo_attribute
.attr
,
928 &no_interrupt_attribute
.attr
,
929 &punc_level_attribute
.attr
,
930 &reading_punc_attribute
.attr
,
931 &say_control_attribute
.attr
,
932 &say_word_ctl_attribute
.attr
,
933 &spell_delay_attribute
.attr
,
937 static struct attribute
*i18n_attrs
[] = {
938 &announcements_attribute
.attr
,
939 &characters_attribute
.attr
,
940 &chartab_attribute
.attr
,
941 &ctl_keys_attribute
.attr
,
942 &colors_attribute
.attr
,
943 &formatted_attribute
.attr
,
944 &function_names_attribute
.attr
,
945 &key_names_attribute
.attr
,
946 &states_attribute
.attr
,
951 * An unnamed attribute group will put all of the attributes directly in
952 * the kobject directory. If we specify a name, a subdirectory will be
953 * created for the attributes with the directory being the name of the
956 static struct attribute_group main_attr_group
= {
960 static struct attribute_group i18n_attr_group
= {
965 static struct kobject
*accessibility_kobj
;
966 struct kobject
*speakup_kobj
;
968 int speakup_kobj_init(void)
973 * Create a simple kobject with the name of "accessibility",
974 * located under /sys/
976 * As this is a simple directory, no uevent will be sent to
977 * userspace. That is why this function should not be used for
978 * any type of dynamic kobjects, where the name and number are
979 * not known ahead of time.
981 accessibility_kobj
= kobject_create_and_add("accessibility", NULL
);
982 if (!accessibility_kobj
)
985 speakup_kobj
= kobject_create_and_add("speakup", accessibility_kobj
);
987 kobject_put(accessibility_kobj
);
991 /* Create the files associated with this kobject */
992 retval
= sysfs_create_group(speakup_kobj
, &main_attr_group
);
996 retval
= sysfs_create_group(speakup_kobj
, &i18n_attr_group
);
1003 void speakup_kobj_exit(void)
1005 kobject_put(speakup_kobj
);
1006 kobject_put(accessibility_kobj
);