📄 cpia_pp.c
字号:
/* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); /* set nErrIntrEn and serviceIntr */ frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Reverse mode. */ parport_pc_data_reverse (port); /* Must be in PS2 mode */ while (left) { int i; char *ptr;#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) long expire = jiffies + port->physport->cad->timeout;#else unsigned long expire = jiffies + port->physport->cad->timeout;#endif DBG ("start of while %i left\n", left); count = left; if (count > maxlen) count = maxlen; dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); set_dma_mode(port->dma, DMA_MODE_READ); set_dma_addr(port->dma, dma_addr); set_dma_count(port->dma, count); /* Set DMA mode */ frob_econtrol (port, 1<<3, 1<<3); /* Clear serviceIntr */ frob_econtrol (port, 1<<2, 0); enable_dma(port->dma); release_dma_lock(dmaflag); /* Wait for interrupt. */ DBG ("about to wait\n"); false_alarm: if (0 > parport_wait_event (port, HZ)) break; if (!time_before (jiffies, expire)) { /* Timed out. */ DBG("DMA read timed out\n"); break; } /* Is serviceIntr set? */ if (!(inb (ECONTROL (port)) & (1<<2))) {#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) if (current->need_resched) schedule ();#else cond_resched();#endif goto false_alarm; } dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); count -= get_dma_residue(port->dma); release_dma_lock(dmaflag);#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) if (current->need_resched) /* Can't yield the port. */ schedule ();#else cond_resched(); /* Can't yield the port. */#endif /* update for possible DMA residue ! */ DBG ("read %i in loop\n", count); if (dma_handle) dma_addr += count; else memcpy(buf, priv->dma_buf, count); buf += count; left -= count; /* (cpia specific): test the last 4 bytes of data for EOI */ endseen = 1; ptr = buf; for (i = 0; i < 4; i++) { ptr--; if(((unsigned char) *ptr ) != EOI) { endseen = 0; break; } } if(endseen) break; } /* Maybe got here through break, so adjust for DMA residue! */ if (left && !endseen) { DBG("exited on break\n"); dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); count -= get_dma_residue(port->dma); release_dma_lock(dmaflag); if (!dma_handle) memcpy(buf, priv->dma_buf, count); left -= count; } frob_econtrol (port, 1<<2, 1<<2); /* Turn off DMA mode */ frob_econtrol (port, 1<<3, 0); if (dma_handle) pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); out_no_data: if (change_mode (port, ECR_PS2)) /* ECP FIFO */ printk (KERN_DEBUG "%s: Warning change_mode ECR_PS2 failed\n", port->name); /* Go to forward idle mode to shut the peripheral up (event 47). */ parport_frob_control (port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); /* event 49: PError goes high */ if( (r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT)) ) { printk (KERN_DEBUG "%s: PE timeout FWDIDLE (%d) in ecp_read_block_dma\n", port->name, r); } else { parport_data_forward (port); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } DBG ("returning %i bytes read, endseen = %d\n", length - left, endseen); return length - left;}#endif /*CPIA_PARPORT_DMA */static ssize_t cpia_parport_read (struct parport *port, void *buffer, size_t len, int stream){ int mode = port->physport->ieee1284.mode; size_t (*fn) (struct parport *, void *, size_t, int); /* Ignore the device-ID-request bit and the address bit. */ mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR); switch (mode) { case IEEE1284_MODE_NIBBLE: if(stream){ DBG("%s: Using cpia nibble stream mode\n", port->name); fn = cpia_read_nibble_stream; } else { DBG("%s: Using cpia nibble mode\n", port->name); fn = cpia_read_nibble; } return (*fn) (port, buffer, len, 0); break; case IEEE1284_MODE_ECP:#ifdef CPIA_PARPORT_DMA if (stream && port->dma != PARPORT_DMA_NONE){ fn = cpia_ecp_read_block_dma; return (*fn) (port, buffer, len, 0); break; }#endif default: return parport_read(port, buffer, len); break; }}/**************************************************************************** * * EndTransferMode * ***************************************************************************/static void EndTransferMode(struct pp_cam_entry *cam){ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);}/**************************************************************************** * * ForwardSetup * ***************************************************************************/static int ForwardSetup(struct pp_cam_entry *cam){ int retry; /* The CPiA uses ECP protocol for Downloads from the Host to the camera. * This will be software-emulated if ECP hardware is not present */ /* the usual camera maximum response time is 10ms, but after receiving * some commands, it needs up to 40ms. (Data Sheet p. 32)*/ for(retry = 0; retry < 4; ++retry) { if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) { break; } mdelay(10); } if(retry == 4) { DBG("Unable to negotiate IEEE1284 ECP Download mode\n"); return -1; } return 0;}/**************************************************************************** * * ReverseSetup * ***************************************************************************/static int ReverseSetup(struct pp_cam_entry *cam, int extensibility){ int retry, mode; int transfer_mode = NIBBLE_TRANSFER; /* The CPiA uses either ECP protocol or non-standard variants of * Nibble protocol for Uploads from the camera to the Host. * ECP protocol will be software-emulated if ECP hardware is not present. * Private CPiA-specific susbstitutes for port->ops->nibble_read_data() * are provided here. */ switch (cam->upload_mode) { case IEEE1284_MODE_ECPSWE: case IEEE1284_MODE_ECP: transfer_mode = ECP_TRANSFER; case IEEE1284_MODE_NIBBLE: /* for non-ECP non-TRISTATE ports */ if(!extensibility) mode = cam->upload_mode; else mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK; /* the usual camera maximum response time is 10ms, but after * receiving some commands, it needs up to 40ms. */ for(retry = 0; retry < 4; ++retry) { if(!parport_negotiate(cam->port, mode)) { break; } mdelay(10); } if(retry == 4) { if(extensibility) DBG("Unable to negotiate IEEE1284 extensibility mode\n"); else DBG("Unable to negotiate IEEE1284 Upload mode\n"); return -1; } if(extensibility) cam->port->ieee1284.mode = cam->upload_mode; return 0; break; default: return -1; break; }}/**************************************************************************** * * WritePacket * ***************************************************************************/static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size){ int retval=0; int size_written; if (packet == NULL) { return -EINVAL; } if (ForwardSetup(cam)) { DBG("Write failed in setup\n"); return -EIO; } size_written = parport_write(cam->port, packet, size); if(size_written != size) { DBG("Write failed, wrote %d/%d\n", size_written, size); retval = -EIO; } EndTransferMode(cam); return retval;}/**************************************************************************** * * ReadPacket * ***************************************************************************/static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size){ int retval = 0, size_read; if (packet == NULL) { return -EINVAL; } if (ReverseSetup(cam, 0)) { DBG("Read failed in setup\n"); return -EIO; } if((size_read = cpia_parport_read(cam->port, packet, size, 0)) != size) { DBG("Read failed, read %d/%d\n", size_read, size); retval = -EIO; } EndTransferMode(cam); return retval;}/**************************************************************************** * * cpia_pp_streamStart * ***************************************************************************/static int cpia_pp_streamStart(void *privdata){ struct pp_cam_entry *cam = privdata; DBG("\n"); cam->streaming=1; cam->image_ready=0; //if (ReverseSetup(cam,1)) return -EIO; if(cam->stream_irq) cpia_parport_enable_irq(cam->port); return 0; }/**************************************************************************** * * cpia_pp_streamStop * ***************************************************************************/static int cpia_pp_streamStop(void *privdata){ struct pp_cam_entry *cam = privdata; DBG("\n"); cam->streaming=0; cpia_parport_disable_irq(cam->port); //EndTransferMode(cam); return 0;}/**************************************************************************** * * cpia_pp_streamRead * ***************************************************************************/static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock){ struct pp_cam_entry *cam = privdata; int read_bytes = 0, endseen = 0, chunks = 0; size_t chunksize = CPIA_UPLOAD_CHUNKSIZE; u8 *buf = buffer, *buf_end = buffer + CPIA_MAX_IMAGE_SIZE; if(cam == NULL) { DBG("Internal driver error: cam is NULL\n"); return -EINVAL; } if(buffer == NULL) { DBG("Internal driver error: buffer is NULL\n"); return -EINVAL; } //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock); if( cam->stream_irq ) { DBG("%d\n", cam->image_ready); cam->image_ready--; } cam->image_complete=0; if (0/*cam->streaming*/) { if(!cam->image_ready) { if(noblock) return -EWOULDBLOCK; interruptible_sleep_on(&cam->wq_stream); if( signal_pending(current) ) return -EINTR; DBG("%d\n", cam->image_ready); } } else { if (ReverseSetup(cam, 1)) { DBG("unable to ReverseSetup\n"); return -EIO; } } if (cam->upload_mode == IEEE1284_MODE_ECP) { chunksize = CPIA_FIFO_UPLOAD_CHUNKSIZE;#ifdef CPIA_PARPORT_DMA if(cam->port->dma != PARPORT_DMA_NONE) chunksize = CPIA_MAX_IMAGE_SIZE;#endif } /* If we are using "Nibble Stream" or Software-Emulated ECP * protocols to upload data byte-by-byte through the parport. * we must read the image in small chunks and call schedule * to avoid eating up all the cpu resources. */ while (read_bytes < CPIA_MAX_IMAGE_SIZE && endseen < 4) { size_t datasize, bufsize; int i; u8 *pos; /* be nice to other processes ! */#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) if (current->need_resched) schedule();#else cond_resched(); #endif bufsize = chunksize; if(bufsize > (size_t)(buf_end - buf)) bufsize = (size_t)(buf_end - buf); datasize = cpia_parport_read(cam->port, buf, bufsize,1); chunks++; buf += datasize; read_bytes += (int) datasize; /* test the last 4 bytes of data for EOI */ if (read_bytes >= 4) { endseen = 1; pos = buf; for (i = 0; i < 4; i++) { pos--; if( *pos != EOI) { endseen = 0; break; } } } if (endseen) { cam->image_complete = 1 ; break; } } EndTransferMode(cam); DBG("read %d bytes in %d chunks of size <= %d, endseen = %d\n", read_bytes, chunks, chunksize, endseen); if( endseen ) DBG("EOI at %d bytes \n", read_bytes); else DBG("EOI not seen, read %d bytes\n", read_bytes); return cam->image_complete ? read_bytes : -EIO; }/**************************************************************************** * * cpia_pp_transferCmd * ***************************************************************************/static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data){ int err; int retval=0; int databytes; struct pp_cam_entry *cam = privdata; if(cam == NULL) { DBG("Internal driver error: cam is NULL\n"); return -EINVAL; } if(command == NULL) { DBG("Internal driver error: command is NULL\n"); return -EINVAL; } databytes = (((int)command[7])<<8) | command[6];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -