#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);
}
return0;
}
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 completioncallbackmayhappenonthisbuffer.Butit's possiblethatitmighthavecompletedafterwenoticed itbutbeforewewipedit.Sodoublecheckitsstatus
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);
}
}
/* Query / set the nominal buffer count */ int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
{ return sp->buffer_target_count;
}
int pvr2_stream_set_buffer_count(struct pvr2_stream *sp, unsignedint cnt)
{ int ret; if (sp->buffer_target_count == cnt) return0;
mutex_lock(&sp->mutex); do {
sp->buffer_target_count = cnt;
ret = pvr2_stream_achieve_buffer_count(sp);
} while (0);
mutex_unlock(&sp->mutex); return ret;
}
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.