main.c 58 KB

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