videocon.c 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. videocon.c
  5. Abstract:
  6. This module implements functionality for a basic console over a video
  7. frame buffer.
  8. Author:
  9. Evan Green 15-Feb-2013
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/kernel/sysres.h>
  18. #include <minoca/lib/basevid.h>
  19. #include <minoca/lib/termlib.h>
  20. //
  21. // --------------------------------------------------------------------- Macros
  22. //
  23. //
  24. // This routine gets the line structure for the given row.
  25. //
  26. #define GET_CONSOLE_LINE(_Console, _Row) \
  27. (PVIDEO_CONSOLE_LINE)((_Console)->Lines + \
  28. (CONSOLE_LINE_SIZE(_Console) * \
  29. CONSOLE_ROW_INDEX(_Console, _Row)))
  30. //
  31. // This routine gets the effective console row number, taking into account the
  32. // rotating nature of the console lines. This verbose conditional avoids
  33. // divides.
  34. //
  35. #define CONSOLE_ROW_INDEX(_Console, _Row) \
  36. ((((_Console)->TopLine + (_Row)) < (_Console)->BufferRows) ? \
  37. ((_Console)->TopLine + (_Row)) : \
  38. ((_Console)->TopLine + (_Row) - (_Console)->BufferRows))
  39. //
  40. // This macro determines the size of one console line.
  41. //
  42. #define CONSOLE_LINE_SIZE(_Console) \
  43. (sizeof(VIDEO_CONSOLE_LINE) + \
  44. ((((_Console)->Columns) + 1 - ANYSIZE_ARRAY) * \
  45. sizeof(BASE_VIDEO_CHARACTER)))
  46. //
  47. // This macro determines if the cursor is within the scroll region.
  48. //
  49. #define CURSOR_IN_SCROLL_REGION(_Console) \
  50. (((_Console)->NextRow >= (_Console)->TopMargin) && \
  51. ((_Console)->NextRow <= \
  52. (_Console)->ScreenRows - 1 - (_Console)->BottomMargin))
  53. //
  54. // ---------------------------------------------------------------- Definitions
  55. //
  56. #define VIDEO_CONSOLE_ALLOCATION_TAG 0x6E6F4356 // 'noCV'
  57. #define VIDEO_CONSOLE_DEFAULT_TAB_WIDTH 4
  58. #define VIDEO_CONSOLE_READ_BUFFER_SIZE 2048
  59. #define VIDEO_CONSOLE_MAX_LINES 10000
  60. //
  61. // Define the number of milliseconds between blinks.
  62. //
  63. #define VIDEO_CONSOLE_BLINK_RATE 500
  64. #define VIDEO_CONSOLE_CURSOR_BLINK_COUNT 60
  65. //
  66. // Define the number of rows to leave at the top for a banner.
  67. //
  68. #define VIDEO_CONSOLE_TOP_BANNER_ROWS 3
  69. //
  70. // Define known characters.
  71. //
  72. #define VIDEO_CHARACTER_SHIFT_IN 0xF
  73. #define VIDEO_CHARACTER_SHIFT_OUT 0xE
  74. //
  75. // Define pending actions.
  76. //
  77. #define VIDEO_ACTION_REDRAW_ENTIRE_SCREEN 0x00000001
  78. #define VIDEO_ACTION_RESET_SCROLL 0x00000002
  79. //
  80. // Define modes.
  81. //
  82. //
  83. // Keyboard action mode locks the keyboard, preventing all further interactions
  84. // with the user until it is unlocked.
  85. //
  86. #define CONSOLE_MODE_KEYBOARD_ACTION 0x00000002
  87. //
  88. // Insert mode causes characters to get shifted over. Characters that move
  89. // past the right margin are lost. If this is not set, it is in replace mode,
  90. // where characters overwrite the previous ones.
  91. //
  92. #define CONSOLE_MODE_INSERT 0x00000004
  93. //
  94. // If this bit is set, characters from the keyboard are not automatically
  95. // echoed to the screen.
  96. //
  97. #define CONSOLE_MODE_DISABLE_LOCAL_ECHO 0x00000008
  98. //
  99. // If this bit is set then Line Feed, Form Feed, and Vertical Tab characters
  100. // all reset the column position to zero in addition to incrementing the
  101. // vertical position.
  102. //
  103. #define CONSOLE_MODE_NEW_LINE 0x00000010
  104. //
  105. // If this bit is set, then the cursor is visible.
  106. //
  107. #define CONSOLE_MODE_CURSOR 0x00000020
  108. //
  109. // If this bit is set, the cursor keys send application control functions. If
  110. // clear, the cursor keys send ANSI cursor control sequences.
  111. //
  112. #define CONSOLE_MODE_APPLICATION_CURSOR_KEYS 0x00000040
  113. //
  114. // If this bit is set, the console switches to VT52 compatibility mode.
  115. //
  116. #define CONSOLE_MODE_VT52 0x00000080
  117. //
  118. // If this bit is set, the console has 132 (or more) columns. If clear, the
  119. // console is set to 80 columns.
  120. //
  121. #define CONSOLE_MODE_132_COLUMN 0x00000100
  122. //
  123. // If this bit is set, smooth scrolling is performed, a maximum of 6 lines per
  124. // second is output. If clear, lines are displayed as they come in.
  125. //
  126. #define CONSOLE_MODE_SMOOTH_SCROLL 0x00000200
  127. //
  128. // If this bit is set, the screen's default foreground and background colors
  129. // are switched.
  130. //
  131. #define CONSOLE_MODE_VIDEO_REVERSED 0x00000400
  132. //
  133. // If this bit is set, the home position is set to the top left of the user
  134. // defined scroll region. The user cannot move out of the scroll region. The
  135. // erase in display command is an exception to that. If this is clear, the
  136. // home position is the upper-left corner of the screen.
  137. //
  138. #define CONSOLE_MODE_ORIGIN 0x00000800
  139. //
  140. // If this bit is set, characters received when the cursor is at the right
  141. // margin appear on the next line. The display scrolls up if the cursor is at
  142. // the end of the scrolling region. If this bit is clear, characters that
  143. // appear at the right replace previously displayed characters.
  144. //
  145. #define CONSOLE_MODE_AUTO_WRAP 0x00001000
  146. //
  147. // If this bit is set, keypad keys send application control functions. If clear,
  148. // keypad keys send numeric values (plus comma, period, plus minus, etc.)
  149. //
  150. #define CONSOLE_MODE_APPLICATION_KEYPAD 0x00002000
  151. //
  152. // If this bit is set, the cursor blinks.
  153. //
  154. #define CONSOLE_MODE_CURSOR_BLINK 0x00004000
  155. //
  156. // Define the default video mode bits when the console is initialized.
  157. //
  158. #define VIDEO_CONSOLE_MODE_DEFAULTS \
  159. (CONSOLE_MODE_CURSOR | CONSOLE_MODE_CURSOR_BLINK | CONSOLE_MODE_AUTO_WRAP)
  160. //
  161. // ------------------------------------------------------ Data Type Definitions
  162. //
  163. /*++
  164. Structure Description:
  165. This structure defines state associated with a single horizontal line of
  166. the video console.
  167. Members:
  168. Attributes - Stores attributes for the entire line.
  169. Character - Stores the array of printable characters in this line.
  170. --*/
  171. typedef struct _VIDEO_CONSOLE_LINE {
  172. USHORT Attributes;
  173. BASE_VIDEO_CHARACTER Character[ANYSIZE_ARRAY];
  174. } VIDEO_CONSOLE_LINE, *PVIDEO_CONSOLE_LINE;
  175. /*++
  176. Structure Description:
  177. This structure defines state associated with a video console.
  178. Members:
  179. PhysicalAddress - Stores the physical address of the frame buffer.
  180. VideoContext - Stores the base video library context used for low level
  181. print routines.
  182. FrameBuffer - Stores the virtual address of the frame buffer.
  183. Width - Stores the width of the frame buffer, in pixels.
  184. Height - Stores the height of the frame buffer, in pixels.
  185. BitsPerPixel - Stores the number of bits that correspond to one pixel.
  186. Columns - Stores the number of text columns in the console.
  187. ScreenRows - Stores the number of rows that can be displayed on the screen.
  188. BufferRows - Stores the number of rows in the buffer. This must be at least
  189. as large as the number of rows on the screen.
  190. MaxRows - Stores the maximum number of rows that should be stored in this
  191. console. Set to 0 for unlimited.
  192. TopMargin - Stores the top margin of the scroll area in lines. A count of
  193. zero means the console will scroll with scrollback.
  194. BottomMargin - Stores the bottom margin of the scroll area in lines. A
  195. count of zero means the console goes to the bottom of the screen.
  196. Lines - Stores a pointer to the array of lines representing the contents of
  197. this console.
  198. Screen - Stores a pointer to the array of lines that represents what's
  199. actually on the screen.
  200. TopLine - Stores the index of the line displaying at the top of the screen.
  201. TabWidth - Stores the number of spaces that expand to a tab.
  202. Lock - Stores a pointer to a lock that serializes access to the console.
  203. NextColumn - Stores the zero-based column number where the next character
  204. will be printed.
  205. NextRow - Stores the zero-based row number where the next character will be
  206. printed. This is a screen row, not a buffer row.
  207. RowViewOffset - Stores the number of lines down from the screen top row to
  208. display the screen.
  209. TextAttributes - Stores the current text attributes for printed text.
  210. Command - Stores the terminal input command data.
  211. PendingAction - Stores a bitfield of flags containing actions that need to
  212. be performed.
  213. Mode - Stores the console mode selections. See VIDEO_*_MODE definitions.
  214. SavedColumn - Stores the cursor column when a save cursor command occurred.
  215. SavedRow - Stores the cursor row when a save cursor command occurred.
  216. SavedAttributes - Stores the next attributes when a save cursor command
  217. occurred.
  218. --*/
  219. typedef struct _VIDEO_CONSOLE_DEVICE {
  220. PHYSICAL_ADDRESS PhysicalAddress;
  221. BASE_VIDEO_CONTEXT VideoContext;
  222. PVOID FrameBuffer;
  223. LONG Width;
  224. LONG Height;
  225. LONG BitsPerPixel;
  226. LONG Columns;
  227. LONG ScreenRows;
  228. LONG BufferRows;
  229. LONG MaxRows;
  230. LONG TopMargin;
  231. LONG BottomMargin;
  232. PVOID Lines;
  233. PVOID Screen;
  234. LONG TopLine;
  235. ULONG TabWidth;
  236. PQUEUED_LOCK Lock;
  237. LONG NextColumn;
  238. LONG NextRow;
  239. LONG RowViewOffset;
  240. USHORT TextAttributes;
  241. TERMINAL_COMMAND_DATA Command;
  242. ULONG PendingAction;
  243. ULONG Mode;
  244. LONG SavedColumn;
  245. LONG SavedRow;
  246. LONG SavedAttributes;
  247. } VIDEO_CONSOLE_DEVICE, *PVIDEO_CONSOLE_DEVICE;
  248. //
  249. // ----------------------------------------------- Internal Function Prototypes
  250. //
  251. KSTATUS
  252. VcAddDevice (
  253. PVOID Driver,
  254. PSTR DeviceId,
  255. PSTR ClassId,
  256. PSTR CompatibleIds,
  257. PVOID DeviceToken
  258. );
  259. VOID
  260. VcDispatchStateChange (
  261. PIRP Irp,
  262. PVOID DeviceContext,
  263. PVOID IrpContext
  264. );
  265. VOID
  266. VcDispatchOpen (
  267. PIRP Irp,
  268. PVOID DeviceContext,
  269. PVOID IrpContext
  270. );
  271. VOID
  272. VcDispatchClose (
  273. PIRP Irp,
  274. PVOID DeviceContext,
  275. PVOID IrpContext
  276. );
  277. VOID
  278. VcDispatchIo (
  279. PIRP Irp,
  280. PVOID DeviceContext,
  281. PVOID IrpContext
  282. );
  283. VOID
  284. VcDispatchSystemControl (
  285. PIRP Irp,
  286. PVOID DeviceContext,
  287. PVOID IrpContext
  288. );
  289. VOID
  290. VcpLocalTerminalRedrawThread (
  291. PVOID Parameter
  292. );
  293. VOID
  294. VcpWriteToConsole (
  295. PVIDEO_CONSOLE_DEVICE Console,
  296. PSTR String,
  297. UINTN StringLength
  298. );
  299. VOID
  300. VcpProcessCommand (
  301. PVIDEO_CONSOLE_DEVICE Console,
  302. PTERMINAL_COMMAND_DATA Command
  303. );
  304. VOID
  305. VcpEraseArea (
  306. PVIDEO_CONSOLE_DEVICE Console,
  307. LONG StartColumn,
  308. LONG StartRow,
  309. LONG EndColumn,
  310. LONG EndRow,
  311. BOOL ResetAttributes
  312. );
  313. VOID
  314. VcpRedrawArea (
  315. PVIDEO_CONSOLE_DEVICE Console,
  316. LONG StartColumn,
  317. LONG StartRow,
  318. LONG EndColumn,
  319. LONG EndRow
  320. );
  321. VOID
  322. VcpSetOrClearMode (
  323. PVIDEO_CONSOLE_DEVICE Console,
  324. ULONG ModeNumber,
  325. TERMINAL_COMMAND Command
  326. );
  327. VOID
  328. VcpAdvanceRow (
  329. PVIDEO_CONSOLE_DEVICE Console
  330. );
  331. VOID
  332. VcpSetColorFromParameters (
  333. PVIDEO_CONSOLE_DEVICE Console,
  334. PTERMINAL_COMMAND_DATA Command
  335. );
  336. VOID
  337. VcpSaveRestoreCursor (
  338. PVIDEO_CONSOLE_DEVICE Console,
  339. BOOL Save
  340. );
  341. VOID
  342. VcpMoveCursorRelative (
  343. PVIDEO_CONSOLE_DEVICE Console,
  344. LONG DistanceX,
  345. LONG DistanceY
  346. );
  347. VOID
  348. VcpMoveCursorAbsolute (
  349. PVIDEO_CONSOLE_DEVICE Console,
  350. LONG Column,
  351. LONG Row,
  352. BOOL ProcessOriginMode
  353. );
  354. VOID
  355. VcpDeleteLines (
  356. PVIDEO_CONSOLE_DEVICE Console,
  357. LONG Count,
  358. LONG StartingRow
  359. );
  360. VOID
  361. VcpInsertLines (
  362. PVIDEO_CONSOLE_DEVICE Console,
  363. LONG Count,
  364. LONG StartingRow
  365. );
  366. VOID
  367. VcpGetCursorPosition (
  368. PVIDEO_CONSOLE_DEVICE Console,
  369. PLONG Row,
  370. PLONG Column
  371. );
  372. //
  373. // -------------------------------------------------------------------- Globals
  374. //
  375. PDRIVER VcDriver = NULL;
  376. //
  377. // Store the next identifier.
  378. //
  379. volatile ULONG VcNextIdentifier = 0;
  380. //
  381. // Store a pointer to the local terminal.
  382. //
  383. PIO_HANDLE VcLocalTerminal;
  384. //
  385. // ------------------------------------------------------------------ Functions
  386. //
  387. KSTATUS
  388. DriverEntry (
  389. PDRIVER Driver
  390. )
  391. /*++
  392. Routine Description:
  393. This routine is the entry point for the video console driver. It registers
  394. its other dispatch functions, and performs driver-wide initialization.
  395. Arguments:
  396. Driver - Supplies a pointer to the driver object.
  397. Return Value:
  398. STATUS_SUCCESS on success.
  399. Failure code on error.
  400. --*/
  401. {
  402. ULONG AllocationSize;
  403. LONG Columns;
  404. PVIDEO_CONSOLE_DEVICE ConsoleDevice;
  405. volatile ULONG DeviceId;
  406. CHAR DeviceIdString[15];
  407. PSYSTEM_RESOURCE_FRAME_BUFFER FrameBufferResource;
  408. DRIVER_FUNCTION_TABLE FunctionTable;
  409. PSYSTEM_RESOURCE_HEADER GenericHeader;
  410. ULONG Height;
  411. LONG LineSize;
  412. PHYSICAL_ADDRESS PhysicalAddress;
  413. LONG Rows;
  414. ULONG RowSize;
  415. KSTATUS Status;
  416. UINTN TopOffset;
  417. SYSTEM_RESOURCE_FRAME_BUFFER VideoResource;
  418. PVOID VirtualAddress;
  419. ULONG Width;
  420. TERMINAL_WINDOW_SIZE WindowSize;
  421. ConsoleDevice = NULL;
  422. VcDriver = Driver;
  423. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  424. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  425. FunctionTable.AddDevice = VcAddDevice;
  426. FunctionTable.DispatchStateChange = VcDispatchStateChange;
  427. FunctionTable.DispatchOpen = VcDispatchOpen;
  428. FunctionTable.DispatchClose = VcDispatchClose;
  429. FunctionTable.DispatchIo = VcDispatchIo;
  430. FunctionTable.DispatchSystemControl = VcDispatchSystemControl;
  431. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  432. if (!KSUCCESS(Status)) {
  433. goto DriverEntryEnd;
  434. }
  435. //
  436. // Get all frame buffers from the boot environment.
  437. //
  438. while (TRUE) {
  439. GenericHeader = KeAcquireSystemResource(SystemResourceFrameBuffer);
  440. if (GenericHeader == NULL) {
  441. break;
  442. }
  443. //
  444. // TODO: The base video library can only handle one frame buffer at a
  445. // time. If multiple frame buffers crop up, retrofit that library to
  446. // support multiple consoles.
  447. //
  448. ASSERT(VcNextIdentifier == 0);
  449. FrameBufferResource = (PSYSTEM_RESOURCE_FRAME_BUFFER)GenericHeader;
  450. //
  451. // Ensure the frame buffer is big enough for at least a character.
  452. //
  453. Height = FrameBufferResource->Height;
  454. Width = FrameBufferResource->Width;
  455. if (FrameBufferResource->Mode == BaseVideoModeBiosText) {
  456. if ((Height <= VIDEO_CONSOLE_TOP_BANNER_ROWS) || (Width < 1)) {
  457. continue;
  458. }
  459. Height -= VIDEO_CONSOLE_TOP_BANNER_ROWS;
  460. RowSize = FrameBufferResource->Width *
  461. FrameBufferResource->BitsPerPixel / BITS_PER_BYTE;
  462. TopOffset = RowSize * VIDEO_CONSOLE_TOP_BANNER_ROWS;
  463. Columns = Width;
  464. Rows = Height;
  465. } else {
  466. ASSERT(FrameBufferResource->Mode == BaseVideoModeFrameBuffer);
  467. if ((Height <=
  468. VIDEO_CONSOLE_TOP_BANNER_ROWS * VidDefaultFont->CellHeight) ||
  469. (Width < VidDefaultFont->CellWidth)) {
  470. continue;
  471. }
  472. Height -= VIDEO_CONSOLE_TOP_BANNER_ROWS *
  473. VidDefaultFont->CellHeight;
  474. RowSize = FrameBufferResource->Width *
  475. FrameBufferResource->BitsPerPixel / BITS_PER_BYTE;
  476. TopOffset = RowSize * (VIDEO_CONSOLE_TOP_BANNER_ROWS *
  477. VidDefaultFont->CellHeight);
  478. Columns = Width / VidDefaultFont->CellWidth;
  479. Rows = Height / VidDefaultFont->CellHeight;
  480. }
  481. VirtualAddress = FrameBufferResource->Header.VirtualAddress + TopOffset;
  482. PhysicalAddress = FrameBufferResource->Header.PhysicalAddress +
  483. TopOffset;
  484. ConsoleDevice = MmAllocatePagedPool(sizeof(VIDEO_CONSOLE_DEVICE),
  485. VIDEO_CONSOLE_ALLOCATION_TAG);
  486. if (ConsoleDevice == NULL) {
  487. goto DriverEntryEnd;
  488. }
  489. RtlZeroMemory(ConsoleDevice, sizeof(VIDEO_CONSOLE_DEVICE));
  490. //
  491. // Determine the size of the allocation needed for the lines.
  492. //
  493. LineSize = sizeof(VIDEO_CONSOLE_LINE) +
  494. ((Columns + 1 - ANYSIZE_ARRAY) *
  495. sizeof(BASE_VIDEO_CHARACTER));
  496. AllocationSize = LineSize * Rows;
  497. //
  498. // Allocate the internal data structure.
  499. //
  500. ConsoleDevice->Lines = MmAllocatePagedPool(
  501. AllocationSize,
  502. VIDEO_CONSOLE_ALLOCATION_TAG);
  503. if (ConsoleDevice->Lines == NULL) {
  504. Status = STATUS_INSUFFICIENT_RESOURCES;
  505. goto DriverEntryEnd;
  506. }
  507. RtlZeroMemory(ConsoleDevice->Lines, AllocationSize);
  508. ConsoleDevice->Screen = MmAllocatePagedPool(
  509. AllocationSize,
  510. VIDEO_CONSOLE_ALLOCATION_TAG);
  511. if (ConsoleDevice->Screen == NULL) {
  512. Status = STATUS_INSUFFICIENT_RESOURCES;
  513. goto DriverEntryEnd;
  514. }
  515. RtlZeroMemory(ConsoleDevice->Screen, AllocationSize);
  516. ConsoleDevice->PhysicalAddress = PhysicalAddress;
  517. ConsoleDevice->FrameBuffer = VirtualAddress;
  518. ConsoleDevice->Width = Width;
  519. ConsoleDevice->Height = Height;
  520. ConsoleDevice->BitsPerPixel = FrameBufferResource->BitsPerPixel;
  521. ConsoleDevice->Columns = Columns;
  522. ConsoleDevice->ScreenRows = Rows;
  523. ConsoleDevice->BufferRows = Rows;
  524. ConsoleDevice->MaxRows = VIDEO_CONSOLE_MAX_LINES;
  525. ConsoleDevice->Mode = VIDEO_CONSOLE_MODE_DEFAULTS;
  526. ConsoleDevice->Lock = KeCreateQueuedLock();
  527. ConsoleDevice->TabWidth = VIDEO_CONSOLE_DEFAULT_TAB_WIDTH;
  528. if (ConsoleDevice->Lock == NULL) {
  529. Status = STATUS_INSUFFICIENT_RESOURCES;
  530. goto DriverEntryEnd;
  531. }
  532. RtlCopyMemory(&VideoResource,
  533. FrameBufferResource,
  534. sizeof(SYSTEM_RESOURCE_FRAME_BUFFER));
  535. VideoResource.Header.VirtualAddress = VirtualAddress;
  536. VideoResource.Header.PhysicalAddress = PhysicalAddress;
  537. VideoResource.Width = Width;
  538. VideoResource.Height = Height;
  539. Status = VidInitialize(&(ConsoleDevice->VideoContext), &VideoResource);
  540. if (!KSUCCESS(Status)) {
  541. goto DriverEntryEnd;
  542. }
  543. //
  544. // Ensure the calculation agrees with the macro. Ideally the macro would
  545. // have been used directly to calculate the line size, but it attempts
  546. // to dereference the console object and thus cannot be used.
  547. //
  548. ASSERT(LineSize == CONSOLE_LINE_SIZE(ConsoleDevice));
  549. DeviceId = RtlAtomicAdd32(&VcNextIdentifier, 1);
  550. RtlPrintToString(DeviceIdString,
  551. 15,
  552. CharacterEncodingDefault,
  553. "VideoConsole%x",
  554. DeviceId);
  555. //
  556. // Get a handle to the master side of the local console terminal and
  557. // create the local console redraw thread.
  558. //
  559. ASSERT(VcLocalTerminal == NULL);
  560. Status = IoOpenLocalTerminalMaster(&VcLocalTerminal);
  561. if (KSUCCESS(Status)) {
  562. Status = PsCreateKernelThread(VcpLocalTerminalRedrawThread,
  563. ConsoleDevice,
  564. "VcpLocalTerminalRedrawThread");
  565. if (!KSUCCESS(Status)) {
  566. goto DriverEntryEnd;
  567. }
  568. }
  569. //
  570. // Set the window size in the terminal.
  571. //
  572. RtlZeroMemory(&WindowSize, sizeof(TERMINAL_WINDOW_SIZE));
  573. WindowSize.Rows = Rows;
  574. WindowSize.Columns = Columns;
  575. WindowSize.PixelsX = Width;
  576. WindowSize.PixelsY = Height;
  577. IoUserControl(VcLocalTerminal,
  578. TerminalControlSetWindowSize,
  579. TRUE,
  580. &WindowSize,
  581. sizeof(TERMINAL_WINDOW_SIZE));
  582. //
  583. // Create the video console device.
  584. //
  585. Status = IoCreateDevice(VcDriver,
  586. ConsoleDevice,
  587. NULL,
  588. DeviceIdString,
  589. CHARACTER_CLASS_ID,
  590. NULL,
  591. NULL);
  592. if (!KSUCCESS(Status)) {
  593. goto DriverEntryEnd;
  594. }
  595. }
  596. DriverEntryEnd:
  597. if (!KSUCCESS(Status)) {
  598. ASSERT(VcNextIdentifier <= 1);
  599. if (ConsoleDevice != NULL) {
  600. if (ConsoleDevice->Lock != NULL) {
  601. KeDestroyQueuedLock(ConsoleDevice->Lock);
  602. }
  603. if (ConsoleDevice->Lines != NULL) {
  604. MmFreePagedPool(ConsoleDevice->Lines);
  605. }
  606. if (ConsoleDevice->Screen != NULL) {
  607. MmFreePagedPool(ConsoleDevice->Screen);
  608. }
  609. MmFreePagedPool(ConsoleDevice);
  610. }
  611. }
  612. return Status;
  613. }
  614. KSTATUS
  615. VcAddDevice (
  616. PVOID Driver,
  617. PSTR DeviceId,
  618. PSTR ClassId,
  619. PSTR CompatibleIds,
  620. PVOID DeviceToken
  621. )
  622. /*++
  623. Routine Description:
  624. This routine is called when a device is detected for which the video console
  625. device acts as the function driver. The driver will attach itself to the
  626. stack.
  627. Arguments:
  628. Driver - Supplies a pointer to the driver being called.
  629. DeviceId - Supplies a pointer to a string with the device ID.
  630. ClassId - Supplies a pointer to a string containing the device's class ID.
  631. CompatibleIds - Supplies a pointer to a string containing device IDs
  632. that would be compatible with this device.
  633. DeviceToken - Supplies an opaque token that the driver can use to identify
  634. the device in the system. This token should be used when attaching to
  635. the stack.
  636. Return Value:
  637. STATUS_SUCCESS on success.
  638. Failure code if the driver was unsuccessful in attaching itself.
  639. --*/
  640. {
  641. //
  642. // The Video console is not a real device, so it is not expected to be
  643. // attaching to emerging stacks.
  644. //
  645. return STATUS_NOT_IMPLEMENTED;
  646. }
  647. VOID
  648. VcDispatchStateChange (
  649. PIRP Irp,
  650. PVOID DeviceContext,
  651. PVOID IrpContext
  652. )
  653. /*++
  654. Routine Description:
  655. This routine handles State Change IRPs.
  656. Arguments:
  657. Irp - Supplies a pointer to the I/O request packet.
  658. DeviceContext - Supplies the context pointer supplied by the driver when it
  659. attached itself to the driver stack. Presumably this pointer contains
  660. driver-specific device context.
  661. IrpContext - Supplies the context pointer supplied by the driver when
  662. the IRP was created.
  663. Return Value:
  664. None.
  665. --*/
  666. {
  667. BOOL CompleteIrp;
  668. KSTATUS Status;
  669. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  670. //
  671. // The IRP is on its way down the stack. Do most processing here.
  672. //
  673. if (Irp->Direction == IrpDown) {
  674. Status = STATUS_NOT_SUPPORTED;
  675. CompleteIrp = TRUE;
  676. switch (Irp->MinorCode) {
  677. case IrpMinorQueryResources:
  678. Status = STATUS_SUCCESS;
  679. break;
  680. case IrpMinorStartDevice:
  681. Status = STATUS_SUCCESS;
  682. break;
  683. case IrpMinorQueryChildren:
  684. Irp->U.QueryChildren.Children = NULL;
  685. Irp->U.QueryChildren.ChildCount = 0;
  686. Status = STATUS_SUCCESS;
  687. break;
  688. //
  689. // Pass all other IRPs down.
  690. //
  691. default:
  692. CompleteIrp = FALSE;
  693. break;
  694. }
  695. //
  696. // Complete the IRP unless there's a reason not to.
  697. //
  698. if (CompleteIrp != FALSE) {
  699. IoCompleteIrp(VcDriver, Irp, Status);
  700. }
  701. //
  702. // The IRP is completed and is on its way back up.
  703. //
  704. } else {
  705. ASSERT(Irp->Direction == IrpUp);
  706. }
  707. return;
  708. }
  709. VOID
  710. VcDispatchOpen (
  711. PIRP Irp,
  712. PVOID DeviceContext,
  713. PVOID IrpContext
  714. )
  715. /*++
  716. Routine Description:
  717. This routine handles Open IRPs.
  718. Arguments:
  719. Irp - Supplies a pointer to the I/O request packet.
  720. DeviceContext - Supplies the context pointer supplied by the driver when it
  721. attached itself to the driver stack. Presumably this pointer contains
  722. driver-specific device context.
  723. IrpContext - Supplies the context pointer supplied by the driver when
  724. the IRP was created.
  725. Return Value:
  726. None.
  727. --*/
  728. {
  729. IoCompleteIrp(VcDriver, Irp, STATUS_SUCCESS);
  730. return;
  731. }
  732. VOID
  733. VcDispatchClose (
  734. PIRP Irp,
  735. PVOID DeviceContext,
  736. PVOID IrpContext
  737. )
  738. /*++
  739. Routine Description:
  740. This routine handles Close IRPs.
  741. Arguments:
  742. Irp - Supplies a pointer to the I/O request packet.
  743. DeviceContext - Supplies the context pointer supplied by the driver when it
  744. attached itself to the driver stack. Presumably this pointer contains
  745. driver-specific device context.
  746. IrpContext - Supplies the context pointer supplied by the driver when
  747. the IRP was created.
  748. Return Value:
  749. None.
  750. --*/
  751. {
  752. IoCompleteIrp(VcDriver, Irp, STATUS_SUCCESS);
  753. return;
  754. }
  755. VOID
  756. VcDispatchIo (
  757. PIRP Irp,
  758. PVOID DeviceContext,
  759. PVOID IrpContext
  760. )
  761. /*++
  762. Routine Description:
  763. This routine handles I/O IRPs.
  764. Arguments:
  765. Irp - Supplies a pointer to the I/O request packet.
  766. DeviceContext - Supplies the context pointer supplied by the driver when it
  767. attached itself to the driver stack. Presumably this pointer contains
  768. driver-specific device context.
  769. IrpContext - Supplies the context pointer supplied by the driver when
  770. the IRP was created.
  771. Return Value:
  772. None.
  773. --*/
  774. {
  775. PVIDEO_CONSOLE_DEVICE Console;
  776. UINTN FragmentIndex;
  777. UINTN FragmentSize;
  778. PIO_BUFFER IoBuffer;
  779. UINTN Size;
  780. KSTATUS Status;
  781. ASSERT(Irp->Direction == IrpDown);
  782. Console = (PVIDEO_CONSOLE_DEVICE)DeviceContext;
  783. //
  784. // Fail reads.
  785. //
  786. if (Irp->MinorCode != IrpMinorIoWrite) {
  787. Status = STATUS_NOT_SUPPORTED;
  788. goto DispatchIoEnd;
  789. }
  790. IoBuffer = Irp->U.ReadWrite.IoBuffer;
  791. Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE);
  792. if (!KSUCCESS(Status)) {
  793. goto DispatchIoEnd;
  794. }
  795. Size = Irp->U.ReadWrite.IoSizeInBytes;
  796. for (FragmentIndex = 0;
  797. FragmentIndex < IoBuffer->FragmentCount;
  798. FragmentIndex += 1) {
  799. FragmentSize = IoBuffer->Fragment[FragmentIndex].Size;
  800. if (FragmentSize > Size) {
  801. FragmentSize = Size;
  802. }
  803. VcpWriteToConsole(Console,
  804. IoBuffer->Fragment[FragmentIndex].VirtualAddress,
  805. FragmentSize);
  806. Size -= FragmentSize;
  807. }
  808. Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes;
  809. Status = STATUS_SUCCESS;
  810. DispatchIoEnd:
  811. IoCompleteIrp(VcDriver, Irp, Status);
  812. return;
  813. }
  814. VOID
  815. VcDispatchSystemControl (
  816. PIRP Irp,
  817. PVOID DeviceContext,
  818. PVOID IrpContext
  819. )
  820. /*++
  821. Routine Description:
  822. This routine handles System Control IRPs.
  823. Arguments:
  824. Irp - Supplies a pointer to the I/O request packet.
  825. DeviceContext - Supplies the context pointer supplied by the driver when it
  826. attached itself to the driver stack. Presumably this pointer contains
  827. driver-specific device context.
  828. IrpContext - Supplies the context pointer supplied by the driver when
  829. the IRP was created.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  835. //
  836. // Do no processing on any IRPs. Let them flow.
  837. //
  838. return;
  839. }
  840. //
  841. // --------------------------------------------------------- Internal Functions
  842. //
  843. VOID
  844. VcpLocalTerminalRedrawThread (
  845. PVOID Parameter
  846. )
  847. /*++
  848. Routine Description:
  849. This routine implements the video console redraw thread, which reads from
  850. the terminal master and draws the output.
  851. Arguments:
  852. Parameter - Supplies the thread parameter, in this case a pointer to the
  853. video console device.
  854. Return Value:
  855. None.
  856. --*/
  857. {
  858. ULONG BlinkCount;
  859. UINTN BytesRead;
  860. USHORT CursorAttributes;
  861. LONG CursorColumn;
  862. LONG CursorRow;
  863. PVIDEO_CONSOLE_DEVICE Device;
  864. PIO_BUFFER IoBuffer;
  865. PVIDEO_CONSOLE_LINE Line;
  866. PCHAR ReadBuffer;
  867. KSTATUS Status;
  868. ULONG Timeout;
  869. BlinkCount = 0;
  870. CursorAttributes = 0;
  871. Device = (PVIDEO_CONSOLE_DEVICE)Parameter;
  872. ReadBuffer = MmAllocatePagedPool(VIDEO_CONSOLE_READ_BUFFER_SIZE,
  873. VIDEO_CONSOLE_ALLOCATION_TAG);
  874. if (ReadBuffer == NULL) {
  875. Status = STATUS_INSUFFICIENT_RESOURCES;
  876. goto LocalTerminalRedrawThread;
  877. }
  878. Status = MmCreateIoBuffer(ReadBuffer,
  879. VIDEO_CONSOLE_READ_BUFFER_SIZE,
  880. IO_BUFFER_FLAG_KERNEL_MODE_DATA,
  881. &IoBuffer);
  882. if (!KSUCCESS(Status)) {
  883. goto LocalTerminalRedrawThread;
  884. }
  885. //
  886. // Loop reading the slave's standard out and printing it to the screen.
  887. //
  888. while (TRUE) {
  889. Timeout = WAIT_TIME_INDEFINITE;
  890. if (((Device->Mode & CONSOLE_MODE_CURSOR) != 0) &&
  891. ((Device->Mode & CONSOLE_MODE_CURSOR_BLINK) != 0)) {
  892. //
  893. // Stop blinking after a little while to save power, but make sure
  894. // the blinking stops on having the cursor drawn.
  895. //
  896. if ((BlinkCount < VIDEO_CONSOLE_CURSOR_BLINK_COUNT) ||
  897. ((CursorAttributes & BASE_VIDEO_CURSOR) == 0)) {
  898. Timeout = VIDEO_CONSOLE_BLINK_RATE;
  899. }
  900. }
  901. Status = IoRead(VcLocalTerminal,
  902. IoBuffer,
  903. VIDEO_CONSOLE_READ_BUFFER_SIZE,
  904. 0,
  905. Timeout,
  906. &BytesRead);
  907. if (Status == STATUS_TIMEOUT) {
  908. ASSERT(BytesRead == 0);
  909. VcpGetCursorPosition(Device, &CursorRow, &CursorColumn);
  910. Line = GET_CONSOLE_LINE(Device, CursorRow);
  911. Line->Character[CursorColumn].Data.Attributes ^= BASE_VIDEO_CURSOR;
  912. CursorAttributes = Line->Character[CursorColumn].Data.Attributes;
  913. VcpRedrawArea(Device,
  914. CursorColumn,
  915. CursorRow,
  916. CursorColumn + 1,
  917. CursorRow);
  918. BlinkCount += 1;
  919. //
  920. // Device I/O error probably means there are no slaves connected. Wait
  921. // a little while and see if one connects.
  922. //
  923. } else if (Status == STATUS_DEVICE_IO_ERROR) {
  924. KeDelayExecution(FALSE, FALSE, 5 * MICROSECONDS_PER_SECOND);
  925. } else if (!KSUCCESS(Status)) {
  926. break;
  927. }
  928. if (BytesRead != 0) {
  929. BlinkCount = 0;
  930. VcpWriteToConsole(Device, ReadBuffer, BytesRead);
  931. }
  932. }
  933. LocalTerminalRedrawThread:
  934. if (!KSUCCESS(Status)) {
  935. RtlDebugPrint("VideoCon: TerminalRedrawThread failure: %x\n", Status);
  936. }
  937. if (IoBuffer != NULL) {
  938. MmFreeIoBuffer(IoBuffer);
  939. }
  940. if (ReadBuffer != NULL) {
  941. MmFreePagedPool(ReadBuffer);
  942. }
  943. return;
  944. }
  945. VOID
  946. VcpWriteToConsole (
  947. PVIDEO_CONSOLE_DEVICE Console,
  948. PSTR String,
  949. UINTN StringLength
  950. )
  951. /*++
  952. Routine Description:
  953. This routine writes the given string to the video console.
  954. Arguments:
  955. Console - Supplies a pointer to the video console to write to.
  956. String - Supplies a pointer to the string to print.
  957. StringLength - Supplies the length of the string buffer, including the null
  958. terminator.
  959. Return Value:
  960. None.
  961. --*/
  962. {
  963. UCHAR Character;
  964. PBASE_VIDEO_CHARACTER Characters;
  965. LONG Column;
  966. LONG CursorColumn;
  967. LONG CursorRow;
  968. LONG EndColumn;
  969. LONG EndRow;
  970. PVIDEO_CONSOLE_LINE Line;
  971. TERMINAL_PARSE_RESULT OutputResult;
  972. LONG StartColumn;
  973. LONG StartRow;
  974. ASSERT(KeGetRunLevel() == RunLevelLow);
  975. KeAcquireQueuedLock(Console->Lock);
  976. VcpGetCursorPosition(Console, &StartRow, &StartColumn);
  977. EndColumn = StartColumn;
  978. EndRow = StartRow;
  979. ASSERT(StartColumn < Console->Columns);
  980. ASSERT(StartRow < Console->ScreenRows);
  981. //
  982. // Clear the cursor flag assuming it's going to move.
  983. //
  984. Line = GET_CONSOLE_LINE(Console, StartRow);
  985. Characters = (PBASE_VIDEO_CHARACTER)(Line->Character);
  986. Characters[StartColumn].Data.Attributes &= ~BASE_VIDEO_CURSOR;
  987. //
  988. // Loop over each character in the string.
  989. //
  990. while (TRUE) {
  991. if (StringLength == 0) {
  992. break;
  993. }
  994. Character = *String;
  995. if (Character == '\0') {
  996. String += 1;
  997. StringLength -= 1;
  998. continue;
  999. }
  1000. OutputResult = TermProcessOutput(&(Console->Command), Character);
  1001. switch (OutputResult) {
  1002. //
  1003. // This is just an ordinary joe character.
  1004. //
  1005. case TerminalParseResultNormalCharacter:
  1006. Console->PendingAction |= VIDEO_ACTION_RESET_SCROLL;
  1007. if (Character == '\t') {
  1008. do {
  1009. //
  1010. // Tab never goes over a line, and leaves one character of
  1011. // space as well at the end of the current line.
  1012. //
  1013. if (Console->NextColumn >= Console->Columns - 1) {
  1014. break;
  1015. }
  1016. Console->NextColumn += 1;
  1017. } while ((Console->NextColumn % Console->TabWidth) != 0);
  1018. //
  1019. // A newline, vertical time, or form feed moves to the next line,
  1020. // and potentially resets the column too.
  1021. //
  1022. } else if ((Character == '\n') || (Character == '\v') ||
  1023. (Character == '\f')) {
  1024. if ((Console->NextColumn == Console->Columns) ||
  1025. ((Console->Mode & CONSOLE_MODE_NEW_LINE) != 0)) {
  1026. Console->NextColumn = 0;
  1027. }
  1028. VcpAdvanceRow(Console);
  1029. Line = NULL;
  1030. //
  1031. // Handle a carraige return.
  1032. //
  1033. } else if (Character == '\r') {
  1034. Console->NextColumn = 0;
  1035. //
  1036. // Handle a backspace.
  1037. //
  1038. } else if (Character == '\b') {
  1039. if (Console->NextColumn != 0) {
  1040. if (Console->NextColumn == Console->Columns) {
  1041. Line = NULL;
  1042. }
  1043. Console->NextColumn -= 1;
  1044. } else {
  1045. if (Console->NextRow != 0) {
  1046. Console->NextColumn = Console->Columns - 1;
  1047. Console->NextRow -= 1;
  1048. Line = NULL;
  1049. }
  1050. }
  1051. //
  1052. // Handle a rubout, which moves the cursor back one and erases the
  1053. // character at that new position. It does not go back up lines.
  1054. //
  1055. } else if (Character == TERMINAL_RUBOUT) {
  1056. if (Console->NextColumn != 0) {
  1057. Console->NextColumn -= 1;
  1058. }
  1059. if (Line == NULL) {
  1060. VcpGetCursorPosition(Console, &CursorRow, &CursorColumn);
  1061. Line = GET_CONSOLE_LINE(Console, CursorRow);
  1062. Characters = (PBASE_VIDEO_CHARACTER)(Line->Character);
  1063. }
  1064. Characters[Console->NextColumn].Data.Character = ' ';
  1065. } else if ((Character >= ' ') && (Character < 0x80)) {
  1066. if (Line == NULL) {
  1067. VcpGetCursorPosition(Console, &CursorRow, &CursorColumn);
  1068. Line = GET_CONSOLE_LINE(Console, CursorRow);
  1069. Characters = (PBASE_VIDEO_CHARACTER)(Line->Character);
  1070. }
  1071. if ((Console->Mode & CONSOLE_MODE_INSERT) != 0) {
  1072. for (Column = Console->Columns - 1;
  1073. Column > Console->NextColumn;
  1074. Column -= 1) {
  1075. Characters[Column].AsUint32 =
  1076. Characters[Column - 1].AsUint32;
  1077. }
  1078. if (EndRow == Console->NextRow) {
  1079. EndColumn = Console->Columns - 1;
  1080. }
  1081. }
  1082. //
  1083. // If the column was actually overhanging, move it down now.
  1084. //
  1085. if (Console->NextColumn == Console->Columns) {
  1086. ASSERT(Console->NextRow != Console->ScreenRows - 1);
  1087. Console->NextColumn = 0;
  1088. VcpAdvanceRow(Console);
  1089. Line = GET_CONSOLE_LINE(Console, Console->NextRow);
  1090. Characters = (PBASE_VIDEO_CHARACTER)(Line->Character);
  1091. }
  1092. Characters[Console->NextColumn].Data.Attributes =
  1093. Console->TextAttributes;
  1094. Characters[Console->NextColumn].Data.Character = Character;
  1095. //
  1096. // Move the column forward.
  1097. //
  1098. if ((Console->Mode & CONSOLE_MODE_AUTO_WRAP) != 0) {
  1099. if (Console->NextColumn < Console->Columns) {
  1100. Console->NextColumn += 1;
  1101. //
  1102. // If this is the last line, create another line so
  1103. // that the cursor can be shown, but readjust the row
  1104. // back to leave the cursor overhanging.
  1105. //
  1106. if ((Console->NextColumn == Console->Columns) &&
  1107. (Console->NextRow == Console->ScreenRows - 1)) {
  1108. VcpAdvanceRow(Console);
  1109. ASSERT(Console->NextRow == Console->ScreenRows - 1);
  1110. Console->NextRow -= 1;
  1111. }
  1112. }
  1113. } else if (Console->NextColumn < Console->Columns - 1) {
  1114. Console->NextColumn += 1;
  1115. }
  1116. } else if (Character == VIDEO_CHARACTER_SHIFT_IN) {
  1117. //
  1118. // TODO: Handle shift in, which invokes the G0 character set.
  1119. //
  1120. } else if (Character == VIDEO_CHARACTER_SHIFT_OUT) {
  1121. //
  1122. // TODO: Handle shift out, which invokes the G1 character set.
  1123. //
  1124. }
  1125. break;
  1126. case TerminalParseResultPartialCommand:
  1127. break;
  1128. case TerminalParseResultCompleteCommand:
  1129. TermNormalizeParameters(&(Console->Command));
  1130. VcpProcessCommand(Console, &(Console->Command));
  1131. Line = NULL;
  1132. break;
  1133. default:
  1134. ASSERT(FALSE);
  1135. break;
  1136. }
  1137. //
  1138. // Potentially widen the redraw area unless a scroll has already
  1139. // occurred, in which case the entire screen will be redrawn anyway.
  1140. //
  1141. if ((Console->PendingAction & VIDEO_ACTION_REDRAW_ENTIRE_SCREEN) == 0) {
  1142. //
  1143. // Potentially move the end region out.
  1144. //
  1145. if (Console->NextRow > EndRow) {
  1146. EndRow = Console->NextRow;
  1147. EndColumn = Console->NextColumn;
  1148. } else if ((Console->NextRow == EndRow) &&
  1149. (Console->NextColumn > EndColumn)) {
  1150. EndColumn = Console->NextColumn;
  1151. }
  1152. //
  1153. // Potentially move the start region.
  1154. //
  1155. if (Console->NextRow < StartRow) {
  1156. StartRow = Console->NextRow;
  1157. StartColumn = Console->NextColumn;
  1158. } else if ((Console->NextRow == StartRow) &&
  1159. (Console->NextColumn < StartColumn)) {
  1160. StartColumn = Console->NextColumn;
  1161. }
  1162. }
  1163. //
  1164. // Move on to the next character.
  1165. //
  1166. String += 1;
  1167. StringLength -= 1;
  1168. }
  1169. //
  1170. // Make the cursor visible on any real events.
  1171. //
  1172. if ((Console->PendingAction & VIDEO_ACTION_RESET_SCROLL) != 0) {
  1173. Console->PendingAction &= ~VIDEO_ACTION_RESET_SCROLL;
  1174. if ((Console->RowViewOffset > Console->NextRow) ||
  1175. (Console->RowViewOffset + Console->ScreenRows < Console->NextRow)) {
  1176. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1177. Console->RowViewOffset = 0;
  1178. }
  1179. }
  1180. if ((Console->PendingAction & VIDEO_ACTION_REDRAW_ENTIRE_SCREEN) != 0) {
  1181. Console->PendingAction &= ~VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1182. StartColumn = 0;
  1183. StartRow = 0;
  1184. EndColumn = Console->Columns;
  1185. EndRow = Console->ScreenRows - 1;
  1186. //
  1187. // Add one extra for the cursor, and adjust for the row view offset.
  1188. //
  1189. } else {
  1190. if (StartColumn == Console->Columns) {
  1191. StartColumn -= 1;
  1192. }
  1193. EndColumn += 1;
  1194. if (EndColumn > Console->Columns) {
  1195. EndColumn -= Console->Columns;
  1196. EndRow += 1;
  1197. }
  1198. StartRow -= Console->RowViewOffset;
  1199. if (StartRow < 0) {
  1200. StartRow = 0;
  1201. } else if (StartRow > Console->ScreenRows - 1) {
  1202. StartRow = Console->ScreenRows - 1;
  1203. }
  1204. EndRow -= Console->RowViewOffset;
  1205. if (EndRow < 0) {
  1206. EndRow = 0;
  1207. } else if (EndRow > Console->ScreenRows - 1) {
  1208. EndRow = Console->ScreenRows - 1;
  1209. }
  1210. if ((EndRow == StartRow) && (EndColumn < StartColumn)) {
  1211. EndColumn = StartColumn;
  1212. }
  1213. }
  1214. //
  1215. // Set the cursor character.
  1216. //
  1217. VcpGetCursorPosition(Console, &CursorRow, &CursorColumn);
  1218. Line = GET_CONSOLE_LINE(Console, CursorRow);
  1219. Characters = (PBASE_VIDEO_CHARACTER)(Line->Character);
  1220. if ((Console->Mode & CONSOLE_MODE_CURSOR) != 0) {
  1221. Characters[CursorColumn].Data.Attributes |= BASE_VIDEO_CURSOR;
  1222. }
  1223. //
  1224. // Redraw the portion of the screen that was modified.
  1225. //
  1226. VcpRedrawArea(Console, StartColumn, StartRow, EndColumn, EndRow);
  1227. KeReleaseQueuedLock(Console->Lock);
  1228. return;
  1229. }
  1230. VOID
  1231. VcpProcessCommand (
  1232. PVIDEO_CONSOLE_DEVICE Console,
  1233. PTERMINAL_COMMAND_DATA Command
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine processes a terminal control sequence.
  1238. Arguments:
  1239. Console - Supplies a pointer to the video console.
  1240. Command - Supplies a pointer to the command to run.
  1241. Return Value:
  1242. None.
  1243. --*/
  1244. {
  1245. LONG Bottom;
  1246. LONG Column;
  1247. LONG Count;
  1248. PVIDEO_CONSOLE_LINE Line;
  1249. UINTN ParameterIndex;
  1250. BOOL ResetCharacterAttributes;
  1251. LONG Row;
  1252. LONG Top;
  1253. //
  1254. // For the purposes of handling a command, the console cannot be
  1255. // overhanging.
  1256. //
  1257. if (Console->NextColumn == Console->Columns) {
  1258. Console->NextColumn -= 1;
  1259. }
  1260. switch (Command->Command) {
  1261. case TerminalCommandInvalid:
  1262. ASSERT(FALSE);
  1263. break;
  1264. case TerminalCommandCursorUp:
  1265. Count = Command->Parameter[0];
  1266. ASSERT((Command->ParameterCount != 0) && (Count > 0));
  1267. VcpMoveCursorRelative(Console, 0, -Count);
  1268. break;
  1269. case TerminalCommandCursorDown:
  1270. Count = Command->Parameter[0];
  1271. ASSERT((Command->ParameterCount != 0) && (Count > 0) &&
  1272. (Console->NextRow <= Console->ScreenRows - 1));
  1273. VcpMoveCursorRelative(Console, 0, Count);
  1274. break;
  1275. case TerminalCommandCursorLeft:
  1276. Count = Command->Parameter[0];
  1277. ASSERT((Command->ParameterCount != 0) && (Count > 0));
  1278. VcpMoveCursorRelative(Console, -Count, 0);
  1279. break;
  1280. case TerminalCommandCursorRight:
  1281. Count = Command->Parameter[0];
  1282. ASSERT((Command->ParameterCount != 0) && (Count > 0));
  1283. ASSERT(Console->NextColumn <= Console->Columns - 1);
  1284. VcpMoveCursorRelative(Console, Count, 0);
  1285. break;
  1286. case TerminalCommandSetCursorRowAbsolute:
  1287. Row = Command->Parameter[0];
  1288. ASSERT((Command->ParameterCount != 0) && (Row > 0));
  1289. Row -= 1;
  1290. VcpMoveCursorAbsolute(Console, Console->NextColumn, Row, TRUE);
  1291. break;
  1292. case TerminalCommandSetCursorColumnAbsolute:
  1293. Column = Command->Parameter[0];
  1294. ASSERT((Command->ParameterCount != 0) && (Column > 0));
  1295. Column -= 1;
  1296. VcpMoveCursorAbsolute(Console, Column, Console->NextRow, FALSE);
  1297. break;
  1298. case TerminalCommandCursorMove:
  1299. Column = Command->Parameter[1];
  1300. Row = Command->Parameter[0];
  1301. ASSERT((Command->ParameterCount == 2) && (Column > 0) && (Row > 0));
  1302. Column -= 1;
  1303. Row -= 1;
  1304. VcpMoveCursorAbsolute(Console, Column, Row, TRUE);
  1305. break;
  1306. case TerminalCommandNextLine:
  1307. Console->NextColumn = 0;
  1308. VcpAdvanceRow(Console);
  1309. break;
  1310. case TerminalCommandReverseLineFeed:
  1311. if (Console->NextRow < Console->TopMargin) {
  1312. if (Console->NextRow != 0) {
  1313. Console->NextRow -= 1;
  1314. }
  1315. } else if (Console->NextRow == Console->TopMargin) {
  1316. VcpInsertLines(Console, 1, Console->NextRow);
  1317. } else {
  1318. ASSERT(Console->NextRow > 0);
  1319. Console->NextRow -= 1;
  1320. }
  1321. break;
  1322. case TerminalCommandSaveCursorAndAttributes:
  1323. VcpSaveRestoreCursor(Console, TRUE);
  1324. break;
  1325. case TerminalCommandRestoreCursorAndAttributes:
  1326. VcpSaveRestoreCursor(Console, FALSE);
  1327. break;
  1328. case TerminalCommandSetHorizontalTab:
  1329. case TerminalCommandClearHorizontalTab:
  1330. break;
  1331. case TerminalCommandSetTopAndBottomMargin:
  1332. Top = 1;
  1333. Bottom = Console->ScreenRows;
  1334. if (Command->ParameterCount > 0) {
  1335. if ((Command->Parameter[0] != 0) &&
  1336. (Command->Parameter[0] <= Console->ScreenRows)) {
  1337. Top = Command->Parameter[0];
  1338. }
  1339. if ((Command->ParameterCount > 1) && (Command->Parameter[1] != 0) &&
  1340. (Command->Parameter[1] <= Console->ScreenRows)) {
  1341. Bottom = Command->Parameter[1];
  1342. }
  1343. }
  1344. if (Top < Bottom) {
  1345. ASSERT((Top > 0) && (Top <= Console->ScreenRows) &&
  1346. (Bottom > Top) && (Bottom <= Console->ScreenRows));
  1347. Console->TopMargin = Top - 1;
  1348. Console->BottomMargin = Console->ScreenRows - Bottom;
  1349. }
  1350. Console->NextColumn = 0;
  1351. Console->NextRow = 0;
  1352. if ((Console->Mode & CONSOLE_MODE_ORIGIN) != 0) {
  1353. Console->NextRow += Console->TopMargin;
  1354. }
  1355. break;
  1356. case TerminalCommandEraseInDisplay:
  1357. case TerminalCommandEraseInDisplaySelective:
  1358. ResetCharacterAttributes = TRUE;
  1359. if (Command->Command == TerminalCommandEraseInDisplaySelective) {
  1360. ResetCharacterAttributes = FALSE;
  1361. }
  1362. //
  1363. // For no parameter or zero, erase from the cursor to the end of the
  1364. // screen, including the cursor.
  1365. //
  1366. if ((Command->ParameterCount == 0) || (Command->Parameter[0] == 0)) {
  1367. VcpEraseArea(Console,
  1368. Console->NextColumn,
  1369. Console->NextRow,
  1370. Console->Columns - 1,
  1371. Console->ScreenRows - 1,
  1372. ResetCharacterAttributes);
  1373. //
  1374. // If the parameter is 1, erase from the top of the screen to the
  1375. // current cursor, including the cursor.
  1376. //
  1377. } else if (Command->Parameter[0] == 1) {
  1378. VcpEraseArea(Console,
  1379. 0,
  1380. 0,
  1381. Console->NextColumn,
  1382. Console->NextRow,
  1383. ResetCharacterAttributes);
  1384. //
  1385. // If the parameter is 2, erase the entire display.
  1386. //
  1387. } else if (Command->Parameter[0] == 2) {
  1388. VcpEraseArea(Console,
  1389. 0,
  1390. 0,
  1391. Console->Columns - 1,
  1392. Console->ScreenRows - 1,
  1393. ResetCharacterAttributes);
  1394. }
  1395. break;
  1396. case TerminalCommandEraseInLine:
  1397. case TerminalCommandEraseInLineSelective:
  1398. ResetCharacterAttributes = TRUE;
  1399. if (Command->Command == TerminalCommandEraseInLineSelective) {
  1400. ResetCharacterAttributes = FALSE;
  1401. }
  1402. //
  1403. // For no parameters or zero, erase from the cursor to the end of the
  1404. // line, including the cursor.
  1405. //
  1406. if ((Command->ParameterCount == 0) || (Command->Parameter[0] == 0)) {
  1407. VcpEraseArea(Console,
  1408. Console->NextColumn,
  1409. Console->NextRow,
  1410. Console->Columns - 1,
  1411. Console->NextRow,
  1412. ResetCharacterAttributes);
  1413. //
  1414. // Erase from the beginning of the line to the cursor, including the
  1415. // cursor.
  1416. //
  1417. } else if (Command->Parameter[0] == 1) {
  1418. VcpEraseArea(Console,
  1419. 0,
  1420. Console->NextRow,
  1421. Console->NextColumn,
  1422. Console->NextRow,
  1423. ResetCharacterAttributes);
  1424. } else if (Command->Parameter[0] == 2) {
  1425. VcpEraseArea(Console,
  1426. 0,
  1427. Console->NextRow,
  1428. Console->Columns - 1,
  1429. Console->NextRow,
  1430. ResetCharacterAttributes);
  1431. }
  1432. break;
  1433. case TerminalCommandInsertLines:
  1434. Count = 1;
  1435. if ((Command->ParameterCount != 0) && (Command->Parameter[0] > 0)) {
  1436. Count = Command->Parameter[0];
  1437. }
  1438. //
  1439. // If the cursor is outside the scroll area.
  1440. //
  1441. if (!CURSOR_IN_SCROLL_REGION(Console)) {
  1442. break;
  1443. }
  1444. Console->NextColumn = 0;
  1445. VcpInsertLines(Console, Count, Console->NextRow);
  1446. break;
  1447. case TerminalCommandDeleteLines:
  1448. Count = 1;
  1449. if ((Command->ParameterCount != 0) && (Command->Parameter[0] > 0)) {
  1450. Count = Command->Parameter[0];
  1451. }
  1452. //
  1453. // If the cursor is outside the scroll area or at the very bottom of it,
  1454. // this command is ignored.
  1455. //
  1456. if (!CURSOR_IN_SCROLL_REGION(Console)) {
  1457. break;
  1458. }
  1459. Console->NextColumn = 0;
  1460. if (Console->NextRow ==
  1461. Console->ScreenRows - 1 - Console->BottomMargin) {
  1462. break;
  1463. }
  1464. VcpDeleteLines(Console, Count, Console->NextRow);
  1465. break;
  1466. case TerminalCommandInsertCharacters:
  1467. Count = 1;
  1468. if ((Command->ParameterCount != 0) && (Command->Parameter[0] != 0)) {
  1469. Count = Command->Parameter[0];
  1470. }
  1471. if (Count > Console->Columns - Console->NextColumn) {
  1472. Count = Console->Columns - Console->NextColumn;
  1473. }
  1474. //
  1475. // If insert mode is set, shift the remaining characters out.
  1476. //
  1477. Line = GET_CONSOLE_LINE(Console, Console->NextRow);
  1478. for (Column = Console->Columns - 1;
  1479. Column >= Console->NextColumn + Count;
  1480. Column -= 1) {
  1481. Line->Character[Column].AsUint32 =
  1482. Line->Character[Column - Count].AsUint32;
  1483. }
  1484. RtlZeroMemory(&(Line->Character[Console->NextColumn]),
  1485. Count * sizeof(BASE_VIDEO_CHARACTER));
  1486. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1487. break;
  1488. case TerminalCommandDeleteCharacters:
  1489. Count = 1;
  1490. if ((Command->ParameterCount != 0) && (Command->Parameter[0] != 0)) {
  1491. Count = Command->Parameter[0];
  1492. }
  1493. if (Count > Console->Columns - Console->NextColumn) {
  1494. Count = Console->Columns - Console->NextColumn;
  1495. }
  1496. //
  1497. // Move the remaining characters backwards.
  1498. //
  1499. Line = GET_CONSOLE_LINE(Console, Console->NextRow);
  1500. for (Column = Console->NextColumn;
  1501. Column < Console->Columns - Count;
  1502. Column += 1) {
  1503. Line->Character[Column].AsUint32 =
  1504. Line->Character[Column + Count].AsUint32;
  1505. }
  1506. //
  1507. // Clear out the space at the right.
  1508. //
  1509. RtlZeroMemory(&(Line->Character[Console->Columns - Count]),
  1510. Count * sizeof(BASE_VIDEO_CHARACTER));
  1511. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1512. break;
  1513. case TerminalCommandEraseCharacters:
  1514. Count = 1;
  1515. if ((Command->ParameterCount != 0) && (Command->Parameter[0] != 0)) {
  1516. Count = Command->Parameter[0];
  1517. }
  1518. if (Count > Console->Columns - Console->NextColumn) {
  1519. Count = Console->Columns - Console->NextColumn;
  1520. }
  1521. //
  1522. // Erase characters starting at the cursor without shifting the line
  1523. // contents.
  1524. //
  1525. VcpEraseArea(Console,
  1526. Console->NextColumn,
  1527. Console->NextRow,
  1528. Console->NextColumn + Count - 1,
  1529. Console->NextRow,
  1530. TRUE);
  1531. break;
  1532. case TerminalCommandKeypadNumeric:
  1533. case TerminalCommandKeypadApplication:
  1534. break;
  1535. case TerminalCommandSetMode:
  1536. case TerminalCommandClearMode:
  1537. case TerminalCommandSetPrivateMode:
  1538. case TerminalCommandClearPrivateMode:
  1539. for (ParameterIndex = 0;
  1540. ParameterIndex < Command->ParameterCount;
  1541. ParameterIndex += 1) {
  1542. VcpSetOrClearMode(Console,
  1543. Command->Parameter[ParameterIndex],
  1544. Command->Command);
  1545. }
  1546. break;
  1547. case TerminalCommandSelectG0CharacterSet:
  1548. case TerminalCommandSelectG1CharacterSet:
  1549. case TerminalCommandSelectG2CharacterSet:
  1550. case TerminalCommandSelectG3CharacterSet:
  1551. break;
  1552. case TerminalCommandSelectGraphicRendition:
  1553. VcpSetColorFromParameters(Console, Command);
  1554. break;
  1555. case TerminalCommandReset:
  1556. case TerminalCommandSoftReset:
  1557. Console->TextAttributes = 0;
  1558. Console->NextRow = 0;
  1559. Console->NextColumn = 0;
  1560. Console->Mode = VIDEO_CONSOLE_MODE_DEFAULTS;
  1561. Console->TopMargin = 0;
  1562. Console->BottomMargin = 0;
  1563. VcpEraseArea(Console,
  1564. 0,
  1565. 0,
  1566. Console->Columns - 1,
  1567. Console->ScreenRows - 1,
  1568. TRUE);
  1569. break;
  1570. case TerminalCommandDeviceAttributesPrimary:
  1571. case TerminalCommandDeviceAttributesSecondary:
  1572. break;
  1573. case TerminalCommandScrollUp:
  1574. Count = Command->Parameter[0];
  1575. if ((Command->ParameterCount == 0) || (Count <= 0)) {
  1576. Count = 1;
  1577. }
  1578. if (Console->TopMargin == 0) {
  1579. Console->RowViewOffset -= Count;
  1580. } else {
  1581. VcpDeleteLines(Console, Count, Console->TopMargin);
  1582. }
  1583. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1584. break;
  1585. case TerminalCommandScrollDown:
  1586. Count = Command->Parameter[0];
  1587. if ((Command->ParameterCount == 0) || (Count <= 0)) {
  1588. Count = 1;
  1589. }
  1590. if (Console->TopMargin == 0) {
  1591. Console->RowViewOffset += Count;
  1592. } else {
  1593. VcpInsertLines(Console, Count, Console->TopMargin);
  1594. }
  1595. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1596. break;
  1597. case TerminalCommandDoubleLineHeightTopHalf:
  1598. case TerminalCommandDoubleLineHeightBottomHalf:
  1599. case TerminalCommandSingleWidthLine:
  1600. case TerminalCommandDoubleWidthLine:
  1601. break;
  1602. //
  1603. // Do nothing for unknown commands.
  1604. //
  1605. default:
  1606. break;
  1607. }
  1608. return;
  1609. }
  1610. VOID
  1611. VcpEraseArea (
  1612. PVIDEO_CONSOLE_DEVICE Console,
  1613. LONG StartColumn,
  1614. LONG StartRow,
  1615. LONG EndColumn,
  1616. LONG EndRow,
  1617. BOOL ResetAttributes
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. This routine erases a portion of the screen.
  1622. Arguments:
  1623. Console - Supplies a pointer to the video console to erase.
  1624. StartColumn - Supplies the starting column, inclusive, to erase.
  1625. StartRow - Supplies the starting row, inclusive, to erase.
  1626. EndColumn - Supplies the ending column, inclusive, to erase.
  1627. EndRow - Supplies the ending row, inclusive, to erase.
  1628. ResetAttributes - Supplies a boolean indicating if the attributes should be
  1629. reset to zero as well or left alone.
  1630. Return Value:
  1631. None.
  1632. --*/
  1633. {
  1634. BOOL Blank;
  1635. LONG Column;
  1636. LONG EndColumnThisRow;
  1637. PVIDEO_CONSOLE_LINE Line;
  1638. LONG LineCount;
  1639. LONG Row;
  1640. LONG SavedBottomMargin;
  1641. LONG SavedTopMargin;
  1642. ASSERT((EndColumn < Console->Columns) && (EndRow < Console->ScreenRows));
  1643. Console->RowViewOffset = 0;
  1644. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1645. if (StartColumn == Console->Columns) {
  1646. StartColumn -= 1;
  1647. }
  1648. if (EndColumn == Console->Columns) {
  1649. EndColumn -= 1;
  1650. }
  1651. //
  1652. // If erasing the whole screen, then actually scroll up until the screen
  1653. // is blank.
  1654. //
  1655. if ((ResetAttributes != FALSE) && (StartColumn == 0) && (StartRow == 0) &&
  1656. (EndColumn == Console->Columns - 1) &&
  1657. (EndRow == Console->ScreenRows - 1)) {
  1658. //
  1659. // Find the last non-blank line.
  1660. //
  1661. for (Row = Console->ScreenRows - 1; Row >= 0; Row -= 1) {
  1662. Blank = TRUE;
  1663. Line = GET_CONSOLE_LINE(Console, Row);
  1664. for (Column = 0; Column < Console->Columns; Column += 1) {
  1665. if ((Line->Character[Column].Data.Character != 0) &&
  1666. (Line->Character[Column].Data.Character != ' ')) {
  1667. Blank = FALSE;
  1668. break;
  1669. }
  1670. if (Line->Character[Column].Data.Attributes != 0) {
  1671. Blank = FALSE;
  1672. break;
  1673. }
  1674. }
  1675. if (Blank == FALSE) {
  1676. break;
  1677. }
  1678. }
  1679. //
  1680. // Scroll up by the number of non-blank lines.
  1681. //
  1682. LineCount = Row + 1;
  1683. Row = Console->NextRow;
  1684. SavedTopMargin = Console->TopMargin;
  1685. SavedBottomMargin = Console->BottomMargin;
  1686. Console->NextRow = Console->ScreenRows - 1;
  1687. Console->TopMargin = 0;
  1688. Console->BottomMargin = 0;
  1689. while (LineCount != 0) {
  1690. VcpAdvanceRow(Console);
  1691. LineCount -= 1;
  1692. }
  1693. Console->NextRow = Row;
  1694. Console->TopMargin = SavedTopMargin;
  1695. Console->BottomMargin = SavedBottomMargin;
  1696. return;
  1697. }
  1698. //
  1699. // Really erase the given region, rather than just scrolling up.
  1700. //
  1701. for (Row = StartRow; Row <= EndRow; Row += 1) {
  1702. Line = GET_CONSOLE_LINE(Console, Row);
  1703. Column = 0;
  1704. if (Row == StartRow) {
  1705. Column = StartColumn;
  1706. }
  1707. EndColumnThisRow = Console->Columns - 1;
  1708. if (Row == EndRow) {
  1709. EndColumnThisRow = EndColumn;
  1710. }
  1711. ASSERT(Column <= EndColumnThisRow);
  1712. if (ResetAttributes != FALSE) {
  1713. while (Column <= EndColumnThisRow) {
  1714. Line->Character[Column].Data.Character = ' ';
  1715. Line->Character[Column].Data.Attributes =
  1716. Console->TextAttributes;
  1717. Column += 1;
  1718. }
  1719. } else {
  1720. while (Column <= EndColumnThisRow) {
  1721. Line->Character[Column].Data.Character = ' ';
  1722. Column += 1;
  1723. }
  1724. }
  1725. }
  1726. return;
  1727. }
  1728. VOID
  1729. VcpSetOrClearMode (
  1730. PVIDEO_CONSOLE_DEVICE Console,
  1731. ULONG ModeNumber,
  1732. TERMINAL_COMMAND Command
  1733. )
  1734. /*++
  1735. Routine Description:
  1736. This routine sets or clears a console mode setting.
  1737. Arguments:
  1738. Console - Supplies a pointer to the video console to alter.
  1739. ModeNumber - Supplies the mode number to set or clear.
  1740. Command - Supplies the command number.
  1741. Return Value:
  1742. None.
  1743. --*/
  1744. {
  1745. ULONG Mask;
  1746. BOOL Set;
  1747. Mask = 0;
  1748. Set = FALSE;
  1749. if ((Command == TerminalCommandSetMode) ||
  1750. (Command == TerminalCommandSetPrivateMode)) {
  1751. Set = TRUE;
  1752. }
  1753. if ((Command == TerminalCommandSetMode) ||
  1754. (Command == TerminalCommandClearMode)) {
  1755. switch (ModeNumber) {
  1756. case TERMINAL_MODE_KEYBOARD_LOCKED:
  1757. Mask = CONSOLE_MODE_KEYBOARD_ACTION;
  1758. break;
  1759. case TERMINAL_MODE_INSERT:
  1760. Mask = CONSOLE_MODE_INSERT;
  1761. break;
  1762. case TERMINAL_MODE_DISABLE_LOCAL_ECHO:
  1763. Mask = CONSOLE_MODE_DISABLE_LOCAL_ECHO;
  1764. break;
  1765. case TERMINAL_MODE_NEW_LINE:
  1766. Mask = CONSOLE_MODE_NEW_LINE;
  1767. break;
  1768. default:
  1769. break;
  1770. }
  1771. } else {
  1772. ASSERT((Command == TerminalCommandSetPrivateMode) ||
  1773. (Command == TerminalCommandClearPrivateMode));
  1774. switch (ModeNumber) {
  1775. case TERMINAL_PRIVATE_MODE_APPLICATION_CURSOR_KEYS:
  1776. Mask = CONSOLE_MODE_APPLICATION_CURSOR_KEYS;
  1777. break;
  1778. case TERMINAL_PRIVATE_MODE_VT52:
  1779. Mask = CONSOLE_MODE_VT52;
  1780. break;
  1781. case TERMINAL_PRIVATE_MODE_132_COLUMNS:
  1782. Mask = CONSOLE_MODE_132_COLUMN;
  1783. break;
  1784. case TERMINAL_PRIVATE_MODE_SMOOTH_SCROLLING:
  1785. Mask = CONSOLE_MODE_KEYBOARD_ACTION;
  1786. break;
  1787. case TERMINAL_PRIVATE_MODE_REVERSE_VIDEO:
  1788. Mask = CONSOLE_MODE_VIDEO_REVERSED;
  1789. Console->PendingAction = VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  1790. break;
  1791. case TERMINAL_PRIVATE_MODE_ORIGIN:
  1792. Mask = CONSOLE_MODE_ORIGIN;
  1793. break;
  1794. case TERMINAL_PRIVATE_MODE_AUTO_WRAP:
  1795. Mask = CONSOLE_MODE_AUTO_WRAP;
  1796. break;
  1797. case TERMINAL_PRIVATE_MODE_BLINKING_CURSOR:
  1798. Mask = CONSOLE_MODE_CURSOR_BLINK;
  1799. break;
  1800. case TERMINAL_PRIVATE_MODE_CURSOR:
  1801. Mask = CONSOLE_MODE_CURSOR;
  1802. break;
  1803. case TERMINAL_PRIVATE_MODE_SAVE_CURSOR:
  1804. VcpSaveRestoreCursor(Console, Set);
  1805. break;
  1806. case TERMINAL_PRIVATE_MODE_ALTERNATE_SCREEN_SAVE_CURSOR:
  1807. VcpSaveRestoreCursor(Console, Set);
  1808. //
  1809. // Erase the screen in lieu of a keeping secondary screen buffer.
  1810. //
  1811. VcpEraseArea(Console,
  1812. 0,
  1813. 0,
  1814. Console->Columns - 1,
  1815. Console->ScreenRows - 1,
  1816. TRUE);
  1817. Console->TopMargin = 0;
  1818. Console->BottomMargin = 0;
  1819. break;
  1820. case TERMINAL_PRIVATE_MODE_AUTO_REPEAT:
  1821. case TERMINAL_PRIVATE_MODE_FORM_FEED:
  1822. case TERMINAL_PRIVATE_MODE_PRINT_FULL_SCREEN:
  1823. case TERMINAL_PRIVATE_MODE_NATIONAL:
  1824. case TERMINAL_PRIVATE_MODE_ALTERNATE_SCREEN:
  1825. break;
  1826. }
  1827. }
  1828. if (Set != FALSE) {
  1829. Console->Mode |= Mask;
  1830. } else {
  1831. Console->Mode &= ~Mask;
  1832. }
  1833. return;
  1834. }
  1835. VOID
  1836. VcpRedrawArea (
  1837. PVIDEO_CONSOLE_DEVICE Console,
  1838. LONG StartColumn,
  1839. LONG StartRow,
  1840. LONG EndColumn,
  1841. LONG EndRow
  1842. )
  1843. /*++
  1844. Routine Description:
  1845. This routine redraws a portion of the screen.
  1846. Arguments:
  1847. Console - Supplies a pointer to the video console to write to.
  1848. StartColumn - Supplies the starting column, inclusive, to redraw at.
  1849. StartRow - Supplies the starting row, inclusive, to redraw at.
  1850. EndColumn - Supplies the ending column, exclusive, to redraw until.
  1851. EndRow - Supplies the ending row, inclusive, to redraw until.
  1852. Return Value:
  1853. None.
  1854. --*/
  1855. {
  1856. BASE_VIDEO_CHARACTER Blank;
  1857. LONG BufferRow;
  1858. PBASE_VIDEO_CHARACTER Characters;
  1859. LONG CurrentColumn;
  1860. LONG CurrentRow;
  1861. LONG EndColumnThisRow;
  1862. PVIDEO_CONSOLE_LINE Line;
  1863. PBASE_VIDEO_CHARACTER ScreenCharacters;
  1864. PVIDEO_CONSOLE_LINE ScreenLine;
  1865. LONG StartDrawColumn;
  1866. LONG Width;
  1867. CurrentColumn = StartColumn;
  1868. CurrentRow = StartRow;
  1869. Width = Console->Columns;
  1870. Blank.Data.Attributes = Console->TextAttributes;
  1871. Blank.Data.Character = ' ';
  1872. ASSERT((StartColumn < Console->Columns) && (EndColumn <= Console->Columns));
  1873. ASSERT((StartRow < Console->ScreenRows) && (EndRow <= Console->ScreenRows));
  1874. //
  1875. // Loop through each row on the screen.
  1876. //
  1877. while (TRUE) {
  1878. //
  1879. // Get the line associated with this row. If the offset plus the
  1880. // current row is greater than the screen size, this is an empty row.
  1881. //
  1882. if (CurrentRow + Console->RowViewOffset >= Console->ScreenRows) {
  1883. Line = NULL;
  1884. //
  1885. // The current row plus the offset also needs to be greater than the
  1886. // bottom of the screen (otherwise the bottom of the screen would show
  1887. // up again if scrolled far enough up).
  1888. //
  1889. } else if (CurrentRow + Console->RowViewOffset <
  1890. -(Console->BufferRows - Console->ScreenRows)) {
  1891. Line = NULL;
  1892. //
  1893. // The offset is reasonable enough that there's a line associated with
  1894. // it. Go find that line. The macro can't be used here because of the
  1895. // potential for the buffer row to go negative during the calculation.
  1896. //
  1897. } else {
  1898. BufferRow = Console->TopLine + CurrentRow + Console->RowViewOffset;
  1899. if (BufferRow >= Console->BufferRows) {
  1900. BufferRow -= Console->BufferRows;
  1901. } else if (BufferRow < 0) {
  1902. BufferRow += Console->BufferRows;
  1903. }
  1904. ASSERT((BufferRow >= 0) && (BufferRow < Console->BufferRows));
  1905. Line = (PVIDEO_CONSOLE_LINE)(Console->Lines +
  1906. (CONSOLE_LINE_SIZE(Console) *
  1907. BufferRow));
  1908. }
  1909. //
  1910. // Figure out the ending column for this row.
  1911. //
  1912. if (CurrentRow == EndRow) {
  1913. EndColumnThisRow = EndColumn;
  1914. } else {
  1915. EndColumnThisRow = Width;
  1916. }
  1917. ScreenLine = (PVIDEO_CONSOLE_LINE)(Console->Screen +
  1918. (CONSOLE_LINE_SIZE(Console) *
  1919. CurrentRow));
  1920. ScreenCharacters = ScreenLine->Character;
  1921. if (Line != NULL) {
  1922. Characters = Line->Character;
  1923. //
  1924. // Line attributes need support here if they're implemented.
  1925. //
  1926. ASSERT(ScreenLine->Attributes == Line->Attributes);
  1927. while (CurrentColumn < EndColumnThisRow) {
  1928. //
  1929. // Skip characters that are already drawn correctly.
  1930. //
  1931. if (ScreenCharacters[CurrentColumn].AsUint32 ==
  1932. Characters[CurrentColumn].AsUint32) {
  1933. CurrentColumn += 1;
  1934. continue;
  1935. }
  1936. //
  1937. // Collect characters that need redrawing.
  1938. //
  1939. StartDrawColumn = CurrentColumn;
  1940. while ((CurrentColumn < EndColumnThisRow) &&
  1941. (ScreenCharacters[CurrentColumn].AsUint32 !=
  1942. Characters[CurrentColumn].AsUint32)) {
  1943. ScreenCharacters[CurrentColumn].AsUint32 =
  1944. Characters[CurrentColumn].AsUint32;
  1945. CurrentColumn += 1;
  1946. }
  1947. VidPrintCharacters(&(Console->VideoContext),
  1948. StartDrawColumn,
  1949. CurrentRow,
  1950. &(ScreenCharacters[StartDrawColumn]),
  1951. CurrentColumn - StartDrawColumn);
  1952. }
  1953. } else {
  1954. while (CurrentColumn < EndColumnThisRow) {
  1955. //
  1956. // Skip characters that are already blank.
  1957. //
  1958. if (ScreenCharacters[CurrentColumn].AsUint32 ==
  1959. Blank.AsUint32) {
  1960. CurrentColumn += 1;
  1961. continue;
  1962. }
  1963. //
  1964. // Batch together characters that need redrawing.
  1965. //
  1966. StartDrawColumn = CurrentColumn;
  1967. while ((CurrentColumn < EndColumnThisRow) &&
  1968. (ScreenCharacters[CurrentColumn].AsUint32 !=
  1969. Blank.AsUint32)) {
  1970. ScreenCharacters[CurrentColumn] = Blank;
  1971. CurrentColumn += 1;
  1972. }
  1973. VidPrintCharacters(&(Console->VideoContext),
  1974. StartDrawColumn,
  1975. CurrentRow,
  1976. &(ScreenCharacters[StartDrawColumn]),
  1977. CurrentColumn - StartDrawColumn);
  1978. }
  1979. }
  1980. //
  1981. // Potentially break if this was the last row.
  1982. //
  1983. if (CurrentRow == EndRow) {
  1984. break;
  1985. }
  1986. //
  1987. // On to the next row.
  1988. //
  1989. CurrentColumn = 0;
  1990. CurrentRow += 1;
  1991. }
  1992. return;
  1993. }
  1994. VOID
  1995. VcpAdvanceRow (
  1996. PVIDEO_CONSOLE_DEVICE Console
  1997. )
  1998. /*++
  1999. Routine Description:
  2000. This routine move the console's "next row" up by one (visually down to the
  2001. next row).
  2002. Arguments:
  2003. Console - Supplies a pointer to the video console to write to.
  2004. ScreenRedrawNeeded - Supplies a pointer where a boolean will be returned
  2005. indicating if the entire screen needs to be redrawn. If not, this
  2006. boolean will be left uninitialized. If so, this boolean will be set to
  2007. TRUE.
  2008. Return Value:
  2009. None.
  2010. --*/
  2011. {
  2012. UINTN LineSize;
  2013. ULONG NewAllocationSize;
  2014. PVIDEO_CONSOLE_LINE NewLastLine;
  2015. PVOID NewLines;
  2016. LONG NewRowCount;
  2017. ULONG OriginalSize;
  2018. LONG Row;
  2019. //
  2020. // It's really easy if there are still extra rows on the screen to be
  2021. // used.
  2022. //
  2023. if (Console->NextRow < Console->ScreenRows - 1 - Console->BottomMargin) {
  2024. Console->NextRow += 1;
  2025. return;
  2026. }
  2027. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  2028. //
  2029. // Do nothing if the cursor made it beyond the bottom of the scroll area.
  2030. //
  2031. if (Console->NextRow > Console->ScreenRows - 1 - Console->BottomMargin) {
  2032. return;
  2033. }
  2034. //
  2035. // If the bottom console line is also the bottom buffer line, look into
  2036. // expanding the buffer.
  2037. //
  2038. if ((Console->TopLine + Console->ScreenRows == Console->BufferRows) &&
  2039. ((Console->BufferRows < Console->MaxRows) ||
  2040. (Console->MaxRows == 0))) {
  2041. NewRowCount = Console->BufferRows * 2;
  2042. if ((Console->MaxRows != 0) && (NewRowCount > Console->MaxRows)) {
  2043. NewRowCount = Console->MaxRows;
  2044. }
  2045. ASSERT(NewRowCount > Console->BufferRows);
  2046. NewAllocationSize = CONSOLE_LINE_SIZE(Console) * NewRowCount;
  2047. NewLines = MmAllocatePagedPool(NewAllocationSize,
  2048. VIDEO_CONSOLE_ALLOCATION_TAG);
  2049. if (NewLines != NULL) {
  2050. OriginalSize = CONSOLE_LINE_SIZE(Console) * Console->BufferRows;
  2051. RtlCopyMemory(NewLines, Console->Lines, OriginalSize);
  2052. RtlZeroMemory(NewLines + OriginalSize,
  2053. NewAllocationSize - OriginalSize);
  2054. MmFreePagedPool(Console->Lines);
  2055. Console->Lines = NewLines;
  2056. Console->BufferRows = NewRowCount;
  2057. }
  2058. }
  2059. LineSize = CONSOLE_LINE_SIZE(Console);
  2060. //
  2061. // If there's a top margin, then actually perform the scroll by copying
  2062. // the lines up.
  2063. //
  2064. if (Console->TopMargin != 0) {
  2065. for (Row = Console->TopMargin;
  2066. Row < Console->ScreenRows - Console->BottomMargin - 1;
  2067. Row += 1) {
  2068. RtlCopyMemory(GET_CONSOLE_LINE(Console, Row),
  2069. GET_CONSOLE_LINE(Console, Row + 1),
  2070. LineSize);
  2071. }
  2072. RtlZeroMemory(GET_CONSOLE_LINE(Console, Row), LineSize);
  2073. Console->RowViewOffset = 0;
  2074. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  2075. return;
  2076. }
  2077. //
  2078. // Initialize and reset a fresh line.
  2079. //
  2080. if (Console->BottomMargin == 0) {
  2081. NewLastLine = GET_CONSOLE_LINE(Console, Console->ScreenRows);
  2082. //
  2083. // There's a bottom margin (but not a top one), so move everything below
  2084. // the bottom margin down one and zero out the bottom margin line.
  2085. //
  2086. } else {
  2087. for (Row = Console->ScreenRows - 1;
  2088. Row > Console->ScreenRows - 1 - Console->BottomMargin;
  2089. Row -= 1) {
  2090. RtlCopyMemory(GET_CONSOLE_LINE(Console, Row),
  2091. GET_CONSOLE_LINE(Console, Row - 1),
  2092. LineSize);
  2093. }
  2094. NewLastLine = GET_CONSOLE_LINE(Console, Row + 1);
  2095. Console->RowViewOffset = 0;
  2096. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN;
  2097. }
  2098. RtlZeroMemory(NewLastLine, LineSize);
  2099. Console->TopLine = Console->TopLine + 1;
  2100. if (Console->TopLine >= Console->BufferRows) {
  2101. Console->TopLine -= Console->BufferRows;
  2102. ASSERT(Console->TopLine < Console->BufferRows);
  2103. }
  2104. //
  2105. // Create the appearance of filling up the space shown because the user
  2106. // scrolled past the end.
  2107. //
  2108. if (Console->RowViewOffset > 0) {
  2109. Console->RowViewOffset -= 1;
  2110. }
  2111. return;
  2112. }
  2113. VOID
  2114. VcpSetColorFromParameters (
  2115. PVIDEO_CONSOLE_DEVICE Console,
  2116. PTERMINAL_COMMAND_DATA Command
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. This routine sets the current text attributes based on the paramters in
  2121. the input parse state.
  2122. Arguments:
  2123. Console - Supplies a pointer to the video console that just got the
  2124. set colors command.
  2125. Command - Supplies a pointer to the command to set attributes from.
  2126. Return Value:
  2127. None.
  2128. --*/
  2129. {
  2130. USHORT Attributes;
  2131. LONG Parameter;
  2132. LONG ParameterIndex;
  2133. Attributes = 0;
  2134. for (ParameterIndex = 0;
  2135. ParameterIndex < Command->ParameterCount;
  2136. ParameterIndex += 1) {
  2137. Parameter = Command->Parameter[ParameterIndex];
  2138. if (Parameter == TERMINAL_GRAPHICS_BOLD) {
  2139. Attributes |= BASE_VIDEO_FOREGROUND_BOLD;
  2140. } else if (Parameter == TERMINAL_GRAPHICS_NEGATIVE) {
  2141. Attributes |= BASE_VIDEO_NEGATIVE;
  2142. } else if ((Parameter >= TERMINAL_GRAPHICS_FOREGROUND) &&
  2143. (Parameter <
  2144. TERMINAL_GRAPHICS_FOREGROUND + AnsiColorCount)) {
  2145. Attributes &= ~BASE_VIDEO_COLOR_MASK;
  2146. Attributes |= Parameter - TERMINAL_GRAPHICS_FOREGROUND +
  2147. AnsiColorBlack;
  2148. } else if ((Parameter >= TERMINAL_GRAPHICS_BACKGROUND) &&
  2149. (Parameter <
  2150. TERMINAL_GRAPHICS_BACKGROUND + AnsiColorCount)) {
  2151. Attributes &= ~(BASE_VIDEO_COLOR_MASK <<
  2152. BASE_VIDEO_BACKGROUND_SHIFT);
  2153. Attributes |= (Parameter - TERMINAL_GRAPHICS_BACKGROUND +
  2154. AnsiColorBlack) << BASE_VIDEO_BACKGROUND_SHIFT;
  2155. }
  2156. }
  2157. Console->TextAttributes = Attributes;
  2158. return;
  2159. }
  2160. VOID
  2161. VcpSaveRestoreCursor (
  2162. PVIDEO_CONSOLE_DEVICE Console,
  2163. BOOL Save
  2164. )
  2165. /*++
  2166. Routine Description:
  2167. This routine saves or restores the cursor position and text attributes.
  2168. Arguments:
  2169. Console - Supplies a pointer to the video console.
  2170. Save - Supplies a boolean indicating whether to save the attributes (TRUE)
  2171. or restore them (FALSE).
  2172. Return Value:
  2173. None.
  2174. --*/
  2175. {
  2176. if (Save != FALSE) {
  2177. Console->SavedColumn = Console->NextColumn;
  2178. Console->SavedRow = Console->NextRow;
  2179. Console->SavedAttributes = Console->TextAttributes;
  2180. } else {
  2181. Console->NextColumn = Console->SavedColumn;
  2182. Console->NextRow = Console->SavedRow;
  2183. Console->TextAttributes = Console->SavedAttributes;
  2184. }
  2185. return;
  2186. }
  2187. VOID
  2188. VcpMoveCursorRelative (
  2189. PVIDEO_CONSOLE_DEVICE Console,
  2190. LONG DistanceX,
  2191. LONG DistanceY
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. This routine moves the cursor relative to its current position.
  2196. Arguments:
  2197. Console - Supplies a pointer to the video console.
  2198. DistanceX - Supplies the distance to move the cursor right. Negative values
  2199. move left.
  2200. DistanceY - Supplies the distance to move the cursor down. Negative values
  2201. move up.
  2202. Return Value:
  2203. None.
  2204. --*/
  2205. {
  2206. LONG NewColumn;
  2207. LONG NewRow;
  2208. NewColumn = Console->NextColumn + DistanceX;
  2209. if (NewColumn < 0) {
  2210. NewColumn = 0;
  2211. } else if (NewColumn >= Console->Columns) {
  2212. NewColumn = Console->Columns - 1;
  2213. }
  2214. NewRow = Console->NextRow + DistanceY;
  2215. if (NewRow < Console->TopMargin) {
  2216. NewRow = Console->TopMargin;
  2217. } else if (NewRow >= Console->ScreenRows - Console->BottomMargin) {
  2218. NewRow = Console->ScreenRows - 1 - Console->BottomMargin;
  2219. }
  2220. Console->NextRow = NewRow;
  2221. Console->NextColumn = NewColumn;
  2222. Console->PendingAction |= VIDEO_ACTION_RESET_SCROLL;
  2223. return;
  2224. }
  2225. VOID
  2226. VcpMoveCursorAbsolute (
  2227. PVIDEO_CONSOLE_DEVICE Console,
  2228. LONG Column,
  2229. LONG Row,
  2230. BOOL ProcessOriginMode
  2231. )
  2232. /*++
  2233. Routine Description:
  2234. This routine moves the cursor to a new absolute position.
  2235. Arguments:
  2236. Console - Supplies a pointer to the video console.
  2237. Column - Supplies the new zero-based column to move to.
  2238. Row - Supplies the new zero-based row to move to.
  2239. ProcessOriginMode - Supplies a boolean indicating if this routine should
  2240. adjust the position if origin mode is set.
  2241. Return Value:
  2242. None.
  2243. --*/
  2244. {
  2245. LONG MaxRow;
  2246. LONG MinRow;
  2247. if (Column < 0) {
  2248. Column = 0;
  2249. } else if (Column >= Console->Columns) {
  2250. Column = Console->Columns - 1;
  2251. }
  2252. MinRow = 0;
  2253. MaxRow = Console->ScreenRows - 1;
  2254. if (((Console->Mode & CONSOLE_MODE_ORIGIN) != 0) &&
  2255. (ProcessOriginMode != FALSE)) {
  2256. MinRow = Console->TopMargin;
  2257. MaxRow -= Console->BottomMargin;
  2258. Row += Console->TopMargin;
  2259. }
  2260. if (Row < MinRow) {
  2261. Row = MinRow;
  2262. }
  2263. if (Row > MaxRow) {
  2264. Row = MaxRow;
  2265. }
  2266. Console->NextRow = Row;
  2267. Console->NextColumn = Column;
  2268. Console->PendingAction |= VIDEO_ACTION_RESET_SCROLL;
  2269. return;
  2270. }
  2271. VOID
  2272. VcpDeleteLines (
  2273. PVIDEO_CONSOLE_DEVICE Console,
  2274. LONG Count,
  2275. LONG StartingRow
  2276. )
  2277. /*++
  2278. Routine Description:
  2279. This routine deletes lines from the console screen, moving following lines
  2280. up.
  2281. Arguments:
  2282. Console - Supplies a pointer to the video console.
  2283. Count - Supplies the number of lines to delete.
  2284. StartingRow - Supplies the first row of the region.
  2285. Return Value:
  2286. None.
  2287. --*/
  2288. {
  2289. UINTN LineSize;
  2290. LONG Row;
  2291. if (StartingRow == Console->ScreenRows - 1 - Console->BottomMargin) {
  2292. return;
  2293. }
  2294. //
  2295. // If more lines are being deleted than can exist in the scroll area,
  2296. // just erase the scroll area.
  2297. //
  2298. if (Count >
  2299. (Console->ScreenRows - Console->BottomMargin -
  2300. StartingRow + 1)) {
  2301. VcpEraseArea(Console,
  2302. 0,
  2303. StartingRow,
  2304. Console->Columns - 1,
  2305. Console->ScreenRows - 1 - Console->BottomMargin,
  2306. TRUE);
  2307. return;
  2308. }
  2309. //
  2310. // Move lines up within the scroll region.
  2311. //
  2312. LineSize = CONSOLE_LINE_SIZE(Console);
  2313. for (Row = StartingRow;
  2314. Row < Console->ScreenRows - Console->BottomMargin - Count;
  2315. Row += 1) {
  2316. RtlCopyMemory(GET_CONSOLE_LINE(Console, Row),
  2317. GET_CONSOLE_LINE(Console, Row + Count),
  2318. LineSize);
  2319. }
  2320. ASSERT(Row <= Console->ScreenRows - 1 - Console->BottomMargin);
  2321. VcpEraseArea(Console,
  2322. 0,
  2323. Row,
  2324. Console->Columns - 1,
  2325. Console->ScreenRows - 1 - Console->BottomMargin,
  2326. TRUE);
  2327. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN |
  2328. VIDEO_ACTION_RESET_SCROLL;
  2329. return;
  2330. }
  2331. VOID
  2332. VcpInsertLines (
  2333. PVIDEO_CONSOLE_DEVICE Console,
  2334. LONG Count,
  2335. LONG StartingRow
  2336. )
  2337. /*++
  2338. Routine Description:
  2339. This routine inserts lines on the console screen, moving following lines
  2340. down.
  2341. Arguments:
  2342. Console - Supplies a pointer to the video console.
  2343. Count - Supplies the number of lines to delete.
  2344. StartingRow - Supplies the first row of the region.
  2345. Return Value:
  2346. None.
  2347. --*/
  2348. {
  2349. UINTN LineSize;
  2350. LONG Row;
  2351. //
  2352. // If more lines are being inserted than exist in the scroll area, just
  2353. // erase the scroll area.
  2354. //
  2355. if (Count > Console->ScreenRows - Console->BottomMargin - StartingRow) {
  2356. VcpEraseArea(Console,
  2357. 0,
  2358. StartingRow,
  2359. Console->Columns - 1,
  2360. Console->ScreenRows - 1 - Console->BottomMargin,
  2361. TRUE);
  2362. return;
  2363. }
  2364. //
  2365. // Move lines down within the scroll region.
  2366. //
  2367. LineSize = CONSOLE_LINE_SIZE(Console);
  2368. for (Row = Console->ScreenRows - Console->BottomMargin - 1;
  2369. Row >= StartingRow + Count;
  2370. Row -= 1) {
  2371. RtlCopyMemory(GET_CONSOLE_LINE(Console, Row),
  2372. GET_CONSOLE_LINE(Console, Row - Count),
  2373. LineSize);
  2374. }
  2375. VcpEraseArea(Console,
  2376. 0,
  2377. StartingRow,
  2378. Console->Columns - 1,
  2379. StartingRow + Count - 1,
  2380. TRUE);
  2381. Console->PendingAction |= VIDEO_ACTION_REDRAW_ENTIRE_SCREEN |
  2382. VIDEO_ACTION_RESET_SCROLL;
  2383. return;
  2384. }
  2385. VOID
  2386. VcpGetCursorPosition (
  2387. PVIDEO_CONSOLE_DEVICE Console,
  2388. PLONG Row,
  2389. PLONG Column
  2390. )
  2391. /*++
  2392. Routine Description:
  2393. This routine returns the row and column where the cursor should appear.
  2394. Arguments:
  2395. Console - Supplies a pointer to the video console.
  2396. Row - Supplies a pointer where the cursor row index will be returned.
  2397. Column - Supplies a pointer where the cursor column index will be returned.
  2398. Return Value:
  2399. None.
  2400. --*/
  2401. {
  2402. ASSERT((Console->NextRow < Console->ScreenRows) &&
  2403. (Console->NextColumn <= Console->Columns));
  2404. *Row = Console->NextRow;
  2405. *Column = Console->NextColumn;
  2406. if (*Column == Console->Columns) {
  2407. ASSERT(*Row != Console->ScreenRows - 1);
  2408. *Column = 0;
  2409. *Row += 1;
  2410. }
  2411. return;
  2412. }