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