sisusb_con.c 36 KB

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