main.c 62 KB

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