main.c 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411
  1. /* speakup.c
  2. * review functions for the speakup screen review package.
  3. * originally written by: Kirk Reiser and Andy Berdan.
  4. *
  5. * extensively modified by David Borowski.
  6. *
  7. ** Copyright (C) 1998 Kirk Reiser.
  8. * Copyright (C) 2003 David Borowski.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. #include <linux/kernel.h>
  25. #include <linux/vt.h>
  26. #include <linux/tty.h>
  27. #include <linux/mm.h> /* __get_free_page() and friends */
  28. #include <linux/vt_kern.h>
  29. #include <linux/ctype.h>
  30. #include <linux/selection.h>
  31. #include <linux/unistd.h>
  32. #include <linux/jiffies.h>
  33. #include <linux/kthread.h>
  34. #include <linux/keyboard.h> /* for KT_SHIFT */
  35. #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
  36. #include <linux/input.h>
  37. #include <linux/kmod.h>
  38. /* speakup_*_selection */
  39. #include <linux/module.h>
  40. #include <linux/sched.h>
  41. #include <linux/slab.h>
  42. #include <linux/types.h>
  43. #include <linux/consolemap.h>
  44. #include <linux/spinlock.h>
  45. #include <linux/notifier.h>
  46. #include <linux/uaccess.h> /* copy_from|to|user() and others */
  47. #include "spk_priv.h"
  48. #include "speakup.h"
  49. #define MAX_DELAY msecs_to_jiffies(500)
  50. #define MINECHOCHAR SPACE
  51. MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
  52. MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
  53. MODULE_DESCRIPTION("Speakup console speech");
  54. MODULE_LICENSE("GPL");
  55. MODULE_VERSION(SPEAKUP_VERSION);
  56. char *synth_name;
  57. module_param_named(synth, synth_name, charp, S_IRUGO);
  58. module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
  59. MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
  60. MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
  61. special_func spk_special_handler;
  62. short spk_pitch_shift, synth_flags;
  63. static char buf[256];
  64. int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
  65. int spk_no_intr, spk_spell_delay;
  66. int spk_key_echo, spk_say_word_ctl;
  67. int spk_say_ctrl, spk_bell_pos;
  68. short spk_punc_mask;
  69. int spk_punc_level, spk_reading_punc;
  70. char spk_str_caps_start[MAXVARLEN + 1] = "\0";
  71. char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
  72. const struct st_bits_data spk_punc_info[] = {
  73. {"none", "", 0},
  74. {"some", "/$%&@", SOME},
  75. {"most", "$%&#()=+*/@^<>|\\", MOST},
  76. {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
  77. {"delimiters", "", B_WDLM},
  78. {"repeats", "()", CH_RPT},
  79. {"extended numeric", "", B_EXNUM},
  80. {"symbols", "", B_SYM},
  81. {NULL, NULL}
  82. };
  83. static char mark_cut_flag;
  84. #define MAX_KEY 160
  85. static u_char *spk_shift_table;
  86. u_char *spk_our_keys[MAX_KEY];
  87. u_char spk_key_buf[600];
  88. const u_char spk_key_defaults[] = {
  89. #include "speakupmap.h"
  90. };
  91. /* Speakup Cursor Track Variables */
  92. static int cursor_track = 1, prev_cursor_track = 1;
  93. /* cursor track modes, must be ordered same as cursor_msgs */
  94. enum {
  95. CT_Off = 0,
  96. CT_On,
  97. CT_Highlight,
  98. CT_Window,
  99. CT_Max
  100. };
  101. #define read_all_mode CT_Max
  102. static struct tty_struct *tty;
  103. static void spkup_write(const char *in_buf, int count);
  104. static char *phonetic[] = {
  105. "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
  106. "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
  107. "papa",
  108. "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
  109. "x ray", "yankee", "zulu"
  110. };
  111. /* array of 256 char pointers (one for each character description)
  112. * initialized to default_chars and user selectable via
  113. * /proc/speakup/characters
  114. */
  115. char *spk_characters[256];
  116. char *spk_default_chars[256] = {
  117. /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
  118. /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
  119. /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
  120. /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
  121. "control",
  122. /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
  123. "tick",
  124. /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
  125. "dot",
  126. "slash",
  127. /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
  128. "eight", "nine",
  129. /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
  130. /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
  131. /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
  132. /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
  133. /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
  134. "caret",
  135. "line",
  136. /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
  137. /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
  138. /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
  139. /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
  140. /*127*/ "del", "control", "control", "control", "control", "control",
  141. "control", "control", "control", "control", "control",
  142. /*138*/ "control", "control", "control", "control", "control",
  143. "control", "control", "control", "control", "control",
  144. "control", "control",
  145. /*150*/ "control", "control", "control", "control", "control",
  146. "control", "control", "control", "control", "control",
  147. /*160*/ "nbsp", "inverted bang",
  148. /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
  149. /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
  150. /*172*/ "not", "soft hyphen", "registered", "macron",
  151. /*176*/ "degrees", "plus or minus", "super two", "super three",
  152. /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
  153. /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
  154. /*188*/ "one quarter", "one half", "three quarters",
  155. "inverted question",
  156. /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
  157. "A RING",
  158. /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
  159. "E OOMLAUT",
  160. /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
  161. "N TILDE",
  162. /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
  163. /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
  164. "U CIRCUMFLEX",
  165. /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
  166. /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
  167. /*230*/ "ae", "c cidella", "e grave", "e acute",
  168. /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
  169. "i circumflex",
  170. /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
  171. "o circumflex",
  172. /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
  173. "u acute",
  174. /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
  175. };
  176. /* array of 256 u_short (one for each character)
  177. * initialized to default_chartab and user selectable via
  178. * /sys/module/speakup/parameters/chartab
  179. */
  180. u_short spk_chartab[256];
  181. static u_short default_chartab[256] = {
  182. B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
  183. B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
  184. B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
  185. B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
  186. WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
  187. PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
  188. NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
  189. NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
  190. PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
  191. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
  192. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
  193. A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
  194. PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
  195. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
  196. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
  197. ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
  198. B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
  199. B_SYM, /* 135 */
  200. B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
  201. B_CAPSYM, /* 143 */
  202. B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
  203. B_SYM, /* 151 */
  204. B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
  205. B_SYM, /* 159 */
  206. WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
  207. B_SYM, /* 167 */
  208. B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
  209. B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
  210. B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
  211. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
  212. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
  213. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
  214. A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
  215. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
  216. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
  217. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
  218. ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
  219. };
  220. struct task_struct *speakup_task;
  221. struct bleep spk_unprocessed_sound;
  222. static int spk_keydown;
  223. static u_char spk_lastkey, spk_close_press, keymap_flags;
  224. static u_char last_keycode, this_speakup_key;
  225. static u_long last_spk_jiffy;
  226. struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
  227. DEFINE_MUTEX(spk_mutex);
  228. static int keyboard_notifier_call(struct notifier_block *,
  229. unsigned long code, void *param);
  230. static struct notifier_block keyboard_notifier_block = {
  231. .notifier_call = keyboard_notifier_call,
  232. };
  233. static int vt_notifier_call(struct notifier_block *,
  234. unsigned long code, void *param);
  235. static struct notifier_block vt_notifier_block = {
  236. .notifier_call = vt_notifier_call,
  237. };
  238. static unsigned char get_attributes(u16 *pos)
  239. {
  240. return (u_char) (scr_readw(pos) >> 8);
  241. }
  242. static void speakup_date(struct vc_data *vc)
  243. {
  244. spk_x = spk_cx = vc->vc_x;
  245. spk_y = spk_cy = vc->vc_y;
  246. spk_pos = spk_cp = vc->vc_pos;
  247. spk_old_attr = spk_attr;
  248. spk_attr = get_attributes((u_short *) spk_pos);
  249. }
  250. static void bleep(u_short val)
  251. {
  252. static const short vals[] = {
  253. 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
  254. };
  255. short freq;
  256. int time = spk_bleep_time;
  257. freq = vals[val % 12];
  258. if (val > 11)
  259. freq *= (1 << (val / 12));
  260. spk_unprocessed_sound.freq = freq;
  261. spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
  262. spk_unprocessed_sound.active = 1;
  263. /* We can only have 1 active sound at a time. */
  264. }
  265. static void speakup_shut_up(struct vc_data *vc)
  266. {
  267. if (spk_killed)
  268. return;
  269. spk_shut_up |= 0x01;
  270. spk_parked &= 0xfe;
  271. speakup_date(vc);
  272. if (synth != NULL)
  273. spk_do_flush();
  274. }
  275. static void speech_kill(struct vc_data *vc)
  276. {
  277. char val = synth->is_alive(synth);
  278. if (val == 0)
  279. return;
  280. /* re-enables synth, if disabled */
  281. if (val == 2 || spk_killed) {
  282. /* dead */
  283. spk_shut_up &= ~0x40;
  284. synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
  285. } else {
  286. synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
  287. spk_shut_up |= 0x40;
  288. }
  289. }
  290. static void speakup_off(struct vc_data *vc)
  291. {
  292. if (spk_shut_up & 0x80) {
  293. spk_shut_up &= 0x7f;
  294. synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
  295. } else {
  296. spk_shut_up |= 0x80;
  297. synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
  298. }
  299. speakup_date(vc);
  300. }
  301. static void speakup_parked(struct vc_data *vc)
  302. {
  303. if (spk_parked & 0x80) {
  304. spk_parked = 0;
  305. synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
  306. } else {
  307. spk_parked |= 0x80;
  308. synth_printf("%s\n", spk_msg_get(MSG_PARKED));
  309. }
  310. }
  311. static void speakup_cut(struct vc_data *vc)
  312. {
  313. static const char err_buf[] = "set selection failed";
  314. int ret;
  315. if (!mark_cut_flag) {
  316. mark_cut_flag = 1;
  317. spk_xs = (u_short) spk_x;
  318. spk_ys = (u_short) spk_y;
  319. spk_sel_cons = vc;
  320. synth_printf("%s\n", spk_msg_get(MSG_MARK));
  321. return;
  322. }
  323. spk_xe = (u_short) spk_x;
  324. spk_ye = (u_short) spk_y;
  325. mark_cut_flag = 0;
  326. synth_printf("%s\n", spk_msg_get(MSG_CUT));
  327. speakup_clear_selection();
  328. ret = speakup_set_selection(tty);
  329. switch (ret) {
  330. case 0:
  331. break; /* no error */
  332. case -EFAULT:
  333. pr_warn("%sEFAULT\n", err_buf);
  334. break;
  335. case -EINVAL:
  336. pr_warn("%sEINVAL\n", err_buf);
  337. break;
  338. case -ENOMEM:
  339. pr_warn("%sENOMEM\n", err_buf);
  340. break;
  341. }
  342. }
  343. static void speakup_paste(struct vc_data *vc)
  344. {
  345. if (mark_cut_flag) {
  346. mark_cut_flag = 0;
  347. synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
  348. } else {
  349. synth_printf("%s\n", spk_msg_get(MSG_PASTE));
  350. speakup_paste_selection(tty);
  351. }
  352. }
  353. static void say_attributes(struct vc_data *vc)
  354. {
  355. int fg = spk_attr & 0x0f;
  356. int bg = spk_attr >> 4;
  357. if (fg > 8) {
  358. synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
  359. fg -= 8;
  360. }
  361. synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
  362. if (bg > 7) {
  363. synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
  364. bg -= 8;
  365. } else
  366. synth_printf(" %s ", spk_msg_get(MSG_ON));
  367. synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
  368. }
  369. enum {
  370. edge_top = 1,
  371. edge_bottom,
  372. edge_left,
  373. edge_right,
  374. edge_quiet
  375. };
  376. static void announce_edge(struct vc_data *vc, int msg_id)
  377. {
  378. if (spk_bleeps & 1)
  379. bleep(spk_y);
  380. if ((spk_bleeps & 2) && (msg_id < edge_quiet))
  381. synth_printf("%s\n",
  382. spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
  383. }
  384. static void speak_char(u_char ch)
  385. {
  386. char *cp = spk_characters[ch];
  387. struct var_t *direct = spk_get_var(DIRECT);
  388. if (direct && direct->u.n.value) {
  389. if (IS_CHAR(ch, B_CAP)) {
  390. spk_pitch_shift++;
  391. synth_printf("%s", spk_str_caps_start);
  392. }
  393. synth_printf("%c", ch);
  394. if (IS_CHAR(ch, B_CAP))
  395. synth_printf("%s", spk_str_caps_stop);
  396. return;
  397. }
  398. if (cp == NULL) {
  399. pr_info("speak_char: cp == NULL!\n");
  400. return;
  401. }
  402. synth_buffer_add(SPACE);
  403. if (IS_CHAR(ch, B_CAP)) {
  404. spk_pitch_shift++;
  405. synth_printf("%s", spk_str_caps_start);
  406. synth_printf("%s", cp);
  407. synth_printf("%s", spk_str_caps_stop);
  408. } else {
  409. if (*cp == '^') {
  410. synth_printf("%s", spk_msg_get(MSG_CTRL));
  411. cp++;
  412. }
  413. synth_printf("%s", cp);
  414. }
  415. synth_buffer_add(SPACE);
  416. }
  417. static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
  418. {
  419. u16 ch = ' ';
  420. if (vc && pos) {
  421. u16 w = scr_readw(pos);
  422. u16 c = w & 0xff;
  423. if (w & vc->vc_hi_font_mask)
  424. c |= 0x100;
  425. ch = inverse_translate(vc, c, 0);
  426. *attribs = (w & 0xff00) >> 8;
  427. }
  428. return ch;
  429. }
  430. static void say_char(struct vc_data *vc)
  431. {
  432. u_short ch;
  433. spk_old_attr = spk_attr;
  434. ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
  435. if (spk_attr != spk_old_attr) {
  436. if (spk_attrib_bleep & 1)
  437. bleep(spk_y);
  438. if (spk_attrib_bleep & 2)
  439. say_attributes(vc);
  440. }
  441. speak_char(ch & 0xff);
  442. }
  443. static void say_phonetic_char(struct vc_data *vc)
  444. {
  445. u_short ch;
  446. spk_old_attr = spk_attr;
  447. ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
  448. if (isascii(ch) && isalpha(ch)) {
  449. ch &= 0x1f;
  450. synth_printf("%s\n", phonetic[--ch]);
  451. } else {
  452. if (IS_CHAR(ch, B_NUM))
  453. synth_printf("%s ", spk_msg_get(MSG_NUMBER));
  454. speak_char(ch);
  455. }
  456. }
  457. static void say_prev_char(struct vc_data *vc)
  458. {
  459. spk_parked |= 0x01;
  460. if (spk_x == 0) {
  461. announce_edge(vc, edge_left);
  462. return;
  463. }
  464. spk_x--;
  465. spk_pos -= 2;
  466. say_char(vc);
  467. }
  468. static void say_next_char(struct vc_data *vc)
  469. {
  470. spk_parked |= 0x01;
  471. if (spk_x == vc->vc_cols - 1) {
  472. announce_edge(vc, edge_right);
  473. return;
  474. }
  475. spk_x++;
  476. spk_pos += 2;
  477. say_char(vc);
  478. }
  479. /* get_word - will first check to see if the character under the
  480. * reading cursor is a space and if spk_say_word_ctl is true it will
  481. * return the word space. If spk_say_word_ctl is not set it will check to
  482. * see if there is a word starting on the next position to the right
  483. * and return that word if it exists. If it does not exist it will
  484. * move left to the beginning of any previous word on the line or the
  485. * beginning off the line whichever comes first..
  486. */
  487. static u_long get_word(struct vc_data *vc)
  488. {
  489. u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
  490. char ch;
  491. u_short attr_ch;
  492. u_char temp;
  493. spk_old_attr = spk_attr;
  494. ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
  495. /* decided to take out the sayword if on a space (mis-information */
  496. if (spk_say_word_ctl && ch == SPACE) {
  497. *buf = '\0';
  498. synth_printf("%s\n", spk_msg_get(MSG_SPACE));
  499. return 0;
  500. } else if ((tmpx < vc->vc_cols - 2)
  501. && (ch == SPACE || ch == 0 || IS_WDLM(ch))
  502. && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
  503. SPACE)) {
  504. tmp_pos += 2;
  505. tmpx++;
  506. } else
  507. while (tmpx > 0) {
  508. ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
  509. if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
  510. && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
  511. SPACE))
  512. break;
  513. tmp_pos -= 2;
  514. tmpx--;
  515. }
  516. attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
  517. buf[cnt++] = attr_ch & 0xff;
  518. while (tmpx < vc->vc_cols - 1) {
  519. tmp_pos += 2;
  520. tmpx++;
  521. ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
  522. if ((ch == SPACE) || ch == 0
  523. || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
  524. break;
  525. buf[cnt++] = ch;
  526. }
  527. buf[cnt] = '\0';
  528. return cnt;
  529. }
  530. static void say_word(struct vc_data *vc)
  531. {
  532. u_long cnt = get_word(vc);
  533. u_short saved_punc_mask = spk_punc_mask;
  534. if (cnt == 0)
  535. return;
  536. spk_punc_mask = PUNC;
  537. buf[cnt++] = SPACE;
  538. spkup_write(buf, cnt);
  539. spk_punc_mask = saved_punc_mask;
  540. }
  541. static void say_prev_word(struct vc_data *vc)
  542. {
  543. u_char temp;
  544. char ch;
  545. u_short edge_said = 0, last_state = 0, state = 0;
  546. spk_parked |= 0x01;
  547. if (spk_x == 0) {
  548. if (spk_y == 0) {
  549. announce_edge(vc, edge_top);
  550. return;
  551. }
  552. spk_y--;
  553. spk_x = vc->vc_cols;
  554. edge_said = edge_quiet;
  555. }
  556. while (1) {
  557. if (spk_x == 0) {
  558. if (spk_y == 0) {
  559. edge_said = edge_top;
  560. break;
  561. }
  562. if (edge_said != edge_quiet)
  563. edge_said = edge_left;
  564. if (state > 0)
  565. break;
  566. spk_y--;
  567. spk_x = vc->vc_cols - 1;
  568. } else
  569. spk_x--;
  570. spk_pos -= 2;
  571. ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
  572. if (ch == SPACE || ch == 0)
  573. state = 0;
  574. else if (IS_WDLM(ch))
  575. state = 1;
  576. else
  577. state = 2;
  578. if (state < last_state) {
  579. spk_pos += 2;
  580. spk_x++;
  581. break;
  582. }
  583. last_state = state;
  584. }
  585. if (spk_x == 0 && edge_said == edge_quiet)
  586. edge_said = edge_left;
  587. if (edge_said > 0 && edge_said < edge_quiet)
  588. announce_edge(vc, edge_said);
  589. say_word(vc);
  590. }
  591. static void say_next_word(struct vc_data *vc)
  592. {
  593. u_char temp;
  594. char ch;
  595. u_short edge_said = 0, last_state = 2, state = 0;
  596. spk_parked |= 0x01;
  597. if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
  598. announce_edge(vc, edge_bottom);
  599. return;
  600. }
  601. while (1) {
  602. ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
  603. if (ch == SPACE || ch == 0)
  604. state = 0;
  605. else if (IS_WDLM(ch))
  606. state = 1;
  607. else
  608. state = 2;
  609. if (state > last_state)
  610. break;
  611. if (spk_x >= vc->vc_cols - 1) {
  612. if (spk_y == vc->vc_rows - 1) {
  613. edge_said = edge_bottom;
  614. break;
  615. }
  616. state = 0;
  617. spk_y++;
  618. spk_x = 0;
  619. edge_said = edge_right;
  620. } else
  621. spk_x++;
  622. spk_pos += 2;
  623. last_state = state;
  624. }
  625. if (edge_said > 0)
  626. announce_edge(vc, edge_said);
  627. say_word(vc);
  628. }
  629. static void spell_word(struct vc_data *vc)
  630. {
  631. static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
  632. char *cp = buf, *str_cap = spk_str_caps_stop;
  633. char *cp1, *last_cap = spk_str_caps_stop;
  634. u_char ch;
  635. if (!get_word(vc))
  636. return;
  637. while ((ch = (u_char) *cp)) {
  638. if (cp != buf)
  639. synth_printf(" %s ", delay_str[spk_spell_delay]);
  640. if (IS_CHAR(ch, B_CAP)) {
  641. str_cap = spk_str_caps_start;
  642. if (*spk_str_caps_stop)
  643. spk_pitch_shift++;
  644. else /* synth has no pitch */
  645. last_cap = spk_str_caps_stop;
  646. } else
  647. str_cap = spk_str_caps_stop;
  648. if (str_cap != last_cap) {
  649. synth_printf("%s", str_cap);
  650. last_cap = str_cap;
  651. }
  652. if (this_speakup_key == SPELL_PHONETIC
  653. && (isascii(ch) && isalpha(ch))) {
  654. ch &= 31;
  655. cp1 = phonetic[--ch];
  656. } else {
  657. cp1 = spk_characters[ch];
  658. if (*cp1 == '^') {
  659. synth_printf("%s", spk_msg_get(MSG_CTRL));
  660. cp1++;
  661. }
  662. }
  663. synth_printf("%s", cp1);
  664. cp++;
  665. }
  666. if (str_cap != spk_str_caps_stop)
  667. synth_printf("%s", spk_str_caps_stop);
  668. }
  669. static int get_line(struct vc_data *vc)
  670. {
  671. u_long tmp = spk_pos - (spk_x * 2);
  672. int i = 0;
  673. u_char tmp2;
  674. spk_old_attr = spk_attr;
  675. spk_attr = get_attributes((u_short *) spk_pos);
  676. for (i = 0; i < vc->vc_cols; i++) {
  677. buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
  678. tmp += 2;
  679. }
  680. for (--i; i >= 0; i--)
  681. if (buf[i] != SPACE)
  682. break;
  683. return ++i;
  684. }
  685. static void say_line(struct vc_data *vc)
  686. {
  687. int i = get_line(vc);
  688. char *cp;
  689. u_short saved_punc_mask = spk_punc_mask;
  690. if (i == 0) {
  691. synth_printf("%s\n", spk_msg_get(MSG_BLANK));
  692. return;
  693. }
  694. buf[i++] = '\n';
  695. if (this_speakup_key == SAY_LINE_INDENT) {
  696. cp = buf;
  697. while (*cp == SPACE)
  698. cp++;
  699. synth_printf("%d, ", (cp - buf) + 1);
  700. }
  701. spk_punc_mask = spk_punc_masks[spk_reading_punc];
  702. spkup_write(buf, i);
  703. spk_punc_mask = saved_punc_mask;
  704. }
  705. static void say_prev_line(struct vc_data *vc)
  706. {
  707. spk_parked |= 0x01;
  708. if (spk_y == 0) {
  709. announce_edge(vc, edge_top);
  710. return;
  711. }
  712. spk_y--;
  713. spk_pos -= vc->vc_size_row;
  714. say_line(vc);
  715. }
  716. static void say_next_line(struct vc_data *vc)
  717. {
  718. spk_parked |= 0x01;
  719. if (spk_y == vc->vc_rows - 1) {
  720. announce_edge(vc, edge_bottom);
  721. return;
  722. }
  723. spk_y++;
  724. spk_pos += vc->vc_size_row;
  725. say_line(vc);
  726. }
  727. static int say_from_to(struct vc_data *vc, u_long from, u_long to,
  728. int read_punc)
  729. {
  730. int i = 0;
  731. u_char tmp;
  732. u_short saved_punc_mask = spk_punc_mask;
  733. spk_old_attr = spk_attr;
  734. spk_attr = get_attributes((u_short *) from);
  735. while (from < to) {
  736. buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
  737. from += 2;
  738. if (i >= vc->vc_size_row)
  739. break;
  740. }
  741. for (--i; i >= 0; i--)
  742. if (buf[i] != SPACE)
  743. break;
  744. buf[++i] = SPACE;
  745. buf[++i] = '\0';
  746. if (i < 1)
  747. return i;
  748. if (read_punc)
  749. spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
  750. spkup_write(buf, i);
  751. if (read_punc)
  752. spk_punc_mask = saved_punc_mask;
  753. return i - 1;
  754. }
  755. static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
  756. int read_punc)
  757. {
  758. u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
  759. u_long end = start + (to * 2);
  760. start += from * 2;
  761. if (say_from_to(vc, start, end, read_punc) <= 0)
  762. if (cursor_track != read_all_mode)
  763. synth_printf("%s\n", spk_msg_get(MSG_BLANK));
  764. }
  765. /* Sentence Reading Commands */
  766. static int currsentence;
  767. static int numsentences[2];
  768. static char *sentbufend[2];
  769. static char *sentmarks[2][10];
  770. static int currbuf;
  771. static int bn;
  772. static char sentbuf[2][256];
  773. static int say_sentence_num(int num, int prev)
  774. {
  775. bn = currbuf;
  776. currsentence = num + 1;
  777. if (prev && --bn == -1)
  778. bn = 1;
  779. if (num > numsentences[bn])
  780. return 0;
  781. spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
  782. return 1;
  783. }
  784. static int get_sentence_buf(struct vc_data *vc, int read_punc)
  785. {
  786. u_long start, end;
  787. int i, bn;
  788. u_char tmp;
  789. currbuf++;
  790. if (currbuf == 2)
  791. currbuf = 0;
  792. bn = currbuf;
  793. start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
  794. end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
  795. numsentences[bn] = 0;
  796. sentmarks[bn][0] = &sentbuf[bn][0];
  797. i = 0;
  798. spk_old_attr = spk_attr;
  799. spk_attr = get_attributes((u_short *) start);
  800. while (start < end) {
  801. sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
  802. if (i > 0) {
  803. if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
  804. && numsentences[bn] < 9) {
  805. /* Sentence Marker */
  806. numsentences[bn]++;
  807. sentmarks[bn][numsentences[bn]] =
  808. &sentbuf[bn][i];
  809. }
  810. }
  811. i++;
  812. start += 2;
  813. if (i >= vc->vc_size_row)
  814. break;
  815. }
  816. for (--i; i >= 0; i--)
  817. if (sentbuf[bn][i] != SPACE)
  818. break;
  819. if (i < 1)
  820. return -1;
  821. sentbuf[bn][++i] = SPACE;
  822. sentbuf[bn][++i] = '\0';
  823. sentbufend[bn] = &sentbuf[bn][i];
  824. return numsentences[bn];
  825. }
  826. static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
  827. {
  828. u_long start = vc->vc_origin, end;
  829. if (from > 0)
  830. start += from * vc->vc_size_row;
  831. if (to > vc->vc_rows)
  832. to = vc->vc_rows;
  833. end = vc->vc_origin + (to * vc->vc_size_row);
  834. for (from = start; from < end; from = to) {
  835. to = from + vc->vc_size_row;
  836. say_from_to(vc, from, to, 1);
  837. }
  838. }
  839. static void say_screen(struct vc_data *vc)
  840. {
  841. say_screen_from_to(vc, 0, vc->vc_rows);
  842. }
  843. static void speakup_win_say(struct vc_data *vc)
  844. {
  845. u_long start, end, from, to;
  846. if (win_start < 2) {
  847. synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
  848. return;
  849. }
  850. start = vc->vc_origin + (win_top * vc->vc_size_row);
  851. end = vc->vc_origin + (win_bottom * vc->vc_size_row);
  852. while (start <= end) {
  853. from = start + (win_left * 2);
  854. to = start + (win_right * 2);
  855. say_from_to(vc, from, to, 1);
  856. start += vc->vc_size_row;
  857. }
  858. }
  859. static void top_edge(struct vc_data *vc)
  860. {
  861. spk_parked |= 0x01;
  862. spk_pos = vc->vc_origin + 2 * spk_x;
  863. spk_y = 0;
  864. say_line(vc);
  865. }
  866. static void bottom_edge(struct vc_data *vc)
  867. {
  868. spk_parked |= 0x01;
  869. spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
  870. spk_y = vc->vc_rows - 1;
  871. say_line(vc);
  872. }
  873. static void left_edge(struct vc_data *vc)
  874. {
  875. spk_parked |= 0x01;
  876. spk_pos -= spk_x * 2;
  877. spk_x = 0;
  878. say_char(vc);
  879. }
  880. static void right_edge(struct vc_data *vc)
  881. {
  882. spk_parked |= 0x01;
  883. spk_pos += (vc->vc_cols - spk_x - 1) * 2;
  884. spk_x = vc->vc_cols - 1;
  885. say_char(vc);
  886. }
  887. static void say_first_char(struct vc_data *vc)
  888. {
  889. int i, len = get_line(vc);
  890. u_char ch;
  891. spk_parked |= 0x01;
  892. if (len == 0) {
  893. synth_printf("%s\n", spk_msg_get(MSG_BLANK));
  894. return;
  895. }
  896. for (i = 0; i < len; i++)
  897. if (buf[i] != SPACE)
  898. break;
  899. ch = buf[i];
  900. spk_pos -= (spk_x - i) * 2;
  901. spk_x = i;
  902. synth_printf("%d, ", ++i);
  903. speak_char(ch);
  904. }
  905. static void say_last_char(struct vc_data *vc)
  906. {
  907. int len = get_line(vc);
  908. u_char ch;
  909. spk_parked |= 0x01;
  910. if (len == 0) {
  911. synth_printf("%s\n", spk_msg_get(MSG_BLANK));
  912. return;
  913. }
  914. ch = buf[--len];
  915. spk_pos -= (spk_x - len) * 2;
  916. spk_x = len;
  917. synth_printf("%d, ", ++len);
  918. speak_char(ch);
  919. }
  920. static void say_position(struct vc_data *vc)
  921. {
  922. synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
  923. vc->vc_num + 1);
  924. synth_printf("\n");
  925. }
  926. /* Added by brianb */
  927. static void say_char_num(struct vc_data *vc)
  928. {
  929. u_char tmp;
  930. u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
  931. ch &= 0xff;
  932. synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
  933. }
  934. /* these are stub functions to keep keyboard.c happy. */
  935. static void say_from_top(struct vc_data *vc)
  936. {
  937. say_screen_from_to(vc, 0, spk_y);
  938. }
  939. static void say_to_bottom(struct vc_data *vc)
  940. {
  941. say_screen_from_to(vc, spk_y, vc->vc_rows);
  942. }
  943. static void say_from_left(struct vc_data *vc)
  944. {
  945. say_line_from_to(vc, 0, spk_x, 1);
  946. }
  947. static void say_to_right(struct vc_data *vc)
  948. {
  949. say_line_from_to(vc, spk_x, vc->vc_cols, 1);
  950. }
  951. /* end of stub functions. */
  952. static void spkup_write(const char *in_buf, int count)
  953. {
  954. static int rep_count;
  955. static u_char ch = '\0', old_ch = '\0';
  956. static u_short char_type, last_type;
  957. int in_count = count;
  958. spk_keydown = 0;
  959. while (count--) {
  960. if (cursor_track == read_all_mode) {
  961. /* Insert Sentence Index */
  962. if ((in_buf == sentmarks[bn][currsentence]) &&
  963. (currsentence <= numsentences[bn]))
  964. synth_insert_next_index(currsentence++);
  965. }
  966. ch = (u_char) *in_buf++;
  967. char_type = spk_chartab[ch];
  968. if (ch == old_ch && !(char_type & B_NUM)) {
  969. if (++rep_count > 2)
  970. continue;
  971. } else {
  972. if ((last_type & CH_RPT) && rep_count > 2) {
  973. synth_printf(" ");
  974. synth_printf(spk_msg_get(MSG_REPEAT_DESC),
  975. ++rep_count);
  976. synth_printf(" ");
  977. }
  978. rep_count = 0;
  979. }
  980. if (ch == spk_lastkey) {
  981. rep_count = 0;
  982. if (spk_key_echo == 1 && ch >= MINECHOCHAR)
  983. speak_char(ch);
  984. } else if (char_type & B_ALPHA) {
  985. if ((synth_flags & SF_DEC) && (last_type & PUNC))
  986. synth_buffer_add(SPACE);
  987. synth_printf("%c", ch);
  988. } else if (char_type & B_NUM) {
  989. rep_count = 0;
  990. synth_printf("%c", ch);
  991. } else if (char_type & spk_punc_mask) {
  992. speak_char(ch);
  993. char_type &= ~PUNC; /* for dec nospell processing */
  994. } else if (char_type & SYNTH_OK) {
  995. /* these are usually puncts like . and , which synth
  996. * needs for expression.
  997. * suppress multiple to get rid of long pauses and
  998. * clear repeat count
  999. * so if someone has
  1000. * repeats on you don't get nothing repeated count
  1001. */
  1002. if (ch != old_ch)
  1003. synth_printf("%c", ch);
  1004. else
  1005. rep_count = 0;
  1006. } else {
  1007. /* send space and record position, if next is num overwrite space */
  1008. if (old_ch != ch)
  1009. synth_buffer_add(SPACE);
  1010. else
  1011. rep_count = 0;
  1012. }
  1013. old_ch = ch;
  1014. last_type = char_type;
  1015. }
  1016. spk_lastkey = 0;
  1017. if (in_count > 2 && rep_count > 2) {
  1018. if (last_type & CH_RPT) {
  1019. synth_printf(" ");
  1020. synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
  1021. ++rep_count);
  1022. synth_printf(" ");
  1023. }
  1024. rep_count = 0;
  1025. }
  1026. }
  1027. static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
  1028. static void read_all_doc(struct vc_data *vc);
  1029. static void cursor_done(u_long data);
  1030. static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
  1031. static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
  1032. {
  1033. unsigned long flags;
  1034. if (synth == NULL || up_flag || spk_killed)
  1035. return;
  1036. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1037. if (cursor_track == read_all_mode) {
  1038. switch (value) {
  1039. case KVAL(K_SHIFT):
  1040. del_timer(&cursor_timer);
  1041. spk_shut_up &= 0xfe;
  1042. spk_do_flush();
  1043. read_all_doc(vc);
  1044. break;
  1045. case KVAL(K_CTRL):
  1046. del_timer(&cursor_timer);
  1047. cursor_track = prev_cursor_track;
  1048. spk_shut_up &= 0xfe;
  1049. spk_do_flush();
  1050. break;
  1051. }
  1052. } else {
  1053. spk_shut_up &= 0xfe;
  1054. spk_do_flush();
  1055. }
  1056. if (spk_say_ctrl && value < NUM_CTL_LABELS)
  1057. synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
  1058. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1059. }
  1060. static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
  1061. {
  1062. unsigned long flags;
  1063. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1064. if (up_flag) {
  1065. spk_lastkey = spk_keydown = 0;
  1066. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1067. return;
  1068. }
  1069. if (synth == NULL || spk_killed) {
  1070. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1071. return;
  1072. }
  1073. spk_shut_up &= 0xfe;
  1074. spk_lastkey = value;
  1075. spk_keydown++;
  1076. spk_parked &= 0xfe;
  1077. if (spk_key_echo == 2 && value >= MINECHOCHAR)
  1078. speak_char(value);
  1079. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1080. }
  1081. int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
  1082. {
  1083. int i = 0, states, key_data_len;
  1084. const u_char *cp = key_info;
  1085. u_char *cp1 = k_buffer;
  1086. u_char ch, version, num_keys;
  1087. version = *cp++;
  1088. if (version != KEY_MAP_VER)
  1089. return -1;
  1090. num_keys = *cp;
  1091. states = (int)cp[1];
  1092. key_data_len = (states + 1) * (num_keys + 1);
  1093. if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
  1094. return -2;
  1095. memset(k_buffer, 0, SHIFT_TBL_SIZE);
  1096. memset(spk_our_keys, 0, sizeof(spk_our_keys));
  1097. spk_shift_table = k_buffer;
  1098. spk_our_keys[0] = spk_shift_table;
  1099. cp1 += SHIFT_TBL_SIZE;
  1100. memcpy(cp1, cp, key_data_len + 3);
  1101. /* get num_keys, states and data */
  1102. cp1 += 2; /* now pointing at shift states */
  1103. for (i = 1; i <= states; i++) {
  1104. ch = *cp1++;
  1105. if (ch >= SHIFT_TBL_SIZE)
  1106. return -3;
  1107. spk_shift_table[ch] = i;
  1108. }
  1109. keymap_flags = *cp1++;
  1110. while ((ch = *cp1)) {
  1111. if (ch >= MAX_KEY)
  1112. return -4;
  1113. spk_our_keys[ch] = cp1;
  1114. cp1 += states + 1;
  1115. }
  1116. return 0;
  1117. }
  1118. static struct var_t spk_vars[] = {
  1119. /* bell must be first to set high limit */
  1120. {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
  1121. {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
  1122. {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
  1123. {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
  1124. {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
  1125. {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
  1126. {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
  1127. {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
  1128. {SAY_CONTROL, TOGGLE_0},
  1129. {SAY_WORD_CTL, TOGGLE_0},
  1130. {NO_INTERRUPT, TOGGLE_0},
  1131. {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
  1132. V_LAST_VAR
  1133. };
  1134. static void toggle_cursoring(struct vc_data *vc)
  1135. {
  1136. if (cursor_track == read_all_mode)
  1137. cursor_track = prev_cursor_track;
  1138. if (++cursor_track >= CT_Max)
  1139. cursor_track = 0;
  1140. synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
  1141. }
  1142. void spk_reset_default_chars(void)
  1143. {
  1144. int i;
  1145. /* First, free any non-default */
  1146. for (i = 0; i < 256; i++) {
  1147. if ((spk_characters[i] != NULL)
  1148. && (spk_characters[i] != spk_default_chars[i]))
  1149. kfree(spk_characters[i]);
  1150. }
  1151. memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
  1152. }
  1153. void spk_reset_default_chartab(void)
  1154. {
  1155. memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
  1156. }
  1157. static const struct st_bits_data *pb_edit;
  1158. static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
  1159. {
  1160. short mask = pb_edit->mask, ch_type = spk_chartab[ch];
  1161. if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
  1162. return -1;
  1163. if (ch == SPACE) {
  1164. synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
  1165. spk_special_handler = NULL;
  1166. return 1;
  1167. }
  1168. if (mask < PUNC && !(ch_type & PUNC))
  1169. return -1;
  1170. spk_chartab[ch] ^= mask;
  1171. speak_char(ch);
  1172. synth_printf(" %s\n",
  1173. (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
  1174. spk_msg_get(MSG_OFF));
  1175. return 1;
  1176. }
  1177. /* Allocation concurrency is protected by the console semaphore */
  1178. static int speakup_allocate(struct vc_data *vc)
  1179. {
  1180. int vc_num;
  1181. vc_num = vc->vc_num;
  1182. if (speakup_console[vc_num] == NULL) {
  1183. speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
  1184. GFP_ATOMIC);
  1185. if (speakup_console[vc_num] == NULL)
  1186. return -ENOMEM;
  1187. speakup_date(vc);
  1188. } else if (!spk_parked)
  1189. speakup_date(vc);
  1190. return 0;
  1191. }
  1192. static void speakup_deallocate(struct vc_data *vc)
  1193. {
  1194. int vc_num;
  1195. vc_num = vc->vc_num;
  1196. kfree(speakup_console[vc_num]);
  1197. speakup_console[vc_num] = NULL;
  1198. }
  1199. static u_char is_cursor;
  1200. static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
  1201. static int cursor_con;
  1202. static void reset_highlight_buffers(struct vc_data *);
  1203. static int read_all_key;
  1204. static void start_read_all_timer(struct vc_data *vc, int command);
  1205. enum {
  1206. RA_NOTHING,
  1207. RA_NEXT_SENT,
  1208. RA_PREV_LINE,
  1209. RA_NEXT_LINE,
  1210. RA_PREV_SENT,
  1211. RA_DOWN_ARROW,
  1212. RA_TIMER,
  1213. RA_FIND_NEXT_SENT,
  1214. RA_FIND_PREV_SENT,
  1215. };
  1216. static void kbd_fakekey2(struct vc_data *vc, int command)
  1217. {
  1218. del_timer(&cursor_timer);
  1219. speakup_fake_down_arrow();
  1220. start_read_all_timer(vc, command);
  1221. }
  1222. static void read_all_doc(struct vc_data *vc)
  1223. {
  1224. if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
  1225. return;
  1226. if (!synth_supports_indexing())
  1227. return;
  1228. if (cursor_track != read_all_mode)
  1229. prev_cursor_track = cursor_track;
  1230. cursor_track = read_all_mode;
  1231. spk_reset_index_count(0);
  1232. if (get_sentence_buf(vc, 0) == -1)
  1233. kbd_fakekey2(vc, RA_DOWN_ARROW);
  1234. else {
  1235. say_sentence_num(0, 0);
  1236. synth_insert_next_index(0);
  1237. start_read_all_timer(vc, RA_TIMER);
  1238. }
  1239. }
  1240. static void stop_read_all(struct vc_data *vc)
  1241. {
  1242. del_timer(&cursor_timer);
  1243. cursor_track = prev_cursor_track;
  1244. spk_shut_up &= 0xfe;
  1245. spk_do_flush();
  1246. }
  1247. static void start_read_all_timer(struct vc_data *vc, int command)
  1248. {
  1249. struct var_t *cursor_timeout;
  1250. cursor_con = vc->vc_num;
  1251. read_all_key = command;
  1252. cursor_timeout = spk_get_var(CURSOR_TIME);
  1253. mod_timer(&cursor_timer,
  1254. jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
  1255. }
  1256. static void handle_cursor_read_all(struct vc_data *vc, int command)
  1257. {
  1258. int indcount, sentcount, rv, sn;
  1259. switch (command) {
  1260. case RA_NEXT_SENT:
  1261. /* Get Current Sentence */
  1262. spk_get_index_count(&indcount, &sentcount);
  1263. /*printk("%d %d ", indcount, sentcount); */
  1264. spk_reset_index_count(sentcount + 1);
  1265. if (indcount == 1) {
  1266. if (!say_sentence_num(sentcount + 1, 0)) {
  1267. kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
  1268. return;
  1269. }
  1270. synth_insert_next_index(0);
  1271. } else {
  1272. sn = 0;
  1273. if (!say_sentence_num(sentcount + 1, 1)) {
  1274. sn = 1;
  1275. spk_reset_index_count(sn);
  1276. } else
  1277. synth_insert_next_index(0);
  1278. if (!say_sentence_num(sn, 0)) {
  1279. kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
  1280. return;
  1281. }
  1282. synth_insert_next_index(0);
  1283. }
  1284. start_read_all_timer(vc, RA_TIMER);
  1285. break;
  1286. case RA_PREV_SENT:
  1287. break;
  1288. case RA_NEXT_LINE:
  1289. read_all_doc(vc);
  1290. break;
  1291. case RA_PREV_LINE:
  1292. break;
  1293. case RA_DOWN_ARROW:
  1294. if (get_sentence_buf(vc, 0) == -1) {
  1295. kbd_fakekey2(vc, RA_DOWN_ARROW);
  1296. } else {
  1297. say_sentence_num(0, 0);
  1298. synth_insert_next_index(0);
  1299. start_read_all_timer(vc, RA_TIMER);
  1300. }
  1301. break;
  1302. case RA_FIND_NEXT_SENT:
  1303. rv = get_sentence_buf(vc, 0);
  1304. if (rv == -1)
  1305. read_all_doc(vc);
  1306. if (rv == 0)
  1307. kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
  1308. else {
  1309. say_sentence_num(1, 0);
  1310. synth_insert_next_index(0);
  1311. start_read_all_timer(vc, RA_TIMER);
  1312. }
  1313. break;
  1314. case RA_FIND_PREV_SENT:
  1315. break;
  1316. case RA_TIMER:
  1317. spk_get_index_count(&indcount, &sentcount);
  1318. if (indcount < 2)
  1319. kbd_fakekey2(vc, RA_DOWN_ARROW);
  1320. else
  1321. start_read_all_timer(vc, RA_TIMER);
  1322. break;
  1323. }
  1324. }
  1325. static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
  1326. {
  1327. unsigned long flags;
  1328. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1329. if (cursor_track == read_all_mode) {
  1330. spk_parked &= 0xfe;
  1331. if (synth == NULL || up_flag || spk_shut_up) {
  1332. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1333. return NOTIFY_STOP;
  1334. }
  1335. del_timer(&cursor_timer);
  1336. spk_shut_up &= 0xfe;
  1337. spk_do_flush();
  1338. start_read_all_timer(vc, value + 1);
  1339. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1340. return NOTIFY_STOP;
  1341. }
  1342. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1343. return NOTIFY_OK;
  1344. }
  1345. static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
  1346. {
  1347. unsigned long flags;
  1348. struct var_t *cursor_timeout;
  1349. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1350. spk_parked &= 0xfe;
  1351. if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
  1352. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1353. return;
  1354. }
  1355. spk_shut_up &= 0xfe;
  1356. if (spk_no_intr)
  1357. spk_do_flush();
  1358. /* the key press flushes if !no_inter but we want to flush on cursor
  1359. * moves regardless of no_inter state
  1360. */
  1361. is_cursor = value + 1;
  1362. old_cursor_pos = vc->vc_pos;
  1363. old_cursor_x = vc->vc_x;
  1364. old_cursor_y = vc->vc_y;
  1365. speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
  1366. cursor_con = vc->vc_num;
  1367. if (cursor_track == CT_Highlight)
  1368. reset_highlight_buffers(vc);
  1369. cursor_timeout = spk_get_var(CURSOR_TIME);
  1370. mod_timer(&cursor_timer,
  1371. jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
  1372. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1373. }
  1374. static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
  1375. {
  1376. int i, bi, hi;
  1377. int vc_num = vc->vc_num;
  1378. bi = (vc->vc_attr & 0x70) >> 4;
  1379. hi = speakup_console[vc_num]->ht.highsize[bi];
  1380. i = 0;
  1381. if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
  1382. speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
  1383. speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
  1384. speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
  1385. }
  1386. while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
  1387. if ((ic[i] > 32) && (ic[i] < 127)) {
  1388. speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
  1389. hi++;
  1390. } else if ((ic[i] == 32) && (hi != 0)) {
  1391. if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
  1392. 32) {
  1393. speakup_console[vc_num]->ht.highbuf[bi][hi] =
  1394. ic[i];
  1395. hi++;
  1396. }
  1397. }
  1398. i++;
  1399. }
  1400. speakup_console[vc_num]->ht.highsize[bi] = hi;
  1401. }
  1402. static void reset_highlight_buffers(struct vc_data *vc)
  1403. {
  1404. int i;
  1405. int vc_num = vc->vc_num;
  1406. for (i = 0; i < 8; i++)
  1407. speakup_console[vc_num]->ht.highsize[i] = 0;
  1408. }
  1409. static int count_highlight_color(struct vc_data *vc)
  1410. {
  1411. int i, bg;
  1412. int cc;
  1413. int vc_num = vc->vc_num;
  1414. u16 ch;
  1415. u16 *start = (u16 *) vc->vc_origin;
  1416. for (i = 0; i < 8; i++)
  1417. speakup_console[vc_num]->ht.bgcount[i] = 0;
  1418. for (i = 0; i < vc->vc_rows; i++) {
  1419. u16 *end = start + vc->vc_cols * 2;
  1420. u16 *ptr;
  1421. for (ptr = start; ptr < end; ptr++) {
  1422. ch = get_attributes(ptr);
  1423. bg = (ch & 0x70) >> 4;
  1424. speakup_console[vc_num]->ht.bgcount[bg]++;
  1425. }
  1426. start += vc->vc_size_row;
  1427. }
  1428. cc = 0;
  1429. for (i = 0; i < 8; i++)
  1430. if (speakup_console[vc_num]->ht.bgcount[i] > 0)
  1431. cc++;
  1432. return cc;
  1433. }
  1434. static int get_highlight_color(struct vc_data *vc)
  1435. {
  1436. int i, j;
  1437. unsigned int cptr[8];
  1438. int vc_num = vc->vc_num;
  1439. for (i = 0; i < 8; i++)
  1440. cptr[i] = i;
  1441. for (i = 0; i < 7; i++)
  1442. for (j = i + 1; j < 8; j++)
  1443. if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
  1444. speakup_console[vc_num]->ht.bgcount[cptr[j]])
  1445. swap(cptr[i], cptr[j]);
  1446. for (i = 0; i < 8; i++)
  1447. if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
  1448. if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
  1449. return cptr[i];
  1450. return -1;
  1451. }
  1452. static int speak_highlight(struct vc_data *vc)
  1453. {
  1454. int hc, d;
  1455. int vc_num = vc->vc_num;
  1456. if (count_highlight_color(vc) == 1)
  1457. return 0;
  1458. hc = get_highlight_color(vc);
  1459. if (hc != -1) {
  1460. d = vc->vc_y - speakup_console[vc_num]->ht.cy;
  1461. if ((d == 1) || (d == -1))
  1462. if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
  1463. return 0;
  1464. spk_parked |= 0x01;
  1465. spk_do_flush();
  1466. spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
  1467. speakup_console[vc_num]->ht.highsize[hc]);
  1468. spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
  1469. spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
  1470. spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
  1471. return 1;
  1472. }
  1473. return 0;
  1474. }
  1475. static void cursor_done(u_long data)
  1476. {
  1477. struct vc_data *vc = vc_cons[cursor_con].d;
  1478. unsigned long flags;
  1479. del_timer(&cursor_timer);
  1480. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1481. if (cursor_con != fg_console) {
  1482. is_cursor = 0;
  1483. goto out;
  1484. }
  1485. speakup_date(vc);
  1486. if (win_enabled) {
  1487. if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
  1488. vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
  1489. spk_keydown = is_cursor = 0;
  1490. goto out;
  1491. }
  1492. }
  1493. if (cursor_track == read_all_mode) {
  1494. handle_cursor_read_all(vc, read_all_key);
  1495. goto out;
  1496. }
  1497. if (cursor_track == CT_Highlight) {
  1498. if (speak_highlight(vc)) {
  1499. spk_keydown = is_cursor = 0;
  1500. goto out;
  1501. }
  1502. }
  1503. if (cursor_track == CT_Window)
  1504. speakup_win_say(vc);
  1505. else if (is_cursor == 1 || is_cursor == 4)
  1506. say_line_from_to(vc, 0, vc->vc_cols, 0);
  1507. else
  1508. say_char(vc);
  1509. spk_keydown = is_cursor = 0;
  1510. out:
  1511. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1512. }
  1513. /* called by: vt_notifier_call() */
  1514. static void speakup_bs(struct vc_data *vc)
  1515. {
  1516. unsigned long flags;
  1517. if (!speakup_console[vc->vc_num])
  1518. return;
  1519. if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
  1520. /* Speakup output, discard */
  1521. return;
  1522. if (!spk_parked)
  1523. speakup_date(vc);
  1524. if (spk_shut_up || synth == NULL) {
  1525. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1526. return;
  1527. }
  1528. if (vc->vc_num == fg_console && spk_keydown) {
  1529. spk_keydown = 0;
  1530. if (!is_cursor)
  1531. say_char(vc);
  1532. }
  1533. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1534. }
  1535. /* called by: vt_notifier_call() */
  1536. static void speakup_con_write(struct vc_data *vc, const char *str, int len)
  1537. {
  1538. unsigned long flags;
  1539. if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
  1540. return;
  1541. if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
  1542. /* Speakup output, discard */
  1543. return;
  1544. if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
  1545. bleep(3);
  1546. if ((is_cursor) || (cursor_track == read_all_mode)) {
  1547. if (cursor_track == CT_Highlight)
  1548. update_color_buffer(vc, str, len);
  1549. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1550. return;
  1551. }
  1552. if (win_enabled) {
  1553. if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
  1554. vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
  1555. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1556. return;
  1557. }
  1558. }
  1559. spkup_write(str, len);
  1560. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1561. }
  1562. static void speakup_con_update(struct vc_data *vc)
  1563. {
  1564. unsigned long flags;
  1565. if (speakup_console[vc->vc_num] == NULL || spk_parked)
  1566. return;
  1567. if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
  1568. /* Speakup output, discard */
  1569. return;
  1570. speakup_date(vc);
  1571. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1572. }
  1573. static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
  1574. {
  1575. unsigned long flags;
  1576. int on_off = 2;
  1577. char *label;
  1578. if (synth == NULL || up_flag || spk_killed)
  1579. return;
  1580. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1581. spk_shut_up &= 0xfe;
  1582. if (spk_no_intr)
  1583. spk_do_flush();
  1584. switch (value) {
  1585. case KVAL(K_CAPS):
  1586. label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
  1587. on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
  1588. break;
  1589. case KVAL(K_NUM):
  1590. label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
  1591. on_off = vt_get_leds(fg_console, VC_NUMLOCK);
  1592. break;
  1593. case KVAL(K_HOLD):
  1594. label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
  1595. on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
  1596. if (speakup_console[vc->vc_num])
  1597. speakup_console[vc->vc_num]->tty_stopped = on_off;
  1598. break;
  1599. default:
  1600. spk_parked &= 0xfe;
  1601. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1602. return;
  1603. }
  1604. if (on_off < 2)
  1605. synth_printf("%s %s\n",
  1606. label, spk_msg_get(MSG_STATUS_START + on_off));
  1607. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1608. }
  1609. static int inc_dec_var(u_char value)
  1610. {
  1611. struct st_var_header *p_header;
  1612. struct var_t *var_data;
  1613. char num_buf[32];
  1614. char *cp = num_buf;
  1615. char *pn;
  1616. int var_id = (int)value - VAR_START;
  1617. int how = (var_id & 1) ? E_INC : E_DEC;
  1618. var_id = var_id / 2 + FIRST_SET_VAR;
  1619. p_header = spk_get_var_header(var_id);
  1620. if (p_header == NULL)
  1621. return -1;
  1622. if (p_header->var_type != VAR_NUM)
  1623. return -1;
  1624. var_data = p_header->data;
  1625. if (spk_set_num_var(1, p_header, how) != 0)
  1626. return -1;
  1627. if (!spk_close_press) {
  1628. for (pn = p_header->name; *pn; pn++) {
  1629. if (*pn == '_')
  1630. *cp = SPACE;
  1631. else
  1632. *cp++ = *pn;
  1633. }
  1634. }
  1635. snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
  1636. var_data->u.n.value);
  1637. synth_printf("%s", num_buf);
  1638. return 0;
  1639. }
  1640. static void speakup_win_set(struct vc_data *vc)
  1641. {
  1642. char info[40];
  1643. if (win_start > 1) {
  1644. synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
  1645. return;
  1646. }
  1647. if (spk_x < win_left || spk_y < win_top) {
  1648. synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
  1649. return;
  1650. }
  1651. if (win_start && spk_x == win_left && spk_y == win_top) {
  1652. win_left = 0;
  1653. win_right = vc->vc_cols - 1;
  1654. win_bottom = spk_y;
  1655. snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
  1656. (int)win_top + 1);
  1657. } else {
  1658. if (!win_start) {
  1659. win_top = spk_y;
  1660. win_left = spk_x;
  1661. } else {
  1662. win_bottom = spk_y;
  1663. win_right = spk_x;
  1664. }
  1665. snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
  1666. (win_start) ?
  1667. spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
  1668. (int)spk_y + 1, (int)spk_x + 1);
  1669. }
  1670. synth_printf("%s\n", info);
  1671. win_start++;
  1672. }
  1673. static void speakup_win_clear(struct vc_data *vc)
  1674. {
  1675. win_top = win_bottom = 0;
  1676. win_left = win_right = 0;
  1677. win_start = 0;
  1678. synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
  1679. }
  1680. static void speakup_win_enable(struct vc_data *vc)
  1681. {
  1682. if (win_start < 2) {
  1683. synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
  1684. return;
  1685. }
  1686. win_enabled ^= 1;
  1687. if (win_enabled)
  1688. synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
  1689. else
  1690. synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
  1691. }
  1692. static void speakup_bits(struct vc_data *vc)
  1693. {
  1694. int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
  1695. if (spk_special_handler != NULL || val < 1 || val > 6) {
  1696. synth_printf("%s\n", spk_msg_get(MSG_ERROR));
  1697. return;
  1698. }
  1699. pb_edit = &spk_punc_info[val];
  1700. synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
  1701. spk_special_handler = edit_bits;
  1702. }
  1703. static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
  1704. {
  1705. static u_char goto_buf[8];
  1706. static int num;
  1707. int maxlen;
  1708. char *cp;
  1709. if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
  1710. goto do_goto;
  1711. if (type == KT_LATIN && ch == '\n')
  1712. goto do_goto;
  1713. if (type != 0)
  1714. goto oops;
  1715. if (ch == 8) {
  1716. if (num == 0)
  1717. return -1;
  1718. ch = goto_buf[--num];
  1719. goto_buf[num] = '\0';
  1720. spkup_write(&ch, 1);
  1721. return 1;
  1722. }
  1723. if (ch < '+' || ch > 'y')
  1724. goto oops;
  1725. goto_buf[num++] = ch;
  1726. goto_buf[num] = '\0';
  1727. spkup_write(&ch, 1);
  1728. maxlen = (*goto_buf >= '0') ? 3 : 4;
  1729. if ((ch == '+' || ch == '-') && num == 1)
  1730. return 1;
  1731. if (ch >= '0' && ch <= '9' && num < maxlen)
  1732. return 1;
  1733. if (num < maxlen - 1 || num > maxlen)
  1734. goto oops;
  1735. if (ch < 'x' || ch > 'y') {
  1736. oops:
  1737. if (!spk_killed)
  1738. synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
  1739. goto_buf[num = 0] = '\0';
  1740. spk_special_handler = NULL;
  1741. return 1;
  1742. }
  1743. goto_pos = simple_strtoul(goto_buf, &cp, 10);
  1744. if (*cp == 'x') {
  1745. if (*goto_buf < '0')
  1746. goto_pos += spk_x;
  1747. else if (goto_pos > 0)
  1748. goto_pos--;
  1749. if (goto_pos >= vc->vc_cols)
  1750. goto_pos = vc->vc_cols - 1;
  1751. goto_x = 1;
  1752. } else {
  1753. if (*goto_buf < '0')
  1754. goto_pos += spk_y;
  1755. else if (goto_pos > 0)
  1756. goto_pos--;
  1757. if (goto_pos >= vc->vc_rows)
  1758. goto_pos = vc->vc_rows - 1;
  1759. goto_x = 0;
  1760. }
  1761. goto_buf[num = 0] = '\0';
  1762. do_goto:
  1763. spk_special_handler = NULL;
  1764. spk_parked |= 0x01;
  1765. if (goto_x) {
  1766. spk_pos -= spk_x * 2;
  1767. spk_x = goto_pos;
  1768. spk_pos += goto_pos * 2;
  1769. say_word(vc);
  1770. } else {
  1771. spk_y = goto_pos;
  1772. spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
  1773. say_line(vc);
  1774. }
  1775. return 1;
  1776. }
  1777. static void speakup_goto(struct vc_data *vc)
  1778. {
  1779. if (spk_special_handler != NULL) {
  1780. synth_printf("%s\n", spk_msg_get(MSG_ERROR));
  1781. return;
  1782. }
  1783. synth_printf("%s\n", spk_msg_get(MSG_GOTO));
  1784. spk_special_handler = handle_goto;
  1785. }
  1786. static void speakup_help(struct vc_data *vc)
  1787. {
  1788. spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
  1789. }
  1790. static void do_nothing(struct vc_data *vc)
  1791. {
  1792. return; /* flush done in do_spkup */
  1793. }
  1794. static u_char key_speakup, spk_key_locked;
  1795. static void speakup_lock(struct vc_data *vc)
  1796. {
  1797. if (!spk_key_locked)
  1798. spk_key_locked = key_speakup = 16;
  1799. else
  1800. spk_key_locked = key_speakup = 0;
  1801. }
  1802. typedef void (*spkup_hand) (struct vc_data *);
  1803. static spkup_hand spkup_handler[] = {
  1804. /* must be ordered same as defines in speakup.h */
  1805. do_nothing, speakup_goto, speech_kill, speakup_shut_up,
  1806. speakup_cut, speakup_paste, say_first_char, say_last_char,
  1807. say_char, say_prev_char, say_next_char,
  1808. say_word, say_prev_word, say_next_word,
  1809. say_line, say_prev_line, say_next_line,
  1810. top_edge, bottom_edge, left_edge, right_edge,
  1811. spell_word, spell_word, say_screen,
  1812. say_position, say_attributes,
  1813. speakup_off, speakup_parked, say_line, /* this is for indent */
  1814. say_from_top, say_to_bottom,
  1815. say_from_left, say_to_right,
  1816. say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
  1817. speakup_bits, speakup_bits, speakup_bits,
  1818. speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
  1819. speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
  1820. };
  1821. static void do_spkup(struct vc_data *vc, u_char value)
  1822. {
  1823. if (spk_killed && value != SPEECH_KILL)
  1824. return;
  1825. spk_keydown = 0;
  1826. spk_lastkey = 0;
  1827. spk_shut_up &= 0xfe;
  1828. this_speakup_key = value;
  1829. if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
  1830. spk_do_flush();
  1831. (*spkup_handler[value]) (vc);
  1832. } else {
  1833. if (inc_dec_var(value) < 0)
  1834. bleep(9);
  1835. }
  1836. }
  1837. static const char *pad_chars = "0123456789+-*/\015,.?()";
  1838. static int
  1839. speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
  1840. int up_flag)
  1841. {
  1842. unsigned long flags;
  1843. int kh;
  1844. u_char *key_info;
  1845. u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
  1846. u_char shift_info, offset;
  1847. int ret = 0;
  1848. if (synth == NULL)
  1849. return 0;
  1850. spin_lock_irqsave(&speakup_info.spinlock, flags);
  1851. tty = vc->port.tty;
  1852. if (type >= 0xf0)
  1853. type -= 0xf0;
  1854. if (type == KT_PAD
  1855. && (vt_get_leds(fg_console, VC_NUMLOCK))) {
  1856. if (up_flag) {
  1857. spk_keydown = 0;
  1858. goto out;
  1859. }
  1860. value = spk_lastkey = pad_chars[value];
  1861. spk_keydown++;
  1862. spk_parked &= 0xfe;
  1863. goto no_map;
  1864. }
  1865. if (keycode >= MAX_KEY)
  1866. goto no_map;
  1867. key_info = spk_our_keys[keycode];
  1868. if (!key_info)
  1869. goto no_map;
  1870. /* Check valid read all mode keys */
  1871. if ((cursor_track == read_all_mode) && (!up_flag)) {
  1872. switch (value) {
  1873. case KVAL(K_DOWN):
  1874. case KVAL(K_UP):
  1875. case KVAL(K_LEFT):
  1876. case KVAL(K_RIGHT):
  1877. case KVAL(K_PGUP):
  1878. case KVAL(K_PGDN):
  1879. break;
  1880. default:
  1881. stop_read_all(vc);
  1882. break;
  1883. }
  1884. }
  1885. shift_info = (shift_state & 0x0f) + key_speakup;
  1886. offset = spk_shift_table[shift_info];
  1887. if (offset) {
  1888. new_key = key_info[offset];
  1889. if (new_key) {
  1890. ret = 1;
  1891. if (new_key == SPK_KEY) {
  1892. if (!spk_key_locked)
  1893. key_speakup = (up_flag) ? 0 : 16;
  1894. if (up_flag || spk_killed)
  1895. goto out;
  1896. spk_shut_up &= 0xfe;
  1897. spk_do_flush();
  1898. goto out;
  1899. }
  1900. if (up_flag)
  1901. goto out;
  1902. if (last_keycode == keycode &&
  1903. time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
  1904. spk_close_press = 1;
  1905. offset = spk_shift_table[shift_info + 32];
  1906. /* double press? */
  1907. if (offset && key_info[offset])
  1908. new_key = key_info[offset];
  1909. }
  1910. last_keycode = keycode;
  1911. last_spk_jiffy = jiffies;
  1912. type = KT_SPKUP;
  1913. value = new_key;
  1914. }
  1915. }
  1916. no_map:
  1917. if (type == KT_SPKUP && spk_special_handler == NULL) {
  1918. do_spkup(vc, new_key);
  1919. spk_close_press = 0;
  1920. ret = 1;
  1921. goto out;
  1922. }
  1923. if (up_flag || spk_killed || type == KT_SHIFT)
  1924. goto out;
  1925. spk_shut_up &= 0xfe;
  1926. kh = (value == KVAL(K_DOWN))
  1927. || (value == KVAL(K_UP))
  1928. || (value == KVAL(K_LEFT))
  1929. || (value == KVAL(K_RIGHT));
  1930. if ((cursor_track != read_all_mode) || !kh)
  1931. if (!spk_no_intr)
  1932. spk_do_flush();
  1933. if (spk_special_handler) {
  1934. if (type == KT_SPEC && value == 1) {
  1935. value = '\n';
  1936. type = KT_LATIN;
  1937. } else if (type == KT_LETTER)
  1938. type = KT_LATIN;
  1939. else if (value == 0x7f)
  1940. value = 8; /* make del = backspace */
  1941. ret = (*spk_special_handler) (vc, type, value, keycode);
  1942. spk_close_press = 0;
  1943. if (ret < 0)
  1944. bleep(9);
  1945. goto out;
  1946. }
  1947. last_keycode = 0;
  1948. out:
  1949. spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  1950. return ret;
  1951. }
  1952. static int keyboard_notifier_call(struct notifier_block *nb,
  1953. unsigned long code, void *_param)
  1954. {
  1955. struct keyboard_notifier_param *param = _param;
  1956. struct vc_data *vc = param->vc;
  1957. int up = !param->down;
  1958. int ret = NOTIFY_OK;
  1959. static int keycode; /* to hold the current keycode */
  1960. if (vc->vc_mode == KD_GRAPHICS)
  1961. return ret;
  1962. /*
  1963. * First, determine whether we are handling a fake keypress on
  1964. * the current processor. If we are, then return NOTIFY_OK,
  1965. * to pass the keystroke up the chain. This prevents us from
  1966. * trying to take the Speakup lock while it is held by the
  1967. * processor on which the simulated keystroke was generated.
  1968. * Also, the simulated keystrokes should be ignored by Speakup.
  1969. */
  1970. if (speakup_fake_key_pressed())
  1971. return ret;
  1972. switch (code) {
  1973. case KBD_KEYCODE:
  1974. /* speakup requires keycode and keysym currently */
  1975. keycode = param->value;
  1976. break;
  1977. case KBD_UNBOUND_KEYCODE:
  1978. /* not used yet */
  1979. break;
  1980. case KBD_UNICODE:
  1981. /* not used yet */
  1982. break;
  1983. case KBD_KEYSYM:
  1984. if (speakup_key(vc, param->shift, keycode, param->value, up))
  1985. ret = NOTIFY_STOP;
  1986. else if (KTYP(param->value) == KT_CUR)
  1987. ret = pre_handle_cursor(vc, KVAL(param->value), up);
  1988. break;
  1989. case KBD_POST_KEYSYM:{
  1990. unsigned char type = KTYP(param->value) - 0xf0;
  1991. unsigned char val = KVAL(param->value);
  1992. switch (type) {
  1993. case KT_SHIFT:
  1994. do_handle_shift(vc, val, up);
  1995. break;
  1996. case KT_LATIN:
  1997. case KT_LETTER:
  1998. do_handle_latin(vc, val, up);
  1999. break;
  2000. case KT_CUR:
  2001. do_handle_cursor(vc, val, up);
  2002. break;
  2003. case KT_SPEC:
  2004. do_handle_spec(vc, val, up);
  2005. break;
  2006. }
  2007. break;
  2008. }
  2009. }
  2010. return ret;
  2011. }
  2012. static int vt_notifier_call(struct notifier_block *nb,
  2013. unsigned long code, void *_param)
  2014. {
  2015. struct vt_notifier_param *param = _param;
  2016. struct vc_data *vc = param->vc;
  2017. switch (code) {
  2018. case VT_ALLOCATE:
  2019. if (vc->vc_mode == KD_TEXT)
  2020. speakup_allocate(vc);
  2021. break;
  2022. case VT_DEALLOCATE:
  2023. speakup_deallocate(vc);
  2024. break;
  2025. case VT_WRITE:
  2026. if (param->c == '\b')
  2027. speakup_bs(vc);
  2028. else if (param->c < 0x100) {
  2029. char d = param->c;
  2030. speakup_con_write(vc, &d, 1);
  2031. }
  2032. break;
  2033. case VT_UPDATE:
  2034. speakup_con_update(vc);
  2035. break;
  2036. }
  2037. return NOTIFY_OK;
  2038. }
  2039. /* called by: module_exit() */
  2040. static void __exit speakup_exit(void)
  2041. {
  2042. int i;
  2043. unregister_keyboard_notifier(&keyboard_notifier_block);
  2044. unregister_vt_notifier(&vt_notifier_block);
  2045. speakup_unregister_devsynth();
  2046. speakup_cancel_paste();
  2047. del_timer(&cursor_timer);
  2048. kthread_stop(speakup_task);
  2049. speakup_task = NULL;
  2050. mutex_lock(&spk_mutex);
  2051. synth_release();
  2052. mutex_unlock(&spk_mutex);
  2053. speakup_kobj_exit();
  2054. for (i = 0; i < MAX_NR_CONSOLES; i++)
  2055. kfree(speakup_console[i]);
  2056. speakup_remove_virtual_keyboard();
  2057. for (i = 0; i < MAXVARS; i++)
  2058. speakup_unregister_var(i);
  2059. for (i = 0; i < 256; i++) {
  2060. if (spk_characters[i] != spk_default_chars[i])
  2061. kfree(spk_characters[i]);
  2062. }
  2063. spk_free_user_msgs();
  2064. }
  2065. /* call by: module_init() */
  2066. static int __init speakup_init(void)
  2067. {
  2068. int i;
  2069. long err = 0;
  2070. struct st_spk_t *first_console;
  2071. struct vc_data *vc = vc_cons[fg_console].d;
  2072. struct var_t *var;
  2073. /* These first few initializations cannot fail. */
  2074. spk_initialize_msgs(); /* Initialize arrays for i18n. */
  2075. spk_reset_default_chars();
  2076. spk_reset_default_chartab();
  2077. spk_strlwr(synth_name);
  2078. spk_vars[0].u.n.high = vc->vc_cols;
  2079. for (var = spk_vars; var->var_id != MAXVARS; var++)
  2080. speakup_register_var(var);
  2081. for (var = synth_time_vars;
  2082. (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
  2083. speakup_register_var(var);
  2084. for (i = 1; spk_punc_info[i].mask != 0; i++)
  2085. spk_set_mask_bits(NULL, i, 2);
  2086. spk_set_key_info(spk_key_defaults, spk_key_buf);
  2087. /* From here on out, initializations can fail. */
  2088. err = speakup_add_virtual_keyboard();
  2089. if (err)
  2090. goto error_virtkeyboard;
  2091. first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
  2092. if (!first_console) {
  2093. err = -ENOMEM;
  2094. goto error_alloc;
  2095. }
  2096. speakup_console[vc->vc_num] = first_console;
  2097. speakup_date(vc);
  2098. for (i = 0; i < MAX_NR_CONSOLES; i++)
  2099. if (vc_cons[i].d) {
  2100. err = speakup_allocate(vc_cons[i].d);
  2101. if (err)
  2102. goto error_kobjects;
  2103. }
  2104. if (spk_quiet_boot)
  2105. spk_shut_up |= 0x01;
  2106. err = speakup_kobj_init();
  2107. if (err)
  2108. goto error_kobjects;
  2109. synth_init(synth_name);
  2110. speakup_register_devsynth();
  2111. /*
  2112. * register_devsynth might fail, but this error is not fatal.
  2113. * /dev/synth is an extra feature; the rest of Speakup
  2114. * will work fine without it.
  2115. */
  2116. err = register_keyboard_notifier(&keyboard_notifier_block);
  2117. if (err)
  2118. goto error_kbdnotifier;
  2119. err = register_vt_notifier(&vt_notifier_block);
  2120. if (err)
  2121. goto error_vtnotifier;
  2122. speakup_task = kthread_create(speakup_thread, NULL, "speakup");
  2123. if (IS_ERR(speakup_task)) {
  2124. err = PTR_ERR(speakup_task);
  2125. goto error_task;
  2126. }
  2127. set_user_nice(speakup_task, 10);
  2128. wake_up_process(speakup_task);
  2129. pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
  2130. pr_info("synth name on entry is: %s\n", synth_name);
  2131. goto out;
  2132. error_task:
  2133. unregister_vt_notifier(&vt_notifier_block);
  2134. error_vtnotifier:
  2135. unregister_keyboard_notifier(&keyboard_notifier_block);
  2136. del_timer(&cursor_timer);
  2137. error_kbdnotifier:
  2138. speakup_unregister_devsynth();
  2139. mutex_lock(&spk_mutex);
  2140. synth_release();
  2141. mutex_unlock(&spk_mutex);
  2142. speakup_kobj_exit();
  2143. error_kobjects:
  2144. for (i = 0; i < MAX_NR_CONSOLES; i++)
  2145. kfree(speakup_console[i]);
  2146. error_alloc:
  2147. speakup_remove_virtual_keyboard();
  2148. error_virtkeyboard:
  2149. for (i = 0; i < MAXVARS; i++)
  2150. speakup_unregister_var(i);
  2151. for (i = 0; i < 256; i++) {
  2152. if (spk_characters[i] != spk_default_chars[i])
  2153. kfree(spk_characters[i]);
  2154. }
  2155. spk_free_user_msgs();
  2156. out:
  2157. return err;
  2158. }
  2159. module_init(speakup_init);
  2160. module_exit(speakup_exit);