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