sisusb_con.c 37 KB

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