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