video.S 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007
  1. /* video.S
  2. *
  3. * Display adapter & video mode setup, version 2.13 (14-May-99)
  4. *
  5. * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
  6. * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
  7. *
  8. * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
  9. *
  10. * For further information, look at Documentation/svga.txt.
  11. *
  12. */
  13. #include <linux/config.h> /* for CONFIG_VIDEO_* */
  14. /* Enable autodetection of SVGA adapters and modes. */
  15. #undef CONFIG_VIDEO_SVGA
  16. /* Enable autodetection of VESA modes */
  17. #define CONFIG_VIDEO_VESA
  18. /* Enable compacting of mode table */
  19. #define CONFIG_VIDEO_COMPACT
  20. /* Retain screen contents when switching modes */
  21. #define CONFIG_VIDEO_RETAIN
  22. /* Enable local mode list */
  23. #undef CONFIG_VIDEO_LOCAL
  24. /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
  25. #undef CONFIG_VIDEO_400_HACK
  26. /* Hack that lets you force specific BIOS mode ID and specific dimensions */
  27. #undef CONFIG_VIDEO_GFX_HACK
  28. #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
  29. #define VIDEO_GFX_BIOS_BX 0x0102
  30. #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
  31. /* This code uses an extended set of video mode numbers. These include:
  32. * Aliases for standard modes
  33. * NORMAL_VGA (-1)
  34. * EXTENDED_VGA (-2)
  35. * ASK_VGA (-3)
  36. * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
  37. * of compatibility when extending the table. These are between 0x00 and 0xff.
  38. */
  39. #define VIDEO_FIRST_MENU 0x0000
  40. /* Standard BIOS video modes (BIOS number + 0x0100) */
  41. #define VIDEO_FIRST_BIOS 0x0100
  42. /* VESA BIOS video modes (VESA number + 0x0200) */
  43. #define VIDEO_FIRST_VESA 0x0200
  44. /* Video7 special modes (BIOS number + 0x0900) */
  45. #define VIDEO_FIRST_V7 0x0900
  46. /* Special video modes */
  47. #define VIDEO_FIRST_SPECIAL 0x0f00
  48. #define VIDEO_80x25 0x0f00
  49. #define VIDEO_8POINT 0x0f01
  50. #define VIDEO_80x43 0x0f02
  51. #define VIDEO_80x28 0x0f03
  52. #define VIDEO_CURRENT_MODE 0x0f04
  53. #define VIDEO_80x30 0x0f05
  54. #define VIDEO_80x34 0x0f06
  55. #define VIDEO_80x60 0x0f07
  56. #define VIDEO_GFX_HACK 0x0f08
  57. #define VIDEO_LAST_SPECIAL 0x0f09
  58. /* Video modes given by resolution */
  59. #define VIDEO_FIRST_RESOLUTION 0x1000
  60. /* The "recalculate timings" flag */
  61. #define VIDEO_RECALC 0x8000
  62. /* Positions of various video parameters passed to the kernel */
  63. /* (see also include/linux/tty.h) */
  64. #define PARAM_CURSOR_POS 0x00
  65. #define PARAM_VIDEO_PAGE 0x04
  66. #define PARAM_VIDEO_MODE 0x06
  67. #define PARAM_VIDEO_COLS 0x07
  68. #define PARAM_VIDEO_EGA_BX 0x0a
  69. #define PARAM_VIDEO_LINES 0x0e
  70. #define PARAM_HAVE_VGA 0x0f
  71. #define PARAM_FONT_POINTS 0x10
  72. #define PARAM_LFB_WIDTH 0x12
  73. #define PARAM_LFB_HEIGHT 0x14
  74. #define PARAM_LFB_DEPTH 0x16
  75. #define PARAM_LFB_BASE 0x18
  76. #define PARAM_LFB_SIZE 0x1c
  77. #define PARAM_LFB_LINELENGTH 0x24
  78. #define PARAM_LFB_COLORS 0x26
  79. #define PARAM_VESAPM_SEG 0x2e
  80. #define PARAM_VESAPM_OFF 0x30
  81. #define PARAM_LFB_PAGES 0x32
  82. #define PARAM_VESA_ATTRIB 0x34
  83. /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
  84. #ifdef CONFIG_VIDEO_RETAIN
  85. #define DO_STORE call store_screen
  86. #else
  87. #define DO_STORE
  88. #endif /* CONFIG_VIDEO_RETAIN */
  89. # This is the main entry point called by setup.S
  90. # %ds *must* be pointing to the bootsector
  91. video: pushw %ds # We use different segments
  92. pushw %ds # FS contains original DS
  93. popw %fs
  94. pushw %cs # DS is equal to CS
  95. popw %ds
  96. pushw %cs # ES is equal to CS
  97. popw %es
  98. xorw %ax, %ax
  99. movw %ax, %gs # GS is zero
  100. cld
  101. call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
  102. #ifdef CONFIG_VIDEO_SELECT
  103. movw %fs:(0x01fa), %ax # User selected video mode
  104. cmpw $ASK_VGA, %ax # Bring up the menu
  105. jz vid2
  106. call mode_set # Set the mode
  107. jc vid1
  108. leaw badmdt, %si # Invalid mode ID
  109. call prtstr
  110. vid2: call mode_menu
  111. vid1:
  112. #ifdef CONFIG_VIDEO_RETAIN
  113. call restore_screen # Restore screen contents
  114. #endif /* CONFIG_VIDEO_RETAIN */
  115. call store_edid
  116. #endif /* CONFIG_VIDEO_SELECT */
  117. call mode_params # Store mode parameters
  118. popw %ds # Restore original DS
  119. ret
  120. # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
  121. basic_detect:
  122. movb $0, %fs:(PARAM_HAVE_VGA)
  123. movb $0x12, %ah # Check EGA/VGA
  124. movb $0x10, %bl
  125. int $0x10
  126. movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
  127. cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
  128. je basret
  129. incb adapter
  130. movw $0x1a00, %ax # Check EGA or VGA?
  131. int $0x10
  132. cmpb $0x1a, %al # 1a means VGA...
  133. jne basret # anything else is EGA.
  134. incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
  135. incb adapter
  136. basret: ret
  137. # Store the video mode parameters for later usage by the kernel.
  138. # This is done by asking the BIOS except for the rows/columns
  139. # parameters in the default 80x25 mode -- these are set directly,
  140. # because some very obscure BIOSes supply insane values.
  141. mode_params:
  142. #ifdef CONFIG_VIDEO_SELECT
  143. cmpb $0, graphic_mode
  144. jnz mopar_gr
  145. #endif
  146. movb $0x03, %ah # Read cursor position
  147. xorb %bh, %bh
  148. int $0x10
  149. movw %dx, %fs:(PARAM_CURSOR_POS)
  150. movb $0x0f, %ah # Read page/mode/width
  151. int $0x10
  152. movw %bx, %fs:(PARAM_VIDEO_PAGE)
  153. movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
  154. cmpb $0x7, %al # MDA/HGA => segment differs
  155. jnz mopar0
  156. movw $0xb000, video_segment
  157. mopar0: movw %gs:(0x485), %ax # Font size
  158. movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
  159. movw force_size, %ax # Forced size?
  160. orw %ax, %ax
  161. jz mopar1
  162. movb %ah, %fs:(PARAM_VIDEO_COLS)
  163. movb %al, %fs:(PARAM_VIDEO_LINES)
  164. ret
  165. mopar1: movb $25, %al
  166. cmpb $0, adapter # If we are on CGA/MDA/HGA, the
  167. jz mopar2 # screen must have 25 lines.
  168. movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
  169. incb %al # location of max lines.
  170. mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
  171. ret
  172. #ifdef CONFIG_VIDEO_SELECT
  173. # Fetching of VESA frame buffer parameters
  174. mopar_gr:
  175. leaw modelist+1024, %di
  176. movb $0x23, %fs:(PARAM_HAVE_VGA)
  177. movw 16(%di), %ax
  178. movw %ax, %fs:(PARAM_LFB_LINELENGTH)
  179. movw 18(%di), %ax
  180. movw %ax, %fs:(PARAM_LFB_WIDTH)
  181. movw 20(%di), %ax
  182. movw %ax, %fs:(PARAM_LFB_HEIGHT)
  183. movb 25(%di), %al
  184. movb $0, %ah
  185. movw %ax, %fs:(PARAM_LFB_DEPTH)
  186. movb 29(%di), %al
  187. movb $0, %ah
  188. movw %ax, %fs:(PARAM_LFB_PAGES)
  189. movl 40(%di), %eax
  190. movl %eax, %fs:(PARAM_LFB_BASE)
  191. movl 31(%di), %eax
  192. movl %eax, %fs:(PARAM_LFB_COLORS)
  193. movl 35(%di), %eax
  194. movl %eax, %fs:(PARAM_LFB_COLORS+4)
  195. movw 0(%di), %ax
  196. movw %ax, %fs:(PARAM_VESA_ATTRIB)
  197. # get video mem size
  198. leaw modelist+1024, %di
  199. movw $0x4f00, %ax
  200. int $0x10
  201. xorl %eax, %eax
  202. movw 18(%di), %ax
  203. movl %eax, %fs:(PARAM_LFB_SIZE)
  204. # switching the DAC to 8-bit is for <= 8 bpp only
  205. movw %fs:(PARAM_LFB_DEPTH), %ax
  206. cmpw $8, %ax
  207. jg dac_done
  208. # get DAC switching capability
  209. xorl %eax, %eax
  210. movb 10(%di), %al
  211. testb $1, %al
  212. jz dac_set
  213. # attempt to switch DAC to 8-bit
  214. movw $0x4f08, %ax
  215. movw $0x0800, %bx
  216. int $0x10
  217. cmpw $0x004f, %ax
  218. jne dac_set
  219. movb %bh, dac_size # store actual DAC size
  220. dac_set:
  221. # set color size to DAC size
  222. movb dac_size, %al
  223. movb %al, %fs:(PARAM_LFB_COLORS+0)
  224. movb %al, %fs:(PARAM_LFB_COLORS+2)
  225. movb %al, %fs:(PARAM_LFB_COLORS+4)
  226. movb %al, %fs:(PARAM_LFB_COLORS+6)
  227. # set color offsets to 0
  228. movb $0, %fs:(PARAM_LFB_COLORS+1)
  229. movb $0, %fs:(PARAM_LFB_COLORS+3)
  230. movb $0, %fs:(PARAM_LFB_COLORS+5)
  231. movb $0, %fs:(PARAM_LFB_COLORS+7)
  232. dac_done:
  233. # get protected mode interface informations
  234. movw $0x4f0a, %ax
  235. xorw %bx, %bx
  236. xorw %di, %di
  237. int $0x10
  238. cmp $0x004f, %ax
  239. jnz no_pm
  240. movw %es, %fs:(PARAM_VESAPM_SEG)
  241. movw %di, %fs:(PARAM_VESAPM_OFF)
  242. no_pm: ret
  243. # The video mode menu
  244. mode_menu:
  245. leaw keymsg, %si # "Return/Space/Timeout" message
  246. call prtstr
  247. call flush
  248. nokey: call getkt
  249. cmpb $0x0d, %al # ENTER ?
  250. je listm # yes - manual mode selection
  251. cmpb $0x20, %al # SPACE ?
  252. je defmd1 # no - repeat
  253. call beep
  254. jmp nokey
  255. defmd1: ret # No mode chosen? Default 80x25
  256. listm: call mode_table # List mode table
  257. listm0: leaw name_bann, %si # Print adapter name
  258. call prtstr
  259. movw card_name, %si
  260. orw %si, %si
  261. jnz an2
  262. movb adapter, %al
  263. leaw old_name, %si
  264. orb %al, %al
  265. jz an1
  266. leaw ega_name, %si
  267. decb %al
  268. jz an1
  269. leaw vga_name, %si
  270. jmp an1
  271. an2: call prtstr
  272. leaw svga_name, %si
  273. an1: call prtstr
  274. leaw listhdr, %si # Table header
  275. call prtstr
  276. movb $0x30, %dl # DL holds mode number
  277. leaw modelist, %si
  278. lm1: cmpw $ASK_VGA, (%si) # End?
  279. jz lm2
  280. movb %dl, %al # Menu selection number
  281. call prtchr
  282. call prtsp2
  283. lodsw
  284. call prthw # Mode ID
  285. call prtsp2
  286. movb 0x1(%si), %al
  287. call prtdec # Rows
  288. movb $0x78, %al # the letter 'x'
  289. call prtchr
  290. lodsw
  291. call prtdec # Columns
  292. movb $0x0d, %al # New line
  293. call prtchr
  294. movb $0x0a, %al
  295. call prtchr
  296. incb %dl # Next character
  297. cmpb $0x3a, %dl
  298. jnz lm1
  299. movb $0x61, %dl
  300. jmp lm1
  301. lm2: leaw prompt, %si # Mode prompt
  302. call prtstr
  303. leaw edit_buf, %di # Editor buffer
  304. lm3: call getkey
  305. cmpb $0x0d, %al # Enter?
  306. jz lment
  307. cmpb $0x08, %al # Backspace?
  308. jz lmbs
  309. cmpb $0x20, %al # Printable?
  310. jc lm3
  311. cmpw $edit_buf+4, %di # Enough space?
  312. jz lm3
  313. stosb
  314. call prtchr
  315. jmp lm3
  316. lmbs: cmpw $edit_buf, %di # Backspace
  317. jz lm3
  318. decw %di
  319. movb $0x08, %al
  320. call prtchr
  321. call prtspc
  322. movb $0x08, %al
  323. call prtchr
  324. jmp lm3
  325. lment: movb $0, (%di)
  326. leaw crlft, %si
  327. call prtstr
  328. leaw edit_buf, %si
  329. cmpb $0, (%si) # Empty string = default mode
  330. jz lmdef
  331. cmpb $0, 1(%si) # One character = menu selection
  332. jz mnusel
  333. cmpw $0x6373, (%si) # "scan" => mode scanning
  334. jnz lmhx
  335. cmpw $0x6e61, 2(%si)
  336. jz lmscan
  337. lmhx: xorw %bx, %bx # Else => mode ID in hex
  338. lmhex: lodsb
  339. orb %al, %al
  340. jz lmuse1
  341. subb $0x30, %al
  342. jc lmbad
  343. cmpb $10, %al
  344. jc lmhx1
  345. subb $7, %al
  346. andb $0xdf, %al
  347. cmpb $10, %al
  348. jc lmbad
  349. cmpb $16, %al
  350. jnc lmbad
  351. lmhx1: shlw $4, %bx
  352. orb %al, %bl
  353. jmp lmhex
  354. lmuse1: movw %bx, %ax
  355. jmp lmuse
  356. mnusel: lodsb # Menu selection
  357. xorb %ah, %ah
  358. subb $0x30, %al
  359. jc lmbad
  360. cmpb $10, %al
  361. jc lmuse
  362. cmpb $0x61-0x30, %al
  363. jc lmbad
  364. subb $0x61-0x30-10, %al
  365. cmpb $36, %al
  366. jnc lmbad
  367. lmuse: call mode_set
  368. jc lmdef
  369. lmbad: leaw unknt, %si
  370. call prtstr
  371. jmp lm2
  372. lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
  373. jz lmbad
  374. movw $0, mt_end # Scanning of modes is
  375. movb $1, scanning # done as new autodetection.
  376. call mode_table
  377. jmp listm0
  378. lmdef: ret
  379. # Additional parts of mode_set... (relative jumps, you know)
  380. setv7: # Video7 extended modes
  381. DO_STORE
  382. subb $VIDEO_FIRST_V7>>8, %bh
  383. movw $0x6f05, %ax
  384. int $0x10
  385. stc
  386. ret
  387. _setrec: jmp setrec # Ugly...
  388. _set_80x25: jmp set_80x25
  389. # Aliases for backward compatibility.
  390. setalias:
  391. movw $VIDEO_80x25, %ax
  392. incw %bx
  393. jz mode_set
  394. movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
  395. incw %bx
  396. jnz setbad # Fall-through!
  397. # Setting of user mode (AX=mode ID) => CF=success
  398. mode_set:
  399. movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
  400. movw %ax, %bx
  401. cmpb $0xff, %ah
  402. jz setalias
  403. testb $VIDEO_RECALC>>8, %ah
  404. jnz _setrec
  405. cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
  406. jnc setres
  407. cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
  408. jz setspc
  409. cmpb $VIDEO_FIRST_V7>>8, %ah
  410. jz setv7
  411. cmpb $VIDEO_FIRST_VESA>>8, %ah
  412. jnc check_vesa
  413. orb %ah, %ah
  414. jz setmenu
  415. decb %ah
  416. jz setbios
  417. setbad: clc
  418. movb $0, do_restore # The screen needn't be restored
  419. ret
  420. setvesa:
  421. DO_STORE
  422. subb $VIDEO_FIRST_VESA>>8, %bh
  423. movw $0x4f02, %ax # VESA BIOS mode set call
  424. int $0x10
  425. cmpw $0x004f, %ax # AL=4f if implemented
  426. jnz setbad # AH=0 if OK
  427. stc
  428. ret
  429. setbios:
  430. DO_STORE
  431. int $0x10 # Standard BIOS mode set call
  432. pushw %bx
  433. movb $0x0f, %ah # Check if really set
  434. int $0x10
  435. popw %bx
  436. cmpb %bl, %al
  437. jnz setbad
  438. stc
  439. ret
  440. setspc: xorb %bh, %bh # Set special mode
  441. cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
  442. jnc setbad
  443. addw %bx, %bx
  444. jmp *spec_inits(%bx)
  445. setmenu:
  446. orb %al, %al # 80x25 is an exception
  447. jz _set_80x25
  448. pushw %bx # Set mode chosen from menu
  449. call mode_table # Build the mode table
  450. popw %ax
  451. shlw $2, %ax
  452. addw %ax, %si
  453. cmpw %di, %si
  454. jnc setbad
  455. movw (%si), %ax # Fetch mode ID
  456. _m_s: jmp mode_set
  457. setres: pushw %bx # Set mode chosen by resolution
  458. call mode_table
  459. popw %bx
  460. xchgb %bl, %bh
  461. setr1: lodsw
  462. cmpw $ASK_VGA, %ax # End of the list?
  463. jz setbad
  464. lodsw
  465. cmpw %bx, %ax
  466. jnz setr1
  467. movw -4(%si), %ax # Fetch mode ID
  468. jmp _m_s
  469. check_vesa:
  470. leaw modelist+1024, %di
  471. subb $VIDEO_FIRST_VESA>>8, %bh
  472. movw %bx, %cx # Get mode information structure
  473. movw $0x4f01, %ax
  474. int $0x10
  475. addb $VIDEO_FIRST_VESA>>8, %bh
  476. cmpw $0x004f, %ax
  477. jnz setbad
  478. movb (%di), %al # Check capabilities.
  479. andb $0x19, %al
  480. cmpb $0x09, %al
  481. jz setvesa # This is a text mode
  482. movb (%di), %al # Check capabilities.
  483. andb $0x99, %al
  484. cmpb $0x99, %al
  485. jnz _setbad # Doh! No linear frame buffer.
  486. subb $VIDEO_FIRST_VESA>>8, %bh
  487. orw $0x4000, %bx # Use linear frame buffer
  488. movw $0x4f02, %ax # VESA BIOS mode set call
  489. int $0x10
  490. cmpw $0x004f, %ax # AL=4f if implemented
  491. jnz _setbad # AH=0 if OK
  492. movb $1, graphic_mode # flag graphic mode
  493. movb $0, do_restore # no screen restore
  494. stc
  495. ret
  496. _setbad: jmp setbad # Ugly...
  497. # Recalculate vertical display end registers -- this fixes various
  498. # inconsistencies of extended modes on many adapters. Called when
  499. # the VIDEO_RECALC flag is set in the mode ID.
  500. setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
  501. call mode_set
  502. jnc rct3
  503. movw %gs:(0x485), %ax # Font size in pixels
  504. movb %gs:(0x484), %bl # Number of rows
  505. incb %bl
  506. mulb %bl # Number of visible
  507. decw %ax # scan lines - 1
  508. movw $0x3d4, %dx
  509. movw %ax, %bx
  510. movb $0x12, %al # Lower 8 bits
  511. movb %bl, %ah
  512. outw %ax, %dx
  513. movb $0x07, %al # Bits 8 and 9 in the overflow register
  514. call inidx
  515. xchgb %al, %ah
  516. andb $0xbd, %ah
  517. shrb %bh
  518. jnc rct1
  519. orb $0x02, %ah
  520. rct1: shrb %bh
  521. jnc rct2
  522. orb $0x40, %ah
  523. rct2: movb $0x07, %al
  524. outw %ax, %dx
  525. stc
  526. rct3: ret
  527. # Table of routines for setting of the special modes.
  528. spec_inits:
  529. .word set_80x25
  530. .word set_8pixel
  531. .word set_80x43
  532. .word set_80x28
  533. .word set_current
  534. .word set_80x30
  535. .word set_80x34
  536. .word set_80x60
  537. .word set_gfx
  538. # Set the 80x25 mode. If already set, do nothing.
  539. set_80x25:
  540. movw $0x5019, force_size # Override possibly broken BIOS
  541. use_80x25:
  542. #ifdef CONFIG_VIDEO_400_HACK
  543. movw $0x1202, %ax # Force 400 scan lines
  544. movb $0x30, %bl
  545. int $0x10
  546. #else
  547. movb $0x0f, %ah # Get current mode ID
  548. int $0x10
  549. cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
  550. jz st80 # on CGA/MDA/HGA and is also available on EGAM
  551. cmpw $0x5003, %ax # Unknown mode, force 80x25 color
  552. jnz force3
  553. st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
  554. jz set80
  555. movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
  556. orb %al, %al # Some buggy BIOS'es set 0 rows
  557. jz set80
  558. cmpb $24, %al # It's hopefully correct
  559. jz set80
  560. #endif /* CONFIG_VIDEO_400_HACK */
  561. force3: DO_STORE
  562. movw $0x0003, %ax # Forced set
  563. int $0x10
  564. set80: stc
  565. ret
  566. # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
  567. set_8pixel:
  568. DO_STORE
  569. call use_80x25 # The base is 80x25
  570. set_8pt:
  571. movw $0x1112, %ax # Use 8x8 font
  572. xorb %bl, %bl
  573. int $0x10
  574. movw $0x1200, %ax # Use alternate print screen
  575. movb $0x20, %bl
  576. int $0x10
  577. movw $0x1201, %ax # Turn off cursor emulation
  578. movb $0x34, %bl
  579. int $0x10
  580. movb $0x01, %ah # Define cursor scan lines 6-7
  581. movw $0x0607, %cx
  582. int $0x10
  583. set_current:
  584. stc
  585. ret
  586. # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
  587. # 80x25 mode with 14-point fonts instead of 16-point.
  588. set_80x28:
  589. DO_STORE
  590. call use_80x25 # The base is 80x25
  591. set14: movw $0x1111, %ax # Use 9x14 font
  592. xorb %bl, %bl
  593. int $0x10
  594. movb $0x01, %ah # Define cursor scan lines 11-12
  595. movw $0x0b0c, %cx
  596. int $0x10
  597. stc
  598. ret
  599. # Set the 80x43 mode. This mode is works on all VGA's.
  600. # It's a 350-scanline mode with 8-pixel font.
  601. set_80x43:
  602. DO_STORE
  603. movw $0x1201, %ax # Set 350 scans
  604. movb $0x30, %bl
  605. int $0x10
  606. movw $0x0003, %ax # Reset video mode
  607. int $0x10
  608. jmp set_8pt # Use 8-pixel font
  609. # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
  610. set_80x30:
  611. call use_80x25 # Start with real 80x25
  612. DO_STORE
  613. movw $0x3cc, %dx # Get CRTC port
  614. inb %dx, %al
  615. movb $0xd4, %dl
  616. rorb %al # Mono or color?
  617. jc set48a
  618. movb $0xb4, %dl
  619. set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
  620. call outidx
  621. movw $0x0b06, %ax # Vertical total
  622. call outidx
  623. movw $0x3e07, %ax # (Vertical) overflow
  624. call outidx
  625. movw $0xea10, %ax # Vertical sync start
  626. call outidx
  627. movw $0xdf12, %ax # Vertical display end
  628. call outidx
  629. movw $0xe715, %ax # Vertical blank start
  630. call outidx
  631. movw $0x0416, %ax # Vertical blank end
  632. call outidx
  633. pushw %dx
  634. movb $0xcc, %dl # Misc output register (read)
  635. inb %dx, %al
  636. movb $0xc2, %dl # (write)
  637. andb $0x0d, %al # Preserve clock select bits and color bit
  638. orb $0xe2, %al # Set correct sync polarity
  639. outb %al, %dx
  640. popw %dx
  641. movw $0x501e, force_size
  642. stc # That's all.
  643. ret
  644. # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
  645. set_80x34:
  646. call set_80x30 # Set 480 scans
  647. call set14 # And 14-pt font
  648. movw $0xdb12, %ax # VGA vertical display end
  649. movw $0x5022, force_size
  650. setvde: call outidx
  651. stc
  652. ret
  653. # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
  654. set_80x60:
  655. call set_80x30 # Set 480 scans
  656. call set_8pt # And 8-pt font
  657. movw $0xdf12, %ax # VGA vertical display end
  658. movw $0x503c, force_size
  659. jmp setvde
  660. # Special hack for ThinkPad graphics
  661. set_gfx:
  662. #ifdef CONFIG_VIDEO_GFX_HACK
  663. movw $VIDEO_GFX_BIOS_AX, %ax
  664. movw $VIDEO_GFX_BIOS_BX, %bx
  665. int $0x10
  666. movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
  667. stc
  668. #endif
  669. ret
  670. #ifdef CONFIG_VIDEO_RETAIN
  671. # Store screen contents to temporary buffer.
  672. store_screen:
  673. cmpb $0, do_restore # Already stored?
  674. jnz stsr
  675. testb $CAN_USE_HEAP, loadflags # Have we space for storing?
  676. jz stsr
  677. pushw %ax
  678. pushw %bx
  679. pushw force_size # Don't force specific size
  680. movw $0, force_size
  681. call mode_params # Obtain params of current mode
  682. popw force_size
  683. movb %fs:(PARAM_VIDEO_LINES), %ah
  684. movb %fs:(PARAM_VIDEO_COLS), %al
  685. movw %ax, %bx # BX=dimensions
  686. mulb %ah
  687. movw %ax, %cx # CX=number of characters
  688. addw %ax, %ax # Calculate image size
  689. addw $modelist+1024+4, %ax
  690. cmpw heap_end_ptr, %ax
  691. jnc sts1 # Unfortunately, out of memory
  692. movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
  693. leaw modelist+1024, %di
  694. stosw
  695. movw %bx, %ax
  696. stosw
  697. pushw %ds # Store the screen
  698. movw video_segment, %ds
  699. xorw %si, %si
  700. rep
  701. movsw
  702. popw %ds
  703. incb do_restore # Screen will be restored later
  704. sts1: popw %bx
  705. popw %ax
  706. stsr: ret
  707. # Restore screen contents from temporary buffer.
  708. restore_screen:
  709. cmpb $0, do_restore # Has the screen been stored?
  710. jz res1
  711. call mode_params # Get parameters of current mode
  712. movb %fs:(PARAM_VIDEO_LINES), %cl
  713. movb %fs:(PARAM_VIDEO_COLS), %ch
  714. leaw modelist+1024, %si # Screen buffer
  715. lodsw # Set cursor position
  716. movw %ax, %dx
  717. cmpb %cl, %dh
  718. jc res2
  719. movb %cl, %dh
  720. decb %dh
  721. res2: cmpb %ch, %dl
  722. jc res3
  723. movb %ch, %dl
  724. decb %dl
  725. res3: movb $0x02, %ah
  726. movb $0x00, %bh
  727. int $0x10
  728. lodsw # Display size
  729. movb %ah, %dl # DL=number of lines
  730. movb $0, %ah # BX=phys. length of orig. line
  731. movw %ax, %bx
  732. cmpb %cl, %dl # Too many?
  733. jc res4
  734. pushw %ax
  735. movb %dl, %al
  736. subb %cl, %al
  737. mulb %bl
  738. addw %ax, %si
  739. addw %ax, %si
  740. popw %ax
  741. movb %cl, %dl
  742. res4: cmpb %ch, %al # Too wide?
  743. jc res5
  744. movb %ch, %al # AX=width of src. line
  745. res5: movb $0, %cl
  746. xchgb %ch, %cl
  747. movw %cx, %bp # BP=width of dest. line
  748. pushw %es
  749. movw video_segment, %es
  750. xorw %di, %di # Move the data
  751. addw %bx, %bx # Convert BX and BP to _bytes_
  752. addw %bp, %bp
  753. res6: pushw %si
  754. pushw %di
  755. movw %ax, %cx
  756. rep
  757. movsw
  758. popw %di
  759. popw %si
  760. addw %bp, %di
  761. addw %bx, %si
  762. decb %dl
  763. jnz res6
  764. popw %es # Done
  765. res1: ret
  766. #endif /* CONFIG_VIDEO_RETAIN */
  767. # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
  768. outidx: outb %al, %dx
  769. pushw %ax
  770. movb %ah, %al
  771. incw %dx
  772. outb %al, %dx
  773. decw %dx
  774. popw %ax
  775. ret
  776. # Build the table of video modes (stored after the setup.S code at the
  777. # `modelist' label. Each video mode record looks like:
  778. # .word MODE-ID (our special mode ID (see above))
  779. # .byte rows (number of rows)
  780. # .byte columns (number of columns)
  781. # Returns address of the end of the table in DI, the end is marked
  782. # with a ASK_VGA ID.
  783. mode_table:
  784. movw mt_end, %di # Already filled?
  785. orw %di, %di
  786. jnz mtab1x
  787. leaw modelist, %di # Store standard modes:
  788. movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
  789. stosl
  790. movb adapter, %al # CGA/MDA/HGA -- no more modes
  791. orb %al, %al
  792. jz mtabe
  793. decb %al
  794. jnz mtabv
  795. movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
  796. stosl
  797. jmp mtabe
  798. mtab1x: jmp mtab1
  799. mtabv: leaw vga_modes, %si # All modes for std VGA
  800. movw $vga_modes_end-vga_modes, %cx
  801. rep # I'm unable to use movsw as I don't know how to store a half
  802. movsb # of the expression above to cx without using explicit shr.
  803. cmpb $0, scanning # Mode scan requested?
  804. jz mscan1
  805. call mode_scan
  806. mscan1:
  807. #ifdef CONFIG_VIDEO_LOCAL
  808. call local_modes
  809. #endif /* CONFIG_VIDEO_LOCAL */
  810. #ifdef CONFIG_VIDEO_VESA
  811. call vesa_modes # Detect VESA VGA modes
  812. #endif /* CONFIG_VIDEO_VESA */
  813. #ifdef CONFIG_VIDEO_SVGA
  814. cmpb $0, scanning # Bypass when scanning
  815. jnz mscan2
  816. call svga_modes # Detect SVGA cards & modes
  817. mscan2:
  818. #endif /* CONFIG_VIDEO_SVGA */
  819. mtabe:
  820. #ifdef CONFIG_VIDEO_COMPACT
  821. leaw modelist, %si
  822. movw %di, %dx
  823. movw %si, %di
  824. cmt1: cmpw %dx, %si # Scan all modes
  825. jz cmt2
  826. leaw modelist, %bx # Find in previous entries
  827. movw 2(%si), %cx
  828. cmt3: cmpw %bx, %si
  829. jz cmt4
  830. cmpw 2(%bx), %cx # Found => don't copy this entry
  831. jz cmt5
  832. addw $4, %bx
  833. jmp cmt3
  834. cmt4: movsl # Copy entry
  835. jmp cmt1
  836. cmt5: addw $4, %si # Skip entry
  837. jmp cmt1
  838. cmt2:
  839. #endif /* CONFIG_VIDEO_COMPACT */
  840. movw $ASK_VGA, (%di) # End marker
  841. movw %di, mt_end
  842. mtab1: leaw modelist, %si # SI=mode list, DI=list end
  843. ret0: ret
  844. # Modes usable on all standard VGAs
  845. vga_modes:
  846. .word VIDEO_8POINT
  847. .word 0x5032 # 80x50
  848. .word VIDEO_80x43
  849. .word 0x502b # 80x43
  850. .word VIDEO_80x28
  851. .word 0x501c # 80x28
  852. .word VIDEO_80x30
  853. .word 0x501e # 80x30
  854. .word VIDEO_80x34
  855. .word 0x5022 # 80x34
  856. .word VIDEO_80x60
  857. .word 0x503c # 80x60
  858. #ifdef CONFIG_VIDEO_GFX_HACK
  859. .word VIDEO_GFX_HACK
  860. .word VIDEO_GFX_DUMMY_RESOLUTION
  861. #endif
  862. vga_modes_end:
  863. # Detect VESA modes.
  864. #ifdef CONFIG_VIDEO_VESA
  865. vesa_modes:
  866. cmpb $2, adapter # VGA only
  867. jnz ret0
  868. movw %di, %bp # BP=original mode table end
  869. addw $0x200, %di # Buffer space
  870. movw $0x4f00, %ax # VESA Get card info call
  871. int $0x10
  872. movw %bp, %di
  873. cmpw $0x004f, %ax # Successful?
  874. jnz ret0
  875. cmpw $0x4556, 0x200(%di)
  876. jnz ret0
  877. cmpw $0x4153, 0x202(%di)
  878. jnz ret0
  879. movw $vesa_name, card_name # Set name to "VESA VGA"
  880. pushw %gs
  881. lgsw 0x20e(%di), %si # GS:SI=mode list
  882. movw $128, %cx # Iteration limit
  883. vesa1:
  884. # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
  885. # XXX: lodsw %gs:(%si), %ax # Get next mode in the list
  886. gs; lodsw
  887. cmpw $0xffff, %ax # End of the table?
  888. jz vesar
  889. cmpw $0x0080, %ax # Check validity of mode ID
  890. jc vesa2
  891. orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
  892. jz vesan # Certain BIOSes report 0x80-0xff!
  893. cmpw $0x0800, %ax
  894. jnc vesae
  895. vesa2: pushw %cx
  896. movw %ax, %cx # Get mode information structure
  897. movw $0x4f01, %ax
  898. int $0x10
  899. movw %cx, %bx # BX=mode number
  900. addb $VIDEO_FIRST_VESA>>8, %bh
  901. popw %cx
  902. cmpw $0x004f, %ax
  903. jnz vesan # Don't report errors (buggy BIOSES)
  904. movb (%di), %al # Check capabilities. We require
  905. andb $0x19, %al # a color text mode.
  906. cmpb $0x09, %al
  907. jnz vesan
  908. cmpw $0xb800, 8(%di) # Standard video memory address required
  909. jnz vesan
  910. testb $2, (%di) # Mode characteristics supplied?
  911. movw %bx, (%di) # Store mode number
  912. jz vesa3
  913. xorw %dx, %dx
  914. movw 0x12(%di), %bx # Width
  915. orb %bh, %bh
  916. jnz vesan
  917. movb %bl, 0x3(%di)
  918. movw 0x14(%di), %ax # Height
  919. orb %ah, %ah
  920. jnz vesan
  921. movb %al, 2(%di)
  922. mulb %bl
  923. cmpw $8193, %ax # Small enough for Linux console driver?
  924. jnc vesan
  925. jmp vesaok
  926. vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
  927. jc vesan # so it must be a standard VESA mode.
  928. cmpw $5, %bx
  929. jnc vesan
  930. movw vesa_text_mode_table(%bx), %ax
  931. movw %ax, 2(%di)
  932. vesaok: addw $4, %di # The mode is valid. Store it.
  933. vesan: loop vesa1 # Next mode. Limit exceeded => error
  934. vesae: leaw vesaer, %si
  935. call prtstr
  936. movw %bp, %di # Discard already found modes.
  937. vesar: popw %gs
  938. ret
  939. # Dimensions of standard VESA text modes
  940. vesa_text_mode_table:
  941. .byte 60, 80 # 0108
  942. .byte 25, 132 # 0109
  943. .byte 43, 132 # 010A
  944. .byte 50, 132 # 010B
  945. .byte 60, 132 # 010C
  946. #endif /* CONFIG_VIDEO_VESA */
  947. # Scan for video modes. A bit dirty, but should work.
  948. mode_scan:
  949. movw $0x0100, %cx # Start with mode 0
  950. scm1: movb $0, %ah # Test the mode
  951. movb %cl, %al
  952. int $0x10
  953. movb $0x0f, %ah
  954. int $0x10
  955. cmpb %cl, %al
  956. jnz scm2 # Mode not set
  957. movw $0x3c0, %dx # Test if it's a text mode
  958. movb $0x10, %al # Mode bits
  959. call inidx
  960. andb $0x03, %al
  961. jnz scm2
  962. movb $0xce, %dl # Another set of mode bits
  963. movb $0x06, %al
  964. call inidx
  965. shrb %al
  966. jc scm2
  967. movb $0xd4, %dl # Cursor location
  968. movb $0x0f, %al
  969. call inidx
  970. orb %al, %al
  971. jnz scm2
  972. movw %cx, %ax # Ok, store the mode
  973. stosw
  974. movb %gs:(0x484), %al # Number of rows
  975. incb %al
  976. stosb
  977. movw %gs:(0x44a), %ax # Number of columns
  978. stosb
  979. scm2: incb %cl
  980. jns scm1
  981. movw $0x0003, %ax # Return back to mode 3
  982. int $0x10
  983. ret
  984. tstidx: outw %ax, %dx # OUT DX,AX and inidx
  985. inidx: outb %al, %dx # Read from indexed VGA register
  986. incw %dx # AL=index, DX=index reg port -> AL=data
  987. inb %dx, %al
  988. decw %dx
  989. ret
  990. # Try to detect type of SVGA card and supply (usually approximate) video
  991. # mode table for it.
  992. #ifdef CONFIG_VIDEO_SVGA
  993. svga_modes:
  994. leaw svga_table, %si # Test all known SVGA adapters
  995. dosvga: lodsw
  996. movw %ax, %bp # Default mode table
  997. orw %ax, %ax
  998. jz didsv1
  999. lodsw # Pointer to test routine
  1000. pushw %si
  1001. pushw %di
  1002. pushw %es
  1003. movw $0xc000, %bx
  1004. movw %bx, %es
  1005. call *%ax # Call test routine
  1006. popw %es
  1007. popw %di
  1008. popw %si
  1009. orw %bp, %bp
  1010. jz dosvga
  1011. movw %bp, %si # Found, copy the modes
  1012. movb svga_prefix, %ah
  1013. cpsvga: lodsb
  1014. orb %al, %al
  1015. jz didsv
  1016. stosw
  1017. movsw
  1018. jmp cpsvga
  1019. didsv: movw %si, card_name # Store pointer to card name
  1020. didsv1: ret
  1021. # Table of all known SVGA cards. For each card, we store a pointer to
  1022. # a table of video modes supported by the card and a pointer to a routine
  1023. # used for testing of presence of the card. The video mode table is always
  1024. # followed by the name of the card or the chipset.
  1025. svga_table:
  1026. .word ati_md, ati_test
  1027. .word oak_md, oak_test
  1028. .word paradise_md, paradise_test
  1029. .word realtek_md, realtek_test
  1030. .word s3_md, s3_test
  1031. .word chips_md, chips_test
  1032. .word video7_md, video7_test
  1033. .word cirrus5_md, cirrus5_test
  1034. .word cirrus6_md, cirrus6_test
  1035. .word cirrus1_md, cirrus1_test
  1036. .word ahead_md, ahead_test
  1037. .word everex_md, everex_test
  1038. .word genoa_md, genoa_test
  1039. .word trident_md, trident_test
  1040. .word tseng_md, tseng_test
  1041. .word 0
  1042. # Test routines and mode tables:
  1043. # S3 - The test algorithm was taken from the SuperProbe package
  1044. # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
  1045. s3_test:
  1046. movw $0x0f35, %cx # we store some constants in cl/ch
  1047. movw $0x03d4, %dx
  1048. movb $0x38, %al
  1049. call inidx
  1050. movb %al, %bh # store current CRT-register 0x38
  1051. movw $0x0038, %ax
  1052. call outidx # disable writing to special regs
  1053. movb %cl, %al # check whether we can write special reg 0x35
  1054. call inidx
  1055. movb %al, %bl # save the current value of CRT reg 0x35
  1056. andb $0xf0, %al # clear bits 0-3
  1057. movb %al, %ah
  1058. movb %cl, %al # and write it to CRT reg 0x35
  1059. call outidx
  1060. call inidx # now read it back
  1061. andb %ch, %al # clear the upper 4 bits
  1062. jz s3_2 # the first test failed. But we have a
  1063. movb %bl, %ah # second chance
  1064. movb %cl, %al
  1065. call outidx
  1066. jmp s3_1 # do the other tests
  1067. s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
  1068. orb %bl, %ah # set the upper 4 bits of ah with the orig value
  1069. call outidx # write ...
  1070. call inidx # ... and reread
  1071. andb %cl, %al # turn off the upper 4 bits
  1072. pushw %ax
  1073. movb %bl, %ah # restore old value in register 0x35
  1074. movb %cl, %al
  1075. call outidx
  1076. popw %ax
  1077. cmpb %ch, %al # setting lower 4 bits was successful => bad
  1078. je no_s3 # writing is allowed => this is not an S3
  1079. s3_1: movw $0x4838, %ax # allow writing to special regs by putting
  1080. call outidx # magic number into CRT-register 0x38
  1081. movb %cl, %al # check whether we can write special reg 0x35
  1082. call inidx
  1083. movb %al, %bl
  1084. andb $0xf0, %al
  1085. movb %al, %ah
  1086. movb %cl, %al
  1087. call outidx
  1088. call inidx
  1089. andb %ch, %al
  1090. jnz no_s3 # no, we can't write => no S3
  1091. movw %cx, %ax
  1092. orb %bl, %ah
  1093. call outidx
  1094. call inidx
  1095. andb %ch, %al
  1096. pushw %ax
  1097. movb %bl, %ah # restore old value in register 0x35
  1098. movb %cl, %al
  1099. call outidx
  1100. popw %ax
  1101. cmpb %ch, %al
  1102. jne no_s31 # writing not possible => no S3
  1103. movb $0x30, %al
  1104. call inidx # now get the S3 id ...
  1105. leaw idS3, %di
  1106. movw $0x10, %cx
  1107. repne
  1108. scasb
  1109. je no_s31
  1110. movb %bh, %ah
  1111. movb $0x38, %al
  1112. jmp s3rest
  1113. no_s3: movb $0x35, %al # restore CRT register 0x35
  1114. movb %bl, %ah
  1115. call outidx
  1116. no_s31: xorw %bp, %bp # Detection failed
  1117. s3rest: movb %bh, %ah
  1118. movb $0x38, %al # restore old value of CRT register 0x38
  1119. jmp outidx
  1120. idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
  1121. .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
  1122. s3_md: .byte 0x54, 0x2b, 0x84
  1123. .byte 0x55, 0x19, 0x84
  1124. .byte 0
  1125. .ascii "S3"
  1126. .byte 0
  1127. # ATI cards.
  1128. ati_test:
  1129. leaw idati, %si
  1130. movw $0x31, %di
  1131. movw $0x09, %cx
  1132. repe
  1133. cmpsb
  1134. je atiok
  1135. xorw %bp, %bp
  1136. atiok: ret
  1137. idati: .ascii "761295520"
  1138. ati_md: .byte 0x23, 0x19, 0x84
  1139. .byte 0x33, 0x2c, 0x84
  1140. .byte 0x22, 0x1e, 0x64
  1141. .byte 0x21, 0x19, 0x64
  1142. .byte 0x58, 0x21, 0x50
  1143. .byte 0x5b, 0x1e, 0x50
  1144. .byte 0
  1145. .ascii "ATI"
  1146. .byte 0
  1147. # AHEAD
  1148. ahead_test:
  1149. movw $0x200f, %ax
  1150. movw $0x3ce, %dx
  1151. outw %ax, %dx
  1152. incw %dx
  1153. inb %dx, %al
  1154. cmpb $0x20, %al
  1155. je isahed
  1156. cmpb $0x21, %al
  1157. je isahed
  1158. xorw %bp, %bp
  1159. isahed: ret
  1160. ahead_md:
  1161. .byte 0x22, 0x2c, 0x84
  1162. .byte 0x23, 0x19, 0x84
  1163. .byte 0x24, 0x1c, 0x84
  1164. .byte 0x2f, 0x32, 0xa0
  1165. .byte 0x32, 0x22, 0x50
  1166. .byte 0x34, 0x42, 0x50
  1167. .byte 0
  1168. .ascii "Ahead"
  1169. .byte 0
  1170. # Chips & Tech.
  1171. chips_test:
  1172. movw $0x3c3, %dx
  1173. inb %dx, %al
  1174. orb $0x10, %al
  1175. outb %al, %dx
  1176. movw $0x104, %dx
  1177. inb %dx, %al
  1178. movb %al, %bl
  1179. movw $0x3c3, %dx
  1180. inb %dx, %al
  1181. andb $0xef, %al
  1182. outb %al, %dx
  1183. cmpb $0xa5, %bl
  1184. je cantok
  1185. xorw %bp, %bp
  1186. cantok: ret
  1187. chips_md:
  1188. .byte 0x60, 0x19, 0x84
  1189. .byte 0x61, 0x32, 0x84
  1190. .byte 0
  1191. .ascii "Chips & Technologies"
  1192. .byte 0
  1193. # Cirrus Logic 5X0
  1194. cirrus1_test:
  1195. movw $0x3d4, %dx
  1196. movb $0x0c, %al
  1197. outb %al, %dx
  1198. incw %dx
  1199. inb %dx, %al
  1200. movb %al, %bl
  1201. xorb %al, %al
  1202. outb %al, %dx
  1203. decw %dx
  1204. movb $0x1f, %al
  1205. outb %al, %dx
  1206. incw %dx
  1207. inb %dx, %al
  1208. movb %al, %bh
  1209. xorb %ah, %ah
  1210. shlb $4, %al
  1211. movw %ax, %cx
  1212. movb %bh, %al
  1213. shrb $4, %al
  1214. addw %ax, %cx
  1215. shlw $8, %cx
  1216. addw $6, %cx
  1217. movw %cx, %ax
  1218. movw $0x3c4, %dx
  1219. outw %ax, %dx
  1220. incw %dx
  1221. inb %dx, %al
  1222. andb %al, %al
  1223. jnz nocirr
  1224. movb %bh, %al
  1225. outb %al, %dx
  1226. inb %dx, %al
  1227. cmpb $0x01, %al
  1228. je iscirr
  1229. nocirr: xorw %bp, %bp
  1230. iscirr: movw $0x3d4, %dx
  1231. movb %bl, %al
  1232. xorb %ah, %ah
  1233. shlw $8, %ax
  1234. addw $0x0c, %ax
  1235. outw %ax, %dx
  1236. ret
  1237. cirrus1_md:
  1238. .byte 0x1f, 0x19, 0x84
  1239. .byte 0x20, 0x2c, 0x84
  1240. .byte 0x22, 0x1e, 0x84
  1241. .byte 0x31, 0x25, 0x64
  1242. .byte 0
  1243. .ascii "Cirrus Logic 5X0"
  1244. .byte 0
  1245. # Cirrus Logic 54XX
  1246. cirrus5_test:
  1247. movw $0x3c4, %dx
  1248. movb $6, %al
  1249. call inidx
  1250. movb %al, %bl # BL=backup
  1251. movw $6, %ax
  1252. call tstidx
  1253. cmpb $0x0f, %al
  1254. jne c5fail
  1255. movw $0x1206, %ax
  1256. call tstidx
  1257. cmpb $0x12, %al
  1258. jne c5fail
  1259. movb $0x1e, %al
  1260. call inidx
  1261. movb %al, %bh
  1262. movb %bh, %ah
  1263. andb $0xc0, %ah
  1264. movb $0x1e, %al
  1265. call tstidx
  1266. andb $0x3f, %al
  1267. jne c5xx
  1268. movb $0x1e, %al
  1269. movb %bh, %ah
  1270. orb $0x3f, %ah
  1271. call tstidx
  1272. xorb $0x3f, %al
  1273. andb $0x3f, %al
  1274. c5xx: pushf
  1275. movb $0x1e, %al
  1276. movb %bh, %ah
  1277. outw %ax, %dx
  1278. popf
  1279. je c5done
  1280. c5fail: xorw %bp, %bp
  1281. c5done: movb $6, %al
  1282. movb %bl, %ah
  1283. outw %ax, %dx
  1284. ret
  1285. cirrus5_md:
  1286. .byte 0x14, 0x19, 0x84
  1287. .byte 0x54, 0x2b, 0x84
  1288. .byte 0
  1289. .ascii "Cirrus Logic 54XX"
  1290. .byte 0
  1291. # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
  1292. # it's misidentified by the Ahead test.
  1293. cirrus6_test:
  1294. movw $0x3ce, %dx
  1295. movb $0x0a, %al
  1296. call inidx
  1297. movb %al, %bl # BL=backup
  1298. movw $0xce0a, %ax
  1299. call tstidx
  1300. orb %al, %al
  1301. jne c2fail
  1302. movw $0xec0a, %ax
  1303. call tstidx
  1304. cmpb $0x01, %al
  1305. jne c2fail
  1306. movb $0xaa, %al
  1307. call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
  1308. shrb $4, %al
  1309. subb $4, %al
  1310. jz c6done
  1311. decb %al
  1312. jz c6done
  1313. subb $2, %al
  1314. jz c6done
  1315. decb %al
  1316. jz c6done
  1317. c2fail: xorw %bp, %bp
  1318. c6done: movb $0x0a, %al
  1319. movb %bl, %ah
  1320. outw %ax, %dx
  1321. ret
  1322. cirrus6_md:
  1323. .byte 0
  1324. .ascii "Cirrus Logic 64XX"
  1325. .byte 0
  1326. # Everex / Trident
  1327. everex_test:
  1328. movw $0x7000, %ax
  1329. xorw %bx, %bx
  1330. int $0x10
  1331. cmpb $0x70, %al
  1332. jne noevrx
  1333. shrw $4, %dx
  1334. cmpw $0x678, %dx
  1335. je evtrid
  1336. cmpw $0x236, %dx
  1337. jne evrxok
  1338. evtrid: leaw trident_md, %bp
  1339. evrxok: ret
  1340. noevrx: xorw %bp, %bp
  1341. ret
  1342. everex_md:
  1343. .byte 0x03, 0x22, 0x50
  1344. .byte 0x04, 0x3c, 0x50
  1345. .byte 0x07, 0x2b, 0x64
  1346. .byte 0x08, 0x4b, 0x64
  1347. .byte 0x0a, 0x19, 0x84
  1348. .byte 0x0b, 0x2c, 0x84
  1349. .byte 0x16, 0x1e, 0x50
  1350. .byte 0x18, 0x1b, 0x64
  1351. .byte 0x21, 0x40, 0xa0
  1352. .byte 0x40, 0x1e, 0x84
  1353. .byte 0
  1354. .ascii "Everex/Trident"
  1355. .byte 0
  1356. # Genoa.
  1357. genoa_test:
  1358. leaw idgenoa, %si # Check Genoa 'clues'
  1359. xorw %ax, %ax
  1360. movb %es:(0x37), %al
  1361. movw %ax, %di
  1362. movw $0x04, %cx
  1363. decw %si
  1364. decw %di
  1365. l1: incw %si
  1366. incw %di
  1367. movb (%si), %al
  1368. testb %al, %al
  1369. jz l2
  1370. cmpb %es:(%di), %al
  1371. l2: loope l1
  1372. orw %cx, %cx
  1373. je isgen
  1374. xorw %bp, %bp
  1375. isgen: ret
  1376. idgenoa: .byte 0x77, 0x00, 0x99, 0x66
  1377. genoa_md:
  1378. .byte 0x58, 0x20, 0x50
  1379. .byte 0x5a, 0x2a, 0x64
  1380. .byte 0x60, 0x19, 0x84
  1381. .byte 0x61, 0x1d, 0x84
  1382. .byte 0x62, 0x20, 0x84
  1383. .byte 0x63, 0x2c, 0x84
  1384. .byte 0x64, 0x3c, 0x84
  1385. .byte 0x6b, 0x4f, 0x64
  1386. .byte 0x72, 0x3c, 0x50
  1387. .byte 0x74, 0x42, 0x50
  1388. .byte 0x78, 0x4b, 0x64
  1389. .byte 0
  1390. .ascii "Genoa"
  1391. .byte 0
  1392. # OAK
  1393. oak_test:
  1394. leaw idoakvga, %si
  1395. movw $0x08, %di
  1396. movw $0x08, %cx
  1397. repe
  1398. cmpsb
  1399. je isoak
  1400. xorw %bp, %bp
  1401. isoak: ret
  1402. idoakvga: .ascii "OAK VGA "
  1403. oak_md: .byte 0x4e, 0x3c, 0x50
  1404. .byte 0x4f, 0x3c, 0x84
  1405. .byte 0x50, 0x19, 0x84
  1406. .byte 0x51, 0x2b, 0x84
  1407. .byte 0
  1408. .ascii "OAK"
  1409. .byte 0
  1410. # WD Paradise.
  1411. paradise_test:
  1412. leaw idparadise, %si
  1413. movw $0x7d, %di
  1414. movw $0x04, %cx
  1415. repe
  1416. cmpsb
  1417. je ispara
  1418. xorw %bp, %bp
  1419. ispara: ret
  1420. idparadise: .ascii "VGA="
  1421. paradise_md:
  1422. .byte 0x41, 0x22, 0x50
  1423. .byte 0x47, 0x1c, 0x84
  1424. .byte 0x55, 0x19, 0x84
  1425. .byte 0x54, 0x2c, 0x84
  1426. .byte 0
  1427. .ascii "Paradise"
  1428. .byte 0
  1429. # Trident.
  1430. trident_test:
  1431. movw $0x3c4, %dx
  1432. movb $0x0e, %al
  1433. outb %al, %dx
  1434. incw %dx
  1435. inb %dx, %al
  1436. xchgb %al, %ah
  1437. xorb %al, %al
  1438. outb %al, %dx
  1439. inb %dx, %al
  1440. xchgb %ah, %al
  1441. movb %al, %bl # Strange thing ... in the book this wasn't
  1442. andb $0x02, %bl # necessary but it worked on my card which
  1443. jz setb2 # is a trident. Without it the screen goes
  1444. # blurred ...
  1445. andb $0xfd, %al
  1446. jmp clrb2
  1447. setb2: orb $0x02, %al
  1448. clrb2: outb %al, %dx
  1449. andb $0x0f, %ah
  1450. cmpb $0x02, %ah
  1451. je istrid
  1452. xorw %bp, %bp
  1453. istrid: ret
  1454. trident_md:
  1455. .byte 0x50, 0x1e, 0x50
  1456. .byte 0x51, 0x2b, 0x50
  1457. .byte 0x52, 0x3c, 0x50
  1458. .byte 0x57, 0x19, 0x84
  1459. .byte 0x58, 0x1e, 0x84
  1460. .byte 0x59, 0x2b, 0x84
  1461. .byte 0x5a, 0x3c, 0x84
  1462. .byte 0
  1463. .ascii "Trident"
  1464. .byte 0
  1465. # Tseng.
  1466. tseng_test:
  1467. movw $0x3cd, %dx
  1468. inb %dx, %al # Could things be this simple ! :-)
  1469. movb %al, %bl
  1470. movb $0x55, %al
  1471. outb %al, %dx
  1472. inb %dx, %al
  1473. movb %al, %ah
  1474. movb %bl, %al
  1475. outb %al, %dx
  1476. cmpb $0x55, %ah
  1477. je istsen
  1478. isnot: xorw %bp, %bp
  1479. istsen: ret
  1480. tseng_md:
  1481. .byte 0x26, 0x3c, 0x50
  1482. .byte 0x2a, 0x28, 0x64
  1483. .byte 0x23, 0x19, 0x84
  1484. .byte 0x24, 0x1c, 0x84
  1485. .byte 0x22, 0x2c, 0x84
  1486. .byte 0x21, 0x3c, 0x84
  1487. .byte 0
  1488. .ascii "Tseng"
  1489. .byte 0
  1490. # Video7.
  1491. video7_test:
  1492. movw $0x3cc, %dx
  1493. inb %dx, %al
  1494. movw $0x3b4, %dx
  1495. andb $0x01, %al
  1496. jz even7
  1497. movw $0x3d4, %dx
  1498. even7: movb $0x0c, %al
  1499. outb %al, %dx
  1500. incw %dx
  1501. inb %dx, %al
  1502. movb %al, %bl
  1503. movb $0x55, %al
  1504. outb %al, %dx
  1505. inb %dx, %al
  1506. decw %dx
  1507. movb $0x1f, %al
  1508. outb %al, %dx
  1509. incw %dx
  1510. inb %dx, %al
  1511. movb %al, %bh
  1512. decw %dx
  1513. movb $0x0c, %al
  1514. outb %al, %dx
  1515. incw %dx
  1516. movb %bl, %al
  1517. outb %al, %dx
  1518. movb $0x55, %al
  1519. xorb $0xea, %al
  1520. cmpb %bh, %al
  1521. jne isnot
  1522. movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
  1523. ret
  1524. video7_md:
  1525. .byte 0x40, 0x2b, 0x50
  1526. .byte 0x43, 0x3c, 0x50
  1527. .byte 0x44, 0x3c, 0x64
  1528. .byte 0x41, 0x19, 0x84
  1529. .byte 0x42, 0x2c, 0x84
  1530. .byte 0x45, 0x1c, 0x84
  1531. .byte 0
  1532. .ascii "Video 7"
  1533. .byte 0
  1534. # Realtek VGA
  1535. realtek_test:
  1536. leaw idrtvga, %si
  1537. movw $0x45, %di
  1538. movw $0x0b, %cx
  1539. repe
  1540. cmpsb
  1541. je isrt
  1542. xorw %bp, %bp
  1543. isrt: ret
  1544. idrtvga: .ascii "REALTEK VGA"
  1545. realtek_md:
  1546. .byte 0x1a, 0x3c, 0x50
  1547. .byte 0x1b, 0x19, 0x84
  1548. .byte 0x1c, 0x1e, 0x84
  1549. .byte 0x1d, 0x2b, 0x84
  1550. .byte 0x1e, 0x3c, 0x84
  1551. .byte 0
  1552. .ascii "REALTEK"
  1553. .byte 0
  1554. #endif /* CONFIG_VIDEO_SVGA */
  1555. # User-defined local mode table (VGA only)
  1556. #ifdef CONFIG_VIDEO_LOCAL
  1557. local_modes:
  1558. leaw local_mode_table, %si
  1559. locm1: lodsw
  1560. orw %ax, %ax
  1561. jz locm2
  1562. stosw
  1563. movsw
  1564. jmp locm1
  1565. locm2: ret
  1566. # This is the table of local video modes which can be supplied manually
  1567. # by the user. Each entry consists of mode ID (word) and dimensions
  1568. # (byte for column count and another byte for row count). These modes
  1569. # are placed before all SVGA and VESA modes and override them if table
  1570. # compacting is enabled. The table must end with a zero word followed
  1571. # by NUL-terminated video adapter name.
  1572. local_mode_table:
  1573. .word 0x0100 # Example: 40x25
  1574. .byte 25,40
  1575. .word 0
  1576. .ascii "Local"
  1577. .byte 0
  1578. #endif /* CONFIG_VIDEO_LOCAL */
  1579. # Read a key and return the ASCII code in al, scan code in ah
  1580. getkey: xorb %ah, %ah
  1581. int $0x16
  1582. ret
  1583. # Read a key with a timeout of 30 seconds.
  1584. # The hardware clock is used to get the time.
  1585. getkt: call gettime
  1586. addb $30, %al # Wait 30 seconds
  1587. cmpb $60, %al
  1588. jl lminute
  1589. subb $60, %al
  1590. lminute:
  1591. movb %al, %cl
  1592. again: movb $0x01, %ah
  1593. int $0x16
  1594. jnz getkey # key pressed, so get it
  1595. call gettime
  1596. cmpb %cl, %al
  1597. jne again
  1598. movb $0x20, %al # timeout, return `space'
  1599. ret
  1600. # Flush the keyboard buffer
  1601. flush: movb $0x01, %ah
  1602. int $0x16
  1603. jz empty
  1604. xorb %ah, %ah
  1605. int $0x16
  1606. jmp flush
  1607. empty: ret
  1608. # Print hexadecimal number.
  1609. prthw: pushw %ax
  1610. movb %ah, %al
  1611. call prthb
  1612. popw %ax
  1613. prthb: pushw %ax
  1614. shrb $4, %al
  1615. call prthn
  1616. popw %ax
  1617. andb $0x0f, %al
  1618. prthn: cmpb $0x0a, %al
  1619. jc prth1
  1620. addb $0x07, %al
  1621. prth1: addb $0x30, %al
  1622. jmp prtchr
  1623. # Print decimal number in al
  1624. prtdec: pushw %ax
  1625. pushw %cx
  1626. xorb %ah, %ah
  1627. movb $0x0a, %cl
  1628. idivb %cl
  1629. cmpb $0x09, %al
  1630. jbe lt100
  1631. call prtdec
  1632. jmp skip10
  1633. lt100: addb $0x30, %al
  1634. call prtchr
  1635. skip10: movb %ah, %al
  1636. addb $0x30, %al
  1637. call prtchr
  1638. popw %cx
  1639. popw %ax
  1640. ret
  1641. store_edid:
  1642. pushw %es # just save all registers
  1643. pushw %ax
  1644. pushw %bx
  1645. pushw %cx
  1646. pushw %dx
  1647. pushw %di
  1648. pushw %fs
  1649. popw %es
  1650. movl $0x13131313, %eax # memset block with 0x13
  1651. movw $32, %cx
  1652. movw $0x140, %di
  1653. cld
  1654. rep
  1655. stosl
  1656. movw $0x4f15, %ax # do VBE/DDC
  1657. movw $0x01, %bx
  1658. movw $0x00, %cx
  1659. movw $0x01, %dx
  1660. movw $0x140, %di
  1661. int $0x10
  1662. popw %di # restore all registers
  1663. popw %dx
  1664. popw %cx
  1665. popw %bx
  1666. popw %ax
  1667. popw %es
  1668. ret
  1669. # VIDEO_SELECT-only variables
  1670. mt_end: .word 0 # End of video mode table if built
  1671. edit_buf: .space 6 # Line editor buffer
  1672. card_name: .word 0 # Pointer to adapter name
  1673. scanning: .byte 0 # Performing mode scan
  1674. do_restore: .byte 0 # Screen contents altered during mode change
  1675. svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
  1676. graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
  1677. dac_size: .byte 6 # DAC bit depth
  1678. # Status messages
  1679. keymsg: .ascii "Press <RETURN> to see video modes available, "
  1680. .ascii "<SPACE> to continue or wait 30 secs"
  1681. .byte 0x0d, 0x0a, 0
  1682. listhdr: .byte 0x0d, 0x0a
  1683. .ascii "Mode: COLSxROWS:"
  1684. crlft: .byte 0x0d, 0x0a, 0
  1685. prompt: .byte 0x0d, 0x0a
  1686. .asciz "Enter mode number or `scan': "
  1687. unknt: .asciz "Unknown mode ID. Try again."
  1688. badmdt: .ascii "You passed an undefined mode number."
  1689. .byte 0x0d, 0x0a, 0
  1690. vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
  1691. .ascii "report to <mj@ucw.cz>."
  1692. .byte 0x0d, 0x0a, 0
  1693. old_name: .asciz "CGA/MDA/HGA"
  1694. ega_name: .asciz "EGA"
  1695. svga_name: .ascii " "
  1696. vga_name: .asciz "VGA"
  1697. vesa_name: .asciz "VESA"
  1698. name_bann: .asciz "Video adapter: "
  1699. #endif /* CONFIG_VIDEO_SELECT */
  1700. # Other variables:
  1701. adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
  1702. video_segment: .word 0xb800 # Video memory segment
  1703. force_size: .word 0 # Use this size instead of the one in BIOS vars