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