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