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