videocon.c 81 KB

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