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