开了外网网站打不开,淮安建立公司网站流程,毕业设计做系统网站,衡东网页设计1 理论
1.1 基本概念
目前对外设的操作#xff0c;都是通过寄存器。寄存器的概念#xff0c;其实就是接口#xff0c;访问硬件接口#xff0c;有I/O端口通信和内存映射I/O (Memory-Mapped I/O)#xff0c;I/O端口通信是比较老的那种#xff0c;都是老的串口并口设备都是通过寄存器。寄存器的概念其实就是接口访问硬件接口有I/O端口通信和内存映射I/O (Memory-Mapped I/O)I/O端口通信是比较老的那种都是老的串口并口设备PS/2鼠标在用感觉现在应该用不到了。以我浅显的比喻就是一个是API通信一个是内存映射。
另外说说这个IO操作模型和总线的关系两者其实没有关系比如说I2C总线可以使用IO端口也可以使用内存映射实际上用的应该是内存映射但是这块现在是被封装在openread这几个接口之后所以一般也感觉不到。 1.2 CPU缓冲
书里面讲的有点绕也可能是翻译的问题其实本质就是多核的情况下可能后面的变量先于前面的变量生效。
// CPU1: Producer
void update_data() {data 42; // 更新数据mb(); // 确保data的更新在flag设置之前完成flag 1; // 设置标志
}
// CPU2: Consumer
void read_data() {while (flag 0); // 等待标志被设置int value data; // 读取数据// 使用value进行后续操作
}
在CPU1中
data 42;更新数据。 mb();插入全内存屏障确保在此之前的所有内存操作即data的更新在此之后的操作即flag的设置之前完成。 flag 1;设置标志通知CPU2数据已准备好。 在CPU2中
while (flag 0);等待flag被设置。 int value data;读取数据确保读取的是更新后的值。 1.3 申请IO的API
这里会使用request_regionrelease_region这几个接口。 申请成功后会在/proc/ioports看到。
soft7080:~/memo$ cat /proc/ioports
0000-0000 : PCI Bus 0000:000000-0000 : dma10000-0000 : pic10000-0000 : timer00000-0000 : timer10000-0000 : keyboard0000-0000 : keyboard0000-0000 : rtc00000-0000 : dma page reg0000-0000 : pic20000-0000 : dma20000-0000 : fpu0000-0000 : PNP0C04:000000-0000 : serial0000-0000 : iTCO_wdt0000-0000 : pnp 00:030000-0000 : pnp 00:010000-0000 : pnp 00:010000-0000 : pnp 00:010000-0000 : pnp 00:010000-0000 : pnp 00:010000-0000 : pnp 00:010000-0000 : pnp 00:01
0000-0000 : PCI conf1
0000-0000 : PCI Bus 0000:000000-0000 : pnp 00:030000-0000 : ACPI PM1a_EVT_BLK0000-0000 : ACPI PM1a_CNT_BLK0000-0000 : ACPI PM_TMR0000-0000 : ACPI PM2_CNT_BLK0000-0000 : pnp 00:050000-0000 : ACPI GPE0_BLK0000-0000 : pnp 00:070000-0000 : 0000:00:02.00000-0000 : 0000:00:17.00000-0000 : ahci0000-0000 : 0000:00:17.00000-0000 : ahci0000-0000 : 0000:00:17.00000-0000 : ahci0000-0000 : 0000:00:1f.40000-0000 : i801_smbus 1.4 操作端口
在asm/io.h中使用unsigned inb(unsigned port);void outb(unsigned char byte, unsigned port);unsigned inl(unsigned port);。这里主要的差别是数据的宽度。在底层8位16位32位都必须要做出区别。 用户空间中也可以通过sys/io.h的接口操作但是需要root权限以及使用ioperm 和 iopl申请权限。
还有接口可以实现直接读取或者写入一串字符 void insb(unsigned port, void *addr, unsigned long count); void outsb(unsigned port, void *addr, unsigned long count); 1.5 平台差异
最后是这些IO接口不是所有平台可用书中列出了这些区别。对我来说x86,ARM,MIPS这几个平台能用就够了。 2 short代码 书中是和并口设备交互串口设备如上图。现在实在是找不到这样的设备了。我的重点是后面的USB所以这次就代码走读为主。代码是short.c就一个c文件。还是很简单。
module_init(short_init); module_exit(short_cleanup);
重点就是两个函数short_init和short_cleanup。
1 short_init
int short_init(void)
{int result;/** first, sort out the base/short_base ambiguity: wed better* use short_base in the code, for clarity, but allow setting* just base at load time. Same for irq.*/short_base base;short_irq irq;/* Get our needed resources. */if (!use_mem) {if (! request_region(short_base, SHORT_NR_PORTS, short)) {printk(KERN_INFO short: cant get I/O port address 0x%lx\n,short_base);return -ENODEV;}} else {if (! request_mem_region(short_base, SHORT_NR_PORTS, short)) {printk(KERN_INFO short: cant get I/O mem address 0x%lx\n,short_base);return -ENODEV;}/* also, ioremap it */short_base (unsigned long) ioremap(short_base, SHORT_NR_PORTS);/* Hmm... we should check the return value */}/* Here we register our device - should not fail thereafter */result register_chrdev(major, short, short_fops);if (result 0) {printk(KERN_INFO short: cant get major number\n);if (!use_mem) {release_region(short_base, SHORT_NR_PORTS);} else {release_mem_region(short_base, SHORT_NR_PORTS);}return result;}if (major 0) major result; /* dynamic */short_buffer __get_free_pages(GFP_KERNEL,0); /* never fails */ /* FIXME */short_head short_tail short_buffer;/** Fill the workqueue structure, used for the bottom half handler.* The cast is there to prevent warnings about the type of the* (unused) argument.*//* this line is in short_init() */INIT_WORK(short_wq, (void (*)(struct work_struct *)) short_do_tasklet);/** Now we deal with the interrupt: either kernel-based* autodetection, DIY detection or default number*/if (short_irq 0 probe 1)short_kernelprobe();if (short_irq 0 probe 2)short_selfprobe();if (short_irq 0) /* not yet specified: force the default on */switch(short_base) {case 0x378: short_irq 7; break;case 0x278: short_irq 2; break;case 0x3bc: short_irq 5; break;}/** If shared has been specified, installed the shared handler* instead of the normal one. Do it first, before a -EBUSY will* force short_irq to -1.*/if (short_irq 0 share 0) {result request_irq(short_irq, short_sh_interrupt,IRQF_SHARED,short,short_sh_interrupt);if (result) {printk(KERN_INFO short: cant get assigned irq %i\n, short_irq);short_irq -1;}else { /* actually enable it -- assume this *is* a parallel port */outb(0x10, short_base2);}return 0; /* the rest of the function only installs handlers */}if (short_irq 0) {result request_irq(short_irq, short_interrupt,0, short, NULL);if (result) {printk(KERN_INFO short: cant get assigned irq %i\n,short_irq);short_irq -1;}else { /* actually enable it -- assume this *is* a parallel port */outb(0x10,short_base2);}}/** Ok, now change the interrupt handler if using top/bottom halves* has been requested*/if (short_irq 0 (wq tasklet) 0) {free_irq(short_irq,NULL);result request_irq(short_irq,tasklet ? short_tl_interrupt :short_wq_interrupt,0, short-bh, NULL);if (result) {printk(KERN_INFO short-bh: cant get assigned irq %i\n,short_irq);short_irq -1;}}return 0;
}
首先是request_region如果配置了内存映射就是request_mem_region和ioremap。
之后是注册字符设备register_chrdev。
内存是用的__get_free_pages。
之后的INIT_WORK看起来是处理中断用的。
之后根据probe状态处理probe有两种short_kernelprobe和short_selfprobe。这两个的区别还要再看看。
后面是request_irq之后outb(0x10,short_base2);向寄存器写入0x10。
在较早的硬件中例如并口设备基地址和中断号通常是预定义的形成了硬件设计上的约定。例如地址0x378通常对应 IRQ 7地址0x278通常对应 IRQ 2。 2 short_cleanup
倒是没啥特别的就是清理。
void short_cleanup(void)
{if (short_irq 0) {outb(0x0, short_base 2); /* disable the interrupt */if (!share) free_irq(short_irq, NULL);else free_irq(short_irq, short_sh_interrupt);}/* Make sure we dont leave work queue/tasklet functions running */if (tasklet)tasklet_disable(short_tasklet);elseflush_scheduled_work();unregister_chrdev(major, short);if (use_mem) {iounmap((void __iomem *)short_base);//release_mem_region(short_base, SHORT_NR_PORTS);release_mem_region(base, SHORT_NR_PORTS);} else {release_region(short_base,SHORT_NR_PORTS);}if (short_buffer) free_page(short_buffer);
}
free_irqunregister_chrdevrelease_mem_regionrelease_regionfree_page。