diff -ur ivtv-cvs/driver/ivtv-api.c ivtv/driver/ivtv-api.c --- ivtv-cvs/driver/ivtv-api.c 2003-10-24 08:17:00.000000000 +0200 +++ ivtv/driver/ivtv-api.c 2003-10-27 14:16:03.000000000 +0100 @@ -468,7 +468,7 @@ /* 3 stream types: mpeg, yuv, passthru */ struct ivtv_v4l2_stream tmk_mpg_stream = { /*MPEG*/ - .capturing = 0, + .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { @@ -488,7 +488,7 @@ struct ivtv_v4l2_stream tmk_yuv_stream = { /*YUV*/ - .capturing = 0, + .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { @@ -508,7 +508,7 @@ //FIXME these settings are way wrong struct ivtv_v4l2_stream tmk_vbi_stream = { - .capturing = 0, + .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_VBI, .format = { @@ -528,7 +528,7 @@ struct ivtv_v4l2_stream dec_mpg_stream = { /*Decoder MPG*/ - .capturing = 0, + .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { @@ -548,7 +548,7 @@ struct ivtv_v4l2_stream dec_yuv_stream = { /*Decoder YUV*/ - .capturing = 0, + .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { @@ -750,7 +750,8 @@ /* Set poll for decoder parts */ itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev.fops->poll = ivtv_dec_poll; - itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev.fops->poll = ivtv_dec_poll; + if (itv->options.dec_yuv_buffers) + itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev.fops->poll = ivtv_dec_poll; break; case IVTV_250_V2: @@ -760,9 +761,6 @@ break; } - /* setup semaphore */ - sema_init(&itv->v4l2.v4l2_lock, 1); - /* pre-init */ retval = ivtv_v4l2_pre_init(itv); if (retval < 0) { @@ -841,7 +839,7 @@ data[0] = 0; /* 0 = pause, 1 = unpause */ if (cmd) data[0] = 1; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_PAUSE_ENCODER, + x = ivtv_api(itv->enc_mbox, &itv->sem_lock, IVTV_API_PAUSE_ENCODER, &result,1, &data[0]); return result; } @@ -1000,6 +998,9 @@ int type,subtype; unsigned int dig; + /* sem_lock must be held */ + IVTV_ASSERT(sem_getcount(&itv->sem_lock) >= 1); + IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv start v4l2 stream\n"); /* NTSC/PAL switching */ @@ -1020,9 +1021,6 @@ break; } - /* FIXME i'm wrapping the whole start-cap in a semaphore */ - down_interruptible(&itv->enc_sem_adm); - /* clear queues */ ivtv_move_queue(&itv->v4l2.streams[id->type].full_q, &itv->v4l2.streams[id->type].free_q); @@ -1040,46 +1038,45 @@ /* FIXME this needs a flag */ data[0] = 1; /* num bytes in block*/ data[1] = 1; /* use info from sg instead */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_DMA_BLOCKLEN, - &result, 2, &data[0]); + x = __ivtv_api(itv->enc_mbox,IVTV_API_ASSIGN_DMA_BLOCKLEN, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 1. Code %d\n",x); /*assign program index info */ /* FIXME need more info on this call */ data[0] = 0; /*Mask 0:Disable */ data[1] = 0; /*Num_req 0:??/ */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_PGM_INDEX_INFO, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_PGM_INDEX_INFO, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 2. Code %d\n",x); /*assign stream type */ data[0] = itv->v4l2.codec.stream_type; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_STREAM_TYPE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_STREAM_TYPE, &result,1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 3. Code %d\n",x); /*assign output port */ data[0] = 0; /*0:Memory */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_OUTPUT_PORT, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_OUTPUT_PORT, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 4. Code %d\n",x); /*assign framerate */ data[0] = itv->v4l2.codec.framerate; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_FRAMERATE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_FRAMERATE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 5. Code %d\n",x); /*assign frame size */ data[0] = vsize; /* height*/ data[1] = hsize; /* width */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_FRAME_SIZE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_FRAME_SIZE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 6. Code %d\n",x); /*assign aspect ratio */ data[0] = itv->v4l2.codec.aspect; /*mpeg spec sez 2 */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_ASPECT_RATIO, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_ASPECT_RATIO, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 7. Code %d\n",x); @@ -1090,46 +1087,46 @@ data[2] = itv->v4l2.codec.bitrate_peak / 400; /* peak/400 */ data[3] = 0; /*??? */ data[4] = 0x70; /*??? */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_BITRATES, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_BITRATES, &result, 5, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 8. Code %d\n",x); /*assign gop properties */ data[0] = itv->v4l2.codec.framespergop; data[1] = itv->v4l2.codec.bframes; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_GOP_PROPERTIES, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_GOP_PROPERTIES, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 9. Code %d\n",x); /*assign 3 2 pulldown */ data[0] = itv->v4l2.codec.pulldown; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_3_2_PULLDOWN, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_3_2_PULLDOWN, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 10. Code %d\n",x); /*assign gop closure */ data[0] = itv->v4l2.codec.gop_closure; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_GOP_CLOSURE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_GOP_CLOSURE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 11. Code %d\n",x); /*assign audio properties */ data[0] = itv->v4l2.codec.audio_bitmap; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_AUDIO_PROPERTIES, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_AUDIO_PROPERTIES, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 12. Code %d\n",x); /*assign dnr filter mode */ data[0] = itv->v4l2.codec.dnr_mode; data[1] = itv->v4l2.codec.dnr_type; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_DNR_FILTER_MODE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_DNR_FILTER_MODE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 13. Code %d\n",x); /*assign dnr filter props*/ data[0] = itv->v4l2.codec.dnr_spatial; data[1] = itv->v4l2.codec.dnr_temporal; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_DNR_FILTER_PROPS, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_DNR_FILTER_PROPS, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 14. Code %d\n",x); @@ -1138,20 +1135,20 @@ data[1] = 255; /*luma_l */ data[2] = 0; /*chroma_h */ data[3] = 255; /*chroma_l */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_CORING_LEVELS, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_CORING_LEVELS, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 15. Code %d\n",x); /*assign spatial filter type */ data[0] = 1; /*luma_t: 1 = horiz_only */ data[1] = 1; /*chroma_t: 1 = horiz_only */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 16. Code %d\n",x); /*assign frame drop rate */ data[0] = 0; - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_FRAME_DROP_RATE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_FRAME_DROP_RATE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 17. Code %d\n",x); @@ -1168,14 +1165,14 @@ data[9] = 0; /*arg6 */ data[10] = 0; /*arg7 */ data[11] = 0; /*arg8 */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_PLACEHOLDER, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_PLACEHOLDER, &result, 12, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 18. Code %d\n\n",x); /* assign num vsync lines */ data[0] = vsync; /*??? */ data[1] = vsync; /* ??? */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_ASSIGN_NUM_VSYNC_LINES, + x = __ivtv_api(itv->enc_mbox, IVTV_API_ASSIGN_NUM_VSYNC_LINES, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 20. Code %d\n",x); @@ -1194,7 +1191,7 @@ data[1] = 1; /*on/off: 1 = on */ data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */ data[3] = -1; /*mbox_id: -1: none */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, + x = __ivtv_api(itv->enc_mbox, IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 2. Code %d\n",x); @@ -1205,7 +1202,7 @@ DECODER_ENABLE_OUTPUT,&dig); /*initialize input (no args) */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, + x = __ivtv_api(itv->enc_mbox, IVTV_API_INITIALIZE_INPUT, &result, 0, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 19. Code %d\n\n",x); @@ -1217,7 +1214,7 @@ IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 100ms\n"); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.1*HZ); + schedule_timeout(HZ/10); } itv->graceful_eos = 0; @@ -1225,7 +1222,7 @@ /* begin_capture */ data[0] = type; /*type: 0 = mpeg */ data[1] = subtype; /*subtype: 3 = video+audio */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_BEGIN_CAPTURE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_BEGIN_CAPTURE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 1. Code %d\n",x); @@ -1238,7 +1235,6 @@ /*you're live! sit back and await interrupts :)*/ atomic_inc(&itv->capturing); - up(&itv->enc_sem_adm); return 0; } @@ -1251,7 +1247,7 @@ data[4] = mute_audio; data[5] = display_fields; - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, IVTV_API_DEC_PLAYBACK_SPEED, &result, 6, &data[0]); + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_PLAYBACK_SPEED, &result, 6, &data[0]); return result; } @@ -1263,12 +1259,11 @@ int type; int standard=0; + /* sem_lock must be held */ + IVTV_ASSERT(sem_getcount(&itv->sem_lock) >= 1); type = id->type; - /* FIXME wrong semaphore */ - down_interruptible(&itv->dec_sem_adm); - if (itv->v4l2.standard.active != 0) { /* if not NTSC */ standard = 1; /* PAL */ } @@ -1297,23 +1292,26 @@ /* set display standard */ data[0] = standard; /* 0 = NTSC, 1 = PAL */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_DISP_STANDARD, + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_DISP_STANDARD, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET DISPLAY STD %d\n",x); /* set audio mode */ data[0] = 0; /* Dual mono-mode action: ??? */ data[1] = 0; /* stereo mode action: 0=stereo, 1=left, 2=right, 3=mono */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_SELECT_AUDIO, + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_SELECT_AUDIO, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET AUDIO MODE %d\n",x); /* set decoder source settings */ data[0] = id->type; /* Data type: 0 = mpeg from host, 1 = yuv from encoder, 2 = yuv_from_host */ data[1] = 720; /* YUV source width*/ - data[2] = 480; /* YUV source height*/ + if (itv->v4l2.standard.active == 1) + data[2] = 576; /* YUV source height*/ + else + data[2] = 480; /* YUV source height*/ data[3] = itv->v4l2.codec.audio_bitmap; /* Audio settings to use, bitmap. see docs.*/ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_DECODE_SOURCE, + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_DECODE_SOURCE, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE DECODER SOURCE %d\n",x); @@ -1323,40 +1321,36 @@ data[1] = 1; /* Enable/Disable: 0 = disabled, 1 = enabled */ data[2] = 0x00010000; /* Bit: interrupt bit to fire */ data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_EVENT_NOTIFICATION, + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE EVENT NOTIFICATION %d\n",x); #endif /* set number of internal decoder buffers */ data[0] = 1; /* 0 = 6 buffers, 1 = 9 buffers */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_DISPLAY_BUFFERS, + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_DISPLAY_BUFFERS, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE # OF DISPLAY BUFFERS %d\n",x); /* prebufferring*/ data[0] = 1; /* 0 = no prebuffering, 1 = enabled, see docs */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_BUFFER, - &result, 1, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_BUFFER, &result, 1,&data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE BUFFER %d\n",x); #if 0 /* set stream input port */ data[0] = 0; /* 0 = memory, 1 = streaming */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_STREAM_INPUT, - &result, 1, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_STREAM_INPUT, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE STREAM INPUT %d\n",x); /* A/V sync delay */ data[0] = 0; /* Delay in 90khz ticks. 0 = synced, negative = audio lags, positive = video lags */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_SET_AV_DELAY, - &result, 1, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_SET_AV_DELAY, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE Audio/Vid sync delay %d\n",x); #endif /* start playback */ data[0] = itv->dec_options.gop_offset; /* frame to start from (in GOP) */ data[1] = itv->dec_options.mute_frames; /* # of audio frames to mute */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_START_PLAYBACK, - &result, 2, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T START PLAYBACK %d\n",x); if (atomic_read(&itv->decoding) == 0) @@ -1369,14 +1363,7 @@ /*you're live! sit back and await interrupts :)*/ atomic_inc(&itv->decoding); - - /* FIXME wrong semaphore still */ - up(&itv->dec_sem_adm); - - /* start thread */ - ivtv_start_decode(itv); - - return 0; + return 0; } void ivtv_v4l2_cleanup(struct ivtv *itv) { @@ -1443,14 +1430,15 @@ INIT_LIST_HEAD(&item->list); - if (down_interruptible(&item->itv->enc_sem_adm)) { + if (down_interruptible(&item->itv->sem_lock)) { kfree(item); return -ERESTARTSYS; } item->open_id = item->itv->open_id++; - up(&item->itv->enc_sem_adm); list_add_tail (&item->list, &item->itv->client_list); + + up(&item->itv->sem_lock); filp->private_data = item; @@ -1471,16 +1459,16 @@ IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read\n"); - if (down_interruptible(&id->itv->v4l2.v4l2_lock)) + if (down_interruptible(&id->itv->sem_lock)) return -ERESTARTSYS; //FIXME need to handle non-blocking io //FIXME needs locking //FIXME this can be collapsed into 1 var i think - if ((id->itv->v4l2.streams[id->type].capturing == 0) && + if (!test_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags) && (id->itv->v4l2.streams[id->type].id == -1)) { - id->itv->v4l2.streams[id->type].capturing = 1; + set_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags); id->itv->v4l2.streams[id->type].id = id->open_id; ret = ivtv_start_v4l2_stream(id); @@ -1489,13 +1477,12 @@ "Error in v4l2 stream init\n"); id->itv->v4l2.streams[id->type].seq = 0; id->itv->v4l2.streams[id->type].ubytes= 0; - up(&id->itv->v4l2.v4l2_lock); } else { if (id->open_id != id->itv->v4l2.streams[id->type].id) ret = -EBUSY; } - up(&id->itv->v4l2.v4l2_lock); + up(&id->itv->sem_lock); if (ret) return ret; @@ -1521,15 +1508,14 @@ (id->type != IVTV_DEC_STREAM_TYPE_YUV)) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Write on read-only interface\n"); return -EINVAL; - } + } - if (down_interruptible(&id->itv->v4l2.v4l2_lock)) + if (down_interruptible(&id->itv->sem_lock)) return -ERESTARTSYS; // Initialize Decoder /* FIXME we'll need to make this its own stream type */ - if(id->itv->v4l2.streams[id->type].capturing == 0) { - id->itv->v4l2.streams[id->type].capturing = 1; + if (!test_and_set_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags)) { id->itv->v4l2.streams[id->type].id = id->open_id; ret = ivtv_start_v4l2_decode(id); } else { @@ -1537,7 +1523,7 @@ ret = -EBUSY; } - up(&id->itv->v4l2.v4l2_lock); + up(&id->itv->sem_lock); if (ret) return ret; @@ -1556,19 +1542,20 @@ return -ENODEV; } + if (down_interruptible(&id->itv->sem_lock)) + return -ERESTARTSYS; + if (id->open_id == id->itv->v4l2.streams[id->type].id) { ivtv_close(id); - if (down_interruptible(&id->itv->v4l2.v4l2_lock)) - return -ERESTARTSYS; - - id->itv->v4l2.streams[id->type].capturing = 0; + clear_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags); id->itv->v4l2.streams[id->type].id = -1; - up(&id->itv->v4l2.v4l2_lock); } list_del(&id->list); + up(&id->itv->sem_lock); + kfree(id); return 0; @@ -1636,11 +1623,10 @@ break; } case IVTV_IOC_GET_FB: { - if (itv->fb_id >= 0) { - copy_to_user((int*)arg, &itv->fb_id, sizeof(itv->fb_id)); - } else { + if (itv->fb_id < 0) return -EINVAL; - } + if (copy_to_user((int*)arg, &itv->fb_id, sizeof(itv->fb_id))) + return -EFAULT; break; } @@ -1654,12 +1640,12 @@ sizeof(struct ivtv_ioctl_fwapi)); /* Encoder - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, fwapi.cmd, + x = ivtv_api(itv->enc_mbox, &itv->sem_lock, fwapi.cmd, &fwapi.result, fwapi.args, &fwapi.data[0]); */ /* Decoder */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, fwapi.cmd, + x = ivtv_api(itv->dec_mbox, &itv->sem_lock, fwapi.cmd, &fwapi.result, fwapi.args, &fwapi.data[0]); memcpy((struct ivtv_ioctl_fwapi *) arg, &fwapi, sizeof(struct ivtv_ioctl_fwapi)); @@ -1684,7 +1670,7 @@ u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = 0; /* 0-based frame # to start from (in GOP) */ data[1] = 0; /* # of audio frames to mute */ - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_w, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0])) IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error starting playback\n"); @@ -1749,7 +1735,7 @@ data[6] = itv->dec_options.sf_mute; /* # of frames to mute on normal speed resume */ - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_PLAYBACK_SPEED, &result, 7, &data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error in slow/fast mode\n"); @@ -1760,7 +1746,7 @@ case IVTV_IOC_PAUSE: { u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = 0; - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_PAUSE_PLAYBACK, &result, 1, &data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error pausing\n"); diff -ur ivtv-cvs/driver/ivtv-driver.c ivtv/driver/ivtv-driver.c --- ivtv-cvs/driver/ivtv-driver.c 2003-10-24 08:17:00.000000000 +0200 +++ ivtv/driver/ivtv-driver.c 2003-10-27 14:14:48.000000000 +0100 @@ -68,7 +68,7 @@ | IVTV_DEBUG_DMA | IVTV_DEBUG_IOCTL | IVTV_DEBUG_I2C | IVTV_DEBUG_IRQ ); #endif -int debug = 1; +int debug = IVTV_DEBUG_ERR; /* tuner.h tuner type for ivtv card */ int tuner = -1; @@ -127,6 +127,16 @@ int SGarray_size = 0; int DSGarray_size = 0; +void ivtv_sleep_timeout(int timeout) +{ + int sleep = timeout; + + do { + set_current_state(TASK_UNINTERRUPTIBLE); + sleep = schedule_timeout(sleep); + } while (sleep); +} + /* ceiling function for ints.. */ int ivtv_ceil(int x, int y) { int floor = (int)(x/y); @@ -440,28 +450,26 @@ data[0] = 1; /* 0: render last frame, 1: stop NOW! :) */ data[1] = 0; /* "low 4 bytes of stop index" */ data[2] = 0; /* 0: stop immedeately */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, IVTV_API_DEC_STOP_PLAYBACK, + x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_STOP_PLAYBACK, &result, 3, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 2. Code %d\n",x); /*halt enc firmware */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_adm, IVTV_API_ENC_HALT_FW, + x = ivtv_api(itv->enc_mbox, &itv->sem_lock, IVTV_API_ENC_HALT_FW, &result, 0, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 3. Code %d\n",x); IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); + ivtv_sleep_timeout(HZ/100); /*halt dec firmware */ if (IVTV_250_V2 != itv->card_type) { - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, IVTV_API_DEC_HALT_FW, + x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_HALT_FW, &result, 0, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 4. Code %d\n",x); IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.01*HZ); + ivtv_sleep_timeout(HZ/100); } return 0; @@ -505,8 +513,7 @@ writel(IVTV_CMD_SPU_STOP, (IVTV_REG_SPU + itv->reg_mem)); IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.01*HZ); + ivtv_sleep_timeout(HZ/100); IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM pre-charge\n"); writel(IVTV_CMD_SDRAM_PRECHARGE_INIT, @@ -524,9 +531,8 @@ writel(IVTV_CMD_SDRAM_REFRESH_INIT, (IVTV_REG_DEC_SDRAM_REFRESH + itv->reg_mem)); - IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for %dms (600 recommended)\n",(int)IVTV_SDRAM_SLEEPTIME*HZ); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(IVTV_SDRAM_SLEEPTIME*HZ); + IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for %dms (600 recommended)\n",(int)IVTV_SDRAM_SLEEPTIME); + ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME); IVTV_DEBUG(IVTV_DEBUG_INFO, "Card ready for firmware!\n"); x = ivtv_firmware_copy(itv); @@ -540,8 +546,7 @@ (IVTV_REG_SPU+itv->reg_mem)); IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ivtv_sleep_timeout(HZ); /*I guess this is read-modify-write :)*/ if (IVTV_250_V2 == itv->card_type) { @@ -554,8 +559,7 @@ } IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); + ivtv_sleep_timeout(HZ); /* FIXME Send Status API commands to encoder and decoder to verify!*/ @@ -666,7 +670,7 @@ int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox, struct semaphore* sem) { int mboxid; - + if (down_interruptible(sem)) return -ERESTARTSYS; mboxid = __ivtv_get_free_mailbox(mbox); up(sem); @@ -740,18 +744,19 @@ return -ENODEV; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.01*HZ); + ivtv_sleep_timeout(HZ/100); readdata = readl(&mbox->flags); while (!(readdata & IVTV_MBOX_FIRMWARE_DONE)) { /*FIXME this is a bad method*/ IVTV_DEBUG(IVTV_DEBUG_API, "[%d]mailbox not ready, sleeping for 10ms\n", count); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.01*HZ); + ivtv_sleep_timeout(HZ/100); readdata = readl(&mbox->flags); /*will this work? heh hope so */ - if (count++ > 100) return -EBUSY; + if (count++ > 100) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "timed out waiting for firmware\n"); + return -EBUSY; + } } if (down_interruptible(sem)) @@ -770,8 +775,11 @@ int count = 0; while (!(readdata = readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { - yield(); - if (count++ > 100) return -EBUSY; + ivtv_sleep_timeout(1); + if (count++ > 100) { + IVTV_DEBUG(IVTV_DEBUG_ERR, "timedout waiting for firmware\n"); + return -EBUSY; + } } *result = readl(&mbox->retval); @@ -854,7 +862,7 @@ /* Encoder */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting encoder firmware rev.\n"); - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_r, IVTV_API_ENC_GETVER, + x = ivtv_api(itv->enc_mbox, &itv->sem_lock, IVTV_API_ENC_GETVER, &result, 0, &data[0]); if (x) { IVTV_DEBUG(IVTV_DEBUG_ERR, @@ -868,7 +876,7 @@ if (itv->card_type != IVTV_250_V2) { /* Decoder */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting decoder firmware rev.\n"); - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_DEC_GETVER, + x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_GETVER, &result, 0, &data[0]); if (x) { IVTV_DEBUG(IVTV_DEBUG_ERR, @@ -889,25 +897,29 @@ int x; id.itv = itv; - down(&itv->v4l2.v4l2_lock); + down(&itv->sem_lock); for (x = 0; x < itv->v4l2.streamcount;x++) { - if (itv->v4l2.streams[x].capturing==1) { + if (test_bit(IVTV_F_S_CAP, &itv->v4l2.streams[x].s_flags)) { id.type=x; ivtv_stop_capture(&id); } } - up(&itv->v4l2.v4l2_lock); + up(&itv->sem_lock); return 0; } int ivtv_stop_capture(struct ivtv_open_id *id) { struct ivtv *itv=id->itv; u32 data[IVTV_MBOX_MAX_DATA], result; + DECLARE_WAITQUEUE(wait, current); int type,subtype; int x; + /* sem_lock must be held */ + IVTV_ASSERT(sem_getcount(&itv->sem_lock) >= 1); + /* FIXME set 'die' ?? */ type = id->type; @@ -924,7 +936,7 @@ data[1] = 0; /*on/off: 0 = off */ data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */ data[3] = -1; /*mbox_id: -1: none */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_EVENT_NOTIFICATION, + x = __ivtv_api(itv->enc_mbox, IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 1. Code %d\n",x); @@ -934,18 +946,20 @@ data[0] = 0; /*when: 0 = end of GOP */ data[1] = type; /*type: 0 = mpeg */ data[2] = subtype; /*subtype: 3 = video+audio */ - x = ivtv_api(itv->enc_mbox, &itv->enc_sem_w, IVTV_API_END_CAPTURE, + x = __ivtv_api(itv->enc_mbox, IVTV_API_END_CAPTURE, &result, 3, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 2. Code %d\n",x); /* check if DMA is pending */ - if (itv->v4l2.streams[type].dma_pending) + if (test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags)) IVTV_DEBUG(IVTV_DEBUG_ERR, "dma still pending! stopping anyway.\n"); + add_wait_queue(&itv->cap_w, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); /* only run these if we're shutting down the last cap */ if (atomic_read(&itv->capturing) == 0) { /* wait 1s for EOS interrupt */ - sleep_on_timeout(&itv->cap_w, 1*HZ); + ivtv_sleep_timeout(HZ); if (0==itv->graceful_eos) IVTV_DEBUG(IVTV_DEBUG_ERR, @@ -956,7 +970,8 @@ writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK)); IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n", itv->irqmask); } - + set_current_state(TASK_RUNNING); + remove_wait_queue(&itv->cap_w, &wait); return 0; } @@ -966,12 +981,15 @@ struct ivtv_buffer *buf; int x; + /* sem_lock must be held */ + IVTV_ASSERT(sem_getcount(&itv->sem_lock) >= 1); + /* FIXME set 'die' ?? */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder stop.\n"); /* stop decoder interrupt timeout */ - del_timer_sync(&itv->dec_timeout); + del_timer_sync(&itv->dec_timeout); /* only run these if we're shutting down the last cap */ if (atomic_read(&itv->decoding) == 0) { @@ -980,16 +998,14 @@ data[1] = 0; /* Enable/Disable: 0 = disabled, 1 = enabled */ data[2] = 0x00010000; /* Bit: interrupt bit to fire */ data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, - IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 1. Code %d\n",x); /* end_capture */ data[0] = itv->dec_options.hide_last_frame; /* 0 = last frame, 1 = black */ data[1] = itv->dec_options.pts_low; /* when: pts low */ data[2] = itv->dec_options.pts_hi; /* when: pts hi */ - x = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_DEC_STOP_PLAYBACK, - &result, 3, &data[0]); + x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_STOP_PLAYBACK, &result, 3, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 2. Code %d\n",x); } @@ -1018,36 +1034,29 @@ ivtv_enq_buf(&itv->v4l2.streams[id->type].free_q, buf); } - if (itv->v4l2.streams[id->type].dma_pending) { + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[id->type].s_flags)) IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: clearing dma_pending\n"); - itv->v4l2.streams[id->type].dma_pending = 0; - } return 0; } -void ivtv_start_decode(struct ivtv *itv) { - return; -} - void ivtv_dec_timeout(unsigned long arg) { struct ivtv *itv = (struct ivtv *)arg; /* FIXME mpg only :/ */ struct ivtv_v4l2_stream *stream = &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG]; - if (!stream->dma_pending) - return; - - IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: lost IRQ; resetting...\n"); + if (!test_bit(IVTV_F_S_DMAP, &stream->s_flags)) + return; + IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: lost IRQ; resetting...\n"); #if 1 - ivtv_dec_DMA_done(itv); - /* kick it off again! */ - itv->dec_needs_data = 1; - ivtv_dec_sched_DMA(itv); + ivtv_dec_DMA_done(itv); + /* kick it off again! */ + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); + ivtv_dec_sched_DMA(itv); #endif - IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: returning...\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: returning...\n"); } static void ivtv_show_irq_status(struct ivtv* itv, u32 irqstat, u32 irqmask, u32 dmastat) { @@ -1131,11 +1140,19 @@ writel(combo, (itv->reg_mem + IVTV_REG_IRQSTATUS)); if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { - ivtv_DMA_done_tasklet((unsigned long)itv); +#if 0 + tasklet_schedule(&itv->dma_done_tq); +#else + ivtv_DMA_done_tasklet((unsigned long) itv); +#endif IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed DMA-complete\n"); } if (combo & IVTV_IRQ_ENC_START_CAP) { - ivtv_sched_DMA_tasklet((unsigned long)itv); +#if 0 + tasklet_schedule(&itv->dma_sched_tq); +#else + ivtv_sched_DMA_tasklet((unsigned long) itv); +#endif IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed enc-startcap\n"); } if (combo & IVTV_IRQ_ENC_EOS) { @@ -1160,7 +1177,7 @@ } if (combo & IVTV_IRQ_DEC_DATA_REQ) { IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder Data Request\n"); - itv->dec_needs_data = 1; + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); ivtv_dec_sched_DMA(itv); } if (combo & IVTV_IRQ_DEC_IFRAME_DONE) { @@ -1216,9 +1233,8 @@ IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet\n"); for (y=0; y < itv->v4l2.streamcount; y++) { - if (itv->v4l2.streams[y].dma_pending) { + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) { stmtype = y; - itv->v4l2.streams[y].dma_pending = 0; break; } } @@ -1231,14 +1247,13 @@ stream = &itv->v4l2.streams[y]; /* Silently return if we're in an overflow state */ - if (stream->overflow) { - stream->overflow = 0; + if (test_and_clear_bit(IVTV_F_S_OVERFLOW, &stream->s_flags)) return; - } /* check DMA status register */ result = readl(itv->reg_mem + IVTV_REG_DMASTATUS); + if (result & IVTV_DMA_WRITE_ERR) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA Error. Result: 0x%08x\n", result); return; @@ -1246,7 +1261,7 @@ if (0 == (result & IVTV_DMA_SUCCESS)) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA interrupt, but no err and no " - "success. odd.\n"); + "success. odd %x.\n", result); return; } @@ -1269,24 +1284,25 @@ /*wake up client*/ wake_up(&stream->waitq); - - return; } int ivtv_ignore_DMA_req(struct ivtv *itv, u32 type) { u32 data[IVTV_MBOX_MAX_DATA], result; + /* set these now, irq could happen right after ivtv_api call */ + set_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags); + set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags); + data[0] = type; data[0] = 0; data[1] = 0; /* ACK the DMA and continue */ - if (ivtv_api(itv->enc_mbox, &itv->enc_sem_w, - IVTV_API_SCHED_DMA_TO_HOST, &result, 2, &data[0])) { + if (ivtv_api_irqsafe(itv->enc_mbox, IVTV_API_SCHED_DMA_TO_HOST, 3, &data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "error sending DMA info\n"); + clear_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags); + clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags); return -EIO; } - itv->v4l2.streams[type].overflow = 1; - itv->v4l2.streams[type].dma_pending = 1; return 0; } @@ -1296,9 +1312,10 @@ u32 data[IVTV_MBOX_MAX_DATA], result; u32 type, size, offset; u32 UVsize=0, UVoffset=0, pts_stamp=0; - int x, bufs_needed, free; + int x, bufs_needed; int uvflag=0; struct ivtv *itv = (struct ivtv *) arg; + long sequence; IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched DMA tasklet\n"); @@ -1350,7 +1367,6 @@ bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE); ivtv_ignore_DMA_req(itv, type); return; - break; case 3: /* VBI */ offset = data[1]; size = data[2]; @@ -1364,25 +1380,6 @@ "DMA/UNKNOWN type 0x%08x, NOT SUPPORTED\n", type); ivtv_ignore_DMA_req(itv, type); return; - break; - } - - free = ivtv_get_free_elements(&itv->v4l2.streams[type].free_q); - /* increment the sequence # */ - itv->v4l2.streams[type].seq++; - - IVTV_DEBUG(IVTV_DEBUG_INFO,"bufs_needed: %d, free: %d\n", bufs_needed, free); - - if (free < bufs_needed) { - IVTV_DEBUG(IVTV_DEBUG_ERR, "Not enough free buffers, stream %d\n", - type); - printk(KERN_DEBUG "(fullq: %d, freeq: %d, dmaq: %d)\n", - itv->v4l2.streams[type].full_q.elements, - free, - itv->v4l2.streams[type].dma_q.elements); - - ivtv_ignore_DMA_req(itv, type); - return; } if (bufs_needed > SGarray_size) { @@ -1392,6 +1389,9 @@ return; } + /* increment the sequence # */ + sequence = ++itv->v4l2.streams[type].seq; + for (x = 0; x < bufs_needed; x++) { struct ivtv_buffer *buf; IVTV_DEBUG(IVTV_DEBUG_INFO, "size: %d 0x%08x\n", size, size); @@ -1405,14 +1405,14 @@ buf = ivtv_deq_buf(&itv->v4l2.streams[type].free_q); if (NULL == buf) { - IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA buffer DeQueue failed!\n"); + IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA buffer DeQueue failed! got %d, want %d\n", x + 1, bufs_needed); ivtv_ignore_DMA_req(itv, type); return; } buf->readpos = 0; buf->buffer.index = x; - buf->buffer.sequence = itv->v4l2.streams[type].seq; + buf->buffer.sequence = sequence; if (size < (IVTV_DMA_BUF_SIZE & 0xffffff00)) { buf->buffer.bytesused = size; @@ -1430,7 +1430,9 @@ itv->SGarray[x].src = offset; offset += buf->buffer.bytesused; - /* FIXME no error checking on pci_map */ + /* unfortunately the pci dma api wasn't properly defined + * for handling mapping errors (running out of iommu space, + * for instance). 0 can be a valid bus address. */ buf->dma_handle = pci_map_single(itv->dev, (void *)buf->buffer.m.userptr, buf->buffer.bytesused, @@ -1463,11 +1465,8 @@ IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched dma: addr: 0x%08x, array_size 0x%08x," " type 0x%08x\n", data[0], data[1], data[2]); + set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags); ivtv_api_irqsafe(itv->enc_mbox, IVTV_API_SCHED_DMA_TO_HOST, 4, &data[0]); - - itv->v4l2.streams[type].dma_pending = 1; - - return; } /* FIXME this function does way more than it should */ @@ -1528,21 +1527,15 @@ break; } - sema_init(&itv->enc_sem_r, 1); - sema_init(&itv->enc_sem_w, 1); - sema_init(&itv->enc_sem_adm, 1); - sema_init(&itv->dec_sem_r, 1); - sema_init(&itv->dec_sem_w, 1); - sema_init(&itv->dec_sem_adm, 1); - sema_init(&itv->dec_sched_dma_sem, 1); + init_MUTEX(&itv->sem_lock); itv->base_addr=pci_resource_start(dev,0); itv->enc_mbox = NULL; itv->dec_mbox = NULL; itv->io_mem = NULL; itv->reg_mem = NULL; + itv->i_flags = 0; atomic_set(&itv->capturing, 0); atomic_set(&itv->decoding, 0); - itv->dec_dma_pending = 0; itv->user_dma_to_device_state = NULL; /* Prepare list for action! */ @@ -1556,6 +1549,9 @@ itv->dec_timeout.function = ivtv_dec_timeout; itv->dec_timeout.data = (unsigned long)itv; + tasklet_init(&itv->dma_done_tq, ivtv_DMA_done_tasklet, (unsigned long) itv); + tasklet_init(&itv->dma_sched_tq, ivtv_sched_DMA_tasklet, (unsigned long) itv); + IVTV_DEBUG(IVTV_DEBUG_INFO, "base addr: 0x%08x\n", itv->base_addr); IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling pci device\n"); @@ -1742,7 +1738,7 @@ IVTV_DEBUG(IVTV_DEBUG_ERR, "Problem starting v4l2\n"); goto ivtv_v4l2_fail; } - + return 0; ivtv_v4l2_fail: @@ -1781,8 +1777,7 @@ writel(itv->irqmask, (itv->reg_mem + IVTV_REG_IRQMASK)); IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping thread\n"); - atomic_set(&itv->decoding, 0); - + atomic_set(&itv->decoding, 0); IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping card parts\n"); x = ivtv_stop_firmware(itv); @@ -1932,6 +1927,7 @@ unsigned long tid; struct ivtv_buffer *buf; struct ivtv_v4l2_stream *st=&itv->v4l2.streams[id->type]; + DECLARE_WAITQUEUE(wait, current); IVTV_DEBUG(IVTV_DEBUG_INFO, " Read stream.. \n"); @@ -1941,30 +1937,36 @@ return -EIO; } - sleepctr = 0; - /* FIXME find a way to gracefully exit capture */ - /* FIXME need spinlock here*/ - while (ivtv_get_free_elements(&st->full_q) == 0) { - - sleepctr++; - sleep_on_timeout(&st->waitq, IVTV_SLEEP_WAIT); - if(signal_pending(current)) - return -ERESTARTSYS; - + sleepctr = retval = 0; + buf = NULL; + add_wait_queue(&st->waitq, &wait); + do { if ((itv->trans_id == 0) && (sleepctr >= IVTV_MAX_DATA_SLEEP)) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Timeout waiting for data!\n"); - return -EIO; + retval = -EIO; + break; } - } - buf = ivtv_deq_peek_head(&st->full_q); + set_current_state(TASK_INTERRUPTIBLE); + buf = ivtv_deq_peek_head(&st->full_q); + if (buf) + break; - if (buf == NULL) { - IVTV_DEBUG(IVTV_DEBUG_ERR, "Error obtaining buffer\n"); - return -EIO; - } + ivtv_sleep_timeout(IVTV_SLEEP_WAIT); + + if (signal_pending(current)) + retval = -ERESTARTSYS; + + sleepctr++; + } while (!retval); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&st->waitq, &wait); + + /* an error (or signal) occured */ + if (retval) + return retval; /* Skip the first 4 bytes of mpg streams to help out * finicky decoders.. but not for iTVC16 */ @@ -2088,7 +2090,7 @@ struct ivtv *itv = id->itv; struct ivtv_v4l2_stream *stream=&itv->v4l2.streams[id->type]; struct ivtv_buffer *buf; - int copybytes=0, bytesread=0; + int copybytes=0, bytesread=0, retval=0; IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_fill_dec_buffers, %d bytes\n", count); @@ -2106,15 +2108,31 @@ * than one, just need loop control logic for it, if it's * deemed necessary. */ while (bytesread == 0) { - while ((buf = ivtv_deq_peek_head(&stream->free_q)) == NULL) { - IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: free_q empty, waiting\n"); + DECLARE_WAITQUEUE(wait, current); + + buf = NULL; + add_wait_queue(&stream->waitq, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + buf = ivtv_deq_peek_head(&stream->free_q); + if (buf) + break; - /* we'll get woken up if need-be */ - interruptible_sleep_on(&stream->waitq); - if(signal_pending(current)) return -ERESTARTSYS; + schedule(); - if (itv->dec_needs_data) ivtv_dec_sched_DMA(id->itv); - } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + if (test_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags)) + ivtv_dec_sched_DMA(id->itv); + } while (!buf); + set_current_state(TASK_RUNNING); + remove_wait_queue(&stream->waitq, &wait); + + if (retval) + return retval; /* bytes left to send > free bytes in current buffer */ if ((count - bytesread) > @@ -2193,14 +2211,14 @@ IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_DMA\n"); /* fancy way of saying "if (ivtv->dec_needs_data == 0)" */ - if (itv->dec_needs_data == 0) { + if (!test_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags)) { IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: no data needed\n"); return 0; } if (in_interrupt()) { IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_dma from interrupt\n"); - if (down_trylock(&itv->dec_sched_dma_sem)) { + if (down_trylock(&itv->sem_lock)) { IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_dma: userspace call in flight," " returning\n"); @@ -2208,14 +2226,15 @@ } } else { IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_dma from userspace\n"); - down_interruptible(&itv->dec_sched_dma_sem); + if (down_interruptible(&itv->sem_lock)) + return -ERESTARTSYS; IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_dma: got semaphore\n"); #if 0 /* this always seemed to be true for me */ if (signal_pending(current)) { IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv_dec_sched_dma: signal while" " down(); returning\n"); /* FIXME need to up()? */ - itv->dec_needs_data = 1; + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); return -ERESTARTSYS; } @@ -2249,15 +2268,15 @@ stream = &itv->v4l2.streams[type]; - if (itv->dec_dma_pending) { + if (test_bit(IVTV_F_I_DMAP, &itv->i_flags)) { IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: decoder busy, delaying\n"); - itv->dec_needs_data = 1; + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); ret = -EBUSY; goto ivtv_dec_sched_dma_return; } /* If we got this far, we have data to send and it wants it */ - itv->dec_needs_data = 0; + clear_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); /* Get card mem addr and size from data array */ mem_offset = data[1]; @@ -2328,7 +2347,7 @@ if (x == 0) { /* no full buffers */ IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Nothing to send\n"); - itv->dec_needs_data = 1; + set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags); ret = -ENOSPC; goto ivtv_dec_sched_dma_return; } @@ -2342,8 +2361,8 @@ data[2] = hw_stream_type; /* note that we're DMA'ing */ - stream->dma_pending = 1; - itv->dec_dma_pending = 1; + set_bit(IVTV_F_S_DMAP, &stream->s_flags); + set_bit(IVTV_F_I_DMAP, &itv->i_flags); ivtv_api_irqsafe(itv->dec_mbox, IVTV_API_DEC_DMA_FROM_HOST, 3, &data[0]); IVTV_DEBUG(IVTV_DEBUG_INFO, @@ -2356,7 +2375,7 @@ ivtv_dec_sched_dma_return: IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: sched_dma returning\n"); - up(&itv->dec_sched_dma_sem); + up(&itv->sem_lock); return ret; } @@ -2367,13 +2386,12 @@ IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: DMA Done tasklet\n"); - itv->dec_dma_pending = 0; - mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT); + clear_bit(IVTV_F_I_DMAP, &itv->i_flags); + mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT); for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) { - if (itv->v4l2.streams[y].dma_pending) { + if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) { stmtype = y; - itv->v4l2.streams[y].dma_pending = 0; break; } } @@ -2419,8 +2437,6 @@ /* wake up queue filler */ wake_up(&stream->waitq); wake_up(&itv->dec_master_w); - - return; } int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info) { @@ -2434,7 +2450,7 @@ * frames played. fortunately, it sets the SCR timestamp to 0 * in that case, which it never is otherwise. cool, huh */ while (info->scr == 0) { /* eliminate bogus values, FIXME ugly */ - ret = ivtv_api(itv->dec_mbox, &itv->dec_sem_w, + ret = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_TIMING_INFO,&result,0,&data[0]); if (ret) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: err sending timing info\n"); @@ -2449,10 +2465,8 @@ IVTV_DEBUG(IVTV_DEBUG_ERR,"Timeout getting frames played\n"); return -1; } - if (info->scr == 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.02*HZ); - } + if (info->scr == 0) + ivtv_sleep_timeout(HZ/50); } return 0; @@ -2468,7 +2482,7 @@ #if 0 /* Lots of extra debugging stuff */ /* Last DMA status? */ - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_w, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_DMA_STATUS,&result,0,&data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error sending status req\n"); } @@ -2478,7 +2492,7 @@ data[0], data[1]); /* buffer fullness stats */ - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_w, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_XFER_INFO,&result,0,&data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error sending DMA info\n"); } @@ -2489,7 +2503,7 @@ /* Timing info. */ - if (ivtv_api(itv->dec_mbox, &itv->dec_sem_w, + if (ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_TIMING_INFO,&result,0,&data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: err sending timing info\n"); } @@ -2532,18 +2546,19 @@ /* add stream's waitq to the poll list */ poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait); - if (down_interruptible(&id->itv->v4l2.v4l2_lock)) + if (down_interruptible(&id->itv->sem_lock)) return -ERESTARTSYS; if(ivtv_dec_stream_has_space(id)) { mask |= POLLOUT | POLLWRNORM; /* Writable */ } - if(id->itv->v4l2.streams[id->type].capturing == 0) { + if (!test_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags)) { /* not capturing, makes no sense to poll */ mask = POLLERR; } + up(&id->itv->sem_lock); return mask; } @@ -2554,20 +2569,19 @@ /* add stream's waitq to the poll list */ poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait); + if (down_interruptible(&id->itv->sem_lock)) + return -ERESTARTSYS; + if(ivtv_stream_has_data(id)) { mask |= POLLIN | POLLRDNORM; /* readable */ } - if (down_interruptible(&id->itv->v4l2.v4l2_lock)) - return -ERESTARTSYS; - - if(id->itv->v4l2.streams[id->type].capturing == 0) { + if (!test_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags)) { /* not capturing, makes no sense to poll */ mask = POLLERR; } - up(&id->itv->v4l2.v4l2_lock); - + up(&id->itv->sem_lock); return mask; } @@ -2576,8 +2590,7 @@ int x,y; IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(.01*HZ); + ivtv_sleep_timeout(HZ/100); if (NULL == mbox) { IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Mailboxes not initialized!\n"); @@ -2627,6 +2640,9 @@ int ivtv_close(struct ivtv_open_id *id) { struct ivtv *itv=id->itv; + /* sem_lock must be held */ + IVTV_ASSERT(sem_getcount(&itv->sem_lock) >= 1); + if( (id->type != IVTV_DEC_STREAM_TYPE_MPG) && (id->type != IVTV_DEC_STREAM_TYPE_YUV)) { if (atomic_read(&itv->capturing)) { atomic_dec(&itv->capturing); diff -ur ivtv-cvs/driver/ivtv-fb.c ivtv/driver/ivtv-fb.c --- ivtv-cvs/driver/ivtv-fb.c 2003-10-24 07:15:45.000000000 +0200 +++ ivtv/driver/ivtv-fb.c 2003-10-27 14:16:31.000000000 +0100 @@ -181,9 +181,9 @@ u32 data[IVTV_MBOX_MAX_DATA], result; int rc; - printk("ivtv-fb: ivtv_api_fb_get_framebuffer\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_framebuffer\n"); - rc = ivtv_api(itv->dec_mbox, &itv->dec_sem_r, + rc = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_FRAMEBUFFER, &result, 0, &data[0]); *fbbase = (void *) data[0]; *fblength = data[1]; @@ -193,9 +193,9 @@ static inline int ivtv_api_fb_get_pixel_format(struct ivtv *itv) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_pixel_format\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_pixel_format\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_PIXEL_FORMAT, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_PIXEL_FORMAT, &result, 0, &data[0]); return data[0]; } @@ -205,9 +205,9 @@ { u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = format; - printk("ivtv-fb: ivtv_api_fb_set_pixel_format\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_pixel_format\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_PIXEL_FORMAT, &result, 1, &data[0]); return result; } @@ -215,9 +215,9 @@ static inline int ivtv_api_fb_get_state(struct ivtv *itv) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_state\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_state\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_STATE, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_STATE, &result, 0, &data[0]); return data[0]; } @@ -226,9 +226,9 @@ { u32 params[IVTV_MBOX_MAX_DATA], result; params[0] = enabled; - printk("ivtv-fb: ivtv_api_fb_set_state\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_state\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, IVTV_API_FB_SET_STATE, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_STATE, &result, 1, ¶ms[0]); return result; } @@ -238,13 +238,13 @@ int width, int height) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_set_framebuffer_window\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_framebuffer_window\n"); data[0] = width; data[1] = height; data[2] = left; data[3] = top; - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_FRAMEBUFFER_WINDOW, &result, 4, &data[0]); return result; } @@ -253,9 +253,9 @@ struct ivtv_osd_coords *osd) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_osd_coords\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_osd_coords\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_OSD_COORDS, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_OSD_COORDS, &result, 0, &data[0]); osd->offset = data[0] - video_rel_base; @@ -273,7 +273,7 @@ *osd) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_set_osd_coords\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_osd_coords\n"); data[0] = osd->offset + video_rel_base; data[1] = osd->pixel_stride; data[2] = osd->lines; @@ -281,7 +281,7 @@ data[4] = osd->y; // FIXME maybe wait on vsync? - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, IVTV_API_FB_SET_OSD_COORDS, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_OSD_COORDS, &result, 5, &data[0]); return result; } @@ -290,9 +290,9 @@ struct rectangle *r) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_screen_coords\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_screen_coords\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_SCREEN_COORDS, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_SCREEN_COORDS, &result, 0, &data[0]); r->x0 = data[0]; @@ -307,13 +307,13 @@ const struct rectangle *r) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_set_screen_coords\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_screen_coords\n"); data[0] = r->x0; data[1] = r->y0; data[2] = r->x1; data[3] = r->y1; - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_SCREEN_COORDS, &result, 4, &data[0]); return result; } @@ -321,9 +321,9 @@ static inline int ivtv_api_fb_get_global_alpha(struct ivtv *itv) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_global_alpha\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_global_alpha\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_GLOBAL_ALPHA, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_GLOBAL_ALPHA, &result, 0, &data[0]); return data[1]; } @@ -333,11 +333,11 @@ int alpha, int enable_local) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_set_global_alpha\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_global_alpha\n"); data[0] = enable_global; data[1] = alpha; data[2] = !enable_local; - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_GLOBAL_ALPHA, &result, 3, &data[0]); return result; } @@ -345,9 +345,9 @@ static inline int ivtv_api_fb_get_flicker_state(struct ivtv *itv) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_get_flicker_state\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_get_flicker_state\n"); - ivtv_api(itv->dec_mbox, &itv->dec_sem_r, IVTV_API_FB_GET_FLICKER_STATE, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_GET_FLICKER_STATE, &result, 0, &data[0]); return data[0]; } @@ -356,10 +356,10 @@ int enabled) { u32 params[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_set_flicker_state\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_set_flicker_state\n"); params[0] = enabled; - ivtv_api(itv->dec_mbox, &itv->dec_sem_adm, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_SET_FLICKER_STATE, &result, 1, ¶ms[0]); return result; } @@ -371,7 +371,7 @@ u32 value) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk("ivtv-fb: ivtv_api_fb_blt_fill\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_fill\n"); data[0] = rasterop; data[1] = alpha_mode; data[2] = alpha_mask_mode; @@ -382,7 +382,7 @@ data[7] = deststride; data[8] = value; - ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_FB_BLT_FILL, &result, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_BLT_FILL, &result, 9, &data[0]); return result; } @@ -394,8 +394,7 @@ int sourcestride, int sourceaddr) { u32 data[IVTV_MBOX_MAX_DATA], result; - printk - ("ivtv_api_fb_blt_copy: width = %d, height = %d, destaddr = %d, deststride = %d, sourcestride = %d, sourceaddr = %d\n", + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_api_fb_blt_copy: width = %d, height = %d, destaddr = %d, deststride = %d, sourcestride = %d, sourceaddr = %d\n", width, height, destaddr, deststride, sourcestride, sourceaddr); data[0] = rasterop; @@ -409,7 +408,7 @@ data[8] = sourcestride; data[9] = sourceaddr; - ivtv_api(itv->dec_mbox, &itv->dec_sem_w, IVTV_API_FB_BLT_COPY, &result, + ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_FB_BLT_COPY, &result, 10, &data[0]); return result; } @@ -457,14 +456,14 @@ static int ivtvfb_update_var(int con, struct fb_info *info) { - printk("ivtv-fb: ivtvfb_update_var\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_update_var\n"); return 0; } static int ivtvfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { - printk("ivtv-fb: ivtvfb_get_fix\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "iTVC15 TV out"); @@ -482,7 +481,7 @@ static int ivtvfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { - printk("ivtv-fb: ivtvfb_get_var\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_var\n"); if (con == -1) memcpy(var, &ivtvfb_defined, sizeof(struct fb_var_screeninfo)); else @@ -496,7 +495,7 @@ struct display *display; struct display_switch *sw; - printk("ivtv-fb: ivtvfb_set_disp\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_disp\n"); if (con >= 0) display = &fb_display[con]; else @@ -529,7 +528,7 @@ struct fb_info *info) { int first=0; - printk("ivtv-fb: ivtvfb_set_var\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_var\n"); if (con >= 0) first = 1; if (var->xres != ivtvfb_defined.xres || @@ -562,14 +561,14 @@ static int ivtvfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - printk("ivtv-fb: ivtvfb_get_cmap\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_get_cmap\n"); return 0; } static int ivtvfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - printk("ivtv-fb: ivtvfb_set_cmap\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_set_cmap\n"); return 0; } @@ -580,7 +579,7 @@ int rc; unsigned long destaddr = ((y * video_width) + x) * 4; - printk("ivtv-fb: ivtv_fb_blt_copy\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_blt_copy\n"); source_offset += shadow_framebuf_offset; rc = ivtv_api_fb_blt_copy(ivtv_fb, 0xa, 0x1, 0x0, width, height, @@ -621,7 +620,7 @@ int ivtvfb_alloc_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma) { - printk("ivtv-fb: ivtvfb_alloc_user_dma_to_device\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_alloc_user_dma_to_device\n"); dma->page_count = 0; dma->sglist = (struct ivtv_SG_element *) kmalloc(sizeof(struct ivtv_SG_element) * @@ -650,8 +649,8 @@ { int i; int size_in_pages = (size_in_bytes + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - - printk("ivtv-fb: ivtvfb_prep_user_dma_to_device, dst: 0x%08x\n", + + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "ivtvfb_prep_user_dma_to_device, dst: 0x%08x\n", (unsigned int) ivtv_dest_addr); dma->page_count = size_in_pages; @@ -689,7 +688,7 @@ int ivtvfb_free_user_dma_to_device(struct ivtvfb_user_dma_to_device *dma) { int i; - printk("ivtv-fb: ivtvfb_free_user_dma_to_device\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_free_user_dma_to_device\n"); /* for (i = 0; i < dma->page_count; i++) { //++MTY NOTE: on ia32, pci_unmap_page() is a nop anyway... @@ -709,13 +708,13 @@ u32 data[IVTV_MBOX_MAX_DATA], result; u64 tstart; int rc; - printk("ivtv-fb: ivtvfb_execute_user_dma_to_device\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtvfb_execute_user_dma_to_device\n"); data[0] = dma->sg_dma_handle; data[1] = dma->page_count; data[2] = 0x1; // 0x1 = OSD data - printk("ivtvfb: Schedule FB DMA: physical address 0x%08x, " + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "Schedule FB DMA: physical address 0x%08x, " "arraysize 0x%08x, type 0x%08x\n", data[0], data[1], data[2]); flush_write_buffers(); @@ -726,20 +725,22 @@ rdtscll(tstart); - rc = ivtv_api(ivtv_fb->dec_mbox, &ivtv_fb->dec_sem_w, + rc = ivtv_api(ivtv_fb->dec_mbox, &ivtv_fb->sem_lock, IVTV_API_DEC_DMA_FROM_HOST, &result, 3, &data[0]); if (rc) { - printk("ivtvfb: error sending DMA info\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_ERR, "error sending DMA info\n"); } else { - ivtv_fb->dec_dma_pending = 1; + set_bit(IVTV_F_I_DMAP, &ivtv_fb->i_flags); } + /* what is the point of this?! -axboe */ +#if 0 up(&ivtv_fb->dec_sched_dma_sem); +#endif - printk("ivtv: started DMA request at timestamp %lld!\n", tstart); - printk("ivtvfb: OK, scheduled FB DMA!"); - + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "started DMA request at timestamp %lld!\n", tstart); + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "OK, scheduled FB DMA!"); return 0; } @@ -747,14 +748,15 @@ unsigned long destaddr, void *srcaddr, int count) { - printk("ivtv-fb: ivtv_fb_prep_frame\n"); + DECLARE_WAITQUEUE(wait, current); + int rc; + //if (!srcaddr || verify_area(...)) ... if ((destaddr + count) > video_size) return -E2BIG; destaddr = IVTV_DEC_MEM_START + video_rel_base + destaddr; - int rc; #ifdef IVTVFB_DEBUG_PER_FRAME printk("ivtv_fb_prep_frame: attempting to acquire semaphore..."); #endif @@ -767,28 +769,35 @@ ("ivtv_fb_prep_frame: acquired semaphore; scheduling the DMA..."); #endif - if(down_interruptible(&ivtv_fb->dec_sched_dma_sem)) { - return -ERESTARTSYS; - } + rc = 0; + add_wait_queue(&ivtv_fb->dec_master_w, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + /* FIXME mini-race still .. need to port to 'stream' format */ + if (!test_bit(IVTV_F_I_DMAP, &ivtv_fb->i_flags)) + break; + + schedule(); + + if (signal_pending(current)) + rc = -ERESTARTSYS; + + } while (!rc); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ivtv_fb->dec_master_w, &wait); + + if (rc) + return rc; - if (ivtv_fb->dec_dma_pending) { - /* FIXME mini-race still .. need to port to 'stream' format */ - interruptible_sleep_on(&ivtv_fb->dec_master_w); - if (ivtv_fb->dec_dma_pending) { - up(&ivtv_fb->dec_sched_dma_sem); - return -ERESTARTSYS; - } - } - if (0 != (rc = ivtvfb_prep_user_dma_to_device(&ivtvfb_current_fb_dma, destaddr, - (char *) srcaddr, count))) + (char *) srcaddr, count))) { - printk("ivtv_fb_prep_frame: err prep user dma to device\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err prep user dma to device=%x\n",rc); return rc; } if (0 != (rc = ivtvfb_execute_user_dma_to_device(&ivtvfb_current_fb_dma))) { - printk("ivtv_fb_prep_frame: err exec user dma to device\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_DMA, "err exec user dma to device=%x\n",rc); return rc; } @@ -801,7 +810,7 @@ int rc; - printk("ivtv-fb: ivtv_fb_ioctl\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "ivtv_fb_ioctl\n"); switch (cmd) { case 0x7777:{ while (MOD_IN_USE) MOD_DEC_USE_COUNT; @@ -813,8 +822,7 @@ state.status = (ivtv_api_fb_get_state(ivtv_fb) & 0x7); state.status |= (ivtv_api_fb_get_flicker_state(ivtv_fb) << 3); state.alpha = ivtv_api_fb_get_global_alpha(ivtv_fb); - printk - ("ivtv-fb: IVTVFB_IOCTL_GET_STATE: status = %lu, alpha = %lu\n", + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_GET_STATE: status = %lu, alpha = %lu\n", state.status, state.alpha); if (copy_to_user((void *) arg, &state, sizeof(state))) return -EFAULT; @@ -824,8 +832,7 @@ struct ivtvfb_ioctl_state_info state; if (copy_from_user(&state, (void *) arg, sizeof(state))) return -EFAULT; - printk - ("ivtv-fb: IVTVFB_IOCTL_SET_STATE: status = %lu, alpha = %lu\n", + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "IVTVFB_IOCTL_SET_STATE: status = %lu, alpha = %lu\n", state.status, state.alpha); ivtv_api_fb_set_state(ivtv_fb, (state.status && IVTVFB_STATUS_ENABLED)); @@ -843,9 +850,9 @@ status & IVTVFB_STATUS_FLICKER_REDUCTION) ? 1 : 0); - printk("ivtv-fb: new state = %d\n", + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "new state = %d\n", ivtv_api_fb_get_state(ivtv_fb)); - printk("ivtv-fb: global alpha now = %d\n", + IVTV_DEBUG_FB(IVTV_DEBUG_IOCTL, "global alpha now = %d\n", ivtv_api_fb_get_global_alpha(ivtv_fb)); return 0; } @@ -1092,7 +1113,7 @@ static void ivtvfb_cleanup(void) { - printk("ivtv-fb: Unloading framebuffer module\n"); + IVTV_DEBUG_FB(IVTV_DEBUG_INFO, "Unloading framebuffer module\n"); unregister_framebuffer(&fb_info); iounmap(video_vbase); mtrr_del(-1, fb_start_aligned_physaddr, diff -ur ivtv-cvs/driver/ivtv.h ivtv/driver/ivtv.h --- ivtv-cvs/driver/ivtv.h 2003-10-24 08:17:00.000000000 +0200 +++ ivtv/driver/ivtv.h 2003-10-27 12:21:40.000000000 +0100 @@ -1,3 +1,6 @@ +#ifndef IVTV_H +#define IVTV_H + /* Header for ivtv project: * Driver for the iTVC15 chip. * Author: Kevin Thayer (nufan_wfk at yahoo.com) @@ -106,9 +109,9 @@ #define IVTV_DMA_MAX_XFER 0x00080000 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */ #define IVTV_DEC_MIN_BUF 0x00050000 /* want this many bytes+ in decoder buffer */ -#define IVTV_SLEEP_WAIT (.1 * HZ) /*100 ms*/ +#define IVTV_SLEEP_WAIT (HZ/10) /*100 ms*/ #define IVTV_MAX_DATA_SLEEP 30 -#define DEC_DMA_TIMEOUT (.1 * HZ) +#define DEC_DMA_TIMEOUT (HZ/10) #define IVTV_DMA_ERR_LIST 0x00000008 #define IVTV_DMA_ERR_WRITE 0x00000004 @@ -177,7 +180,7 @@ #define IVTV_CMD_SPU_STOP 0x00000001 #define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A #define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 -#define IVTV_SDRAM_SLEEPTIME .6 /*value in seconds*/ +#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600ms /*Used for locating the firmware mailboxes*/ #define IVTV_FIRM_ENC_FILENAME "/lib/modules/ivtv-fw-enc.bin" @@ -287,7 +290,8 @@ #define IVTV_DEBUG_IOCTL (1 << 4) #define IVTV_DEBUG_I2C (1 << 5) #define IVTV_DEBUG_IRQ (1 << 6) -#define IVTV_DEBUG(x,args...) if(x&debug) printk("ivtv: " args); +#define IVTV_DEBUG(x,args...) if((x)&debug) printk("ivtv: " args); +#define IVTV_DEBUG_FB(x,args...) if((x)&debug) printk("ivtv-fb: " args); /* Temp saa7115 hack FIXME */ #define DECODER_SET_SIZE 76598 @@ -557,14 +561,21 @@ int fr_field; /* 1 = show every field, 0 = show every frame */ }; +/* encoder */ +#define IVTV_F_S_DMAP 0 +#define IVTV_F_S_OVERFLOW 1 +#define IVTV_F_S_CAP 2 + +/* decoder */ +#define IVTV_F_I_DMAP 3 +#define IVTV_F_I_NEEDS_DATA 4 + struct ivtv_v4l2_stream { - int capturing; int buf_size; /* size of buffers this stream */ long id; long seq; int ubytes; /* bytes written back to user this frame */ - int dma_pending; - int overflow; + unsigned long s_flags; int v4l_reg_type; wait_queue_head_t waitq; struct video_device v4l2dev; @@ -595,7 +606,6 @@ struct ivtv_v4l2 { u32 capabilities; - struct semaphore v4l2_lock; struct ivtv_v4l2_table input; int audio_output; struct ivtv_v4l2_table output; @@ -638,14 +648,13 @@ int num; /* invalidate during init! */ int first_read; /* used to clean up stream */ int first_write; /* don't schedule decodes until buffers full */ + unsigned long i_flags; atomic_t capturing; atomic_t decoding; - struct semaphore enc_sem_r, enc_sem_w, enc_sem_adm; - struct semaphore dec_sem_r, dec_sem_w, dec_sem_adm; - struct semaphore dec_sched_dma_sem; + struct semaphore sem_lock; int readslot,writeslot,overflow; - int graceful_eos, dma_pending; + int graceful_eos; long open_id; /* incremented each time an open occurs used as unique ID */ int sg_count; @@ -670,9 +679,6 @@ dma_addr_t SG_handle, DSG_handle; /* Decoder */ - int dec_dma_pending; - int dec_needs_data; - int dec_dma_reset; struct ivtv_ioctl_framesync dec_timestamp; wait_queue_head_t dec_master_w; struct timer_list dec_timeout; @@ -762,7 +768,6 @@ long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count); int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info); ssize_t ivtv_write(struct ivtv_open_id *id, const char *buf, size_t count); -void ivtv_start_decode(struct ivtv *itv); int ivtv_stream_has_data(struct ivtv_open_id *id); unsigned int ivtv_poll(struct file *filp, poll_table *wait); unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait); @@ -795,3 +800,17 @@ void ivtv_print_boxes(struct ivtv_mailbox *mbox); int tmk_test2(struct inode *inode, struct file *filep); int tmk_test1(struct inode *inode, struct file *filep); + +/* debug stuff, to get the locking right */ +#ifndef WARN_ON +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) +#endif + +#define IVTV_ASSERT(x) WARN_ON((x)) + +#endif diff -ur ivtv-cvs/driver/msp3400.c ivtv/driver/msp3400.c --- ivtv-cvs/driver/msp3400.c 2003-08-13 09:24:06.000000000 +0200 +++ ivtv/driver/msp3400.c 2003-10-26 22:34:02.000000000 +0100 @@ -45,20 +45,21 @@ #include #include #include -#include #include +#include -#ifdef CONFIG_SMP #include -#include -#endif -/* kernel_thread */ -#define __KERNEL_SYSCALLS__ -#include +#include #include "audiochip.h" #include "msp3400.h" +#ifdef INIT_SIGHAND +#define SIGMASK_LOCK(current) (&(current)->siglock) +#else +#define SIGMASK_LOCK(current) (&(current)->sigmask_lock) +#endif + /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END}; @@ -758,20 +759,17 @@ struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; -#ifdef CONFIG_SMP - lock_kernel(); -#endif - daemonize(); + exit_files(current); + reparent_to_init(); + + spin_lock_irq(SIGMASK_LOCK(current)); sigfillset(¤t->blocked); + spin_unlock_irq(SIGMASK_LOCK(current)); strcpy(current->comm,"msp3400"); msp->thread = current; -#ifdef CONFIG_SMP - unlock_kernel(); -#endif - printk("msp3400: daemon started\n"); if(msp->notify != NULL) up(msp->notify); @@ -1013,21 +1011,19 @@ struct i2c_client *client = data; struct msp3400c *msp = client->data; int mode,val,i,std; - -#ifdef CONFIG_SMP - lock_kernel(); -#endif - + daemonize(); + exit_files(current); + reparent_to_init(); + + spin_lock_irq(¤t->sigmask_lock); sigfillset(¤t->blocked); + spin_unlock_irq(¤t->sigmask_lock); + strcpy(current->comm,"msp3410 [auto]"); msp->thread = current; -#ifdef CONFIG_SMP - unlock_kernel(); -#endif - printk("msp3410: daemon started\n"); if(msp->notify != NULL) up(msp->notify);