The Pedigree Project 0.1
DevicesCommand.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/debugger/DebuggerIO.h"
21#include "pedigree/kernel/debugger/commands/DevicesCommand.h"
22#include "pedigree/kernel/machine/Device.h"
23#include "pedigree/kernel/utilities/String.h"
24#include "pedigree/kernel/utilities/utility.h"
25
27
29
31
33 InterruptState& state, DebuggerIO* pScreen) {
34 // Let's enter 'raw' screen mode.
35 pScreen->disableCli();
36
37 // Work out where the split will be between the tree and the info.
38 // Give the tree 3/4 of the available lines.
39 int nLines = ((pScreen->getHeight() - 2) * 3) / 4;
40
41 static DeviceTree tree;
42 tree.move(0, 1);
43 tree.resize(pScreen->getWidth(), nLines);
44 tree.setScrollKeys('o', 'p');
45
46 static DeviceInfo info;
47 info.move(0, nLines + 2);
48 info.resize(pScreen->getWidth(), pScreen->getHeight() - nLines - 3);
49 info.setScrollKeys('j', 'k');
50
51 pScreen->disableRefreshes();
52 drawBackground(nLines, pScreen);
53 tree.refresh(pScreen);
54 info.refresh(pScreen);
55 pScreen->enableRefreshes();
56
57 // Here we enter our main runloop.
58 bool bContinue = true;
59 while (bContinue) {
60 char c;
61 while ((c = pScreen->getChar()) == 0)
62 ;
63 if (c == 'q')
64 break;
65 else if (c == 'o') {
66 if (tree.m_Line > 0)
67 tree.m_Line--;
68 tree.centreOn(tree.m_Line);
69 tree.refresh(pScreen);
70 info.setDevice(tree.getDevForIndex(tree.m_Line));
71 info.refresh(pScreen);
72 } else if (c == 'p') {
73 if (tree.m_Line < tree.getLineCount() - 1)
74 tree.m_Line++;
75 tree.centreOn(tree.m_Line);
76 tree.refresh(pScreen);
77 info.setDevice(tree.getDevForIndex(tree.m_Line));
78 info.refresh(pScreen);
79 } else if (c == 'j') {
80 info.scroll(-1);
81 info.refresh(pScreen);
82 } else if (c == 'k') {
83 info.scroll(1);
84 info.refresh(pScreen);
85 } else if (c == 'd') {
86 // Dump.
87 String str;
88 info.getDevice()->dump(str);
89 drawBackground(0, pScreen);
90 pScreen->drawString("Querying device - press any key to exit. ", 1, 0, DebuggerIO::White,
91 DebuggerIO::Black);
92 pScreen->drawString(str.cstr(), 2, 0, DebuggerIO::LightGrey, DebuggerIO::Black);
93 while ((c = pScreen->getChar()) == 0)
94 ;
95 drawBackground(nLines, pScreen);
96 tree.refresh(pScreen);
97 info.refresh(pScreen);
98 }
99 }
100
101 // Let's enter CLI screen mode again.
102 pScreen->enableCli();
103 return true; // Return control to the debugger.
104}
105
106void DevicesCommand::drawBackground(size_t nLines, DebuggerIO* pScreen) {
107 // Destroy all text.
108 pScreen->cls();
109
110 // Clear the top and bottom status lines.
111 pScreen->drawHorizontalLine(' ', 0, 0, pScreen->getWidth() - 1, DebuggerIO::White,
112 DebuggerIO::Green);
113 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 1, 0, pScreen->getWidth() - 1,
114 DebuggerIO::White, DebuggerIO::Green);
115 // Write the correct text in the upper status line.
116 pScreen->drawString("Pedigree debugger - Device tree", 0, 0, DebuggerIO::White,
117 DebuggerIO::Green);
118 // Write some helper text in the lower status line.
119 pScreen->drawString("", pScreen->getHeight() - 1, 0, DebuggerIO::White, DebuggerIO::Green);
120
121 pScreen->drawHorizontalLine('-', nLines + 1, 0, pScreen->getWidth(), DebuggerIO::DarkGrey,
122 DebuggerIO::Black);
123}
124
125DevicesCommand::DeviceTree::DeviceTree() : m_Line(0), m_LinearTree() {
126 // Create the (flattened) device tree, so we can look up the index of any
127 // particular device.
128 auto pusher = [this](Device* p) {
129 m_LinearTree.pushBack(p);
130 return p;
131 };
132
133 auto callback = pedigree_std::make_callable(pusher);
134
135 // Get the first device.
136 Device::foreach (callback, 0);
137}
138
139void DevicesCommand::DeviceTree::probeDev(Device* pDev) {
140 for (unsigned int i = 0; i < pDev->getNumChildren(); i++) {
141 m_LinearTree.pushBack(pDev->getChild(i));
142 probeDev(pDev->getChild(i));
143 }
144}
145
146const char* DevicesCommand::DeviceTree::getLine1(size_t index, DebuggerIO::Colour& colour,
147 DebuggerIO::Colour& bgColour) {
148 static NormalStaticString str;
149
150 // Grab the device to describe.
151 Device* pDev = m_LinearTree[index];
152
153 // Set the foreground colour.
154 colour = DebuggerIO::Yellow;
155
156 // If we're the selected line, add our background colour.
157 if (m_Line == index)
158 bgColour = DebuggerIO::Blue;
159
160 // How many parents does this node have? that will determine how many |'s to
161 // draw.
162 while (pDev->getParent() != 0) {
163 pDev = pDev->getParent();
164 str += " ";
165 }
166 str += "- ";
167
168 return str;
169}
170
171const char* DevicesCommand::DeviceTree::getLine2(size_t index, size_t& colOffset,
172 DebuggerIO::Colour& colour,
173 DebuggerIO::Colour& bgColour) {
174 static LargeStaticString str;
175
176 // Grab the device to describe.
177 Device* pDev = m_LinearTree[index];
178
179 // Set the foreground colour.
180 colour = DebuggerIO::White;
181
182 String str2;
183 pDev->getName(str2);
184 str += str2;
185 str += "(";
186 str += pDev->getSpecificType();
187 str += ")";
188
189 // Calculate the column offset.
190 // How many parents does this node have? that will determine how many |'s to
191 // draw.
192 colOffset = 0;
193 while (pDev->getParent() != 0) {
194 pDev = pDev->getParent();
195 colOffset++;
196 }
197 colOffset += 2; // For '- '
198
199 // If we're selected, add our background colour and pad to the end-of-line.
200 if (m_Line == index) {
201 bgColour = DebuggerIO::Blue;
202 }
203 str.pad(m_width - colOffset);
204
205 return str;
206}
207
208size_t DevicesCommand::DeviceTree::getLineCount() {
209 return m_LinearTree.count();
210}
211
212Device* DevicesCommand::DeviceTree::getDevForIndex(size_t index) {
213 return m_LinearTree[index];
214}
215
216DevicesCommand::DeviceInfo::DeviceInfo() : m_pDev(0) {}
217
218void DevicesCommand::DeviceInfo::setDevice(Device* dev) {
219 m_pDev = dev;
220}
221
222const char* DevicesCommand::DeviceInfo::getLine1(size_t index, DebuggerIO::Colour& colour,
223 DebuggerIO::Colour& bgColour) {
224 colour = DebuggerIO::Yellow;
225 switch (index) {
226 case 0:
227 return "Name";
228 case 1:
229 return "(Abstract) type";
230 case 2:
231 return "(Specific) type";
232 case 3:
233 return "Interrupt";
234 case 4:
235 return "Addresses";
236 default:
237 return "";
238 };
239}
240
241const char* DevicesCommand::DeviceInfo::getLine2(size_t index, size_t& colOffset,
242 DebuggerIO::Colour& colour,
243 DebuggerIO::Colour& bgColour) {
244 if (!m_pDev)
245 return "";
246 static LargeStaticString str;
247 colOffset = 40;
248 switch (index) {
249 case 0: {
250 String str2;
251 m_pDev->getName(str2);
252 str += str2;
253 break;
254 }
255 case 1:
256 str += static_cast<unsigned int>(m_pDev->getType());
257 break;
258 case 2:
259 str += m_pDev->getSpecificType();
260 break;
261 case 3:
262 str += m_pDev->getInterruptNumber();
263 break;
264 default: {
265 unsigned int i = index - 4;
266 if (i >= m_pDev->addresses().count())
267 break;
268 Device::Address* address = m_pDev->addresses()[i];
269 str += address->m_Name;
270 if (address->m_IsIoSpace)
271 str += " (IO) @ ";
272 else
273 str += " (MEM) @ ";
274 str.append(address->m_Address, 16);
275 str += "-";
276 str.append(address->m_Address + address->m_Size, 16);
277 break;
278 }
279 };
280 return str;
281}
282
283size_t DevicesCommand::DeviceInfo::getLineCount() {
284 if (m_pDev)
285 return 4 + m_pDev->addresses().count();
286 else
287 return 4;
288}
virtual void enableCli()=0
virtual void enableRefreshes()=0
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
virtual size_t getWidth()=0
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0
virtual char getChar()=0
size_t getNumChildren()
Definition Device.cc:143
Device * getChild(size_t n)
Definition Device.cc:139
static void foreach(Callback callback, Device *root=0)
Definition Device.cc:107
virtual const String & getSpecificType()
Definition Device.h:183
virtual void getName(String &str)
Definition Device.cc:130
Device * getParent() const
Definition Device.h:166
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)
void autocomplete(const HugeStaticString &input, HugeStaticString &output)
void pushBack(const T &value)
Definition Vector.h:275