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