📄 bpp.c
字号:
pins |= BPP_PP_nStrobe; set_pins(pins, minor); } return cnt - remaining;}/* * Write data using ECP mode. Watch out that the port may be set up * for reading. If so, turn the port around. */static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt){ unsigned short pins = get_pins(minor); unsigned long remaining = cnt; if (instances[minor].direction) { int rc; /* Event 47 Request bus be turned around */ pins |= BPP_PP_nInit; set_pins(pins, minor); /* Wait for Event 49: Peripheral relinquished bus */ rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); pins |= BPP_PP_nAutoFd; instances[minor].direction = 0; set_pins(pins, minor); } while (remaining > 0) { unsigned char byte; int rc; if (get_user(byte, c)) return -EFAULT; rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); if (rc == -1) return -ETIMEDOUT; c += 1; bpp_outb_p(byte, base_addrs[minor]); pins &= ~BPP_PP_nStrobe; set_pins(pins, minor); pins |= BPP_PP_nStrobe; rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); if (rc == -1) return -EIO; set_pins(pins, minor); } return cnt - remaining;}/* * Write to the peripheral. Be sensitive of the current mode. If I'm * in a mode that can be turned around (ECP) then just do * that. Otherwise, terminate and do my writing in compat mode. This * is the safest course as any device can handle it. */static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos){ long errno = 0; unsigned minor = iminor(f->f_dentry->d_inode); if (minor >= BPP_NO) return -ENODEV; if (!instances[minor].present) return -ENODEV; switch (instances[minor].mode) { case ECP: case ECP_RLE: errno = write_ecp(minor, c, cnt); break; case COMPATIBILITY: errno = write_compat(minor, c, cnt); break; default: terminate(minor); errno = write_compat(minor, c, cnt); } return errno;}static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, unsigned long arg){ int errno = 0; unsigned minor = iminor(inode); if (minor >= BPP_NO) return -ENODEV; if (!instances[minor].present) return -ENODEV; switch (cmd) { case BPP_PUT_PINS: set_pins(arg, minor); break; case BPP_GET_PINS: errno = get_pins(minor); break; case BPP_PUT_DATA: bpp_outb_p(arg, base_addrs[minor]); break; case BPP_GET_DATA: errno = bpp_inb_p(base_addrs[minor]); break; case BPP_SET_INPUT: if (arg) if (instances[minor].enhanced) { unsigned short bits = get_pins(minor); instances[minor].direction = 0x20; set_pins(bits, minor); } else { errno = -ENOTTY; } else { unsigned short bits = get_pins(minor); instances[minor].direction = 0x00; set_pins(bits, minor); } break; default: errno = -EINVAL; } return errno;}static struct file_operations bpp_fops = { .owner = THIS_MODULE, .read = bpp_read, .write = bpp_write, .ioctl = bpp_ioctl, .open = bpp_open, .release = bpp_release,};#if defined(__i386__)#define collectLptPorts() {}static void probeLptPort(unsigned idx){ unsigned int testvalue; const unsigned short lpAddr = base_addrs[idx]; instances[idx].present = 0; instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; instances[idx].run_length = 0; instances[idx].run_flag = 0; if (!request_region(lpAddr,3, dev_name)) return; /* * First, make sure the instance exists. Do this by writing to * the data latch and reading the value back. If the port *is* * present, test to see if it supports extended-mode * operation. This will be required for IEEE1284 reverse * transfers. */ outb_p(BPP_PROBE_CODE, lpAddr); for (testvalue=0; testvalue<BPP_DELAY; testvalue++) ; testvalue = inb_p(lpAddr); if (testvalue == BPP_PROBE_CODE) { unsigned save; instances[idx].present = 1; save = inb_p(lpAddr+2); for (testvalue=0; testvalue<BPP_DELAY; testvalue++) ; outb_p(save|0x20, lpAddr+2); for (testvalue=0; testvalue<BPP_DELAY; testvalue++) ; outb_p(~BPP_PROBE_CODE, lpAddr); for (testvalue=0; testvalue<BPP_DELAY; testvalue++) ; testvalue = inb_p(lpAddr); if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE)) instances[idx].enhanced = 0; else instances[idx].enhanced = 1; outb_p(save, lpAddr+2); } else { release_region(lpAddr,3); } /* * Leave the port in compat idle mode. */ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx], instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");}static inline void freeLptPort(int idx){ release_region(base_addrs[idx], 3);}#endif#if defined(__sparc__)static void __iomem *map_bpp(struct sbus_dev *dev, int idx){ return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp");}static int collectLptPorts(void){ struct sbus_bus *bus; struct sbus_dev *dev; int count; count = 0; for_all_sbusdev(dev, bus) { if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { if (count >= BPP_NO) { printk(KERN_NOTICE "bpp: More than %d bpp ports," " rest is ignored\n", BPP_NO); return count; } base_addrs[count] = map_bpp(dev, count); count++; } } return count;}static void probeLptPort(unsigned idx){ void __iomem *rp = base_addrs[idx]; __u32 csr; char *brand; instances[idx].present = 0; instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; instances[idx].run_length = 0; instances[idx].run_flag = 0; if (!rp) return; instances[idx].present = 1; instances[idx].enhanced = 1; /* Sure */ csr = sbus_readl(rp + BPP_CSR); if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { udelay(20); csr = sbus_readl(rp + BPP_CSR); if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); } } printk("bpp%d: reset with 0x%08x ..", idx, csr); sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR); udelay(500); sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR); csr = sbus_readl(rp + BPP_CSR); printk(" done with csr=0x%08x ocr=0x%04x\n", csr, sbus_readw(rp + BPP_OCR)); switch (csr & P_DEV_ID_MASK) { case P_DEV_ID_ZEBRA: brand = "Zebra"; break; case P_DEV_ID_L64854: brand = "DMA2"; break; default: brand = "Unknown"; } printk("bpp%d: %s at %p\n", idx, brand, rp); /* * Leave the port in compat idle mode. */ set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); return;}static inline void freeLptPort(int idx){ sbus_iounmap(base_addrs[idx], BPP_SIZE);}#endifstatic int __init bpp_init(void){ int rc; unsigned idx; rc = collectLptPorts(); if (rc == 0) return -ENODEV; rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops); if (rc < 0) return rc; for (idx = 0; idx < BPP_NO; idx++) { instances[idx].opened = 0; probeLptPort(idx); } devfs_mk_dir("bpp"); for (idx = 0; idx < BPP_NO; idx++) { devfs_mk_cdev(MKDEV(BPP_MAJOR, idx), S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx); } return 0;}static void __exit bpp_cleanup(void){ unsigned idx; for (idx = 0; idx < BPP_NO; idx++) devfs_remove("bpp/%d", idx); devfs_remove("bpp"); unregister_chrdev(BPP_MAJOR, dev_name); for (idx = 0; idx < BPP_NO; idx++) { if (instances[idx].present) freeLptPort(idx); }}module_init(bpp_init);module_exit(bpp_cleanup);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -