当前位置: 首页 > news >正文

南京网站开发询南京乐识如何注册公司注册公司需要什么

南京网站开发询南京乐识,如何注册公司注册公司需要什么,网站开发公司名字,wordpress 国外主题站前情提要 上一节我们实现了锁与信号量#xff0c;这一节我们就可以实现键盘驱动了#xff0c;访问键盘输入的数据也属于临界区资源#xff0c;所以需要锁的存在。 一、键盘简介 之前的 ps/2 键盘使用的是中断驱动的#xff0c;在当时#xff0c;按下键盘就会触发中断这一节我们就可以实现键盘驱动了访问键盘输入的数据也属于临界区资源所以需要锁的存在。 一、键盘简介 之前的 ps/2 键盘使用的是中断驱动的在当时按下键盘就会触发中断引导操作系统去处理这个按键行文。但是当今的usb键盘使用的是轮询机制cpu会定时访问键盘看有没有按下键盘。 我个人认为这是cpu技术的进步导致的在之前cpu的频率比较低使用轮询可能会导致漏掉用户按键的行为。但是在今天cpu的主频已经非常高了处理一个按键行为就触发中断这个开销太大了而且轮询的频率也上来了现在每秒访问几千次对电脑一点影响都没有所以现在大多采用了轮询机制。 不过据说中断驱动的还是比较快现在一些电竞主板还是支持ps/2的接口这个未经论证。 1.1、键盘的通码与断码 键盘的状态要么是按下要么是弹起因此一个键便有两个编码按键按下时的编码叫做通码键盘上的触电接通了电路使硬件产生了一个编码故此通码叫makecode。按键在被按住不松手时会持续产生相同的码直到按键被松开时才终止因此按键被松开弹起时产生的编码叫断码也就是电路被断开了不再持续产生码了故断码也称为breakcode。 无论是按下键或是松开键当键的状态改变后键盘中的8048芯片把按键对应的扫描码通码或断码发送到主板上的8042芯片由8042处理后保存在自己的寄存器中然后向8259A发送中断信号这样处理器便去执行键盘中断处理程序将8042处理过的扫描码从它的寄存器中读取出来继续进行下一步处理。 1.2、键盘扫描码 键的扫描码是由键盘中的键盘编码器决定的不同的编码方案便是不同的键盘扫描码也就是说相同的键在不同的编码方案下产生的通码和断码也是不同的。 根据不同的编码方案键盘扫描码有三套分别称为scan code set 1、scan code set 2、scan code set 3。 其中scan code set 1是XT键盘用的扫描码这个历史就比较久远了。scan code set 2是AT键盘的扫描码这个键盘和我们当今的键盘也不是很一样但是已经比较接近了。scan code set 3是IBM PS/2系列高端计算机所用的键盘上IBM蓝色巨人现在都凉了这个键盘也就很少看到了。 第二套键盘扫描码几乎是目前所使用的键盘的标准因此大多数键盘向8042发送的扫描码都是第二套扫描码。但是难免有别的键盘所以才会出现8042这个芯片这个芯片做一个中间层为了兼容第一套键盘扫描码对应的中断处理程序不管键盘用的是何种键盘扫描码当键盘将扫描码发送到8042后都由8042转换成第一套扫描码我们再从8042中读取扫描码。 这里我们给出常用键位的扫描码这里的扫描码就是通码加0x80就是断码 按键扫描码按键扫描码按键扫描码Esc0x01F10x3BF20x3CF30x3DF40x3EF50x3FF60x40F70x41F80x42F90x43F100x44F110x57F120x58PrintSc0x37ScrollLk0x46Pause/Brk0x450x2910x0220x0330x0440x0550x0660x0770x0880x0990x0A00x0B-0x0C0x0DBackspace0x0ETab0x0FQ0x10W0x11E0x12R0x13T0x14Y0x15U0x16I0x17O0x18P0x19[0x1A]0x1B|0x2BCapsLock0x3AA0x1ES0x1FD0x20F0x21G0x22H0x23J0x24K0x25L0x26;0x27’0x28Enter0x1CShift左0x2AZ0x2CX0x2DC0x2EV0x2FB0x30N0x31M0x32,0x33.0x34/0x35Shift右0x36Ctrl左0x1DWin左0xE0Alt左0x38Space0x39Alt右0xE038Win右0xE0Menu0xE0Ctrl右0xE01D 问为什么会有通码和断码通码不就够了嘛 **答**如果按一个组合键的话比如ctrla是先按下ctrl再按a再松开ctrl再松开a。如果没有断码我们无法判断ctrl是否松开。 1.3、键盘的芯片 和键盘相关的芯片只有8042和8048它们都是独立的处理器都有自己的寄存器和内存。Intel 8048芯片或兼容芯片位于键盘中它是键盘编码器Intel 8042芯片或兼容芯片被集成在主板上的南桥芯片中它是键盘控制器也就是键盘的IO接口因此它是8048的代理也是前面所得到的处理器和键盘的“中间层”。我们只需要学习8042就够了 他的端口如下 寄存器端口读写Output Buffer输出缓冲区0x60读Input Buffer输入缓冲区0x60写Status Register状态寄存器0x64读Control Register控制寄存器0x64写 状态寄存器8位宽度的寄存器只读反映8048和8042的内部工作状态。各位意义如下。 1位0置1时表示输出缓冲区寄存器已满处理器通过in指令读取后该位自动置0。 2位1置1时表示输入缓冲区寄存器已满8042将值读取后该位自动置0。 3位2系统标志位最初加电时为0自检通过后置为1。 4位3置1时表示输入缓冲区中的内容是命令置0时输入缓冲区中的内容是普通数据。 5位4置1时表示键盘启用置0时表示键盘禁用。 6位5置1时表示发送超时。 7位6置1时表示接收超时。 8位7来自8048的数据在奇偶校验时出错。 8位宽度的寄存器只写用于写入命令控制字。每个位都可以设置一种工作方式意义如下。 1位0置1时启用键盘中断。 2位1置1时启用鼠标中断。 3位2设置状态寄存器的位2。 4位3置1时状态寄存器的位4无效。 5位4置1时禁止键盘。 6位5置1时禁止鼠标。 7位6将第二套键盘扫描码转换为第一套键盘扫描码。 8位7保留位默认为0。 二、环形队列 键盘中断的数据是放在队列中的等待其他线程的读取。如果我们之前做过关于软件相关的工作很容易理解这个概念就是buffer缓冲区。因为我们是一直在输入的所以这里设计成了环形队列。 我们看一下环形队列的数据结构 #define bufsize 256/* 环形队列 */ struct ioqueue {// 生产者消费者问题struct lock lock;// 生产者,缓冲区不满时就继续往里面放数据struct task_struct* producer;// 消费者,缓冲区不空时就继续从往里面拿数据struct task_struct* consumer;char buf[bufsize]; // 缓冲区大小int32_t head; // 队首,数据往队首处写入int32_t tail; // 队尾,数据从队尾处读出 };这个就很明朗了。一个生产者一个消费者生产者向buf中添加数据消费者从buf中取出数据为了防止buf中的数据出错生产者和消费者同时只能有一个可以访问到buf。如果buf中数据满了生产者就不能放了此时阻塞生产者如果buf中数据为空消费者就不能拿了此时阻塞消费者。 我们看一下具体的实现 /* 初始化io队列ioq */ void ioqueue_init(struct ioqueue* ioq) {lock_init(ioq-lock); // 初始化io队列的锁ioq-producer ioq-consumer NULL; // 生产者和消费者置空ioq-head ioq-tail 0; // 队列的首尾指针指向缓冲区数组第0个位置 }/* 返回pos在缓冲区中的下一个位置值 */ static inline int32_t next_pos(int32_t pos) {return (pos 1) % bufsize; }/* 判断队列是否已满 */ bool ioq_full(struct ioqueue* ioq) {return next_pos(ioq-head) ioq-tail; }/* 判断队列是否已空 */ bool ioq_empty(struct ioqueue* ioq) {return ioq-head ioq-tail; }/* 使当前生产者或消费者在此缓冲区上等待 */ static void ioq_wait(struct task_struct** waiter) {// 二级指针不为空指向的pcb指针地址为空ASSERT(*waiter NULL waiter ! NULL);*waiter running_thread();thread_block(TASK_BLOCKED); }/* 唤醒waiter */ static void wakeup(struct task_struct** waiter) {// 二级指针指向不为空ASSERT(*waiter ! NULL);thread_unblock(*waiter);*waiter NULL; }/* 消费者从ioq队列中获取一个字符 */ char ioq_getchar(struct ioqueue* ioq) {// 若缓冲区(队列)为空,把消费者ioq-consumer记为当前线程自己,等待生产者唤醒while (ioq_empty(ioq)) {lock_acquire(ioq-lock);ioq_wait(ioq-consumer);lock_release(ioq-lock);}char byte ioq-buf[ioq-tail]; // 从缓冲区中取出ioq-tail next_pos(ioq-tail); // 把读游标移到下一位置if (ioq-producer ! NULL) {wakeup(ioq-producer); // 唤醒生产者}return byte; }/* 生产者往ioq队列中写入一个字符byte */ void ioq_putchar(struct ioqueue* ioq, char byte) {// 若缓冲区(队列)已经满了,把生产者ioq-producer记为自己,等待消费者线程唤醒自己while (ioq_full(ioq)) {lock_acquire(ioq-lock);ioq_wait(ioq-producer);lock_release(ioq-lock);}ioq-buf[ioq-head] byte; // 把字节放入缓冲区中ioq-head next_pos(ioq-head); // 把写游标移到下一位置if (ioq-consumer ! NULL) {wakeup(ioq-consumer); // 唤醒消费者} }我们看一下后面两个函数wait和wakeup这两个函数这两个函数传入的是一个pcb指针的地址所以这里是一个二级指针。所以无论是阻塞还是解除阻塞都是取这个二级指针的地址也就得到了pcb指针。这里对于不熟悉指针的人来说可能会有点扰。 三、键盘驱动 #define KBD_BUF_PORT 0x60 // 键盘buffer寄存器端口号为0x60/* 用转义字符定义部分控制字符 */ #define esc \033 // 八进制表示字符,也可以用十六进制\x1b #define backspace \b #define tab \t #define enter \r #define delete \177 // 八进制表示字符,十六进制为\x7f/* 以上不可见字符一律定义为0 */ #define char_invisible 0 #define ctrl_l_char char_invisible #define ctrl_r_char char_invisible #define shift_l_char char_invisible #define shift_r_char char_invisible #define alt_l_char char_invisible #define alt_r_char char_invisible #define caps_lock_char char_invisible/* 定义控制字符的通码和断码 */ #define shift_l_make 0x2a #define shift_r_make 0x36 #define alt_l_make 0x38 #define alt_r_make 0xe038 #define alt_r_break 0xe0b8 #define ctrl_l_make 0x1d #define ctrl_r_make 0xe01d #define ctrl_r_break 0xe09d #define caps_lock_make 0x3astruct ioqueue kbd_buf; // 定义键盘缓冲区/* 定义以下变量记录相应键是否按下的状态,* ext_scancode用于记录makecode是否以0xe0开头 */ static bool ctrl_status, shift_status, alt_status, caps_lock_status, ext_scancode;/* 以通码make_code为索引的二维数组 */ static char keymap[][2] {/* 扫描码 未与shift组合 与shift组合*//* ---------------------------------- *//* 0x00 */ {0, 0},/* 0x01 */ {esc, esc},/* 0x02 */ {1, !},/* 0x03 */ {2, },/* 0x04 */ {3, #},/* 0x05 */ {4, $},/* 0x06 */ {5, %},/* 0x07 */ {6, ^},/* 0x08 */ {7, },/* 0x09 */ {8, *},/* 0x0A */ {9, (},/* 0x0B */ {0, )},/* 0x0C */ {-, _},/* 0x0D */ {, },/* 0x0E */ {backspace, backspace},/* 0x0F */ {tab, tab},/* 0x10 */ {q, Q},/* 0x11 */ {w, W},/* 0x12 */ {e, E},/* 0x13 */ {r, R},/* 0x14 */ {t, T},/* 0x15 */ {y, Y},/* 0x16 */ {u, U},/* 0x17 */ {i, I},/* 0x18 */ {o, O},/* 0x19 */ {p, P},/* 0x1A */ {[, {},/* 0x1B */ {], }},/* 0x1C */ {enter, enter},/* 0x1D */ {ctrl_l_char, ctrl_l_char},/* 0x1E */ {a, A},/* 0x1F */ {s, S},/* 0x20 */ {d, D},/* 0x21 */ {f, F},/* 0x22 */ {g, G},/* 0x23 */ {h, H},/* 0x24 */ {j, J},/* 0x25 */ {k, K},/* 0x26 */ {l, L},/* 0x27 */ {;, :},/* 0x28 */ {\, },/* 0x29 */ {, ~},/* 0x2A */ {shift_l_char, shift_l_char},/* 0x2B */ {\\, |},/* 0x2C */ {z, Z},/* 0x2D */ {x, X},/* 0x2E */ {c, C},/* 0x2F */ {v, V},/* 0x30 */ {b, B},/* 0x31 */ {n, N},/* 0x32 */ {m, M},/* 0x33 */ {,, },/* 0x34 */ {., },/* 0x35 */ {/, ?},/* 0x36 */ {shift_r_char, shift_r_char},/* 0x37 */ {*, *},/* 0x38 */ {alt_l_char, alt_l_char},/* 0x39 */ { , },/* 0x3A */ {caps_lock_char, caps_lock_char}/*其它按键暂不处理*/ };/* 键盘中断处理程序 */ static void intr_keyboard_handler(void) {/* 这次中断发生前的上一次中断,以下任意三个键是否有按下 */bool ctrl_down_last ctrl_status;bool shift_down_last shift_status;bool caps_lock_last caps_lock_status;uint16_t scancode inb(KBD_BUF_PORT);// 若扫描码是e0开头的, 结束此次中断处理函数,等待下一个扫描码进来if (scancode 0xe0) {ext_scancode true; // 打开e0标记return;}// 如果上次是以0xe0开头,将扫描码合并if (ext_scancode) {scancode ((0xe000) | scancode);ext_scancode false; // 关闭e0标记}// 若是断码(按键弹起时产生的扫描码)if ((scancode 0x0080) ! 0) {// 获得相应的通码uint16_t make_code (scancode 0xff7f);// 若是任意以下三个键弹起了,将状态置为falseif (make_code ctrl_l_make || make_code ctrl_r_make) {ctrl_status false;}else if (make_code shift_l_make || make_code shift_r_make) {shift_status false;}else if (make_code alt_l_make || make_code alt_r_make) {alt_status false;}// 若是其他非控制键位不需要处理那些键位我们只需要知道通码return;}// 若是通码,只处理数组中定义的键以及alt_right和ctrl键,全是make_codeelse if ((scancode 0x00 scancode 0x3b) || (scancode alt_r_make) || (scancode ctrl_r_make)) {// keymap的二维索引bool shift false;// 按下的键不是字母if ((scancode 0x0e) || (scancode 0x29) || \(scancode 0x1a) || (scancode 0x1b) || \(scancode 0x2b) || (scancode 0x27) || \(scancode 0x28) || (scancode 0x33) || \(scancode 0x34) || (scancode 0x35)) { if (shift_down_last) {shift true;}}// 如果按下的键是字母需要和CapsLock配合else {if (shift_down_last caps_lock_last) { // 如果shift和capslock同时按下shift false;}else if (shift_down_last || caps_lock_last) { // 如果shift和capslock任意被按下shift true;}else {shift false;}}// 将扫描码的高字节置0,主要是针对高字节是e0的扫描码.uint8_t index (scancode 0x00ff);// 在数组中找到对应的字符char cur_char keymap[index][shift];// 如果cur_char不为0,也就是ascii码为除\0外的字符就加入键盘缓冲区中if (cur_char) {// 如果ctrl按下且输入的字符为‘l’或者‘u’那就保存为 cur_char-‘a’主要是‘a’前面26位没啥用if ((ctrl_down_last cur_char l) || (ctrl_down_last cur_char u)) {cur_char - a;}// 如果缓冲区未满就将其加入缓冲区if (!ioq_full(kbd_buf)) {ioq_putchar(kbd_buf, cur_char);}return;}// 记录本次是否按下了下面几类控制键之一,供下次键入时判断组合键if (scancode ctrl_l_make || scancode ctrl_r_make) {ctrl_status true;}else if (scancode shift_l_make || scancode shift_r_make) {shift_status true;}else if (scancode alt_l_make || scancode alt_r_make) {alt_status true;}// 这里注意大写的锁定键是取反else if (scancode caps_lock_make) {caps_lock_status !caps_lock_status;}}else {put_str(unknown key\n);} }/* 键盘初始化 */ void keyboard_init() {put_str(keyboard init start\n);ioqueue_init(kbd_buf);register_handler(0x21, intr_keyboard_handler);put_str(keyboard init done\n); }键盘驱动就稍显复杂一点主要是涉及到了shiftctrlaltcaplock这些个控制键这些键位是否按下所表示的通码断码是不一样的。这里就是处理字符相信大家看代码就可以看明白。 四、仿真 我们创建一个线程键盘输入什么打印什么 结束语 本节我们编写了键盘驱动以及其使用的环形队列数据结构。下一节我们将实现一个用户进程即特权级为3的进程。 老规矩代码地址为 https://github.com/lyajpunov/os
http://www.tj-hxxt.cn/news/141544.html

相关文章:

  • 全省建设信息网站参考消息电子版报纸
  • 成都建站模板网站开发怎么破解wordpress图片防盗链
  • 如何用ps做网站导航条项目管理软件project手机版
  • 如何利用开源代码做网站广州比较好的外贸公司有哪些
  • 在百度上如何上传自己的网站品牌设计网站公司
  • 网站 优化 件大企业网站建设公司排名
  • 视觉设计的网站和app响应式网站建设方案
  • php工具箱是直接做网站的吗wordpress guid
  • 免费的ai写作网站网站开发专业都有哪些课程
  • 西安企业建站机构那里有甘肃省建设厅执业注册中心网站
  • 家政网站模板wordpress模板 手机版
  • html5网站开发特点小程序开发平台哪家性价比高
  • 景德镇网站维护wordpress本站导航在哪里
  • 破解php网站后台密码相册模板
  • 微网站建设的第一步是进行首页的设置深圳 网站科技
  • 寮步网站建设公司寺庙网站模板
  • 2345官方网站做淘宝店标的网站
  • 杭州微网站开发公司电话佳木斯哈尔滨网站建设
  • 苏州新区城乡建设网站前端和后端哪个难
  • 太和网站开发招聘新闻20条摘抄大全
  • 天津手机版建站系统网站建设主要做什么
  • 有没有做招聘网站的深圳网站设计十年乐云seo
  • 网站风格定位怎么写c2c模式在我国开始于1999年的
  • 网站是先解析后备案吗网站职业技术培训学校
  • 龙之向导免费网站网络平台贷款还不了会有什么后果
  • 农家院网站素材物流网站制作目的
  • 微信公众号网页版登录入口哈尔滨网站关键词优化
  • 怎么做虚拟网站手机兼职赚钱
  • 网站主机免备案吗网站开发学历要求
  • 建设银行官方网站广州提高wordpress 权重