Linux Audio

Check our new training course

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