📄 bpp.c
字号:
bpp_outb_p(mode, base_addrs[minor]); snooze(TIME_PSetup, minor); /* Event 1: Strobe the mode code into the peripheral */ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); /* Wait for Event 2: Peripheral responds as a 1284 device. */ rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, BPP_GP_nAck, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; /* Event 3: latch extensibility request */ set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); /* ... quick nap while peripheral ponders the byte i'm sending...*/ snooze(1, minor); /* Event 4: restore strobe, to ACK peripheral's response. */ set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); /* Wait for Event 6: Peripheral latches response bits */ rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); if (rc == -1) return -EIO; /* A 1284 device cannot refuse nibble mode */ if (mode == DEFAULT_NIBBLE) return 0; if (pins & BPP_GP_Select) return 0; return -EPROTONOSUPPORT;}static int terminate(unsigned minor){ int rc; /* Event 22: Request termination of 1284 mode */ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); /* Wait for Events 23 and 24: ACK termination request. */ rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, BPP_GP_nAck, TIME_PSetup+TIME_PResponse, minor); instances[minor].direction = 0; instances[minor].mode = COMPATIBILITY; if (rc == -1) { return -EIO; } /* Event 25: Handshake by lowering nAutoFd */ set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); /* Event 26: Peripheral wiggles lines... */ /* Event 27: Peripheral sets nAck HIGH to ack handshake */ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); if (rc == -1) { set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); return -EIO; } /* Event 28: Finish phase by raising nAutoFd */ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); return 0;}static spinlock_t bpp_open_lock = SPIN_LOCK_UNLOCKED;/* * Allow only one process to open the device at a time. */static int bpp_open(struct inode *inode, struct file *f){ unsigned minor = iminor(inode); int ret; spin_lock(&bpp_open_lock); ret = 0; if (minor >= BPP_NO) { ret = -ENODEV; } else { if (! instances[minor].present) { ret = -ENODEV; } else { if (instances[minor].opened) ret = -EBUSY; else instances[minor].opened = 1; } } spin_unlock(&bpp_open_lock); return ret;}/* * When the process closes the device, this method is called to clean * up and reset the hardware. Always leave the device in compatibility * mode as this is a reasonable place to clean up from messes made by * ioctls, or other mayhem. */static int bpp_release(struct inode *inode, struct file *f){ unsigned minor = iminor(inode); spin_lock(&bpp_open_lock); instances[minor].opened = 0; if (instances[minor].mode != COMPATIBILITY) terminate(minor); spin_unlock(&bpp_open_lock); return 0;}static long read_nibble(unsigned minor, char __user *c, unsigned long cnt){ unsigned long remaining = cnt; long rc; while (remaining > 0) { unsigned char byte = 0; int pins; /* Event 7: request nibble */ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); /* Wait for event 9: Peripher strobes first nibble */ pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); if (pins == -1) return -ETIMEDOUT; /* Event 10: I handshake nibble */ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); if (pins & BPP_GP_nFault) byte |= 0x01; if (pins & BPP_GP_Select) byte |= 0x02; if (pins & BPP_GP_PError) byte |= 0x04; if (pins & BPP_GP_Busy) byte |= 0x08; /* Wait for event 11: Peripheral handshakes nibble */ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); /* Event 7: request nibble */ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); /* Wait for event 9: Peripher strobes first nibble */ pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; /* Event 10: I handshake nibble */ set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); if (pins & BPP_GP_nFault) byte |= 0x10; if (pins & BPP_GP_Select) byte |= 0x20; if (pins & BPP_GP_PError) byte |= 0x40; if (pins & BPP_GP_Busy) byte |= 0x80; if (put_user(byte, c)) return -EFAULT; c += 1; remaining -= 1; /* Wait for event 11: Peripheral handshakes nibble */ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); if (rc == -1) return -EIO; } return cnt - remaining;}static long read_ecp(unsigned minor, char __user *c, unsigned long cnt){ unsigned long remaining; long rc; /* Turn ECP mode from forward to reverse if needed. */ if (! instances[minor].direction) { unsigned short pins = get_pins(minor); /* Event 38: Turn the bus around */ instances[minor].direction = 0x20; pins &= ~BPP_PP_nAutoFd; set_pins(pins, minor); /* Event 39: Set pins for reverse mode. */ snooze(TIME_PSetup, minor); set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); /* Wait for event 40: Peripheral ready to be strobed */ rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; } remaining = cnt; while (remaining > 0) { /* If there is a run length for a repeated byte, repeat */ /* that byte a few times. */ if (instances[minor].run_length && !instances[minor].run_flag) { char buffer[128]; unsigned idx; unsigned repeat = remaining < instances[minor].run_length ? remaining : instances[minor].run_length; for (idx = 0 ; idx < repeat ; idx += 1) buffer[idx] = instances[minor].repeat_byte; if (copy_to_user(c, buffer, repeat)) return -EFAULT; remaining -= repeat; c += repeat; instances[minor].run_length -= repeat; } if (remaining == 0) break; /* Wait for Event 43: Data active on the bus. */ rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); if (rc == -1) break; if (rc & BPP_GP_Busy) { /* OK, this is data. read it in. */ unsigned char byte = bpp_inb(base_addrs[minor]); if (put_user(byte, c)) return -EFAULT; c += 1; remaining -= 1; if (instances[minor].run_flag) { instances[minor].repeat_byte = byte; instances[minor].run_flag = 0; } } else { unsigned char byte = bpp_inb(base_addrs[minor]); if (byte & 0x80) { printk("bpp%d: " "Ignoring ECP channel %u from device.\n", minor, byte & 0x7f); } else { instances[minor].run_length = byte; instances[minor].run_flag = 1; } } /* Event 44: I got it. */ set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); /* Wait for event 45: peripheral handshake */ rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; /* Event 46: Finish handshake */ set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); } return cnt - remaining;}static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos){ long rc; unsigned minor = iminor(f->f_dentry->d_inode); if (minor >= BPP_NO) return -ENODEV; if (!instances[minor].present) return -ENODEV; switch (instances[minor].mode) { default: if (instances[minor].mode != COMPATIBILITY) terminate(minor); if (instances[minor].enhanced) { /* For now, do all reads with ECP-RLE mode */ unsigned short pins; rc = negotiate(DEFAULT_ECP, minor); if (rc < 0) break; instances[minor].mode = ECP_RLE; /* Event 30: set nAutoFd low to setup for ECP mode */ pins = get_pins(minor); pins &= ~BPP_PP_nAutoFd; set_pins(pins, minor); /* Wait for Event 31: peripheral ready */ rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; rc = read_ecp(minor, c, cnt); } else { rc = negotiate(DEFAULT_NIBBLE, minor); if (rc < 0) break; instances[minor].mode = NIBBLE; rc = read_nibble(minor, c, cnt); } break; case NIBBLE: rc = read_nibble(minor, c, cnt); break; case ECP: case ECP_RLE: rc = read_ecp(minor, c, cnt); break; } return rc;}/* * Compatibility mode handshaking is a matter of writing data, * strobing it, and waiting for the printer to stop being busy. */static long write_compat(unsigned minor, const char __user *c, unsigned long cnt){ long rc; unsigned short pins = get_pins(minor); unsigned long remaining = cnt; while (remaining > 0) { unsigned char byte; if (get_user(byte, c)) return -EFAULT; c += 1; rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); if (rc == -1) return -ETIMEDOUT; bpp_outb_p(byte, base_addrs[minor]); remaining -= 1; /* snooze(1, minor); */ pins &= ~BPP_PP_nStrobe; set_pins(pins, minor); rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -