#ifdef SANITY_CHECK_BUFFERS #define BUFFER_CHECK(bp) do { \ if ((bp)->signature != BUFFER_SIG) { \
pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ "Buffer %p is bad at %s:%d", \
(bp), __FILE__, __LINE__); \
pvr2_buffer_describe(bp, "BadSig"); \
BUG(); \
} \
} while (0) #else #define BUFFER_CHECK(bp) do {} while (0) #endif
struct pvr2_stream { /* Buffers queued for reading */ struct list_head queued_list; unsignedint q_count; unsignedint q_bcount; /* Buffers with retrieved data */ struct list_head ready_list; unsignedint r_count; unsignedint r_bcount; /* Buffers available for use */ struct list_head idle_list; unsignedint i_count; unsignedint i_bcount; /* Pointers to all buffers */ struct pvr2_buffer **buffers; /* Array size of buffers */ unsignedint buffer_slot_count; /* Total buffers actually in circulation */ unsignedint buffer_total_count; /* Designed number of buffers to be in circulation */ unsignedint buffer_target_count; /* Executed when ready list become non-empty */
pvr2_stream_callback callback_func; void *callback_data; /* Context for transfer endpoint */ struct usb_device *dev; int endpoint; /* Overhead for mutex enforcement */
spinlock_t list_lock; struct mutex mutex; /* Tracking state for tolerating errors */ unsignedint fail_count; unsignedint fail_tolerance;
struct pvr2_buffer { int id; int signature; enum pvr2_buffer_state state; void *ptr; /* Pointer to storage area */ unsignedint max_count; /* Size of storage area */ unsignedint used_count; /* Amount of valid data in storage area */ int status; /* Transfer result status */ struct pvr2_stream *stream; struct list_head list_overhead; struct urb *purb;
};
staticconstchar *pvr2_buffer_state_decode(enum pvr2_buffer_state st)
{ switch (st) { case pvr2_buffer_state_none: return"none"; case pvr2_buffer_state_idle: return"idle"; case pvr2_buffer_state_queued: return"queued"; case pvr2_buffer_state_ready: return"ready";
} return"unknown";
}
if (sp->buffer_total_count < sp->buffer_target_count) { return pvr2_stream_buffer_count(sp, sp->buffer_target_count);
}
cnt = 0; while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) {
bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; if (bp->state != pvr2_buffer_state_idle) break;
cnt++;
} if (cnt) {
pvr2_stream_buffer_count(sp, sp->buffer_total_count - cnt);
}
return 0;
}
staticvoid pvr2_stream_internal_flush(struct pvr2_stream *sp)
{ struct list_head *lp; struct pvr2_buffer *bp1; while ((lp = sp->queued_list.next) != &sp->queued_list) {
bp1 = list_entry(lp, struct pvr2_buffer, list_overhead);
pvr2_buffer_wipe(bp1); /* At this point, we should be guaranteed that no completion callback may happen on this buffer. But it's possible that it might have completed after we noticed it but before we wiped it. So double check its status
here first. */ if (bp1->state != pvr2_buffer_state_queued) continue;
pvr2_buffer_set_idle(bp1);
} if (sp->buffer_total_count != sp->buffer_target_count) {
pvr2_stream_achieve_buffer_count(sp);
}
}
struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp, int id)
{ if (id < 0) return NULL; if (id >= sp->buffer_total_count) return NULL; return sp->buffers[id];
}
int pvr2_stream_get_ready_count(struct pvr2_stream *sp)
{ return sp->r_count;
}
void pvr2_stream_kill(struct pvr2_stream *sp)
{ struct pvr2_buffer *bp;
mutex_lock(&sp->mutex); do {
pvr2_stream_internal_flush(sp); while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) {
pvr2_buffer_set_idle(bp);
} if (sp->buffer_total_count != sp->buffer_target_count) {
pvr2_stream_achieve_buffer_count(sp);
}
} while (0);
mutex_unlock(&sp->mutex);
}
int pvr2_buffer_queue(struct pvr2_buffer *bp)
{ #undef SEED_BUFFER #ifdef SEED_BUFFER unsignedint idx; unsignedint val; #endif int ret = 0; struct pvr2_stream *sp; if (!bp) return -EINVAL;
sp = bp->stream;
mutex_lock(&sp->mutex); do {
pvr2_buffer_wipe(bp); if (!sp->dev) {
ret = -EIO; break;
}
pvr2_buffer_set_queued(bp); #ifdef SEED_BUFFER for (idx = 0; idx < (bp->max_count) / 4; idx++) {
val = bp->id << 24;
val |= idx;
((unsignedint *)(bp->ptr))[idx] = val;
} #endif
bp->status = -EINPROGRESS;
usb_fill_bulk_urb(bp->purb, // struct urb *urb
sp->dev, // struct usb_device *dev // endpoint (below)
usb_rcvbulkpipe(sp->dev, sp->endpoint),
bp->ptr, // void *transfer_buffer
bp->max_count, // int buffer_length
buffer_complete,
bp);
usb_submit_urb(bp->purb, GFP_KERNEL);
} while (0);
mutex_unlock(&sp->mutex); return ret;
}
int pvr2_buffer_set_buffer(struct pvr2_buffer *bp, void *ptr, unsignedint cnt)
{ int ret = 0; unsignedlong irq_flags; struct pvr2_stream *sp; if (!bp) return -EINVAL;
sp = bp->stream;
mutex_lock(&sp->mutex); do {
spin_lock_irqsave(&sp->list_lock, irq_flags); if (bp->state != pvr2_buffer_state_idle) {
ret = -EPERM;
} else {
bp->ptr = ptr;
bp->stream->i_bcount -= bp->max_count;
bp->max_count = cnt;
bp->stream->i_bcount += bp->max_count;
pvr2_trace(PVR2_TRACE_BUF_FLOW, "/*---TRACE_FLOW---*/ bufferPool %8s cap cap=%07d cnt=%02d",
pvr2_buffer_state_decode(
pvr2_buffer_state_idle),
bp->stream->i_bcount, bp->stream->i_count);
}
spin_unlock_irqrestore(&sp->list_lock, irq_flags);
} while (0);
mutex_unlock(&sp->mutex); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.