/** * * Reads one frame from the device and puts it in the storage buffer. * * @param InstancePtr - a pointer to the XHwIcap instance to be worked on. * * @param Block - Block Address (XHI_FAR_CLB_BLOCK, * XHI_FAR_BRAM_BLOCK, XHI_FAR_BRAM_INT_BLOCK) * * @param MajorFrame - selects the column * * @param MinorFrame - selects frame inside column * * @return XST_SUCCESS, XST_BUFFER_TOO_SMALL or XST_INVALID_PARAM. * * @note None. * *****************************************************************************/ XStatus XHwIcap_DeviceReadFrame(XHwIcap *InstancePtr, s32 Block, s32 MajorFrame, s32 MinorFrame) { s32 Packet; s32 Data; s32 TotalWords; XStatus Status; /* Make sure we aren't trying to read more than what we have room * for. */ if (InstancePtr->BytesPerFrame > (XHI_MAX_BUFFER_BYTES-XHI_HEADER_BUFFER_BYTES)) { return XST_BUFFER_TOO_SMALL; } /* DUMMY and SYNC */ XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET); XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET); /* Setup CMD register to read configuration */ Packet = XHwIcap_Type1Write(XHI_CMD) | 1; Data = XHI_CMD_RCFG; XHwIcap_StorageBufferWrite(InstancePtr, 2,Packet); XHwIcap_StorageBufferWrite(InstancePtr, 3,Data); /* Setup FAR register. */ Packet = XHwIcap_Type1Write(XHI_FAR) | 1; Data = XHwIcap_SetupFar(Block, MajorFrame, MinorFrame); XHwIcap_StorageBufferWrite(InstancePtr, 4,Packet); XHwIcap_StorageBufferWrite(InstancePtr, 5,Data); /* Setup read data packet header. */ TotalWords = InstancePtr->WordsPerFrame << 1; /* mult by 2 */ /* Create Type one packet */ Packet = XHwIcap_Type1Read(XHI_FDRO) | TotalWords; XHwIcap_StorageBufferWrite(InstancePtr, 6,Packet); XHwIcap_StorageBufferWrite(InstancePtr, 7,0); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 8,0); /* flush */ /* Write To ICAP. */ Status = XHwIcap_DeviceWrite(InstancePtr, 0, 9); if (Status != XST_SUCCESS) { return Status; } /* Read pad frame (skip header). */ Status = XHwIcap_DeviceRead(InstancePtr, XHI_HEADER_BUFFER_WORDS, InstancePtr->WordsPerFrame); if (Status != XST_SUCCESS) { return Status; } /* Read data on top of pad frame (skip header). */ Status = XHwIcap_DeviceRead(InstancePtr, XHI_HEADER_BUFFER_WORDS, InstancePtr->WordsPerFrame); if (Status != XST_SUCCESS) { return Status; } /* send DESYNC command */ Status = XHwIcap_CommandDesync(InstancePtr); if (Status != XST_SUCCESS) { return Status; } return XST_SUCCESS; };
static ssize_t xhwicap_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { struct xhwicap_instance *inst; size_t write_count=count; XStatus status; const char *user_buf=buf; DBPRINTK("write\n"); DBPRINTK("count is %lX\n",count); /* FIXME! Assume instance is first in list - this is bogus */ inst = inst_list; if(!inst) return -ENODEV; /* Deal with any left overs from last time */ DBPRINTK("PREAMBLE: %i bytes pending\n",inst->pendingByteCount); ASSERT(inst->pendingByteCount<4); /* Only enter the preamble if there is stuff left from last time */ while(inst->pendingByteCount && inst->pendingByteCount<4 && write_count) { unsigned char tmp; /* Accumulate into the pendingWord */ copy_from_user(&tmp, user_buf++, 1); inst->pendingWord=(inst->pendingWord) << 8 | (tmp & 0xFF); inst->pendingByteCount++; write_count--; } /* Did we accumulated a full word? */ if(inst->pendingByteCount==4) { DBPRINTK("Writing pendingword\n"); /* Write the word to the buffer */ XHwIcap_StorageBufferWrite(&(inst->HwIcap),0,inst->pendingWord); XHwIcap_DeviceWrite(&(inst->HwIcap), 0, 1); inst->pendingByteCount=0; inst->pendingWord=0; } ASSERT(write_count==0 || inst->pendingByteCount==0); /* Minimum possible chunk size is 4 bytes */ while(write_count>3) { int chunk_word_count=0; size_t chunk_size, chunk_left; /* don't use full limit of BUFFER_BYTES, seems to break the hardware.. Round down to nearest multiple of 4 */ chunk_size=chunk_left=min(write_count, (size_t)XHI_MAX_BUFFER_BYTES-8) & ~0x3; DBPRINTK("chunk size %lX\n",chunk_size); DBPRINTK("copying chunk to buffer\n"); while(chunk_left) { u32 tmp; copy_from_user(&tmp, user_buf, 4); XHwIcap_StorageBufferWrite(&(inst->HwIcap), chunk_word_count++, tmp); user_buf+=4; chunk_left-=4; } ASSERT(chunk_word_count); DBPRINTK("done\nWriting chunk to device.."); /* initiate write of private buffer to device */ DBPRINTK("chunk_word_count:%X\n",chunk_word_count); status = XHwIcap_DeviceWrite(&(inst->HwIcap), 0, chunk_word_count); if(status==XST_BUFFER_TOO_SMALL) return -ENOSPC; else if(status==XST_DEVICE_BUSY) return -EBUSY; else if(status==XST_INVALID_PARAM) return -EINVAL; write_count-=chunk_word_count*4; } DBPRINTK("POSTAMBLE: %i bytes remaining\n",write_count); ASSERT(write_count<4); /* No more than 3 bytes remaining */ /*ASSERT(inst->pendingByteCount==0); *//* pending buffer is empty */ /* Put remaining bytes into the pending buffer */ while(write_count) { unsigned char tmp; copy_from_user(&tmp, user_buf++, 1); inst->pendingWord=(inst->pendingWord) << 8 | (tmp & 0xFF); write_count--; inst->pendingByteCount++; } DBPRINTK("finished\n"); return count-write_count; }
/** * * Reads one frame from the device and puts it in the storage buffer. * * @param InstancePtr - a pointer to the XHwIcap instance to be worked on. * @param Top - top (0) or bottom (1) half of device * @param Block - Block Address (XHI_FAR_CLB_BLOCK, * XHI_FAR_BRAM_BLOCK, XHI_FAR_BRAM_INT_BLOCK) * @param HClkRow - selects the HClk Row * @param MajorFrame - selects the column * @param MinorFrame - selects frame inside column * * @return XST_SUCCESS, XST_BUFFER_TOO_SMALL or XST_INVALID_PARAM. * * @note None. * *****************************************************************************/ XStatus XHwIcap_DeviceReadFrameV4(XHwIcap *InstancePtr, Xint32 Top, Xint32 Block, Xint32 HClkRow, Xint32 MajorFrame, Xint32 MinorFrame) { Xint32 Packet; Xint32 Data; Xint32 TotalWords; XStatus Status; /* Make sure we aren't trying to read more than what we have room * for. */ if (InstancePtr->BytesPerFrame > (XHI_MAX_BUFFER_BYTES-XHI_HEADER_BUFFER_BYTES)) { return XST_BUFFER_TOO_SMALL; } /* DUMMY and SYNC */ XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET); XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET); XHwIcap_StorageBufferWrite(InstancePtr, 2, XHI_NOOP_PACKET); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_NOOP_PACKET); /* flush */ /* Reset CRC */ Packet = XHwIcap_Type1Write(XHI_CMD) | 1; XHwIcap_StorageBufferWrite(InstancePtr, 4, Packet); XHwIcap_StorageBufferWrite(InstancePtr, 5, XHI_CMD_RCRC); XHwIcap_StorageBufferWrite(InstancePtr, 6, XHI_NOOP_PACKET); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 7, XHI_NOOP_PACKET); /* flush */ /* Setup CMD register to read configuration */ Packet = XHwIcap_Type1Write(XHI_CMD) | 1; XHwIcap_StorageBufferWrite(InstancePtr, 8, Packet); XHwIcap_StorageBufferWrite(InstancePtr, 9, XHI_CMD_RCFG); XHwIcap_StorageBufferWrite(InstancePtr, 10, XHI_NOOP_PACKET); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 11, XHI_NOOP_PACKET); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 12, XHI_NOOP_PACKET); /* flush */ /* Setup FAR register. */ Packet = XHwIcap_Type1Write(XHI_FAR) | 1; Data = XHwIcap_SetupFarV4(Top, Block, HClkRow, MajorFrame, MinorFrame); XHwIcap_StorageBufferWrite(InstancePtr, 13, Packet); XHwIcap_StorageBufferWrite(InstancePtr, 14, Data); /* Setup read data packet header. */ /* The frame will be preceeded by a dummy frame, and we need to read one extra word - see Configuration Guide Chapter 8 */ TotalWords = (InstancePtr->WordsPerFrame << 1) + 1; /* Create Type one packet */ Packet = XHwIcap_Type1Read(XHI_FDRO) | TotalWords; XHwIcap_StorageBufferWrite(InstancePtr, 15, Packet); XHwIcap_StorageBufferWrite(InstancePtr, 16, XHI_NOOP_PACKET); /* flush */ XHwIcap_StorageBufferWrite(InstancePtr, 17, XHI_NOOP_PACKET); /* flush */ /* Write To ICAP. */ Status = XHwIcap_DeviceWrite(InstancePtr, 0, 18); if (Status != XST_SUCCESS) { return Status; } /* Read pad frame (skip header). */ /* Status = XHwIcap_DeviceRead(InstancePtr, XHI_HEADER_BUFFER_WORDS, InstancePtr->WordsPerFrame); if (Status != XST_SUCCESS) { return Status; } */ /* In previous versions we could read the pad frame and the real frame in two steps. However the behaviour of the opb_hwicap peripheral has changed, such that the first byte out of the ICAP port is always ignored. If we perform a read in two steps we will lose a byte in the middle - so we must read in one go. */ /* Read data on top of pad frame (skip header). */ Status = XHwIcap_DeviceRead(InstancePtr, XHI_HEADER_BUFFER_WORDS, TotalWords); if (Status != XST_SUCCESS) { return Status; } /* send DESYNC command */ Status = XHwIcap_CommandDesync(InstancePtr); if (Status != XST_SUCCESS) { return Status; } return XST_SUCCESS; };