sisusb_con.c 37 KB

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