sisusb_con.c 37 KB

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