向外设中的控制器发送指令:
out xx,al
一段操纵外设的程序
int fd = open("/dev/xxx"); for (int i = 0; i < 10; i++) { write(fd, i, sizeof(int)); } colse(fd);
- 操作系统为用户提供统一的接口:open、read、write、close……
- 不同的设备对应不同的设备文件(/dev/xxx),根据设备文件找到控制器的地址、内容格式等
向显示器输出
printf 库展开后的部分是创建缓存buf,然后再
write(1, buf, ……)
// linux/fs/read_write.c // fd是找到file的索引 int sys_write(unsigned int fd, char *buf, int count) { struct file* file; file = current->filp[fd]; inode = file->f_inode; // ... }
因为是被current指向,所以是从fork中来。显然打开文件列表filp是拷贝而来的
void main(void) { if (!fork()) { init(); } }
void init(void) { open("/dev/tty0", O_RDWR, 0); // 0 dup(0); // 1 拷贝文件 dup(0); // 2 execve("/bin/sh", argv, envp); }
// linux/fs/open.c int sys_open(const char* filename, int flag) { i = open_namei(filename, flag, &inode); // inode是文件信息 current->filp[fd] = f; // 第一个空闲的fd f=f_mode = inode->i_mode; f->f_inode = inode; f->f_count = 1; return fd; }
// linux/fs/read_write.c int sys_write(unsigned int fd,char * buf,int count) { // ... inode=file->f_inode; if (S_ISCHR(inode->i_mode)) return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_write(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISREG(inode->i_mode)) return file_write(inode,file,buf,count); // ... }
// linux/fs/char_dev.c static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) { return ((rw==READ)?tty_read(minor,buf,count): tty_write(minor,buf,count)); } static crw_ptr crw_table[]={ NULL, /* nodev */ rw_memory, /* /dev/mem etc */ NULL, /* /dev/fd */ NULL, /* /dev/hd */ rw_ttyx, /* /dev/ttyx */ rw_tty, /* /dev/tty */ NULL, /* /dev/lp */ NULL}; /* unnamed pipes */ int rw_char(int rw,int dev, char * buf, int count, off_t * pos) { crw_ptr call_addr; if (!(call_addr=crw_table[MAJOR(dev)])) return -ENODEV; return call_addr(rw,MINOR(dev),buf,count,pos); }
// linux/kernel/tty_io.c int tty_write(unsigned channel, char * buf, int nr) { struct tty_struct * tty; char c, *b=buf; tty = channel + tty_table; while (nr>0) { sleep_if_full(&tty->write_q); // ... while (nr>0 && !FULL(tty->write_q)) { c=get_fs_byte(b); // 从用户缓存区读 // ... PUTCH(c,tty->write_q); } tty->write(tty); } // ... }
// include/linux/tty.h struct tty_struct { // ... void (*write)(struct tty_struct * tty); struct tty_queue read_q; struct tty_queue write_q; struct tty_queue secondary; };
struct tty_struct tty_table[] = { con_write, {0, 0, 0, 0, ""}, {0, 0, 0, 0, ""}, {}, // ... }
// linux/kernel/chr_drv/console.c void con_write(struct tty_struct * tty) { // ... GETCH(tty->write_q,c); switch(state) { case 0: if (c>31 && c<127) { if (x>=video_num_columns) { x -= video_num_columns; pos -= video_size_row; lf(); } __asm__("movb attr,%%ah\n\t" "movw %%ax,%1\n\t" ::"a" (c),"m" (*(short *)pos) ); pos += 2; x++; } // ... }
prinf的整个过程