📄 pvrusb2-hdw.c
字号:
mutex_init(&hdw->big_lock_mutex); return hdw; fail: if (hdw) { if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb); if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb); if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer); if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer); if (hdw->controls) kfree(hdw->controls); kfree(hdw); } return 0;}/* Remove _all_ associations between this driver and the underlying USB layer. */void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw){ if (hdw->flag_disconnected) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw); if (hdw->ctl_read_urb) { usb_kill_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_read_urb); hdw->ctl_read_urb = 0; } if (hdw->ctl_write_urb) { usb_kill_urb(hdw->ctl_write_urb); usb_free_urb(hdw->ctl_write_urb); hdw->ctl_write_urb = 0; } if (hdw->ctl_read_buffer) { kfree(hdw->ctl_read_buffer); hdw->ctl_read_buffer = 0; } if (hdw->ctl_write_buffer) { kfree(hdw->ctl_write_buffer); hdw->ctl_write_buffer = 0; } pvr2_hdw_render_useless_unlocked(hdw); hdw->flag_disconnected = !0; hdw->usb_dev = 0; hdw->usb_intf = 0;}/* Destroy hardware interaction structure */void pvr2_hdw_destroy(struct pvr2_hdw *hdw){ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); if (hdw->fw_buffer) { kfree(hdw->fw_buffer); hdw->fw_buffer = 0; } if (hdw->vid_stream) { pvr2_stream_destroy(hdw->vid_stream); hdw->vid_stream = 0; } if (hdw->audio_stat) { hdw->audio_stat->detach(hdw->audio_stat->ctxt); } if (hdw->decoder_ctrl) { hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt); } pvr2_i2c_core_done(hdw); pvr2_hdw_remove_usb_stuff(hdw); down(&pvr2_unit_sem); do { if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM) && (unit_pointers[hdw->unit_number] == hdw)) { unit_pointers[hdw->unit_number] = 0; } } while (0); up(&pvr2_unit_sem); kfree(hdw->controls); if (hdw->std_defs) kfree(hdw->std_defs); if (hdw->video_std_names) kfree(hdw->video_std_names); kfree(hdw);}int pvr2_hdw_init_ok(struct pvr2_hdw *hdw){ return hdw->flag_init_ok;}int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw){ return (hdw && hdw->flag_ok);}/* Called when hardware has been unplugged */void pvr2_hdw_disconnect(struct pvr2_hdw *hdw){ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw); LOCK_TAKE(hdw->big_lock); LOCK_TAKE(hdw->ctl_lock); pvr2_hdw_remove_usb_stuff(hdw); LOCK_GIVE(hdw->ctl_lock); LOCK_GIVE(hdw->big_lock);}static int pvr2_ctl_set_chanprog_id(struct pvr2_ctrl *cptr,int value){ /* This is a special case; the value to store is to an array, and the element to select is determined by PVR_CID_CHANPROG_ID. */ struct pvr2_hdw *hdw = cptr->hdw; int id = hdw->controls[PVR2_CID_CHANPROG_ID].value; if ((id < 1) || (id > FREQTABLE_SIZE)) return 0; hdw->freqTable[id-1] = value; if (hdw->controls[PVR2_CID_CHANNEL].value == id) { /* If the current channel happens to be the slot we just set, then act like the current channel just got changed so we'll update that too. */ hdw->controls[PVR2_CID_CHANNEL].dirty = !0; } return 0;}static int pvr2_ctl_get_chanprog_id(struct pvr2_ctrl *cptr){ /* This is a special case; the value to return is from an array, and the element to select is determined by PVR_CID_CHANPROG_ID. */ struct pvr2_hdw *hdw = cptr->hdw; int id = hdw->controls[PVR2_CID_CHANPROG_ID].value; if ((id < 1) || (id > FREQTABLE_SIZE)) return 0; return hdw->freqTable[id-1];}// Template data for possible enumerated video standardsstatic struct v4l2_standard pvr_standards[] = { { .id = V4L2_STD_PAL_BG, .frameperiod = { .numerator = 1, .denominator= 25 }, .framelines = 625, .reserved = {0,0,0,0} }, { .id = V4L2_STD_PAL_I, .frameperiod = { .numerator = 1, .denominator= 25 }, .framelines = 625, .reserved = {0,0,0,0} }, { .id = V4L2_STD_PAL_DK, .frameperiod = { .numerator = 1, .denominator= 25 }, .framelines = 625, .reserved = {0,0,0,0} }, { .id = V4L2_STD_SECAM, .frameperiod = { .numerator = 1, .denominator= 25 }, .framelines = 625, .reserved = {0,0,0,0} }, { .id = V4L2_STD_NTSC_M, .frameperiod = { .numerator = 1001, .denominator= 30000 }, .framelines = 525, .reserved = {0,0,0,0} }, { .id = V4L2_STD_PAL_M, .frameperiod = { .numerator = 1001, .denominator= 30000 }, .framelines = 525, .reserved = {0,0,0,0} }};#define pvr_standards_cnt (sizeof(pvr_standards)/sizeof(pvr_standards[0]))struct name_data { struct v4l2_standard *std; unsigned int bcnt; unsigned int scnt;};static void name_build(struct name_data *dp,const char *str){ if (!dp->bcnt) { dp->bcnt = scnprintf(dp->std->name, sizeof(dp->std->name)-1,"%s",str); dp->scnt = 0; return; } dp->bcnt += scnprintf(dp->std->name+dp->bcnt, sizeof(dp->std->name)-(1+dp->bcnt), "%s%s", (dp->scnt ? "/" : "-"),str); (dp->scnt)++;}// Generate a descriptive name for a given standardstatic void name_bucket(struct v4l2_standard *std){ struct name_data nd; nd.std = std; nd.bcnt = 0; if (std->id & (V4L2_STD_PAL_B| V4L2_STD_PAL_B1| V4L2_STD_PAL_G| V4L2_STD_PAL_H| V4L2_STD_PAL_I| V4L2_STD_PAL_D| V4L2_STD_PAL_D1| V4L2_STD_PAL_K)) { name_build(&nd,"PAL"); if (std->id & V4L2_STD_PAL_B) name_build(&nd,"B"); if (std->id & V4L2_STD_PAL_B1) name_build(&nd,"B1"); if (std->id & V4L2_STD_PAL_D) name_build(&nd,"D"); if (std->id & V4L2_STD_PAL_D1) name_build(&nd,"D1"); if (std->id & V4L2_STD_PAL_G) name_build(&nd,"G"); if (std->id & V4L2_STD_PAL_H) name_build(&nd,"H"); if (std->id & V4L2_STD_PAL_I) name_build(&nd,"I"); if (std->id & V4L2_STD_PAL_K) name_build(&nd,"K"); if (std->id & V4L2_STD_PAL_M) name_build(&nd,"M"); if (std->id & V4L2_STD_PAL_N) name_build(&nd,"N"); if (std->id & V4L2_STD_PAL_Nc) name_build(&nd,"Nc"); if (std->id & V4L2_STD_PAL_60) name_build(&nd,"60"); std->name[nd.bcnt] = 0; return; } if (std->id & (V4L2_STD_NTSC_M| V4L2_STD_NTSC_M_JP| V4L2_STD_NTSC_443)) { name_build(&nd,"NTSC"); if (std->id & V4L2_STD_NTSC_M) name_build(&nd,"M"); if (std->id & V4L2_STD_NTSC_M_JP) name_build(&nd,"Mjp"); if (std->id & V4L2_STD_NTSC_443) name_build(&nd,"443"); std->name[nd.bcnt] = 0; return; } if (std->id & (V4L2_STD_SECAM_B| V4L2_STD_SECAM_D| V4L2_STD_SECAM_G| V4L2_STD_SECAM_H| V4L2_STD_SECAM_K| V4L2_STD_SECAM_K1| V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC)) { name_build(&nd,"SECAM"); if (std->id & V4L2_STD_SECAM_B) name_build(&nd,"B"); if (std->id & V4L2_STD_SECAM_D) name_build(&nd,"D"); if (std->id & V4L2_STD_SECAM_G) name_build(&nd,"G"); if (std->id & V4L2_STD_SECAM_H) name_build(&nd,"H"); if (std->id & V4L2_STD_SECAM_K) name_build(&nd,"K"); if (std->id & V4L2_STD_SECAM_K1) name_build(&nd,"K1"); if (std->id & V4L2_STD_SECAM_L) name_build(&nd,"L"); if (std->id & V4L2_STD_SECAM_LC) name_build(&nd,"LC"); std->name[nd.bcnt] = 0; return; } std->name[0] = 0;}// Given a mask of viable video standards to choose from, generate an// appropriate array of v4l2_standard data that corresponds to it and set// up related state in the driver to match.void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw,int arg){ v4l2_std_id buckets[pvr_standards_cnt]; unsigned int idx1,idx2,std_cnt; v4l2_std_id mmsk,amsk; amsk = (v4l2_std_id)arg; // Figure out which standard groups we can work with std_cnt = 0; mmsk = 0; for (idx1 = 0; idx1 < pvr_standards_cnt; idx1++) { buckets[idx1] = pvr_standards[idx1].id & amsk; if (!buckets[idx1]) continue; mmsk |= buckets[idx1]; amsk &= ~buckets[idx1]; std_cnt++; } if (amsk) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Failed to bucketize the following standards: 0x%llx", amsk); } if (hdw->std_defs) { kfree(hdw->std_defs); hdw->std_defs = 0; } if (hdw->video_std_names) { kfree(hdw->video_std_names); hdw->video_std_names = 0; } hdw->std_cnt = 0; if (!std_cnt) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Failed to identify any viable standard groups"); hdw->video_std_avail = 0; pvr2_hdw_internal_set_std_cur(hdw,0); return; } if (std_cnt) { // Allocate new video standard array hdw->std_defs = kmalloc(sizeof(struct v4l2_standard) * std_cnt, GFP_KERNEL); hdw->std_cnt = std_cnt; memset(hdw->std_defs,0,sizeof(struct v4l2_standard) * std_cnt); hdw->video_std_names = kmalloc(sizeof(char *) * std_cnt, GFP_KERNEL); memset(hdw->video_std_names,0,sizeof(char *) * std_cnt); idx2 = 0; // Initialize video standard array for (idx1 = 0; idx1 < pvr_standards_cnt; idx1++) { if (!buckets[idx1]) continue; memcpy(hdw->std_defs + idx2, pvr_standards + idx1, sizeof(struct v4l2_standard)); hdw->std_defs[idx2].id = buckets[idx1]; idx2++; } // Generate a name for each known video standard for (idx1 = 0; idx1 < std_cnt; idx1++) { name_bucket(hdw->std_defs + idx1); hdw->video_std_names[idx1] = hdw->std_defs[idx1].name; } // Set up the dynamic control for this standard hdw->video_std_enum.value_defs_ptr = hdw->video_std_names; hdw->video_std_enum.value_defs_count = std_cnt; } hdw->video_std_avail = mmsk; if (!(hdw->video_std_avail & hdw->video_std_cur)) { // Reselect standard if there isn't one that matches... pvr2_hdw_internal_set_stdenum_cur(hdw,0); }}unsigned int pvr2_hdw_get_stdenum_count(struct pvr2_hdw *hdw){ return hdw->std_cnt;}const struct v4l2_standard *pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw, unsigned int idx){ if (idx >= hdw->std_cnt) return 0; return hdw->std_defs + idx;}int pvr2_hdw_internal_set_stdenum_cur(struct pvr2_hdw *hdw,int val){ if (val < 0) return -EINVAL; if (val >= hdw->std_cnt) return -EINVAL; pvr2_hdw_internal_set_std_cur(hdw,hdw->std_defs[val].id); return 0;}void pvr2_hdw_internal_set_std_cur(struct pvr2_hdw *hdw,int val){ unsigned int idx; v4l2_std_id msk,id; id = (v4l2_std_id)val; // Only select from available standards id &= hdw->video_std_avail; // Only select a single bit for (idx = 0, msk = 1; msk; idx++, msk <<= 1) { if (!(id & msk)) continue; id = msk; break; } // Get out if nothing found if (!msk) return; // Fix up standard group now hdw->video_std_cur = id; hdw->controls[PVR2_CID_STDCUR].value = id; hdw->controls[PVR2_CID_STDCUR].dirty = !0; for (idx = 0; idx < hdw->std_cnt; idx++) { if (hdw->std_defs[idx].id & id) { hdw->std_id = idx; return; } } // Should never really get here, but just in case... hdw->std_id = 0;}static int pvr2_ctl_set_stdcur(struct pvr2_ctrl *cptr,int val){ pvr2_hdw_internal_set_std_cur(cptr->hdw,val); return 0;}static int pvr2_ctl_get_stdcur(struct pvr2_ctrl *cptr){ return (int)(cptr->hdw->video_std_cur);}static int pvr2_ctl_set_stdenumcur(struct pvr2_ctrl *cptr,int val){ if (val < 0) return -EINVAL; if (val >= cptr->hdw->std_cnt) return -EINVAL; cptr->hdw->std_id = val; pvr2_hdw_internal_set_std_cur(cptr->hdw, cptr->hdw->std_id); return 0;}static int pvr2_ctl_get_stdenumcur(struct pvr2_ctrl *cptr){ return cptr->hdw->std_id;}static int pvr2_ctl_get_stdavail(struct pvr2_ctrl *cptr){ return (int)(cptr->hdw->video_std_avail);}/* Get the number of defined controls */unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw){ return CTRL_COUNT;}/* Retrieve a control handle given its index (0..count-1) */struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw, unsigned int idx){ if (idx < 0) return 0; if (idx >= CTRL_COUNT) return 0; return hdw->controls + idx;}/* Given an ID, retrieve the control structure associated with it. */struct pvr2_ctrl *pvr2_hdw_get_ctrl(struct pvr2_hdw *hdw,unsigned int ctl_id){ struct pvr2_ctrl *cptr; unsigned int idx; int i; /* This could be made a lot more efficient, but for now... */ for (idx = 0; idx < CTRL_COUNT; idx++) { cptr = hdw->controls + idx; i = cptr->ctl_def->id; if (i && (i == ctl_id)) return cptr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -