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