at v4.13 1047 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, 110 const char *buf, size_t count) 111{ 112 char *cp = (char *)buf; 113 char *end = cp + count; /* the null at the end of the buffer */ 114 char *linefeed = NULL; 115 char keyword[MAX_DESC_LEN + 1]; 116 char *outptr = NULL; /* Will hold keyword or desc. */ 117 char *temp = NULL; 118 char *desc = NULL; 119 ssize_t retval = count; 120 unsigned long flags; 121 unsigned long index = 0; 122 int charclass = 0; 123 int received = 0; 124 int used = 0; 125 int rejected = 0; 126 int reset = 0; 127 int do_characters = !strcmp(attr->attr.name, "characters"); 128 size_t desc_length = 0; 129 int i; 130 131 spin_lock_irqsave(&speakup_info.spinlock, flags); 132 while (cp < end) { 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 && !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, 409 const char *buf, size_t count) 410{ 411 u_char tmp[256]; 412 int len; 413 int bytes; 414 const char *ptr = buf; 415 unsigned long flags; 416 417 if (!synth) 418 return -EPERM; 419 420 len = strlen(buf); 421 spin_lock_irqsave(&speakup_info.spinlock, flags); 422 while (len > 0) { 423 bytes = min_t(size_t, len, 250); 424 strncpy(tmp, ptr, bytes); 425 tmp[bytes] = '\0'; 426 string_unescape_any_inplace(tmp); 427 synth_printf("%s", tmp); 428 ptr += bytes; 429 len -= bytes; 430 } 431 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 432 return count; 433} 434 435/* 436 * This function is called when a user reads the version. 437 */ 438static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr, 439 char *buf) 440{ 441 char *cp; 442 443 cp = buf; 444 cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION); 445 if (synth) 446 cp += sprintf(cp, "%s synthesizer driver version %s\n", 447 synth->name, synth->version); 448 return cp - buf; 449} 450 451/* 452 * This is called when a user reads the punctuation settings. 453 */ 454static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr, 455 char *buf) 456{ 457 int i; 458 char *cp = buf; 459 struct st_var_header *p_header; 460 struct punc_var_t *var; 461 struct st_bits_data *pb; 462 short mask; 463 unsigned long flags; 464 465 p_header = spk_var_header_by_name(attr->attr.name); 466 if (!p_header) { 467 pr_warn("p_header is null, attr->attr.name is %s\n", 468 attr->attr.name); 469 return -EINVAL; 470 } 471 472 var = spk_get_punc_var(p_header->var_id); 473 if (!var) { 474 pr_warn("var is null, p_header->var_id is %i\n", 475 p_header->var_id); 476 return -EINVAL; 477 } 478 479 spin_lock_irqsave(&speakup_info.spinlock, flags); 480 pb = (struct st_bits_data *)&spk_punc_info[var->value]; 481 mask = pb->mask; 482 for (i = 33; i < 128; i++) { 483 if (!(spk_chartab[i] & mask)) 484 continue; 485 *cp++ = (char)i; 486 } 487 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 488 return cp - buf; 489} 490 491/* 492 * This is called when a user changes the punctuation settings. 493 */ 494static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr, 495 const char *buf, size_t count) 496{ 497 int x; 498 struct st_var_header *p_header; 499 struct punc_var_t *var; 500 char punc_buf[100]; 501 unsigned long flags; 502 503 x = strlen(buf); 504 if (x < 1 || x > 99) 505 return -EINVAL; 506 507 p_header = spk_var_header_by_name(attr->attr.name); 508 if (!p_header) { 509 pr_warn("p_header is null, attr->attr.name is %s\n", 510 attr->attr.name); 511 return -EINVAL; 512 } 513 514 var = spk_get_punc_var(p_header->var_id); 515 if (!var) { 516 pr_warn("var is null, p_header->var_id is %i\n", 517 p_header->var_id); 518 return -EINVAL; 519 } 520 521 strncpy(punc_buf, buf, x); 522 523 while (x && punc_buf[x - 1] == '\n') 524 x--; 525 punc_buf[x] = '\0'; 526 527 spin_lock_irqsave(&speakup_info.spinlock, flags); 528 529 if (*punc_buf == 'd' || *punc_buf == 'r') 530 x = spk_set_mask_bits(NULL, var->value, 3); 531 else 532 x = spk_set_mask_bits(punc_buf, var->value, 3); 533 534 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 535 return count; 536} 537 538/* 539 * This function is called when a user reads one of the variable parameters. 540 */ 541ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr, 542 char *buf) 543{ 544 int rv = 0; 545 struct st_var_header *param; 546 struct var_t *var; 547 char *cp1; 548 char *cp; 549 char ch; 550 unsigned long flags; 551 552 param = spk_var_header_by_name(attr->attr.name); 553 if (!param) 554 return -EINVAL; 555 556 spin_lock_irqsave(&speakup_info.spinlock, flags); 557 var = (struct var_t *)param->data; 558 switch (param->var_type) { 559 case VAR_NUM: 560 case VAR_TIME: 561 if (var) 562 rv = sprintf(buf, "%i\n", var->u.n.value); 563 else 564 rv = sprintf(buf, "0\n"); 565 break; 566 case VAR_STRING: 567 if (var) { 568 cp1 = buf; 569 *cp1++ = '"'; 570 for (cp = (char *)param->p_val; (ch = *cp); cp++) { 571 if (ch >= ' ' && ch < '~') 572 *cp1++ = ch; 573 else 574 cp1 += sprintf(cp1, "\\x%02x", ch); 575 } 576 *cp1++ = '"'; 577 *cp1++ = '\n'; 578 *cp1 = '\0'; 579 rv = cp1 - buf; 580 } else { 581 rv = sprintf(buf, "\"\"\n"); 582 } 583 break; 584 default: 585 rv = sprintf(buf, "Bad parameter %s, type %i\n", 586 param->name, param->var_type); 587 break; 588 } 589 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 590 return rv; 591} 592EXPORT_SYMBOL_GPL(spk_var_show); 593 594/* 595 * Used to reset either default_pitch or default_vol. 596 */ 597static inline void spk_reset_default_value(char *header_name, 598 int *synth_default_value, int idx) 599{ 600 struct st_var_header *param; 601 602 if (synth && synth_default_value) { 603 param = spk_var_header_by_name(header_name); 604 if (param) { 605 spk_set_num_var(synth_default_value[idx], 606 param, E_NEW_DEFAULT); 607 spk_set_num_var(0, param, E_DEFAULT); 608 pr_info("%s reset to default value\n", param->name); 609 } 610 } 611} 612 613/* 614 * This function is called when a user echos a value to one of the 615 * variable parameters. 616 */ 617ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr, 618 const char *buf, size_t count) 619{ 620 struct st_var_header *param; 621 int ret; 622 int len; 623 char *cp; 624 struct var_t *var_data; 625 long value; 626 unsigned long flags; 627 628 param = spk_var_header_by_name(attr->attr.name); 629 if (!param) 630 return -EINVAL; 631 if (!param->data) 632 return 0; 633 ret = 0; 634 cp = (char *)buf; 635 string_unescape_any_inplace(cp); 636 637 spin_lock_irqsave(&speakup_info.spinlock, flags); 638 switch (param->var_type) { 639 case VAR_NUM: 640 case VAR_TIME: 641 if (*cp == 'd' || *cp == 'r' || *cp == '\0') 642 len = E_DEFAULT; 643 else if (*cp == '+' || *cp == '-') 644 len = E_INC; 645 else 646 len = E_SET; 647 if (kstrtol(cp, 10, &value) == 0) 648 ret = spk_set_num_var(value, param, len); 649 else 650 pr_warn("overflow or parsing error has occurred"); 651 if (ret == -ERANGE) { 652 var_data = param->data; 653 pr_warn("value for %s out of range, expect %d to %d\n", 654 param->name, 655 var_data->u.n.low, var_data->u.n.high); 656 } 657 658 /* 659 * If voice was just changed, we might need to reset our default 660 * pitch and volume. 661 */ 662 if (param->var_id == VOICE && synth && 663 (ret == 0 || ret == -ERESTART)) { 664 var_data = param->data; 665 value = var_data->u.n.value; 666 spk_reset_default_value("pitch", synth->default_pitch, 667 value); 668 spk_reset_default_value("vol", synth->default_vol, 669 value); 670 } 671 break; 672 case VAR_STRING: 673 len = strlen(cp); 674 if ((len >= 1) && (cp[len - 1] == '\n')) 675 --len; 676 if ((len >= 2) && (cp[0] == '"') && (cp[len - 1] == '"')) { 677 ++cp; 678 len -= 2; 679 } 680 cp[len] = '\0'; 681 ret = spk_set_string_var(cp, param, len); 682 if (ret == -E2BIG) 683 pr_warn("value too long for %s\n", 684 param->name); 685 break; 686 default: 687 pr_warn("%s unknown type %d\n", 688 param->name, (int)param->var_type); 689 break; 690 } 691 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 692 693 if (ret == -ERESTART) 694 pr_info("%s reset to default value\n", param->name); 695 return count; 696} 697EXPORT_SYMBOL_GPL(spk_var_store); 698 699/* 700 * Functions for reading and writing lists of i18n messages. Incomplete. 701 */ 702 703static ssize_t message_show_helper(char *buf, enum msg_index_t first, 704 enum msg_index_t last) 705{ 706 size_t bufsize = PAGE_SIZE; 707 char *buf_pointer = buf; 708 int printed; 709 enum msg_index_t cursor; 710 int index = 0; 711 *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */ 712 713 for (cursor = first; cursor <= last; cursor++, index++) { 714 if (bufsize <= 1) 715 break; 716 printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n", 717 index, spk_msg_get(cursor)); 718 buf_pointer += printed; 719 bufsize -= printed; 720 } 721 722 return buf_pointer - buf; 723} 724 725static void report_msg_status(int reset, int received, int used, 726 int rejected, char *groupname) 727{ 728 int len; 729 char buf[160]; 730 731 if (reset) { 732 pr_info("i18n messages from group %s reset to defaults\n", 733 groupname); 734 } else if (received) { 735 len = snprintf(buf, sizeof(buf), 736 " updated %d of %d i18n messages from group %s\n", 737 used, received, groupname); 738 if (rejected) 739 snprintf(buf + (len - 1), sizeof(buf) - (len - 1), 740 " with %d reject%s\n", 741 rejected, rejected > 1 ? "s" : ""); 742 printk(buf); 743 } 744} 745 746static ssize_t message_store_helper(const char *buf, size_t count, 747 struct msg_group_t *group) 748{ 749 char *cp = (char *)buf; 750 char *end = cp + count; 751 char *linefeed = NULL; 752 char *temp = NULL; 753 ssize_t msg_stored = 0; 754 ssize_t retval = count; 755 size_t desc_length = 0; 756 unsigned long index = 0; 757 int received = 0; 758 int used = 0; 759 int rejected = 0; 760 int reset = 0; 761 enum msg_index_t firstmessage = group->start; 762 enum msg_index_t lastmessage = group->end; 763 enum msg_index_t curmessage; 764 765 while (cp < end) { 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 if (WARN_ON(!group)) 838 return -EINVAL; 839 840 spin_lock_irqsave(&speakup_info.spinlock, flags); 841 retval = message_show_helper(buf, group->start, group->end); 842 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 843 return retval; 844} 845 846static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr, 847 const char *buf, size_t count) 848{ 849 struct msg_group_t *group = spk_find_msg_group(attr->attr.name); 850 851 if (WARN_ON(!group)) 852 return -EINVAL; 853 854 return message_store_helper(buf, count, group); 855} 856 857/* 858 * Declare the attributes. 859 */ 860static struct kobj_attribute keymap_attribute = 861 __ATTR_RW(keymap); 862static struct kobj_attribute silent_attribute = 863 __ATTR_WO(silent); 864static struct kobj_attribute synth_attribute = 865 __ATTR_RW(synth); 866static struct kobj_attribute synth_direct_attribute = 867 __ATTR_WO(synth_direct); 868static struct kobj_attribute version_attribute = 869 __ATTR_RO(version); 870 871static struct kobj_attribute delimiters_attribute = 872 __ATTR(delimiters, 0644, punc_show, punc_store); 873static struct kobj_attribute ex_num_attribute = 874 __ATTR(ex_num, 0644, punc_show, punc_store); 875static struct kobj_attribute punc_all_attribute = 876 __ATTR(punc_all, 0644, punc_show, punc_store); 877static struct kobj_attribute punc_most_attribute = 878 __ATTR(punc_most, 0644, punc_show, punc_store); 879static struct kobj_attribute punc_some_attribute = 880 __ATTR(punc_some, 0644, punc_show, punc_store); 881static struct kobj_attribute repeats_attribute = 882 __ATTR(repeats, 0644, punc_show, punc_store); 883 884static struct kobj_attribute attrib_bleep_attribute = 885 __ATTR(attrib_bleep, 0644, spk_var_show, spk_var_store); 886static struct kobj_attribute bell_pos_attribute = 887 __ATTR(bell_pos, 0644, spk_var_show, spk_var_store); 888static struct kobj_attribute bleep_time_attribute = 889 __ATTR(bleep_time, 0644, spk_var_show, spk_var_store); 890static struct kobj_attribute bleeps_attribute = 891 __ATTR(bleeps, 0644, spk_var_show, spk_var_store); 892static struct kobj_attribute cursor_time_attribute = 893 __ATTR(cursor_time, 0644, spk_var_show, spk_var_store); 894static struct kobj_attribute key_echo_attribute = 895 __ATTR(key_echo, 0644, spk_var_show, spk_var_store); 896static struct kobj_attribute no_interrupt_attribute = 897 __ATTR(no_interrupt, 0644, spk_var_show, spk_var_store); 898static struct kobj_attribute punc_level_attribute = 899 __ATTR(punc_level, 0644, spk_var_show, spk_var_store); 900static struct kobj_attribute reading_punc_attribute = 901 __ATTR(reading_punc, 0644, spk_var_show, spk_var_store); 902static struct kobj_attribute say_control_attribute = 903 __ATTR(say_control, 0644, spk_var_show, spk_var_store); 904static struct kobj_attribute say_word_ctl_attribute = 905 __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store); 906static struct kobj_attribute spell_delay_attribute = 907 __ATTR(spell_delay, 0644, spk_var_show, spk_var_store); 908 909/* 910 * These attributes are i18n related. 911 */ 912static struct kobj_attribute announcements_attribute = 913 __ATTR(announcements, 0644, message_show, message_store); 914static struct kobj_attribute characters_attribute = 915 __ATTR(characters, 0644, chars_chartab_show, 916 chars_chartab_store); 917static struct kobj_attribute chartab_attribute = 918 __ATTR(chartab, 0644, chars_chartab_show, 919 chars_chartab_store); 920static struct kobj_attribute ctl_keys_attribute = 921 __ATTR(ctl_keys, 0644, message_show, message_store); 922static struct kobj_attribute colors_attribute = 923 __ATTR(colors, 0644, message_show, message_store); 924static struct kobj_attribute formatted_attribute = 925 __ATTR(formatted, 0644, message_show, message_store); 926static struct kobj_attribute function_names_attribute = 927 __ATTR(function_names, 0644, message_show, message_store); 928static struct kobj_attribute key_names_attribute = 929 __ATTR(key_names, 0644, message_show, message_store); 930static struct kobj_attribute states_attribute = 931 __ATTR(states, 0644, message_show, message_store); 932 933/* 934 * Create groups of attributes so that we can create and destroy them all 935 * at once. 936 */ 937static struct attribute *main_attrs[] = { 938 &keymap_attribute.attr, 939 &silent_attribute.attr, 940 &synth_attribute.attr, 941 &synth_direct_attribute.attr, 942 &version_attribute.attr, 943 &delimiters_attribute.attr, 944 &ex_num_attribute.attr, 945 &punc_all_attribute.attr, 946 &punc_most_attribute.attr, 947 &punc_some_attribute.attr, 948 &repeats_attribute.attr, 949 &attrib_bleep_attribute.attr, 950 &bell_pos_attribute.attr, 951 &bleep_time_attribute.attr, 952 &bleeps_attribute.attr, 953 &cursor_time_attribute.attr, 954 &key_echo_attribute.attr, 955 &no_interrupt_attribute.attr, 956 &punc_level_attribute.attr, 957 &reading_punc_attribute.attr, 958 &say_control_attribute.attr, 959 &say_word_ctl_attribute.attr, 960 &spell_delay_attribute.attr, 961 NULL, 962}; 963 964static struct attribute *i18n_attrs[] = { 965 &announcements_attribute.attr, 966 &characters_attribute.attr, 967 &chartab_attribute.attr, 968 &ctl_keys_attribute.attr, 969 &colors_attribute.attr, 970 &formatted_attribute.attr, 971 &function_names_attribute.attr, 972 &key_names_attribute.attr, 973 &states_attribute.attr, 974 NULL, 975}; 976 977/* 978 * An unnamed attribute group will put all of the attributes directly in 979 * the kobject directory. If we specify a name, a subdirectory will be 980 * created for the attributes with the directory being the name of the 981 * attribute group. 982 */ 983static const struct attribute_group main_attr_group = { 984 .attrs = main_attrs, 985}; 986 987static const struct attribute_group i18n_attr_group = { 988 .attrs = i18n_attrs, 989 .name = "i18n", 990}; 991 992static struct kobject *accessibility_kobj; 993struct kobject *speakup_kobj; 994 995int speakup_kobj_init(void) 996{ 997 int retval; 998 999 /* 1000 * Create a simple kobject with the name of "accessibility", 1001 * located under /sys/ 1002 * 1003 * As this is a simple directory, no uevent will be sent to 1004 * userspace. That is why this function should not be used for 1005 * any type of dynamic kobjects, where the name and number are 1006 * not known ahead of time. 1007 */ 1008 accessibility_kobj = kobject_create_and_add("accessibility", NULL); 1009 if (!accessibility_kobj) { 1010 retval = -ENOMEM; 1011 goto out; 1012 } 1013 1014 speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj); 1015 if (!speakup_kobj) { 1016 retval = -ENOMEM; 1017 goto err_acc; 1018 } 1019 1020 /* Create the files associated with this kobject */ 1021 retval = sysfs_create_group(speakup_kobj, &main_attr_group); 1022 if (retval) 1023 goto err_speakup; 1024 1025 retval = sysfs_create_group(speakup_kobj, &i18n_attr_group); 1026 if (retval) 1027 goto err_group; 1028 1029 goto out; 1030 1031err_group: 1032 sysfs_remove_group(speakup_kobj, &main_attr_group); 1033err_speakup: 1034 kobject_put(speakup_kobj); 1035err_acc: 1036 kobject_put(accessibility_kobj); 1037out: 1038 return retval; 1039} 1040 1041void speakup_kobj_exit(void) 1042{ 1043 sysfs_remove_group(speakup_kobj, &i18n_attr_group); 1044 sysfs_remove_group(speakup_kobj, &main_attr_group); 1045 kobject_put(speakup_kobj); 1046 kobject_put(accessibility_kobj); 1047}