0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/slab.h> /* For kmalloc. */
0016 #include <linux/kernel.h>
0017 #include <linux/kobject.h>
0018 #include <linux/string.h>
0019 #include <linux/string_helpers.h>
0020 #include <linux/sysfs.h>
0021 #include <linux/ctype.h>
0022
0023 #include "speakup.h"
0024 #include "spk_priv.h"
0025
0026
0027
0028
0029 static ssize_t chars_chartab_show(struct kobject *kobj,
0030 struct kobj_attribute *attr, char *buf)
0031 {
0032 int i;
0033 int len = 0;
0034 char *cp;
0035 char *buf_pointer = buf;
0036 size_t bufsize = PAGE_SIZE;
0037 unsigned long flags;
0038
0039 spin_lock_irqsave(&speakup_info.spinlock, flags);
0040 *buf_pointer = '\0';
0041 for (i = 0; i < 256; i++) {
0042 if (bufsize <= 1)
0043 break;
0044 if (strcmp("characters", attr->attr.name) == 0) {
0045 len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
0046 i, spk_characters[i]);
0047 } else {
0048 if (IS_TYPE(i, B_CTL))
0049 cp = "B_CTL";
0050 else if (IS_TYPE(i, WDLM))
0051 cp = "WDLM";
0052 else if (IS_TYPE(i, A_PUNC))
0053 cp = "A_PUNC";
0054 else if (IS_TYPE(i, PUNC))
0055 cp = "PUNC";
0056 else if (IS_TYPE(i, NUM))
0057 cp = "NUM";
0058 else if (IS_TYPE(i, A_CAP))
0059 cp = "A_CAP";
0060 else if (IS_TYPE(i, ALPHA))
0061 cp = "ALPHA";
0062 else if (IS_TYPE(i, B_CAPSYM))
0063 cp = "B_CAPSYM";
0064 else if (IS_TYPE(i, B_SYM))
0065 cp = "B_SYM";
0066 else
0067 cp = "0";
0068 len =
0069 scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp);
0070 }
0071 bufsize -= len;
0072 buf_pointer += len;
0073 }
0074 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0075 return buf_pointer - buf;
0076 }
0077
0078
0079
0080
0081
0082 static void report_char_chartab_status(int reset, int received, int used,
0083 int rejected, int do_characters)
0084 {
0085 static char const *object_type[] = {
0086 "character class entries",
0087 "character descriptions",
0088 };
0089 int len;
0090 char buf[80];
0091
0092 if (reset) {
0093 pr_info("%s reset to defaults\n", object_type[do_characters]);
0094 } else if (received) {
0095 len = snprintf(buf, sizeof(buf),
0096 " updated %d of %d %s\n",
0097 used, received, object_type[do_characters]);
0098 if (rejected)
0099 snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
0100 " with %d reject%s\n",
0101 rejected, rejected > 1 ? "s" : "");
0102 pr_info("%s", buf);
0103 }
0104 }
0105
0106
0107
0108
0109 static ssize_t chars_chartab_store(struct kobject *kobj,
0110 struct kobj_attribute *attr,
0111 const char *buf, size_t count)
0112 {
0113 char *cp = (char *)buf;
0114 char *end = cp + count;
0115 char *linefeed = NULL;
0116 char keyword[MAX_DESC_LEN + 1];
0117 char *outptr = NULL;
0118 char *temp = NULL;
0119 char *desc = NULL;
0120 ssize_t retval = count;
0121 unsigned long flags;
0122 unsigned long index = 0;
0123 int charclass = 0;
0124 int received = 0;
0125 int used = 0;
0126 int rejected = 0;
0127 int reset = 0;
0128 int do_characters = !strcmp(attr->attr.name, "characters");
0129 size_t desc_length = 0;
0130 int i;
0131
0132 spin_lock_irqsave(&speakup_info.spinlock, flags);
0133 while (cp < end) {
0134 while ((cp < end) && (*cp == ' ' || *cp == '\t'))
0135 cp++;
0136
0137 if (cp == end)
0138 break;
0139 if ((*cp == '\n') || strchr("dDrR", *cp)) {
0140 reset = 1;
0141 break;
0142 }
0143 received++;
0144
0145 linefeed = strchr(cp, '\n');
0146 if (!linefeed) {
0147 rejected++;
0148 break;
0149 }
0150
0151 if (!isdigit(*cp)) {
0152 rejected++;
0153 cp = linefeed + 1;
0154 continue;
0155 }
0156
0157
0158
0159
0160
0161 index = simple_strtoul(cp, &temp, 10);
0162 if (index > 255) {
0163 rejected++;
0164 cp = linefeed + 1;
0165 continue;
0166 }
0167
0168 while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
0169 temp++;
0170
0171 desc_length = linefeed - temp;
0172 if (desc_length > MAX_DESC_LEN) {
0173 rejected++;
0174 cp = linefeed + 1;
0175 continue;
0176 }
0177 if (do_characters) {
0178 desc = kmalloc(desc_length + 1, GFP_ATOMIC);
0179 if (!desc) {
0180 retval = -ENOMEM;
0181 reset = 1;
0182 break;
0183 }
0184 outptr = desc;
0185 } else {
0186 outptr = keyword;
0187 }
0188
0189 for (i = 0; i < desc_length; i++)
0190 outptr[i] = temp[i];
0191 outptr[desc_length] = '\0';
0192
0193 if (do_characters) {
0194 if (spk_characters[index] != spk_default_chars[index])
0195 kfree(spk_characters[index]);
0196 spk_characters[index] = desc;
0197 used++;
0198 } else {
0199 charclass = spk_chartab_get_value(keyword);
0200 if (charclass == 0) {
0201 rejected++;
0202 cp = linefeed + 1;
0203 continue;
0204 }
0205 if (charclass != spk_chartab[index]) {
0206 spk_chartab[index] = charclass;
0207 used++;
0208 }
0209 }
0210 cp = linefeed + 1;
0211 }
0212
0213 if (reset) {
0214 if (do_characters)
0215 spk_reset_default_chars();
0216 else
0217 spk_reset_default_chartab();
0218 }
0219
0220 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0221 report_char_chartab_status(reset, received, used, rejected,
0222 do_characters);
0223 return retval;
0224 }
0225
0226
0227
0228
0229 static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
0230 char *buf)
0231 {
0232 char *cp = buf;
0233 int i;
0234 int n;
0235 int num_keys;
0236 int nstates;
0237 u_char *cp1;
0238 u_char ch;
0239 unsigned long flags;
0240
0241 spin_lock_irqsave(&speakup_info.spinlock, flags);
0242 cp1 = spk_key_buf + SHIFT_TBL_SIZE;
0243 num_keys = (int)(*cp1);
0244 nstates = (int)cp1[1];
0245 cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
0246 cp1 += 2;
0247
0248
0249
0250 for (n = 0; n <= num_keys; n++) {
0251 for (i = 0; i <= nstates; i++) {
0252 ch = *cp1++;
0253 cp += sprintf(cp, "%d,", (int)ch);
0254 *cp++ = (i < nstates) ? SPACE : '\n';
0255 }
0256 }
0257 cp += sprintf(cp, "0, %d\n", KEY_MAP_VER);
0258 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0259 return (int)(cp - buf);
0260 }
0261
0262
0263
0264
0265 static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
0266 const char *buf, size_t count)
0267 {
0268 int i;
0269 ssize_t ret = count;
0270 char *in_buff = NULL;
0271 char *cp;
0272 u_char *cp1;
0273 unsigned long flags;
0274
0275 spin_lock_irqsave(&speakup_info.spinlock, flags);
0276 in_buff = kmemdup(buf, count + 1, GFP_ATOMIC);
0277 if (!in_buff) {
0278 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0279 return -ENOMEM;
0280 }
0281 if (strchr("dDrR", *in_buff)) {
0282 spk_set_key_info(spk_key_defaults, spk_key_buf);
0283 pr_info("keymap set to default values\n");
0284 kfree(in_buff);
0285 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0286 return count;
0287 }
0288 if (in_buff[count - 1] == '\n')
0289 in_buff[count - 1] = '\0';
0290 cp = in_buff;
0291 cp1 = (u_char *)in_buff;
0292 for (i = 0; i < 3; i++) {
0293 cp = spk_s2uchar(cp, cp1);
0294 cp1++;
0295 }
0296 i = (int)cp1[-2] + 1;
0297 i *= (int)cp1[-1] + 1;
0298 i += 2;
0299 if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
0300 i + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
0301 pr_warn("i %d %d %d %d\n", i,
0302 (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
0303 kfree(in_buff);
0304 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0305 return -EINVAL;
0306 }
0307 while (--i >= 0) {
0308 cp = spk_s2uchar(cp, cp1);
0309 cp1++;
0310 if (!(*cp))
0311 break;
0312 }
0313 if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
0314 ret = -EINVAL;
0315 pr_warn("end %d %d %d %d\n", i,
0316 (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
0317 } else {
0318 if (spk_set_key_info(in_buff, spk_key_buf)) {
0319 spk_set_key_info(spk_key_defaults, spk_key_buf);
0320 ret = -EINVAL;
0321 pr_warn("set key failed\n");
0322 }
0323 }
0324 kfree(in_buff);
0325 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0326 return ret;
0327 }
0328
0329
0330
0331
0332 static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
0333 const char *buf, size_t count)
0334 {
0335 int len;
0336 struct vc_data *vc = vc_cons[fg_console].d;
0337 char ch = 0;
0338 char shut;
0339 unsigned long flags;
0340
0341 len = strlen(buf);
0342 if (len > 0 && len < 3) {
0343 ch = buf[0];
0344 if (ch == '\n')
0345 ch = '0';
0346 }
0347 if (ch < '0' || ch > '7') {
0348 pr_warn("silent value '%c' not in range (0,7)\n", ch);
0349 return -EINVAL;
0350 }
0351 spin_lock_irqsave(&speakup_info.spinlock, flags);
0352 if (ch & 2) {
0353 shut = 1;
0354 spk_do_flush();
0355 } else {
0356 shut = 0;
0357 }
0358 if (ch & 4)
0359 shut |= 0x40;
0360 if (ch & 1)
0361 spk_shut_up |= shut;
0362 else
0363 spk_shut_up &= ~shut;
0364 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0365 return count;
0366 }
0367
0368
0369
0370
0371 static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
0372 char *buf)
0373 {
0374 int rv;
0375
0376 if (!synth)
0377 rv = sprintf(buf, "%s\n", "none");
0378 else
0379 rv = sprintf(buf, "%s\n", synth->name);
0380 return rv;
0381 }
0382
0383
0384
0385
0386 static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
0387 const char *buf, size_t count)
0388 {
0389 int len;
0390 char new_synth_name[10];
0391
0392 len = strlen(buf);
0393 if (len < 2 || len > 9)
0394 return -EINVAL;
0395 memcpy(new_synth_name, buf, len);
0396 if (new_synth_name[len - 1] == '\n')
0397 len--;
0398 new_synth_name[len] = '\0';
0399 spk_strlwr(new_synth_name);
0400 if (synth && !strcmp(new_synth_name, synth->name)) {
0401 pr_warn("%s already in use\n", new_synth_name);
0402 } else if (synth_init(new_synth_name) != 0) {
0403 pr_warn("failed to init synth %s\n", new_synth_name);
0404 return -ENODEV;
0405 }
0406 return count;
0407 }
0408
0409
0410
0411
0412 static ssize_t synth_direct_store(struct kobject *kobj,
0413 struct kobj_attribute *attr,
0414 const char *buf, size_t count)
0415 {
0416 u_char tmp[256];
0417 int len;
0418 int bytes;
0419 const char *ptr = buf;
0420 unsigned long flags;
0421
0422 if (!synth)
0423 return -EPERM;
0424
0425 len = strlen(buf);
0426 spin_lock_irqsave(&speakup_info.spinlock, flags);
0427 while (len > 0) {
0428 bytes = min_t(size_t, len, 250);
0429 strncpy(tmp, ptr, bytes);
0430 tmp[bytes] = '\0';
0431 string_unescape_any_inplace(tmp);
0432 synth_printf("%s", tmp);
0433 ptr += bytes;
0434 len -= bytes;
0435 }
0436 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0437 return count;
0438 }
0439
0440
0441
0442
0443 static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
0444 char *buf)
0445 {
0446 char *cp;
0447
0448 cp = buf;
0449 cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
0450 if (synth)
0451 cp += sprintf(cp, "%s synthesizer driver version %s\n",
0452 synth->name, synth->version);
0453 return cp - buf;
0454 }
0455
0456
0457
0458
0459 static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
0460 char *buf)
0461 {
0462 int i;
0463 char *cp = buf;
0464 struct st_var_header *p_header;
0465 struct punc_var_t *var;
0466 struct st_bits_data *pb;
0467 short mask;
0468 unsigned long flags;
0469
0470 p_header = spk_var_header_by_name(attr->attr.name);
0471 if (!p_header) {
0472 pr_warn("p_header is null, attr->attr.name is %s\n",
0473 attr->attr.name);
0474 return -EINVAL;
0475 }
0476
0477 var = spk_get_punc_var(p_header->var_id);
0478 if (!var) {
0479 pr_warn("var is null, p_header->var_id is %i\n",
0480 p_header->var_id);
0481 return -EINVAL;
0482 }
0483
0484 spin_lock_irqsave(&speakup_info.spinlock, flags);
0485 pb = (struct st_bits_data *)&spk_punc_info[var->value];
0486 mask = pb->mask;
0487 for (i = 33; i < 128; i++) {
0488 if (!(spk_chartab[i] & mask))
0489 continue;
0490 *cp++ = (char)i;
0491 }
0492 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0493 return cp - buf;
0494 }
0495
0496
0497
0498
0499 static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
0500 const char *buf, size_t count)
0501 {
0502 int x;
0503 struct st_var_header *p_header;
0504 struct punc_var_t *var;
0505 char punc_buf[100];
0506 unsigned long flags;
0507
0508 x = strlen(buf);
0509 if (x < 1 || x > 99)
0510 return -EINVAL;
0511
0512 p_header = spk_var_header_by_name(attr->attr.name);
0513 if (!p_header) {
0514 pr_warn("p_header is null, attr->attr.name is %s\n",
0515 attr->attr.name);
0516 return -EINVAL;
0517 }
0518
0519 var = spk_get_punc_var(p_header->var_id);
0520 if (!var) {
0521 pr_warn("var is null, p_header->var_id is %i\n",
0522 p_header->var_id);
0523 return -EINVAL;
0524 }
0525
0526 memcpy(punc_buf, buf, x);
0527
0528 while (x && punc_buf[x - 1] == '\n')
0529 x--;
0530 punc_buf[x] = '\0';
0531
0532 spin_lock_irqsave(&speakup_info.spinlock, flags);
0533
0534 if (*punc_buf == 'd' || *punc_buf == 'r')
0535 x = spk_set_mask_bits(NULL, var->value, 3);
0536 else
0537 x = spk_set_mask_bits(punc_buf, var->value, 3);
0538
0539 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0540 return count;
0541 }
0542
0543
0544
0545
0546 ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
0547 char *buf)
0548 {
0549 int rv = 0;
0550 struct st_var_header *param;
0551 struct var_t *var;
0552 char *cp1;
0553 char *cp;
0554 char ch;
0555 unsigned long flags;
0556
0557 param = spk_var_header_by_name(attr->attr.name);
0558 if (!param)
0559 return -EINVAL;
0560
0561 spin_lock_irqsave(&speakup_info.spinlock, flags);
0562 var = (struct var_t *)param->data;
0563 switch (param->var_type) {
0564 case VAR_NUM:
0565 case VAR_TIME:
0566 if (var)
0567 rv = sprintf(buf, "%i\n", var->u.n.value);
0568 else
0569 rv = sprintf(buf, "0\n");
0570 break;
0571 case VAR_STRING:
0572 if (var) {
0573 cp1 = buf;
0574 *cp1++ = '"';
0575 for (cp = (char *)param->p_val; (ch = *cp); cp++) {
0576 if (ch >= ' ' && ch < '~')
0577 *cp1++ = ch;
0578 else
0579 cp1 += sprintf(cp1, "\\x%02x", ch);
0580 }
0581 *cp1++ = '"';
0582 *cp1++ = '\n';
0583 *cp1 = '\0';
0584 rv = cp1 - buf;
0585 } else {
0586 rv = sprintf(buf, "\"\"\n");
0587 }
0588 break;
0589 default:
0590 rv = sprintf(buf, "Bad parameter %s, type %i\n",
0591 param->name, param->var_type);
0592 break;
0593 }
0594 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0595 return rv;
0596 }
0597 EXPORT_SYMBOL_GPL(spk_var_show);
0598
0599
0600
0601
0602 static inline void spk_reset_default_value(char *header_name,
0603 int *synth_default_value, int idx)
0604 {
0605 struct st_var_header *param;
0606
0607 if (synth && synth_default_value) {
0608 param = spk_var_header_by_name(header_name);
0609 if (param) {
0610 spk_set_num_var(synth_default_value[idx],
0611 param, E_NEW_DEFAULT);
0612 spk_set_num_var(0, param, E_DEFAULT);
0613 pr_info("%s reset to default value\n", param->name);
0614 }
0615 }
0616 }
0617
0618
0619
0620
0621
0622 ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
0623 const char *buf, size_t count)
0624 {
0625 struct st_var_header *param;
0626 int ret;
0627 int len;
0628 char *cp;
0629 struct var_t *var_data;
0630 long value;
0631 unsigned long flags;
0632
0633 param = spk_var_header_by_name(attr->attr.name);
0634 if (!param)
0635 return -EINVAL;
0636 if (!param->data)
0637 return 0;
0638 ret = 0;
0639 cp = (char *)buf;
0640 string_unescape_any_inplace(cp);
0641
0642 spin_lock_irqsave(&speakup_info.spinlock, flags);
0643 switch (param->var_type) {
0644 case VAR_NUM:
0645 case VAR_TIME:
0646 if (*cp == 'd' || *cp == 'r' || *cp == '\0')
0647 len = E_DEFAULT;
0648 else if (*cp == '+' || *cp == '-')
0649 len = E_INC;
0650 else
0651 len = E_SET;
0652 if (kstrtol(cp, 10, &value) == 0)
0653 ret = spk_set_num_var(value, param, len);
0654 else
0655 pr_warn("overflow or parsing error has occurred");
0656 if (ret == -ERANGE) {
0657 var_data = param->data;
0658 pr_warn("value for %s out of range, expect %d to %d\n",
0659 param->name,
0660 var_data->u.n.low, var_data->u.n.high);
0661 }
0662
0663
0664
0665
0666
0667 if (param->var_id == VOICE && synth &&
0668 (ret == 0 || ret == -ERESTART)) {
0669 var_data = param->data;
0670 value = var_data->u.n.value;
0671 spk_reset_default_value("pitch", synth->default_pitch,
0672 value);
0673 spk_reset_default_value("vol", synth->default_vol,
0674 value);
0675 }
0676 break;
0677 case VAR_STRING:
0678 len = strlen(cp);
0679 if ((len >= 1) && (cp[len - 1] == '\n'))
0680 --len;
0681 if ((len >= 2) && (cp[0] == '"') && (cp[len - 1] == '"')) {
0682 ++cp;
0683 len -= 2;
0684 }
0685 cp[len] = '\0';
0686 ret = spk_set_string_var(cp, param, len);
0687 if (ret == -E2BIG)
0688 pr_warn("value too long for %s\n",
0689 param->name);
0690 break;
0691 default:
0692 pr_warn("%s unknown type %d\n",
0693 param->name, (int)param->var_type);
0694 break;
0695 }
0696 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0697
0698 if (ret == -ERESTART)
0699 pr_info("%s reset to default value\n", param->name);
0700 return count;
0701 }
0702 EXPORT_SYMBOL_GPL(spk_var_store);
0703
0704
0705
0706
0707
0708 static ssize_t message_show_helper(char *buf, enum msg_index_t first,
0709 enum msg_index_t last)
0710 {
0711 size_t bufsize = PAGE_SIZE;
0712 char *buf_pointer = buf;
0713 int printed;
0714 enum msg_index_t cursor;
0715 int index = 0;
0716 *buf_pointer = '\0';
0717
0718 for (cursor = first; cursor <= last; cursor++, index++) {
0719 if (bufsize <= 1)
0720 break;
0721 printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
0722 index, spk_msg_get(cursor));
0723 buf_pointer += printed;
0724 bufsize -= printed;
0725 }
0726
0727 return buf_pointer - buf;
0728 }
0729
0730 static void report_msg_status(int reset, int received, int used,
0731 int rejected, char *groupname)
0732 {
0733 int len;
0734 char buf[160];
0735
0736 if (reset) {
0737 pr_info("i18n messages from group %s reset to defaults\n",
0738 groupname);
0739 } else if (received) {
0740 len = snprintf(buf, sizeof(buf),
0741 " updated %d of %d i18n messages from group %s\n",
0742 used, received, groupname);
0743 if (rejected)
0744 snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
0745 " with %d reject%s\n",
0746 rejected, rejected > 1 ? "s" : "");
0747 pr_info("%s", buf);
0748 }
0749 }
0750
0751 static ssize_t message_store_helper(const char *buf, size_t count,
0752 struct msg_group_t *group)
0753 {
0754 char *cp = (char *)buf;
0755 char *end = cp + count;
0756 char *linefeed = NULL;
0757 char *temp = NULL;
0758 ssize_t msg_stored = 0;
0759 ssize_t retval = count;
0760 size_t desc_length = 0;
0761 unsigned long index = 0;
0762 int received = 0;
0763 int used = 0;
0764 int rejected = 0;
0765 int reset = 0;
0766 enum msg_index_t firstmessage = group->start;
0767 enum msg_index_t lastmessage = group->end;
0768 enum msg_index_t curmessage;
0769
0770 while (cp < end) {
0771 while ((cp < end) && (*cp == ' ' || *cp == '\t'))
0772 cp++;
0773
0774 if (cp == end)
0775 break;
0776 if (strchr("dDrR", *cp)) {
0777 reset = 1;
0778 break;
0779 }
0780 received++;
0781
0782 linefeed = strchr(cp, '\n');
0783 if (!linefeed) {
0784 rejected++;
0785 break;
0786 }
0787
0788 if (!isdigit(*cp)) {
0789 rejected++;
0790 cp = linefeed + 1;
0791 continue;
0792 }
0793
0794
0795
0796
0797
0798 index = simple_strtoul(cp, &temp, 10);
0799
0800 while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
0801 temp++;
0802
0803 desc_length = linefeed - temp;
0804 curmessage = firstmessage + index;
0805
0806
0807
0808
0809
0810
0811
0812
0813 if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
0814 rejected++;
0815 cp = linefeed + 1;
0816 continue;
0817 }
0818
0819 msg_stored = spk_msg_set(curmessage, temp, desc_length);
0820 if (msg_stored < 0) {
0821 retval = msg_stored;
0822 if (msg_stored == -ENOMEM)
0823 reset = 1;
0824 break;
0825 }
0826
0827 used++;
0828
0829 cp = linefeed + 1;
0830 }
0831
0832 if (reset)
0833 spk_reset_msg_group(group);
0834
0835 report_msg_status(reset, received, used, rejected, group->name);
0836 return retval;
0837 }
0838
0839 static ssize_t message_show(struct kobject *kobj,
0840 struct kobj_attribute *attr, char *buf)
0841 {
0842 ssize_t retval = 0;
0843 struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
0844 unsigned long flags;
0845
0846 if (WARN_ON(!group))
0847 return -EINVAL;
0848
0849 spin_lock_irqsave(&speakup_info.spinlock, flags);
0850 retval = message_show_helper(buf, group->start, group->end);
0851 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
0852 return retval;
0853 }
0854
0855 static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
0856 const char *buf, size_t count)
0857 {
0858 struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
0859
0860 if (WARN_ON(!group))
0861 return -EINVAL;
0862
0863 return message_store_helper(buf, count, group);
0864 }
0865
0866
0867
0868
0869 static struct kobj_attribute keymap_attribute =
0870 __ATTR_RW(keymap);
0871 static struct kobj_attribute silent_attribute =
0872 __ATTR_WO(silent);
0873 static struct kobj_attribute synth_attribute =
0874 __ATTR_RW(synth);
0875 static struct kobj_attribute synth_direct_attribute =
0876 __ATTR_WO(synth_direct);
0877 static struct kobj_attribute version_attribute =
0878 __ATTR_RO(version);
0879
0880 static struct kobj_attribute delimiters_attribute =
0881 __ATTR(delimiters, 0644, punc_show, punc_store);
0882 static struct kobj_attribute ex_num_attribute =
0883 __ATTR(ex_num, 0644, punc_show, punc_store);
0884 static struct kobj_attribute punc_all_attribute =
0885 __ATTR(punc_all, 0644, punc_show, punc_store);
0886 static struct kobj_attribute punc_most_attribute =
0887 __ATTR(punc_most, 0644, punc_show, punc_store);
0888 static struct kobj_attribute punc_some_attribute =
0889 __ATTR(punc_some, 0644, punc_show, punc_store);
0890 static struct kobj_attribute repeats_attribute =
0891 __ATTR(repeats, 0644, punc_show, punc_store);
0892
0893 static struct kobj_attribute attrib_bleep_attribute =
0894 __ATTR(attrib_bleep, 0644, spk_var_show, spk_var_store);
0895 static struct kobj_attribute bell_pos_attribute =
0896 __ATTR(bell_pos, 0644, spk_var_show, spk_var_store);
0897 static struct kobj_attribute bleep_time_attribute =
0898 __ATTR(bleep_time, 0644, spk_var_show, spk_var_store);
0899 static struct kobj_attribute bleeps_attribute =
0900 __ATTR(bleeps, 0644, spk_var_show, spk_var_store);
0901 static struct kobj_attribute cursor_time_attribute =
0902 __ATTR(cursor_time, 0644, spk_var_show, spk_var_store);
0903 static struct kobj_attribute key_echo_attribute =
0904 __ATTR(key_echo, 0644, spk_var_show, spk_var_store);
0905 static struct kobj_attribute no_interrupt_attribute =
0906 __ATTR(no_interrupt, 0644, spk_var_show, spk_var_store);
0907 static struct kobj_attribute punc_level_attribute =
0908 __ATTR(punc_level, 0644, spk_var_show, spk_var_store);
0909 static struct kobj_attribute reading_punc_attribute =
0910 __ATTR(reading_punc, 0644, spk_var_show, spk_var_store);
0911 static struct kobj_attribute say_control_attribute =
0912 __ATTR(say_control, 0644, spk_var_show, spk_var_store);
0913 static struct kobj_attribute say_word_ctl_attribute =
0914 __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store);
0915 static struct kobj_attribute spell_delay_attribute =
0916 __ATTR(spell_delay, 0644, spk_var_show, spk_var_store);
0917
0918
0919
0920
0921 static struct kobj_attribute announcements_attribute =
0922 __ATTR(announcements, 0644, message_show, message_store);
0923 static struct kobj_attribute characters_attribute =
0924 __ATTR(characters, 0644, chars_chartab_show,
0925 chars_chartab_store);
0926 static struct kobj_attribute chartab_attribute =
0927 __ATTR(chartab, 0644, chars_chartab_show,
0928 chars_chartab_store);
0929 static struct kobj_attribute ctl_keys_attribute =
0930 __ATTR(ctl_keys, 0644, message_show, message_store);
0931 static struct kobj_attribute colors_attribute =
0932 __ATTR(colors, 0644, message_show, message_store);
0933 static struct kobj_attribute formatted_attribute =
0934 __ATTR(formatted, 0644, message_show, message_store);
0935 static struct kobj_attribute function_names_attribute =
0936 __ATTR(function_names, 0644, message_show, message_store);
0937 static struct kobj_attribute key_names_attribute =
0938 __ATTR(key_names, 0644, message_show, message_store);
0939 static struct kobj_attribute states_attribute =
0940 __ATTR(states, 0644, message_show, message_store);
0941
0942
0943
0944
0945
0946 static struct attribute *main_attrs[] = {
0947 &keymap_attribute.attr,
0948 &silent_attribute.attr,
0949 &synth_attribute.attr,
0950 &synth_direct_attribute.attr,
0951 &version_attribute.attr,
0952 &delimiters_attribute.attr,
0953 &ex_num_attribute.attr,
0954 &punc_all_attribute.attr,
0955 &punc_most_attribute.attr,
0956 &punc_some_attribute.attr,
0957 &repeats_attribute.attr,
0958 &attrib_bleep_attribute.attr,
0959 &bell_pos_attribute.attr,
0960 &bleep_time_attribute.attr,
0961 &bleeps_attribute.attr,
0962 &cursor_time_attribute.attr,
0963 &key_echo_attribute.attr,
0964 &no_interrupt_attribute.attr,
0965 &punc_level_attribute.attr,
0966 &reading_punc_attribute.attr,
0967 &say_control_attribute.attr,
0968 &say_word_ctl_attribute.attr,
0969 &spell_delay_attribute.attr,
0970 NULL,
0971 };
0972
0973 static struct attribute *i18n_attrs[] = {
0974 &announcements_attribute.attr,
0975 &characters_attribute.attr,
0976 &chartab_attribute.attr,
0977 &ctl_keys_attribute.attr,
0978 &colors_attribute.attr,
0979 &formatted_attribute.attr,
0980 &function_names_attribute.attr,
0981 &key_names_attribute.attr,
0982 &states_attribute.attr,
0983 NULL,
0984 };
0985
0986
0987
0988
0989
0990
0991
0992 static const struct attribute_group main_attr_group = {
0993 .attrs = main_attrs,
0994 };
0995
0996 static const struct attribute_group i18n_attr_group = {
0997 .attrs = i18n_attrs,
0998 .name = "i18n",
0999 };
1000
1001 static struct kobject *accessibility_kobj;
1002 struct kobject *speakup_kobj;
1003
1004 int speakup_kobj_init(void)
1005 {
1006 int retval;
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 accessibility_kobj = kobject_create_and_add("accessibility", NULL);
1018 if (!accessibility_kobj) {
1019 retval = -ENOMEM;
1020 goto out;
1021 }
1022
1023 speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
1024 if (!speakup_kobj) {
1025 retval = -ENOMEM;
1026 goto err_acc;
1027 }
1028
1029
1030 retval = sysfs_create_group(speakup_kobj, &main_attr_group);
1031 if (retval)
1032 goto err_speakup;
1033
1034 retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
1035 if (retval)
1036 goto err_group;
1037
1038 goto out;
1039
1040 err_group:
1041 sysfs_remove_group(speakup_kobj, &main_attr_group);
1042 err_speakup:
1043 kobject_put(speakup_kobj);
1044 err_acc:
1045 kobject_put(accessibility_kobj);
1046 out:
1047 return retval;
1048 }
1049
1050 void speakup_kobj_exit(void)
1051 {
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);
1056 }