/*========================================================================== * lsadrv-isoc.c : Linux driver for eIT-Xiroku optical touch sensor * * Copyright (C) 2009 eIT Co., Ltd. and Xiroku Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================================*/ #include "lsadrv.h" #include "lsadrv-ioctl.h" #define STREAM_TRANSFER_COUNT 2U /* ring buffer for isochronous stream data */ struct lsadrv_ring_buffer { unsigned char *inPtr; unsigned char *outPtr; unsigned int totalSize; unsigned int currentSize; unsigned char *buffer; spinlock_t *spinLock; /* for manipulating the buffer pointers */ wait_queue_head_t *waitq; /* waken up when ring buffer have available data */ }; /* isochronous transfer object per urb */ struct lsadrv_iso_transfer_object { unsigned int frame; struct lsadrv_iso_stream_object *stream; struct urb *urb; unsigned char *data; #if LSADRV_DEBUG /* for debug */ unsigned int trans_count; #endif //LSADRV_DEBUG }; /* isochronous stream object */ struct lsadrv_iso_stream_object { struct lsadrv_device *xdev; unsigned int PacketSize; unsigned int TransferBufferLength; unsigned int FramesPerBuffer; unsigned int BufferCount; unsigned int TransferCount; unsigned int PendingTransfers; struct lsadrv_ring_buffer *RingBuffer; struct lsadrv_iso_transfer_object *transferObjects; // data error count unsigned int TotalDataErrorCount; }; /***************************************************************************/ /* Private functions */ static void FreeRingBuffer(struct lsadrv_ring_buffer *ringBuffer) { Trace(LSADRV_TRACE_MEMORY, "FreeRingBuffer:0x%p\n", ringBuffer); if (ringBuffer) { lsadrv_free_waitqueue_head(ringBuffer->waitq); lsadrv_spin_lock_term(ringBuffer->spinLock); lsadrv_free(ringBuffer->buffer); lsadrv_free(ringBuffer); } } static struct lsadrv_ring_buffer* AllocRingBuffer(size_t size) { struct lsadrv_ring_buffer *ringBuffer = NULL; ringBuffer = lsadrv_malloc(sizeof(struct lsadrv_ring_buffer)); if (!ringBuffer) { return NULL; } ringBuffer->buffer = lsadrv_malloc(size); if (!ringBuffer->buffer) { lsadrv_free(ringBuffer); return NULL; } ringBuffer->inPtr = ringBuffer->buffer; ringBuffer->outPtr = ringBuffer->buffer; ringBuffer->totalSize = size; ringBuffer->currentSize = 0; lsadrv_spin_lock_init(&ringBuffer->spinLock); if (ringBuffer->spinLock == NULL) { lsadrv_free(ringBuffer->buffer); lsadrv_free(ringBuffer); return NULL; } lsadrv_init_waitqueue_head(&ringBuffer->waitq); /* waken up when ring buffer have available data */ if (ringBuffer->waitq == NULL) { lsadrv_spin_lock_term(ringBuffer->spinLock); lsadrv_free(ringBuffer->buffer); lsadrv_free(ringBuffer); return NULL; } return ringBuffer; } static unsigned int ReadRingBuffer( struct lsadrv_ring_buffer *ringBuffer, unsigned char *readBuffer, unsigned int numberOfBytesToRead) { unsigned int byteCount; unsigned long flags; if (numberOfBytesToRead > ringBuffer->totalSize) { return 0; } //printk(">R "); lsadrv_spin_lock(ringBuffer->spinLock, &flags); byteCount = ringBuffer->currentSize; if (byteCount == 0) { lsadrv_spin_unlock(ringBuffer->spinLock, &flags); return 0; } if (numberOfBytesToRead < byteCount) { byteCount = numberOfBytesToRead; } /* * two cases. Read either wraps or it doesn't. * Handle the non-wrapped case first */ if ((ringBuffer->outPtr + byteCount - 1) < (ringBuffer->buffer + ringBuffer->totalSize)) { if (readBuffer) { memcpy(readBuffer, ringBuffer->outPtr, byteCount); } ringBuffer->outPtr += byteCount; if (ringBuffer->outPtr == ringBuffer->buffer + ringBuffer->totalSize) { ringBuffer->outPtr = ringBuffer->buffer; } } /* now handle the wrapped case */ else { unsigned int fragSize; fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->outPtr; if (readBuffer) { // get the first half of the read memcpy(readBuffer, ringBuffer->outPtr, fragSize); // now get the rest memcpy(readBuffer + fragSize, ringBuffer->buffer, byteCount - fragSize); } ringBuffer->outPtr = ringBuffer->buffer + byteCount - fragSize; } /* * update the current size of the ring buffer. Use spinlock to insure * atomic operation. */ ringBuffer->currentSize -= byteCount; lsadrv_spin_unlock(ringBuffer->spinLock, &flags); //printk("W%d ", numberOfBytesToWrite); //Trace(LSADRV_TRACE_FLOW, "W(%u)", numberOfBytesToWrite); if (numberOfBytesToWrite > ringBuffer->totalSize) { return 0; } lsadrv_spin_lock(ringBuffer->spinLock, &flags); maxBytes = ringBuffer->totalSize - ringBuffer->currentSize; if (numberOfBytesToWrite > maxBytes) { if (!overWriteFlg) { lsadrv_spin_unlock(ringBuffer->spinLock, &flags); return 0; } else { /* waste oldest data */ byteCount = numberOfBytesToWrite - maxBytes; ringBuffer->outPtr += byteCount; if (ringBuffer->outPtr >= ringBuffer->buffer + ringBuffer->totalSize) { ringBuffer->outPtr -= ringBuffer->totalSize; } ringBuffer->currentSize -= byteCount; } } if (numberOfBytesToWrite > 0) { /* * two cases. Write either wraps or it doesn't. * Handle the non-wrapped case first */ if ((ringBuffer->inPtr + numberOfBytesToWrite - 1) < (ringBuffer->buffer + ringBuffer->totalSize)) { if (writeBuffer) { memcpy(ringBuffer->inPtr, writeBuffer, numberOfBytesToWrite); } ringBuffer->inPtr += numberOfBytesToWrite; if (ringBuffer->inPtr == ringBuffer->buffer + ringBuffer->totalSize) { ringBuffer->inPtr = ringBuffer->buffer; } } /* now handle the wrapped case */ else { unsigned int fragSize; fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->inPtr; if (writeBuffer) { /* write the first fragment */ memcpy(ringBuffer->inPtr, writeBuffer, fragSize); /* now write the rest */ memcpy(ringBuffer->buffer, writeBuffer + fragSize, numberOfBytesToWrite - fragSize); } ringBuffer->inPtr = ringBuffer->buffer + numberOfBytesToWrite - fragSize; } } /* * update the current size of the ring buffer. */ ringBuffer->currentSize += numberOfBytesToWrite; lsadrv_spin_unlock(ringBuffer->spinLock, &flags); /* wake up the waiting threads */ lsadrv_wake_up_interruptible(ringBuffer->waitq); //printk("spinLock, &flags); /* not necessary ? */ byteCount = ringBuffer->currentSize; lsadrv_spin_unlock(ringBuffer->spinLock, &flags); Trace(LSADRV_TRACE_FLOW, "G(%d)", byteCount); return byteCount; } #if LSADRV_DEBUG static void dump(unsigned char *dat, unsigned int len) { unsigned int i; char buf[60], *p = buf; for (i = 0; i < len; i++) { p += sprintf(p, "%02x ", dat[i]); if ((i & 0xf) == 0xf) { lsadrv_printk("%s\n", buf); p = buf; } } if (i & 0xf) { lsadrv_printk("%s\n", buf); } } #endif /*LSADRV_DEBUG*/ /* * Isochronous transfer urb completion routine */ void lsadrv_isoc_handler(void *context, int status) { struct lsadrv_iso_transfer_object *trans = (struct lsadrv_iso_transfer_object *) context; struct lsadrv_iso_stream_object *stream; struct lsadrv_device *xdev; int i; unsigned int num_packets; unsigned char *src; struct lsadrv_iso_packet_desc *mydesc; unsigned int recSize; unsigned long flags; //if (status == 0) { // lsadrv_printk(">>hdr(%d)\n", trans->frame); //} //else { // lsadrv_printk(">>hdr(%d):status=%d\n", trans->frame, status); //} Trace(LSADRV_TRACE_STREAM, ">>isoc_handler %d\n", trans->frame); stream = trans->stream; if (stream == NULL) { Err("isoc_handler: stream==NULL\n"); Trace(LSADRV_TRACE_STREAM, "<frame); return; } xdev = stream->xdev; if (xdev == NULL) { Err("isoc_handler() called with NULL device?!\n"); Trace(LSADRV_TRACE_STREAM, "<frame); return; } /* report error status */ if (status != 0) { char *errmsg = NULL; /* error case */ switch (status) { case -ENOENT: Trace(LSADRV_TRACE_STREAM, "%s: URB(%p) unlinked synchronuously.\n", __func__, trans->urb); break; case -ECONNRESET: Trace(LSADRV_TRACE_STREAM, "%s: URB(%p) unlinked asynchronuously.\n", __func__, trans->urb); break; case -EINPROGRESS: break; case -ECOMM: //USB_ST_BUFFEROVERRUN errmsg = "Buffer overrun"; break; case -ENOSR: //USB_ST_BUFFERUNDERRUN errmsg = "Buffer underrun"; break; case -EXDEV: //USB_ST_PARTIAL_ERROR errmsg = "partial error"; break; case -ENODEV: errmsg = "device removed"; break; case -EPIPE: errmsg = "Stalled (device not responding)"; break; case -EOVERFLOW: //USB_ST_DATAOVERRUN errmsg = "Data overrun"; break; case -EREMOTEIO: //USB_ST_DATAUNDERRUN,USB_ST_SHORT_PACKET errmsg = "Data underrun"; break; case -EPROTO: //USB_ST_BITSTUFF,USB_ST_INTERNALERROR errmsg = "Bit-stuff/internal error"; break; case -EILSEQ: //USB_ST_CRC errmsg = "CRC error"; break; case -ETIMEDOUT: //USB_ST_NORESPONSE errmsg = "timed out"; break; default: errmsg = "unexpected error"; break; } if (errmsg) { Info("isoc_handler: status %d [%s].\n", status, errmsg); } } num_packets = stream->FramesPerBuffer; recSize = stream->PacketSize + sizeof(struct lsadrv_iso_packet_desc); /* data + packet descriptor */ for (i = 0; i < num_packets; i++) { src = trans->data + i * recSize; mydesc = (struct lsadrv_iso_packet_desc *)(src + stream->PacketSize); lsadrv_get_isoc_desc(trans->urb, i, &mydesc->Status, &mydesc->Length); } if (status == -ENOSR || status == -EXDEV || status == -EILSEQ) { Info("isoc_handler: status %d [Buffer underrun].\n", status); for (i = 0; i < num_packets; i++) { src = trans->data + i * recSize; mydesc = (struct lsadrv_iso_packet_desc *)(src + stream->PacketSize); if (mydesc->Length != 0) { Info(" %d: length=%d, status=%d\n", i, mydesc->Length, mydesc->Status); mydesc->Length = 0; } } status = 0; } /* add data to ring buffer */ if (status == 0) { #if LSADRV_DEBUG int dump_flg = 0; #endif /*LSADRV_DEBUG*/ for (i = 0; i < num_packets; i++) { src = trans->data + i * recSize; mydesc = (struct lsadrv_iso_packet_desc *)(src + stream->PacketSize); //Info("%d:[%d]", i, mydesc->Length); //Trace(LSADRV_TRACE_FLOW, "[%d]", mydesc->Length); if (mydesc->Status == 0) { if (mydesc->Length > 0) { #if LSADRV_DEBUG if (trans->trans_count <= 100) { lsadrv_printk("%d: len=%d\n", trans->trans_count, mydesc->Length); // dump(src, mydesc->Length); trans->trans_count++; // dump_flg = 1; } #endif /*LSADRV_DEBUG*/ WriteRingBuffer(stream->RingBuffer, src, recSize, 1); /* overwrite */ } } /* This is normally not interesting to the user, unless you are really debugging something */ else { stream->TotalDataErrorCount++; Trace(LSADRV_TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, mydesc->Status); } } #if LSADRV_DEBUG if (dump_flg) { lsadrv_printk("%d: alldump: trans:data=0x%p,len=%u\n", trans->trans_count, trans->data, stream->TransferBufferLength); for (i = 0; i < num_packets; i++) { dump(trans->data + recSize * i, stream->TransferBufferLength); } } #endif /*LSADRV_DEBUG*/ } if (status == 0 && !xdev->StopIsoStream && !xdev->CancelIsoStream && !xdev->unplugged && xdev->statusStreamStopReason == 0 //one error will stop all transfers ) { int ret; /* resubmit urb */ Trace(LSADRV_TRACE_STREAM, "isoc_handler %d: submit urb\n", trans->frame); //printk("submit(%d)\n", trans->frame); ret = lsadrv_usb_resubmit_urb(trans->urb, xdev->udev); if (!ret) { //lsadrv_modunlock(xdev); //printk("<frame); Trace(LSADRV_TRACE_STREAM, "<frame); return; } Err("submit_urb %d:0x%p failed with error %d\n", trans->frame, trans->urb, ret); status = ret; } /**** error or cancel case ****/ //printk("h:locking\n"); //lsadrv_modlock(xdev); lsadrv_spin_lock(xdev->streamLock, &flags); /* * Set error code */ if (xdev->statusStreamStopReason == 0 || status == -ENOENT || status == -ECONNRESET) { if (status) { xdev->statusStreamStopReason = status; } else if (xdev->StopIsoStream || xdev->CancelIsoStream) { xdev->statusStreamStopReason = 1; //STATUS_CANCELLED } else if (xdev->unplugged) { xdev->statusStreamStopReason = -ENODEV; } else { xdev->statusStreamStopReason = -EFAULT; } if (status) { xdev->LastFailedStreamUrbStatus = status; } } Trace(LSADRV_TRACE_STREAM, "isoc_handler: stopping transfer %d\n", trans->frame); stream->PendingTransfers--; //printk("h:unlocking\n"); //lsadrv_modunlock(xdev); lsadrv_spin_unlock(xdev->streamLock, &flags); /* * stop stream */ //printk("h:waking-up\n"); lsadrv_wake_up_interruptible(stream->RingBuffer->waitq); Trace(LSADRV_TRACE_STREAM, "<frame); } static void WaitForIsoStreamDone(struct lsadrv_iso_stream_object *stream) { struct lsadrv_ring_buffer *ringBuffer; //DECLARE_WAITQUEUE(wait, current); unsigned char waitbuf[64]; /* sufficient size */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)) wait_queue_entry_t *wait = (wait_queue_entry_t *) waitbuf; #else wait_queue_t *wait = (wait_queue_t *) waitbuf; #endif struct lsadrv_device *xdev; unsigned int pendingTransfers; if (stream == NULL || (ringBuffer = stream->RingBuffer) == NULL) { return; } lsadrv_init_waitqueue_entry(waitbuf, sizeof(waitbuf)); xdev = stream->xdev; //printk(">>Wait\n"); //printk("add_wait_queue\n"); lsadrv_add_wait_queue(ringBuffer->waitq, wait); lsadrv_set_current_state(TASK_INTERRUPTIBLE); while (1) { unsigned long flags; //lsadrv_modlock(xdev); lsadrv_spin_lock(xdev->streamLock, &flags); pendingTransfers = stream->PendingTransfers; lsadrv_spin_unlock(xdev->streamLock, &flags); //lsadrv_modunlock(xdev); if (pendingTransfers == 0) { break; } Trace(LSADRV_TRACE_STREAM, "waiting stream done: transfers=%d\n", pendingTransfers); //printk("sched\n"); lsadrv_schedule(); } lsadrv_set_current_state(TASK_RUNNING); //printk("remove_wait_queue\n"); lsadrv_remove_wait_queue(ringBuffer->waitq, wait); //printk("<transferObjects) { /* free transfer buffers and urbs */ for (i = 0; i < stream->TransferCount; i++) { struct lsadrv_iso_transfer_object *trans = &stream->transferObjects[i]; lsadrv_usb_unlink_urb(trans->urb); lsadrv_usb_free_urb(trans->urb); lsadrv_free(trans->data); } lsadrv_free(stream->transferObjects); } /* free ring buffer */ FreeRingBuffer(stream->RingBuffer); /* free stream object */ lsadrv_free(stream); } /* start isochronous stream */ int lsadrv_start_iso_stream( struct lsadrv_device *xdev, unsigned int ep, /* endpoint address(1-15) + direction(0x80 for IN) */ unsigned int PacketSize, /* ISO packet size. how much data is transferred each frame. * Should be equal to the maxpacketsize for the endpoint. */ unsigned int PacketCount, /* Total number of ISO packets to transfer. */ unsigned int FramesPerBuffer, unsigned int BufferCount) { struct usb_device *udev = xdev->udev; unsigned int pipe; unsigned int max_packet_size; struct lsadrv_iso_stream_object *stream = NULL; unsigned int transferCount; unsigned int recSize; unsigned int i; Trace(LSADRV_TRACE_STREAM, ">> start_iso_stream\n"); /* device is ready ? */ if (xdev->unplugged) { Err("%s: device is absent\n", __func__); return -ENODEV; } /* Only one stream can be opened at a time */ if (xdev->iso_init) { Err("%s: stream is already started\n", __func__); return -EFAULT; } /* pipe attribute check */ if ((ep & ~(USB_DIR_IN|0xf)) || !(ep & USB_DIR_IN)) { Info("%s: Pipe number 0x%x is invalid\n", __func__, ep); return -EINVAL; } if (lsadrv_usb_check_epnum(udev, ep & 0x8f)) { Info("%s: endpoint 0x%x not found\n", __func__, ep); return -EINVAL; } pipe = lsadrv_usb_rcvisocpipe(udev, ep & 0xf); max_packet_size = lsadrv_usb_maxpacket(udev, pipe, 0); if (max_packet_size != PacketSize) { Info("%s: Packet size mismatch: actual=%d, specified=%d\n", __func__, max_packet_size, PacketSize); return -EINVAL; } #ifdef STREAM_TRANSFER_COUNT transferCount = min(BufferCount, STREAM_TRANSFER_COUNT); #else //STREAM_TRANSFER_COUNT transferCount = BufferCount; #endif //STREAM_TRANSFER_COUNT /* buffer size per packet (including packet descriptor) */ recSize = PacketSize + sizeof(struct lsadrv_iso_packet_desc); /* data + packet descriptor */ /* allocate stream object */ stream = lsadrv_malloc(sizeof(struct lsadrv_iso_stream_object)); if (!stream) { return -ENOMEM; } memset(stream, 0, sizeof(*stream)); stream->xdev = xdev; stream->PacketSize = PacketSize; stream->TransferBufferLength = recSize * FramesPerBuffer; stream->FramesPerBuffer = FramesPerBuffer; stream->BufferCount = BufferCount; stream->TransferCount = transferCount; stream->PendingTransfers = 0; stream->TotalDataErrorCount = 0; stream->RingBuffer = NULL; stream->transferObjects = NULL; /* allocate ring buffer */ stream->RingBuffer = AllocRingBuffer(PacketCount * recSize); if (!stream->RingBuffer) { lsadrv_free(stream); return -ENOMEM; } /* allocate transfer objects */ stream->transferObjects = lsadrv_malloc(sizeof(struct lsadrv_iso_transfer_object) * transferCount); if (!stream->transferObjects) { FreeRingBuffer(stream->RingBuffer); lsadrv_free(stream); return -ENOMEM; } memset(stream->transferObjects, 0, sizeof(struct lsadrv_iso_transfer_object) * transferCount); /* allocate transfer buffers and urbs */ for (i = 0; i < transferCount; i++) { struct lsadrv_iso_transfer_object *trans = &stream->transferObjects[i]; trans->frame = i; trans->stream = stream; /* allocate transfer buffers */ trans->data = lsadrv_malloc(stream->TransferBufferLength); if (!trans->data) { FreeStreamObject(stream); return -ENOMEM; } /* allocate urb */ trans->urb = lsadrv_usb_alloc_urb(stream->FramesPerBuffer); if (trans->urb == NULL) { Err("Failed to allocate urb %d\n", i); FreeStreamObject(stream); return -ENOMEM; } } /* init URB structure */ for (i = 0; i < transferCount; i++) { struct lsadrv_iso_transfer_object *trans = &stream->transferObjects[i]; lsadrv_fill_isoc_urb(trans->urb, udev, pipe, trans, trans->data, stream->FramesPerBuffer, max_packet_size, recSize); } xdev->stream = stream; xdev->StopIsoStream = 0; xdev->CancelIsoStream = 0; xdev->statusStreamStopReason = 0; xdev->LastFailedStreamUrbStatus = 0; /* submit urbs */ for (i = 0; i < transferCount; i++) { struct lsadrv_iso_transfer_object *trans = &stream->transferObjects[i]; int ret; ret = lsadrv_usb_submit_urb(trans->urb); if (!ret) { unsigned long flags; lsadrv_spin_lock(xdev->streamLock, &flags); //lsadrv_modlock(xdev); stream->PendingTransfers++; lsadrv_spin_unlock(xdev->streamLock, &flags); //lsadrv_modunlock(xdev); Trace(LSADRV_TRACE_STREAM, "URB 0x%p submitted.\n", trans->urb); } else { Err("start_iso_stream: submit_urb %d failed with error %d\n", i, ret); } } /* All is done... */ xdev->iso_init = 1; Trace(LSADRV_TRACE_STREAM, "<< start_iso_stream\n"); return 0; } int lsadrv_stop_iso_stream(struct lsadrv_device *xdev) { unsigned long flags; //printk(">>stop_iso_stream\n"); Trace(LSADRV_TRACE_STREAM, ">> stop_iso_stream\n"); //printk("locking "); lsadrv_spin_lock(xdev->streamLock, &flags); //lsadrv_modlock(xdev); xdev->StopIsoStream = 1; //printk("unlocking "); lsadrv_spin_unlock(xdev->streamLock, &flags); //lsadrv_modunlock(xdev); if (xdev->stream) { struct lsadrv_iso_stream_object *stream = xdev->stream; int transferCount = stream->TransferCount; int i; for (i = 0; i < transferCount; i++) { struct lsadrv_iso_transfer_object *trans = &stream->transferObjects[i]; // printk("locking(%d)", trans->frame); // lsadrv_modlock(xdev); //printk("unlink(%d)", trans->frame); lsadrv_usb_unlink_urb(trans->urb); // printk("unlocking(%d)", trans->frame); // lsadrv_modunlock(xdev); } WaitForIsoStreamDone(xdev->stream); FreeStreamObject(xdev->stream); xdev->stream = NULL; } xdev->iso_init = 0; //printk("<stream; struct lsadrv_ring_buffer *ringBuffer; //DECLARE_WAITQUEUE(wait, current); unsigned char waitbuf[64]; /* sufficient size */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)) wait_queue_entry_t *wait = (wait_queue_entry_t *) waitbuf; #else wait_queue_t *wait = (wait_queue_t *) waitbuf; #endif unsigned int recSize = PacketSize + sizeof(struct lsadrv_iso_packet_desc); unsigned int bytesToRead = PacketCount * recSize; unsigned int bytesRead = 0; unsigned int ret = 0; unsigned int size = 0; // Trace(LSADRV_TRACE_READ, ">> read_iso_buffer\n"); *pBytesRead = 0; if (stream == NULL || (ringBuffer = stream->RingBuffer) == NULL) { Err("read_iso_buffer: buffer is absent\n"); return -EFAULT; } if (stream->PacketSize != PacketSize) { Err("read_iso_buffer: PacketSize mismatch\n"); return -EINVAL; } // check error status if (xdev->statusStreamStopReason != 0 || xdev->StopIsoStream || xdev->CancelIsoStream) { if (xdev->statusStreamStopReason != 0) { Info("read_iso_buffer: stop reason=%d\n", xdev->statusStreamStopReason); return xdev->statusStreamStopReason; } else { Err("read_iso_buffer: stream is stopped\n"); return -EFAULT; } } lsadrv_init_waitqueue_entry(waitbuf, sizeof(waitbuf)); lsadrv_add_wait_queue(ringBuffer->waitq, wait); lsadrv_set_current_state(TASK_INTERRUPTIBLE); while (timeout) { if (xdev->statusStreamStopReason != 0) { ret = xdev->statusStreamStopReason; break; } else if (xdev->StopIsoStream || xdev->CancelIsoStream) { Info("read_iso_buffer: stream is stopped\n"); //ret = -EFAULT; break; } else if ((size = GetRingBufferCurrentSize(ringBuffer))) { break; } timeout = lsadrv_schedule_timeout(timeout); } //Trace(LSADRV_TRACE_FLOW, "\n"); lsadrv_set_current_state(TASK_RUNNING); lsadrv_remove_wait_queue(ringBuffer->waitq, wait); if (ret) { /* error */ Info("read_iso_buffer: stop reason=%d\n", ret); } else if (size) { // read data & descriptors from ring buffer bytesRead = ReadRingBuffer(ringBuffer, dataBuffer, bytesToRead); //Trace(LSADRV_TRACE_FLOW, "R[%d]\n", bytesRead); *pBytesRead = bytesRead; Trace(LSADRV_TRACE_FLOW, "read_iso_buffer: %d bytes, frame=%d\n", bytesRead, (dataBuffer[4] | (int) dataBuffer[5] << 8)); } else { /* timedout */ Trace(LSADRV_TRACE_FLOW, "read_iso_buffer: timed out\n"); } // Trace(LSADRV_TRACE_READ, "<< read_iso_buffer\n"); return ret; }