‫In this lecture, we are going to talk about keyboard access in protected mode now, currently we have
‫used a programs that can print messages to the screen.
‫I imagine you want to be able to get some sort of input so that we can build some sort of shell later
‫on, some sort of terminal for our operating system.
‫That's why this lecture is essential.
‫I teach you how keyboard access works in protective mode and how we are going to go about implementing
‫it.
‫Listen to this lecture all the way through so that when we actually come to implementing the keyboard
‫drive up, it won't be so confusing for you.
‫So understanding keyboard access and protect about keyboard access is interest driven.
‫Each process has its own keyboard buffer that gets pushed and pop to OK, we must pause what's known
‫as scan codes.
‫And upon passing the scan codes, we can find the ASCII equivalents.
‫We will not concern ourselves with Unicode in this operating system costs at least to begin with.
‫So before we go any further, if you remember a couple hours ago in lecture time we implemented the
‫standard I arcus we did this by Remak in the pic to zero 20 because we remap the pic to zero 20.
‫That means the keyboard interrupt.
‫Is that twenty one interest zero x twenty one.
‫Whenever you press a key on the keyboard interrupts you X 21 will be invoked.
‫So each time a key is pressed to keep you interrupt is called the Cortazar Interim Handler to run.
‫As I explained 021, is that interrupt because we map the picture into select twenty and looking at
‫that table once again, you can see that if we map to zero 20, the timer will be zero x twenty.
‫Keyboard interrupts you x 21 and so on.
‫Essentially it's the base plus the offset and the offset be in the IQ in this table.
‫So this keyboard buffa represented in this image will be inside our process structure once we're done
‫implementing the keyboard and essentially represents a keyboard buffa, like its size is based on this
‫definition.
‫Ours will be called Petroskey Wilberforce's.
‫We have a tail variable and a head variable.
‫This allows us to push and pop from the keyboard buffa, which is pretty important.
‫Simply put, the tail will represent the index in the buffer of the tail on the stack and the head will
‫point to an index in the keyboard for the represents the head of the stack.
‫OK, so this buffer acts as a stack because we have talin had variables here.
‫OK, we can push and pop from our keyboard buffer.
‫So this is how the keyboard push function looks.
‫We get the current process that's active.
‫Active processes are basically the process you can see on screen, OK, that's the active process.
‫So we get the active process by column process current.
‫We get the index of the tail by calling keyboard cat tail index will explain more about that later.
‫And then we finally set that index to the character we're pushing and we increment the tail by one.
‫We then call a bunch of keyboard listeners, but we won't be implementing that in this course.
‫So keyboard pop works similarly, apart from we we don't use the current process, we use the current
‫tasks process, OK, and that's very important because in a multitasking environment, many tasks can
‫be running OK.
‫And just because you're looking at Process B, that doesn't mean the Process A isn't popping from its
‫own keyboard buffer.
‫So if we did process current here and we were on process B, so we were looking at process B on the
‫screen, then unfortunately what would happen is it will pop from post Espy's buffer and not process
‫a buffer.
‫So that's why we use Tasco for the process.
‫Here we go.
‫TASC current process here and keyboard push.
‫We use process current.
‫That's because we want to push to the to the process we are looking at, not the current task that is
‫running.
‫Does that make sense?
‫However, when we pop in from the keyboard, many tasks might want to be popping from that keyboard
‫before, you know, I mean, so we need to use TASC current process.
‫We can't rely on process code.
‫Likewise, we can't use Tasca.
‫We can't use TASC current process here because we're interested in pushing to the process.
‫We're looking at not the process that's currently running while the test is currently running, I should
‫say.
‫So the real index is calculated by taking the keyboard head and using the modulus operator with the
‫size of the buffer will be explained how that works later on.
‫Let's just explain these functions for the time being.
‫So essentially what we do here, we grab from the buffer where the head is pointing to and we return
‫zero if there's nothing to pop.
‫Otherwise, we set that part of the buffer to zero and we increment the head and return the character.
‫We PopTech.
‫And the keyboard cattail index you saw on the keyboard push, it looks like this, OK, does a similar
‫thing modulus.
‫OK, so we're now going to understand the keyboard for I'm going to break this down.
‫I've shown you a bunch of code so far.
‫Let's break it down into a visual way so it's a bit easier to understand.
‫So firstly, imagine a keyboard.
‫That's 1024 bytes in size.
‫We have a head verbal that's equal to zero signifying the head.
‫Is that index zero.
‫So essentially the head's variable points to the first index in the keyboard buffer.
‫We also have a tail variable equal to zero signifies the tail is an index.
‫So once again, the tail is pointing to the first bite in the keyboard buffer by zero.
‫Index zero.
‫OK.
‫So as you know, before, we've done anything before, we've pushed or popped the tail and the head
‫both equals zero, they're both pointing to indexer of the keyboard buffer.
‫So you can see the keyboard buff is represented by this table here and here that here are the tail and
‫had variables.
‫OK, so just be aware that they both point to index zero.
‫So we want to push the character AIDS, the keyboard buffa, how do we do it?
‫We set the keyboard Buffer's index zero to eight.
‫And why do we do that?
‫Because the tail's equal to zero.
‫So this is the CECO keyboard perfectly.
‫OK, that's the first thing we do.
‫We now increment the tail and then the tail now points to index one.
‫So you can see by this arrow the tail now points to index one.
‫The head is still pointing to index zero.
‫So that's that's how you push to the buffer.
‫OK, let's try that again.
‫So we want to push character B to the keyboard buffer.
‫So we set Keibel buffer index one to be Y, index one because the tail points to index one.
‫So we go keyboarder fatally.
‫Casby index one now has been it tail is equal to one.
‫OK, we now increment the tail.
‫So now the tail points to index two.
‫Index zero contains A, index one contains B in this keyboard.
‫OK, so we set the child's point index to as I've explained.
‫So that's gone ahead now.
‫Incremented.
‫So we now want to pop from the buffer, so how do we do it while we go?
‫Chassy EQUASS kebob ahead.
‫So we now have a start and we'll see why, because head points to index zero.
‫OK, so we've popped from the front of the stack there.
‫OK, so we have made a stack by using two variables, basically that act as pointers to the not C pointers,
‫but index pointers to the correct indexes in the array.
‫OK, so we now have a start in the variable C what do we do now.
‫We increment the head variable so the have variable now equals one.
‫So it's now pointing to index one.
‫So the next time you call Keibel Pop it pops out B OK.
‫And then where will the pointing index to.
‫Of course.
‫So I can see what you're thinking now will eventually tail is going to be above 1024, well above or
‫equal 1024, HADOPI above equal 1024 because they're incrementing.
‫So how so what what what's going to happen?
‫We're going to overflow the buffer, right?
‫Well, yes, you're right.
‫So what we need to do is we need to look back around to index zero.
‫Now, one way of doing that is to have an if statement.
‫And if it's about to exceed set the index back to zero.
‫OK, set the table back to zero.
‫Set the head back to zero, and that'll work as a loop back.
‫All right.
‫So when you go when you go to push too far ahead, it'll instead loop back around and push to index
‫zero instead.
‫That's one way of doing it.
‫But there's a there's a more efficient solution.
‫That solution is the modulus operator index equals tail modulus, the buffer size of 1024.
‫That gives us zero if the tail is equal to 1024.
‫OK, we can do the same with the head.
‫So let's pretend that says you go to 1024 index equals tail modulars, 1024 because 1024 is the size
‫of the keyboard buffa index is now equal to zero.
‫So what if A was one thousand twenty five?
‫The index was equal to one, of course, 1026, the index with equal to two.
‫So you can see using the model operator, we allow it to wrap back around without having to reset any
‫variables.
‫OK, so, you know, that's pretty efficient and that's pretty easy to do as well.
‫And we do the same with the head as well.
‫Guys like we do the same with the head.
‫And this makes it impossible for the tail to exceed the bounds of the array of the buffer, the keeper
‫buffer, and for the head to exceed the bounds, the keeper buffer, because the index it generates
‫will always fit into 1024.
‫OK, so that's that's how the models operate.
‫It works if it's your first time understanding the model operator to a bit of research about it before
‫you continue, because it's a very important operator in programming low level programming.
‫So by using the modulus operator, there's no need for a false statements and resetting the variable
‫manually.
‫So, yes, a pretty clean solution and it gets the job done.
‫So another thing, we need to pause scan codes.
‫The pic doesn't tell us which key was pressed.
‫It doesn't tell us.
‫They pressed a they they pressed a lowercase A because the caps lock was on.
‫We have to program all of that.
‫We have to program.
‫So we look for the caps lock being on or off.
‫None of this is done for us.
‫So what happens is when you press a key, it gives us a scan code.
‫Now we use some sort of table to to find the ASCII equivalent based on the key that they press.
‫So if they press a it'll give us some sort of scan code.
‫We take that scan code and we find the ASCII equivalent.
‫OK, now we still don't know if it's a capitally or a lowercase say.
‫Well, that depends.
‫Did they have the caps lock on when they pressed?
‫Always the caps lock off.
‫Were they holding the shift when they pressed sake or not?
‫So those things we need to take all of those things into account, whether the caps lock was on, where
‫they were holding certain keys, and then we choose the correct ASCII character to use.
‫OK, based on all the information on the scan code.
‫So we can't do anything with the code without the table.
‫OK, and when we have the table, we can associate the Schanker with the ASCII character.
‫OK, now we won't be implementing Unicode in in this cos like I've already told you, that's why our
‫keyboard buffer takes charge and not you.
‫And it's 16, OK, it doesn't take wide shots because we're not going to implement Unicode for now.
‫So we want to keep this simple so you can understand this.
‫So these are the tables I was talking about, right?
‫So we have keyboard scans, everyone you can see index here is no index one is the zombie index, two
‫is decimal one, index three, decimal two.
‫So, you know, we can take the scan code and pull the ASCII value directly from this table, from the
‫sky said, OK.
‫And obviously the the keyboard controller, the pick the pick knows which scan codes to send for which
‫keys were pressed.
‫OK, and we we have the tables so we know which key was pressed for, for which character was pressed.
‫So we can do something like this classic keyboard scan code to char and we pass in the scan code.
‫This function here, we would obviously create this function.
‫It would return the actual character that was pressed, OK, and then we call Keibel push to push it
‫to the pros, the current processes, keyboard buffer.
‫So we will also have a virtual keyboard player.
‫So just like we did with the filesystems, we will have a virtual keyboard layer.
‫This will allow us to create drivers for any type of keyboard.
‫We wish I was only going to implement one keyboard driver, but the point is, by having the virtual
‫keyboard layer, there's a possibility to even have virtual keyboards, maybe keyboards, the type on
‫their own.
‫You know, maybe we want to test certain functionality.
‫So, you know, it's best to abstract everything out because in the real world world, there's many
‫different types of protocols.
‫OK, so it's best to have some sort of abstraction that they all use so that you can load as many keyboard
‫drivers as you like.
‫So this is the example of a keyboard player you can see here we have struck keyboard, which represents
‫a keyboard driver, OK, that has an initialization function.
‫So you can see here typedef and a keyboard in a function, it takes no arguments and it returns integer.
‫OK, so if this and a function return zero, everything was initialized.
‫OK, you can see the keyboards have names that can hold 20 bytes.
‫OK, so Apple keyboard, something like that, you know, you know, Logitech keyboard, something like
‫that, you know what I mean?
‫And we have a this this keyboard structure is a linked list.
‫OK, so we have appointed to the next keyboard available OK.
‫And a keyboard driver inserts its driver functionality by calling keyboard insert so it'll insert its
‫own keyboard structure into the system.
‫And that's how that works.
‫So you can see here keyboard pusch that is the function that pushes to the keyboard.
‫OK, keyboard pop as well will pop from it.
‫OK, so I hope I've brought you all up to speed with, with exactly what we're going to be doing.
‫And now you will understand why we have had tail variables and why we're not resetting variables and
‫using modulus.
‫I've explained all of that.
‫So we will now start implementing the keyboard driver.