sisusb_con.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536
  1. /*
  2. * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
  3. *
  4. * VGA text mode console part
  5. *
  6. * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
  7. *
  8. * If distributed as part of the Linux kernel, this code is licensed under the
  9. * terms of the GPL v2.
  10. *
  11. * Otherwise, the following license terms apply:
  12. *
  13. * * Redistribution and use in source and binary forms, with or without
  14. * * modification, are permitted provided that the following conditions
  15. * * are met:
  16. * * 1) Redistributions of source code must retain the above copyright
  17. * * notice, this list of conditions and the following disclaimer.
  18. * * 2) Redistributions in binary form must reproduce the above copyright
  19. * * notice, this list of conditions and the following disclaimer in the
  20. * * documentation and/or other materials provided with the distribution.
  21. * * 3) The name of the author may not be used to endorse or promote products
  22. * * derived from this software without specific psisusbr written permission.
  23. * *
  24. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  25. * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  26. * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  27. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  28. * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  29. * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  30. * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31. * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32. * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  33. * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. * Author: Thomas Winischhofer <thomas@winischhofer.net>
  36. *
  37. * Portions based on vgacon.c which are
  38. * Created 28 Sep 1997 by Geert Uytterhoeven
  39. * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
  40. * based on code Copyright (C) 1991, 1992 Linus Torvalds
  41. * 1995 Jay Estabrook
  42. *
  43. * A note on using in_atomic() in here: We can't handle console
  44. * calls from non-schedulable context due to our USB-dependend
  45. * nature. For now, this driver just ignores any calls if it
  46. * detects this state.
  47. *
  48. */
  49. #include <linux/mutex.h>
  50. #include <linux/module.h>
  51. #include <linux/kernel.h>
  52. #include <linux/signal.h>
  53. #include <linux/fs.h>
  54. #include <linux/usb.h>
  55. #include <linux/tty.h>
  56. #include <linux/console.h>
  57. #include <linux/string.h>
  58. #include <linux/kd.h>
  59. #include <linux/init.h>
  60. #include <linux/vt_kern.h>
  61. #include <linux/selection.h>
  62. #include <linux/spinlock.h>
  63. #include <linux/kref.h>
  64. #include <linux/ioport.h>
  65. #include <linux/interrupt.h>
  66. #include <linux/vmalloc.h>
  67. #include "sisusb.h"
  68. #include "sisusb_init.h"
  69. #ifdef INCL_SISUSB_CON
  70. #define sisusbcon_writew(val, addr) (*(addr) = (val))
  71. #define sisusbcon_readw(addr) (*(addr))
  72. #define sisusbcon_memmovew(d, s, c) memmove(d, s, c)
  73. #define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c)
  74. /* vc_data -> sisusb conversion table */
  75. static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
  76. /* Forward declaration */
  77. static const struct consw sisusb_con;
  78. static inline void
  79. sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
  80. {
  81. count /= 2;
  82. while (count--)
  83. sisusbcon_writew(c, s++);
  84. }
  85. static inline void
  86. sisusb_initialize(struct sisusb_usb_data *sisusb)
  87. {
  88. /* Reset cursor and start address */
  89. if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00))
  90. return;
  91. if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00))
  92. return;
  93. if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00))
  94. return;
  95. sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00);
  96. }
  97. static inline void
  98. sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c)
  99. {
  100. sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2;
  101. sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
  102. sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
  103. }
  104. void
  105. sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location)
  106. {
  107. if (sisusb->sisusb_cursor_loc == location)
  108. return;
  109. sisusb->sisusb_cursor_loc = location;
  110. /* Hardware bug: Text cursor appears twice or not at all
  111. * at some positions. Work around it with the cursor skew
  112. * bits.
  113. */
  114. if ((location & 0x0007) == 0x0007) {
  115. sisusb->bad_cursor_pos = 1;
  116. location--;
  117. if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20))
  118. return;
  119. } else if (sisusb->bad_cursor_pos) {
  120. if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f))
  121. return;
  122. sisusb->bad_cursor_pos = 0;
  123. }
  124. if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8)))
  125. return;
  126. sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff));
  127. }
  128. static inline struct sisusb_usb_data *
  129. sisusb_get_sisusb(unsigned short console)
  130. {
  131. return mysisusbs[console];
  132. }
  133. static inline int
  134. sisusb_sisusb_valid(struct sisusb_usb_data *sisusb)
  135. {
  136. if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev)
  137. return 0;
  138. return 1;
  139. }
  140. static struct sisusb_usb_data *
  141. sisusb_get_sisusb_lock_and_check(unsigned short console)
  142. {
  143. struct sisusb_usb_data *sisusb;
  144. /* We can't handle console calls in non-schedulable
  145. * context due to our locks and the USB transport.
  146. * So we simply ignore them. This should only affect
  147. * some calls to printk.
  148. */
  149. if (in_atomic())
  150. return NULL;
  151. sisusb = sisusb_get_sisusb(console);
  152. if (!sisusb)
  153. return NULL;
  154. mutex_lock(&sisusb->lock);
  155. if (!sisusb_sisusb_valid(sisusb) ||
  156. !sisusb->havethisconsole[console]) {
  157. mutex_unlock(&sisusb->lock);
  158. return NULL;
  159. }
  160. return sisusb;
  161. }
  162. static int
  163. sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb)
  164. {
  165. if (sisusb->is_gfx ||
  166. sisusb->textmodedestroyed ||
  167. c->vc_mode != KD_TEXT)
  168. return 1;
  169. return 0;
  170. }
  171. /* con_startup console interface routine */
  172. static const char *
  173. sisusbcon_startup(void)
  174. {
  175. return "SISUSBCON";
  176. }
  177. /* con_init console interface routine */
  178. static void
  179. sisusbcon_init(struct vc_data *c, int init)
  180. {
  181. struct sisusb_usb_data *sisusb;
  182. int cols, rows;
  183. /* This is called by do_take_over_console(),
  184. * ie by us/under our control. It is
  185. * only called after text mode and fonts
  186. * are set up/restored.
  187. */
  188. sisusb = sisusb_get_sisusb(c->vc_num);
  189. if (!sisusb)
  190. return;
  191. mutex_lock(&sisusb->lock);
  192. if (!sisusb_sisusb_valid(sisusb)) {
  193. mutex_unlock(&sisusb->lock);
  194. return;
  195. }
  196. c->vc_can_do_color = 1;
  197. c->vc_complement_mask = 0x7700;
  198. c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0;
  199. sisusb->haveconsole = 1;
  200. sisusb->havethisconsole[c->vc_num] = 1;
  201. /* We only support 640x400 */
  202. c->vc_scan_lines = 400;
  203. c->vc_font.height = sisusb->current_font_height;
  204. /* We only support width = 8 */
  205. cols = 80;
  206. rows = c->vc_scan_lines / c->vc_font.height;
  207. /* Increment usage count for our sisusb.
  208. * Doing so saves us from upping/downing
  209. * the disconnect semaphore; we can't
  210. * lose our sisusb until this is undone
  211. * in con_deinit. For all other console
  212. * interface functions, it suffices to
  213. * use sisusb->lock and do a quick check
  214. * of sisusb for device disconnection.
  215. */
  216. kref_get(&sisusb->kref);
  217. if (!*c->vc_uni_pagedir_loc)
  218. con_set_default_unimap(c);
  219. mutex_unlock(&sisusb->lock);
  220. if (init) {
  221. c->vc_cols = cols;
  222. c->vc_rows = rows;
  223. } else
  224. vc_resize(c, cols, rows);
  225. }
  226. /* con_deinit console interface routine */
  227. static void
  228. sisusbcon_deinit(struct vc_data *c)
  229. {
  230. struct sisusb_usb_data *sisusb;
  231. int i;
  232. /* This is called by do_take_over_console()
  233. * and others, ie not under our control.
  234. */
  235. sisusb = sisusb_get_sisusb(c->vc_num);
  236. if (!sisusb)
  237. return;
  238. mutex_lock(&sisusb->lock);
  239. /* Clear ourselves in mysisusbs */
  240. mysisusbs[c->vc_num] = NULL;
  241. sisusb->havethisconsole[c->vc_num] = 0;
  242. /* Free our font buffer if all consoles are gone */
  243. if (sisusb->font_backup) {
  244. for(i = 0; i < MAX_NR_CONSOLES; i++) {
  245. if (sisusb->havethisconsole[c->vc_num])
  246. break;
  247. }
  248. if (i == MAX_NR_CONSOLES) {
  249. vfree(sisusb->font_backup);
  250. sisusb->font_backup = NULL;
  251. }
  252. }
  253. mutex_unlock(&sisusb->lock);
  254. /* decrement the usage count on our sisusb */
  255. kref_put(&sisusb->kref, sisusb_delete);
  256. }
  257. /* interface routine */
  258. static u8
  259. sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
  260. u8 blink, u8 underline, u8 reverse, u8 unused)
  261. {
  262. u8 attr = color;
  263. if (underline)
  264. attr = (attr & 0xf0) | c->vc_ulcolor;
  265. else if (intensity == 0)
  266. attr = (attr & 0xf0) | c->vc_halfcolor;
  267. if (reverse)
  268. attr = ((attr) & 0x88) |
  269. ((((attr) >> 4) |
  270. ((attr) << 4)) & 0x77);
  271. if (blink)
  272. attr ^= 0x80;
  273. if (intensity == 2)
  274. attr ^= 0x08;
  275. return attr;
  276. }
  277. /* Interface routine */
  278. static void
  279. sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count)
  280. {
  281. /* Invert a region. This is called with a pointer
  282. * to the console's internal screen buffer. So we
  283. * simply do the inversion there and rely on
  284. * a call to putc(s) to update the real screen.
  285. */
  286. while (count--) {
  287. u16 a = sisusbcon_readw(p);
  288. a = ((a) & 0x88ff) |
  289. (((a) & 0x7000) >> 4) |
  290. (((a) & 0x0700) << 4);
  291. sisusbcon_writew(a, p++);
  292. }
  293. }
  294. #define SISUSB_VADDR(x,y) \
  295. ((u16 *)c->vc_origin + \
  296. (y) * sisusb->sisusb_num_columns + \
  297. (x))
  298. #define SISUSB_HADDR(x,y) \
  299. ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \
  300. (y) * sisusb->sisusb_num_columns + \
  301. (x))
  302. /* Interface routine */
  303. static void
  304. sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
  305. {
  306. struct sisusb_usb_data *sisusb;
  307. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  308. if (!sisusb)
  309. return;
  310. /* sisusb->lock is down */
  311. if (sisusb_is_inactive(c, sisusb)) {
  312. mutex_unlock(&sisusb->lock);
  313. return;
  314. }
  315. sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
  316. (long)SISUSB_HADDR(x, y), 2);
  317. mutex_unlock(&sisusb->lock);
  318. }
  319. /* Interface routine */
  320. static void
  321. sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
  322. int count, int y, int x)
  323. {
  324. struct sisusb_usb_data *sisusb;
  325. u16 *dest;
  326. int i;
  327. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  328. if (!sisusb)
  329. return;
  330. /* sisusb->lock is down */
  331. /* Need to put the characters into the buffer ourselves,
  332. * because the vt does this AFTER calling us.
  333. */
  334. dest = SISUSB_VADDR(x, y);
  335. for (i = count; i > 0; i--)
  336. sisusbcon_writew(sisusbcon_readw(s++), dest++);
  337. if (sisusb_is_inactive(c, sisusb)) {
  338. mutex_unlock(&sisusb->lock);
  339. return;
  340. }
  341. sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
  342. (long)SISUSB_HADDR(x, y), count * 2);
  343. mutex_unlock(&sisusb->lock);
  344. }
  345. /* Interface routine */
  346. static void
  347. sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
  348. {
  349. struct sisusb_usb_data *sisusb;
  350. u16 eattr = c->vc_video_erase_char;
  351. int i, length, cols;
  352. u16 *dest;
  353. if (width <= 0 || height <= 0)
  354. return;
  355. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  356. if (!sisusb)
  357. return;
  358. /* sisusb->lock is down */
  359. /* Need to clear buffer ourselves, because the vt does
  360. * this AFTER calling us.
  361. */
  362. dest = SISUSB_VADDR(x, y);
  363. cols = sisusb->sisusb_num_columns;
  364. if (width > cols)
  365. width = cols;
  366. if (x == 0 && width >= c->vc_cols) {
  367. sisusbcon_memsetw(dest, eattr, height * cols * 2);
  368. } else {
  369. for (i = height; i > 0; i--, dest += cols)
  370. sisusbcon_memsetw(dest, eattr, width * 2);
  371. }
  372. if (sisusb_is_inactive(c, sisusb)) {
  373. mutex_unlock(&sisusb->lock);
  374. return;
  375. }
  376. length = ((height * cols) - x - (cols - width - x)) * 2;
  377. sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
  378. (long)SISUSB_HADDR(x, y), length);
  379. mutex_unlock(&sisusb->lock);
  380. }
  381. /* interface routine */
  382. static int
  383. sisusbcon_switch(struct vc_data *c)
  384. {
  385. struct sisusb_usb_data *sisusb;
  386. int length;
  387. /* Returnvalue 0 means we have fully restored screen,
  388. * and vt doesn't need to call do_update_region().
  389. * Returnvalue != 0 naturally means the opposite.
  390. */
  391. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  392. if (!sisusb)
  393. return 0;
  394. /* sisusb->lock is down */
  395. /* Don't write to screen if in gfx mode */
  396. if (sisusb_is_inactive(c, sisusb)) {
  397. mutex_unlock(&sisusb->lock);
  398. return 0;
  399. }
  400. /* That really should not happen. It would mean we are
  401. * being called while the vc is using its private buffer
  402. * as origin.
  403. */
  404. if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
  405. mutex_unlock(&sisusb->lock);
  406. dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
  407. return 0;
  408. }
  409. /* Check that we don't copy too much */
  410. length = min((int)c->vc_screenbuf_size,
  411. (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
  412. /* Restore the screen contents */
  413. sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf,
  414. length);
  415. sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
  416. (long)SISUSB_HADDR(0, 0),
  417. length);
  418. mutex_unlock(&sisusb->lock);
  419. return 0;
  420. }
  421. /* interface routine */
  422. static void
  423. sisusbcon_save_screen(struct vc_data *c)
  424. {
  425. struct sisusb_usb_data *sisusb;
  426. int length;
  427. /* Save the current screen contents to vc's private
  428. * buffer.
  429. */
  430. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  431. if (!sisusb)
  432. return;
  433. /* sisusb->lock is down */
  434. if (sisusb_is_inactive(c, sisusb)) {
  435. mutex_unlock(&sisusb->lock);
  436. return;
  437. }
  438. /* Check that we don't copy too much */
  439. length = min((int)c->vc_screenbuf_size,
  440. (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
  441. /* Save the screen contents to vc's private buffer */
  442. sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
  443. length);
  444. mutex_unlock(&sisusb->lock);
  445. }
  446. /* interface routine */
  447. static void
  448. sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
  449. {
  450. struct sisusb_usb_data *sisusb;
  451. int i, j;
  452. /* Return value not used by vt */
  453. if (!con_is_visible(c))
  454. return;
  455. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  456. if (!sisusb)
  457. return;
  458. /* sisusb->lock is down */
  459. if (sisusb_is_inactive(c, sisusb)) {
  460. mutex_unlock(&sisusb->lock);
  461. return;
  462. }
  463. for (i = j = 0; i < 16; i++) {
  464. if (sisusb_setreg(sisusb, SISCOLIDX, table[i]))
  465. break;
  466. if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
  467. break;
  468. if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
  469. break;
  470. if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
  471. break;
  472. }
  473. mutex_unlock(&sisusb->lock);
  474. }
  475. /* interface routine */
  476. static int
  477. sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
  478. {
  479. struct sisusb_usb_data *sisusb;
  480. u8 sr1, cr17, pmreg, cr63;
  481. int ret = 0;
  482. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  483. if (!sisusb)
  484. return 0;
  485. /* sisusb->lock is down */
  486. if (mode_switch)
  487. sisusb->is_gfx = blank ? 1 : 0;
  488. if (sisusb_is_inactive(c, sisusb)) {
  489. mutex_unlock(&sisusb->lock);
  490. return 0;
  491. }
  492. switch (blank) {
  493. case 1: /* Normal blanking: Clear screen */
  494. case -1:
  495. sisusbcon_memsetw((u16 *)c->vc_origin,
  496. c->vc_video_erase_char,
  497. c->vc_screenbuf_size);
  498. sisusb_copy_memory(sisusb,
  499. (unsigned char *)c->vc_origin,
  500. (u32)(sisusb->vrambase +
  501. (c->vc_origin - sisusb->scrbuf)),
  502. c->vc_screenbuf_size);
  503. sisusb->con_blanked = 1;
  504. ret = 1;
  505. break;
  506. default: /* VESA blanking */
  507. switch (blank) {
  508. case 0: /* Unblank */
  509. sr1 = 0x00;
  510. cr17 = 0x80;
  511. pmreg = 0x00;
  512. cr63 = 0x00;
  513. ret = 1;
  514. sisusb->con_blanked = 0;
  515. break;
  516. case VESA_VSYNC_SUSPEND + 1:
  517. sr1 = 0x20;
  518. cr17 = 0x80;
  519. pmreg = 0x80;
  520. cr63 = 0x40;
  521. break;
  522. case VESA_HSYNC_SUSPEND + 1:
  523. sr1 = 0x20;
  524. cr17 = 0x80;
  525. pmreg = 0x40;
  526. cr63 = 0x40;
  527. break;
  528. case VESA_POWERDOWN + 1:
  529. sr1 = 0x20;
  530. cr17 = 0x00;
  531. pmreg = 0xc0;
  532. cr63 = 0x40;
  533. break;
  534. default:
  535. mutex_unlock(&sisusb->lock);
  536. return -EINVAL;
  537. }
  538. sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1);
  539. sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17);
  540. sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg);
  541. sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63);
  542. }
  543. mutex_unlock(&sisusb->lock);
  544. return ret;
  545. }
  546. /* interface routine */
  547. static void
  548. sisusbcon_scrolldelta(struct vc_data *c, int lines)
  549. {
  550. struct sisusb_usb_data *sisusb;
  551. int margin = c->vc_size_row * 4;
  552. int ul, we, p, st;
  553. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  554. if (!sisusb)
  555. return;
  556. /* sisusb->lock is down */
  557. if (sisusb_is_inactive(c, sisusb)) {
  558. mutex_unlock(&sisusb->lock);
  559. return;
  560. }
  561. if (!lines) /* Turn scrollback off */
  562. c->vc_visible_origin = c->vc_origin;
  563. else {
  564. if (sisusb->con_rolled_over >
  565. (c->vc_scr_end - sisusb->scrbuf) + margin) {
  566. ul = c->vc_scr_end - sisusb->scrbuf;
  567. we = sisusb->con_rolled_over + c->vc_size_row;
  568. } else {
  569. ul = 0;
  570. we = sisusb->scrbuf_size;
  571. }
  572. p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we +
  573. lines * c->vc_size_row;
  574. st = (c->vc_origin - sisusb->scrbuf - ul + we) % we;
  575. if (st < 2 * margin)
  576. margin = 0;
  577. if (p < margin)
  578. p = 0;
  579. if (p > st - margin)
  580. p = st;
  581. c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we;
  582. }
  583. sisusbcon_set_start_address(sisusb, c);
  584. mutex_unlock(&sisusb->lock);
  585. }
  586. /* Interface routine */
  587. static void
  588. sisusbcon_cursor(struct vc_data *c, int mode)
  589. {
  590. struct sisusb_usb_data *sisusb;
  591. int from, to, baseline;
  592. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  593. if (!sisusb)
  594. return;
  595. /* sisusb->lock is down */
  596. if (sisusb_is_inactive(c, sisusb)) {
  597. mutex_unlock(&sisusb->lock);
  598. return;
  599. }
  600. if (c->vc_origin != c->vc_visible_origin) {
  601. c->vc_visible_origin = c->vc_origin;
  602. sisusbcon_set_start_address(sisusb, c);
  603. }
  604. if (mode == CM_ERASE) {
  605. sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
  606. sisusb->sisusb_cursor_size_to = -1;
  607. mutex_unlock(&sisusb->lock);
  608. return;
  609. }
  610. sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2);
  611. baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
  612. switch (c->vc_cursor_type & 0x0f) {
  613. case CUR_BLOCK: from = 1;
  614. to = c->vc_font.height;
  615. break;
  616. case CUR_TWO_THIRDS: from = c->vc_font.height / 3;
  617. to = baseline;
  618. break;
  619. case CUR_LOWER_HALF: from = c->vc_font.height / 2;
  620. to = baseline;
  621. break;
  622. case CUR_LOWER_THIRD: from = (c->vc_font.height * 2) / 3;
  623. to = baseline;
  624. break;
  625. case CUR_NONE: from = 31;
  626. to = 30;
  627. break;
  628. default:
  629. case CUR_UNDERLINE: from = baseline - 1;
  630. to = baseline;
  631. break;
  632. }
  633. if (sisusb->sisusb_cursor_size_from != from ||
  634. sisusb->sisusb_cursor_size_to != to) {
  635. sisusb_setidxreg(sisusb, SISCR, 0x0a, from);
  636. sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to);
  637. sisusb->sisusb_cursor_size_from = from;
  638. sisusb->sisusb_cursor_size_to = to;
  639. }
  640. mutex_unlock(&sisusb->lock);
  641. }
  642. static int
  643. sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
  644. int t, int b, int dir, int lines)
  645. {
  646. int cols = sisusb->sisusb_num_columns;
  647. int length = ((b - t) * cols) * 2;
  648. u16 eattr = c->vc_video_erase_char;
  649. /* sisusb->lock is down */
  650. /* Scroll an area which does not match the
  651. * visible screen's dimensions. This needs
  652. * to be done separately, as it does not
  653. * use hardware panning.
  654. */
  655. switch (dir) {
  656. case SM_UP:
  657. sisusbcon_memmovew(SISUSB_VADDR(0, t),
  658. SISUSB_VADDR(0, t + lines),
  659. (b - t - lines) * cols * 2);
  660. sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr,
  661. lines * cols * 2);
  662. break;
  663. case SM_DOWN:
  664. sisusbcon_memmovew(SISUSB_VADDR(0, t + lines),
  665. SISUSB_VADDR(0, t),
  666. (b - t - lines) * cols * 2);
  667. sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr,
  668. lines * cols * 2);
  669. break;
  670. }
  671. sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
  672. (long)SISUSB_HADDR(0, t), length);
  673. mutex_unlock(&sisusb->lock);
  674. return 1;
  675. }
  676. /* Interface routine */
  677. static int
  678. sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
  679. {
  680. struct sisusb_usb_data *sisusb;
  681. u16 eattr = c->vc_video_erase_char;
  682. int copyall = 0;
  683. unsigned long oldorigin;
  684. unsigned int delta = lines * c->vc_size_row;
  685. u32 originoffset;
  686. /* Returning != 0 means we have done the scrolling successfully.
  687. * Returning 0 makes vt do the scrolling on its own.
  688. * Note that con_scroll is only called if the console is
  689. * visible. In that case, the origin should be our buffer,
  690. * not the vt's private one.
  691. */
  692. if (!lines)
  693. return 1;
  694. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  695. if (!sisusb)
  696. return 0;
  697. /* sisusb->lock is down */
  698. if (sisusb_is_inactive(c, sisusb)) {
  699. mutex_unlock(&sisusb->lock);
  700. return 0;
  701. }
  702. /* Special case */
  703. if (t || b != c->vc_rows)
  704. return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines);
  705. if (c->vc_origin != c->vc_visible_origin) {
  706. c->vc_visible_origin = c->vc_origin;
  707. sisusbcon_set_start_address(sisusb, c);
  708. }
  709. /* limit amount to maximum realistic size */
  710. if (lines > c->vc_rows)
  711. lines = c->vc_rows;
  712. oldorigin = c->vc_origin;
  713. switch (dir) {
  714. case SM_UP:
  715. if (c->vc_scr_end + delta >=
  716. sisusb->scrbuf + sisusb->scrbuf_size) {
  717. sisusbcon_memcpyw((u16 *)sisusb->scrbuf,
  718. (u16 *)(oldorigin + delta),
  719. c->vc_screenbuf_size - delta);
  720. c->vc_origin = sisusb->scrbuf;
  721. sisusb->con_rolled_over = oldorigin - sisusb->scrbuf;
  722. copyall = 1;
  723. } else
  724. c->vc_origin += delta;
  725. sisusbcon_memsetw(
  726. (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta),
  727. eattr, delta);
  728. break;
  729. case SM_DOWN:
  730. if (oldorigin - delta < sisusb->scrbuf) {
  731. sisusbcon_memmovew((u16 *)(sisusb->scrbuf +
  732. sisusb->scrbuf_size -
  733. c->vc_screenbuf_size +
  734. delta),
  735. (u16 *)oldorigin,
  736. c->vc_screenbuf_size - delta);
  737. c->vc_origin = sisusb->scrbuf +
  738. sisusb->scrbuf_size -
  739. c->vc_screenbuf_size;
  740. sisusb->con_rolled_over = 0;
  741. copyall = 1;
  742. } else
  743. c->vc_origin -= delta;
  744. c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
  745. scr_memsetw((u16 *)(c->vc_origin), eattr, delta);
  746. break;
  747. }
  748. originoffset = (u32)(c->vc_origin - sisusb->scrbuf);
  749. if (copyall)
  750. sisusb_copy_memory(sisusb,
  751. (char *)c->vc_origin,
  752. (u32)(sisusb->vrambase + originoffset),
  753. c->vc_screenbuf_size);
  754. else if (dir == SM_UP)
  755. sisusb_copy_memory(sisusb,
  756. (char *)c->vc_origin + c->vc_screenbuf_size - delta,
  757. (u32)sisusb->vrambase + originoffset +
  758. c->vc_screenbuf_size - delta,
  759. delta);
  760. else
  761. sisusb_copy_memory(sisusb,
  762. (char *)c->vc_origin,
  763. (u32)(sisusb->vrambase + originoffset),
  764. delta);
  765. c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
  766. c->vc_visible_origin = c->vc_origin;
  767. sisusbcon_set_start_address(sisusb, c);
  768. c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
  769. mutex_unlock(&sisusb->lock);
  770. return 1;
  771. }
  772. /* Interface routine */
  773. static int
  774. sisusbcon_set_origin(struct vc_data *c)
  775. {
  776. struct sisusb_usb_data *sisusb;
  777. /* Returning != 0 means we were successful.
  778. * Returning 0 will vt make to use its own
  779. * screenbuffer as the origin.
  780. */
  781. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  782. if (!sisusb)
  783. return 0;
  784. /* sisusb->lock is down */
  785. if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
  786. mutex_unlock(&sisusb->lock);
  787. return 0;
  788. }
  789. c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
  790. sisusbcon_set_start_address(sisusb, c);
  791. sisusb->con_rolled_over = 0;
  792. mutex_unlock(&sisusb->lock);
  793. return 1;
  794. }
  795. /* Interface routine */
  796. static int
  797. sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
  798. unsigned int user)
  799. {
  800. struct sisusb_usb_data *sisusb;
  801. int fh;
  802. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  803. if (!sisusb)
  804. return -ENODEV;
  805. fh = sisusb->current_font_height;
  806. mutex_unlock(&sisusb->lock);
  807. /* We are quite unflexible as regards resizing. The vt code
  808. * handles sizes where the line length isn't equal the pitch
  809. * quite badly. As regards the rows, our panning tricks only
  810. * work well if the number of rows equals the visible number
  811. * of rows.
  812. */
  813. if (newcols != 80 || c->vc_scan_lines / fh != newrows)
  814. return -EINVAL;
  815. return 0;
  816. }
  817. int
  818. sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
  819. u8 *arg, int cmapsz, int ch512, int dorecalc,
  820. struct vc_data *c, int fh, int uplock)
  821. {
  822. int font_select = 0x00, i, err = 0;
  823. u32 offset = 0;
  824. u8 dummy;
  825. /* sisusb->lock is down */
  826. /*
  827. * The default font is kept in slot 0.
  828. * A user font is loaded in slot 2 (256 ch)
  829. * or 2+3 (512 ch).
  830. */
  831. if ((slot != 0 && slot != 2) || !fh) {
  832. if (uplock)
  833. mutex_unlock(&sisusb->lock);
  834. return -EINVAL;
  835. }
  836. if (set)
  837. sisusb->font_slot = slot;
  838. /* Default font is always 256 */
  839. if (slot == 0)
  840. ch512 = 0;
  841. else
  842. offset = 4 * cmapsz;
  843. font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a);
  844. err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
  845. err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */
  846. err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */
  847. err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */
  848. if (err)
  849. goto font_op_error;
  850. err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */
  851. err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */
  852. err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */
  853. if (err)
  854. goto font_op_error;
  855. if (arg) {
  856. if (set)
  857. for (i = 0; i < cmapsz; i++) {
  858. err |= sisusb_writeb(sisusb,
  859. sisusb->vrambase + offset + i,
  860. arg[i]);
  861. if (err)
  862. break;
  863. }
  864. else
  865. for (i = 0; i < cmapsz; i++) {
  866. err |= sisusb_readb(sisusb,
  867. sisusb->vrambase + offset + i,
  868. &arg[i]);
  869. if (err)
  870. break;
  871. }
  872. /*
  873. * In 512-character mode, the character map is not contiguous if
  874. * we want to remain EGA compatible -- which we do
  875. */
  876. if (ch512) {
  877. if (set)
  878. for (i = 0; i < cmapsz; i++) {
  879. err |= sisusb_writeb(sisusb,
  880. sisusb->vrambase + offset +
  881. (2 * cmapsz) + i,
  882. arg[cmapsz + i]);
  883. if (err)
  884. break;
  885. }
  886. else
  887. for (i = 0; i < cmapsz; i++) {
  888. err |= sisusb_readb(sisusb,
  889. sisusb->vrambase + offset +
  890. (2 * cmapsz) + i,
  891. &arg[cmapsz + i]);
  892. if (err)
  893. break;
  894. }
  895. }
  896. }
  897. if (err)
  898. goto font_op_error;
  899. err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
  900. err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */
  901. err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */
  902. if (set)
  903. sisusb_setidxreg(sisusb, SISSR, 0x03, font_select);
  904. err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */
  905. if (err)
  906. goto font_op_error;
  907. err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */
  908. err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */
  909. err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */
  910. if (err)
  911. goto font_op_error;
  912. if ((set) && (ch512 != sisusb->current_font_512)) {
  913. /* Font is shared among all our consoles.
  914. * And so is the hi_font_mask.
  915. */
  916. for (i = 0; i < MAX_NR_CONSOLES; i++) {
  917. struct vc_data *d = vc_cons[i].d;
  918. if (d && d->vc_sw == &sisusb_con)
  919. d->vc_hi_font_mask = ch512 ? 0x0800 : 0;
  920. }
  921. sisusb->current_font_512 = ch512;
  922. /* color plane enable register:
  923. 256-char: enable intensity bit
  924. 512-char: disable intensity bit */
  925. sisusb_getreg(sisusb, SISINPSTAT, &dummy);
  926. sisusb_setreg(sisusb, SISAR, 0x12);
  927. sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f);
  928. sisusb_getreg(sisusb, SISINPSTAT, &dummy);
  929. sisusb_setreg(sisusb, SISAR, 0x20);
  930. sisusb_getreg(sisusb, SISINPSTAT, &dummy);
  931. }
  932. if (dorecalc) {
  933. /*
  934. * Adjust the screen to fit a font of a certain height
  935. */
  936. unsigned char ovr, vde, fsr;
  937. int rows = 0, maxscan = 0;
  938. if (c) {
  939. /* Number of video rows */
  940. rows = c->vc_scan_lines / fh;
  941. /* Scan lines to actually display-1 */
  942. maxscan = rows * fh - 1;
  943. /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n",
  944. rows, maxscan, fh, c->vc_scan_lines);*/
  945. sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr);
  946. vde = maxscan & 0xff;
  947. ovr = (ovr & 0xbd) |
  948. ((maxscan & 0x100) >> 7) |
  949. ((maxscan & 0x200) >> 3);
  950. sisusb_setidxreg(sisusb, SISCR, 0x07, ovr);
  951. sisusb_setidxreg(sisusb, SISCR, 0x12, vde);
  952. }
  953. sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr);
  954. fsr = (fsr & 0xe0) | (fh - 1);
  955. sisusb_setidxreg(sisusb, SISCR, 0x09, fsr);
  956. sisusb->current_font_height = fh;
  957. sisusb->sisusb_cursor_size_from = -1;
  958. sisusb->sisusb_cursor_size_to = -1;
  959. }
  960. if (uplock)
  961. mutex_unlock(&sisusb->lock);
  962. if (dorecalc && c) {
  963. int rows = c->vc_scan_lines / fh;
  964. /* Now adjust our consoles' size */
  965. for (i = 0; i < MAX_NR_CONSOLES; i++) {
  966. struct vc_data *vc = vc_cons[i].d;
  967. if (vc && vc->vc_sw == &sisusb_con) {
  968. if (con_is_visible(vc)) {
  969. vc->vc_sw->con_cursor(vc, CM_DRAW);
  970. }
  971. vc->vc_font.height = fh;
  972. vc_resize(vc, 0, rows);
  973. }
  974. }
  975. }
  976. return 0;
  977. font_op_error:
  978. if (uplock)
  979. mutex_unlock(&sisusb->lock);
  980. return -EIO;
  981. }
  982. /* Interface routine */
  983. static int
  984. sisusbcon_font_set(struct vc_data *c, struct console_font *font,
  985. unsigned flags)
  986. {
  987. struct sisusb_usb_data *sisusb;
  988. unsigned charcount = font->charcount;
  989. if (font->width != 8 || (charcount != 256 && charcount != 512))
  990. return -EINVAL;
  991. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  992. if (!sisusb)
  993. return -ENODEV;
  994. /* sisusb->lock is down */
  995. /* Save the user-provided font into a buffer. This
  996. * is used for restoring text mode after quitting
  997. * from X and for the con_getfont routine.
  998. */
  999. if (sisusb->font_backup) {
  1000. if (sisusb->font_backup_size < charcount) {
  1001. vfree(sisusb->font_backup);
  1002. sisusb->font_backup = NULL;
  1003. }
  1004. }
  1005. if (!sisusb->font_backup)
  1006. sisusb->font_backup = vmalloc(charcount * 32);
  1007. if (sisusb->font_backup) {
  1008. memcpy(sisusb->font_backup, font->data, charcount * 32);
  1009. sisusb->font_backup_size = charcount;
  1010. sisusb->font_backup_height = font->height;
  1011. sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
  1012. }
  1013. /* do_font_op ups sisusb->lock */
  1014. return sisusbcon_do_font_op(sisusb, 1, 2, font->data,
  1015. 8192, (charcount == 512),
  1016. (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0,
  1017. c, font->height, 1);
  1018. }
  1019. /* Interface routine */
  1020. static int
  1021. sisusbcon_font_get(struct vc_data *c, struct console_font *font)
  1022. {
  1023. struct sisusb_usb_data *sisusb;
  1024. sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
  1025. if (!sisusb)
  1026. return -ENODEV;
  1027. /* sisusb->lock is down */
  1028. font->width = 8;
  1029. font->height = c->vc_font.height;
  1030. font->charcount = 256;
  1031. if (!font->data) {
  1032. mutex_unlock(&sisusb->lock);
  1033. return 0;
  1034. }
  1035. if (!sisusb->font_backup) {
  1036. mutex_unlock(&sisusb->lock);
  1037. return -ENODEV;
  1038. }
  1039. /* Copy 256 chars only, like vgacon */
  1040. memcpy(font->data, sisusb->font_backup, 256 * 32);
  1041. mutex_unlock(&sisusb->lock);
  1042. return 0;
  1043. }
  1044. /*
  1045. * The console `switch' structure for the sisusb console
  1046. */
  1047. static const struct consw sisusb_con = {
  1048. .owner = THIS_MODULE,
  1049. .con_startup = sisusbcon_startup,
  1050. .con_init = sisusbcon_init,
  1051. .con_deinit = sisusbcon_deinit,
  1052. .con_clear = sisusbcon_clear,
  1053. .con_putc = sisusbcon_putc,
  1054. .con_putcs = sisusbcon_putcs,
  1055. .con_cursor = sisusbcon_cursor,
  1056. .con_scroll = sisusbcon_scroll,
  1057. .con_switch = sisusbcon_switch,
  1058. .con_blank = sisusbcon_blank,
  1059. .con_font_set = sisusbcon_font_set,
  1060. .con_font_get = sisusbcon_font_get,
  1061. .con_set_palette = sisusbcon_set_palette,
  1062. .con_scrolldelta = sisusbcon_scrolldelta,
  1063. .con_build_attr = sisusbcon_build_attr,
  1064. .con_invert_region = sisusbcon_invert_region,
  1065. .con_set_origin = sisusbcon_set_origin,
  1066. .con_save_screen = sisusbcon_save_screen,
  1067. .con_resize = sisusbcon_resize,
  1068. };
  1069. /* Our very own dummy console driver */
  1070. static const char *sisusbdummycon_startup(void)
  1071. {
  1072. return "SISUSBVGADUMMY";
  1073. }
  1074. static void sisusbdummycon_init(struct vc_data *vc, int init)
  1075. {
  1076. vc->vc_can_do_color = 1;
  1077. if (init) {
  1078. vc->vc_cols = 80;
  1079. vc->vc_rows = 25;
  1080. } else
  1081. vc_resize(vc, 80, 25);
  1082. }
  1083. static int sisusbdummycon_dummy(void)
  1084. {
  1085. return 0;
  1086. }
  1087. #define SISUSBCONDUMMY (void *)sisusbdummycon_dummy
  1088. static const struct consw sisusb_dummy_con = {
  1089. .owner = THIS_MODULE,
  1090. .con_startup = sisusbdummycon_startup,
  1091. .con_init = sisusbdummycon_init,
  1092. .con_deinit = SISUSBCONDUMMY,
  1093. .con_clear = SISUSBCONDUMMY,
  1094. .con_putc = SISUSBCONDUMMY,
  1095. .con_putcs = SISUSBCONDUMMY,
  1096. .con_cursor = SISUSBCONDUMMY,
  1097. .con_scroll = SISUSBCONDUMMY,
  1098. .con_switch = SISUSBCONDUMMY,
  1099. .con_blank = SISUSBCONDUMMY,
  1100. .con_font_set = SISUSBCONDUMMY,
  1101. .con_font_get = SISUSBCONDUMMY,
  1102. .con_font_default = SISUSBCONDUMMY,
  1103. .con_font_copy = SISUSBCONDUMMY,
  1104. };
  1105. int
  1106. sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
  1107. {
  1108. int i, ret;
  1109. mutex_lock(&sisusb->lock);
  1110. /* Erm.. that should not happen */
  1111. if (sisusb->haveconsole || !sisusb->SiS_Pr) {
  1112. mutex_unlock(&sisusb->lock);
  1113. return 1;
  1114. }
  1115. sisusb->con_first = first;
  1116. sisusb->con_last = last;
  1117. if (first > last ||
  1118. first > MAX_NR_CONSOLES ||
  1119. last > MAX_NR_CONSOLES) {
  1120. mutex_unlock(&sisusb->lock);
  1121. return 1;
  1122. }
  1123. /* If gfxcore not initialized or no consoles given, quit graciously */
  1124. if (!sisusb->gfxinit || first < 1 || last < 1) {
  1125. mutex_unlock(&sisusb->lock);
  1126. return 0;
  1127. }
  1128. sisusb->sisusb_cursor_loc = -1;
  1129. sisusb->sisusb_cursor_size_from = -1;
  1130. sisusb->sisusb_cursor_size_to = -1;
  1131. /* Set up text mode (and upload default font) */
  1132. if (sisusb_reset_text_mode(sisusb, 1)) {
  1133. mutex_unlock(&sisusb->lock);
  1134. dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
  1135. return 1;
  1136. }
  1137. /* Initialize some gfx registers */
  1138. sisusb_initialize(sisusb);
  1139. for (i = first - 1; i <= last - 1; i++) {
  1140. /* Save sisusb for our interface routines */
  1141. mysisusbs[i] = sisusb;
  1142. }
  1143. /* Initial console setup */
  1144. sisusb->sisusb_num_columns = 80;
  1145. /* Use a 32K buffer (matches b8000-bffff area) */
  1146. sisusb->scrbuf_size = 32 * 1024;
  1147. /* Allocate screen buffer */
  1148. if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
  1149. mutex_unlock(&sisusb->lock);
  1150. dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
  1151. return 1;
  1152. }
  1153. mutex_unlock(&sisusb->lock);
  1154. /* Now grab the desired console(s) */
  1155. console_lock();
  1156. ret = do_take_over_console(&sisusb_con, first - 1, last - 1, 0);
  1157. console_unlock();
  1158. if (!ret)
  1159. sisusb->haveconsole = 1;
  1160. else {
  1161. for (i = first - 1; i <= last - 1; i++)
  1162. mysisusbs[i] = NULL;
  1163. }
  1164. return ret;
  1165. }
  1166. void
  1167. sisusb_console_exit(struct sisusb_usb_data *sisusb)
  1168. {
  1169. int i;
  1170. /* This is called if the device is disconnected
  1171. * and while disconnect and lock semaphores
  1172. * are up. This should be save because we
  1173. * can't lose our sisusb any other way but by
  1174. * disconnection (and hence, the disconnect
  1175. * sema is for protecting all other access
  1176. * functions from disconnection, not the
  1177. * other way round).
  1178. */
  1179. /* Now what do we do in case of disconnection:
  1180. * One alternative would be to simply call
  1181. * give_up_console(). Nah, not a good idea.
  1182. * give_up_console() is obviously buggy as it
  1183. * only discards the consw pointer from the
  1184. * driver_map, but doesn't adapt vc->vc_sw
  1185. * of the affected consoles. Hence, the next
  1186. * call to any of the console functions will
  1187. * eventually take a trip to oops county.
  1188. * Also, give_up_console for some reason
  1189. * doesn't decrement our module refcount.
  1190. * Instead, we switch our consoles to a private
  1191. * dummy console. This, of course, keeps our
  1192. * refcount up as well, but it works perfectly.
  1193. */
  1194. if (sisusb->haveconsole) {
  1195. for (i = 0; i < MAX_NR_CONSOLES; i++)
  1196. if (sisusb->havethisconsole[i]) {
  1197. console_lock();
  1198. do_take_over_console(&sisusb_dummy_con, i, i, 0);
  1199. console_unlock();
  1200. /* At this point, con_deinit for all our
  1201. * consoles is executed by do_take_over_console().
  1202. */
  1203. }
  1204. sisusb->haveconsole = 0;
  1205. }
  1206. vfree((void *)sisusb->scrbuf);
  1207. sisusb->scrbuf = 0;
  1208. vfree(sisusb->font_backup);
  1209. sisusb->font_backup = NULL;
  1210. }
  1211. void __init sisusb_init_concode(void)
  1212. {
  1213. int i;
  1214. for (i = 0; i < MAX_NR_CONSOLES; i++)
  1215. mysisusbs[i] = NULL;
  1216. }
  1217. #endif /* INCL_CON */