📄 pvrusb2-hdw.c
字号:
} pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, PVR2_VID_ENDPOINT,idx); } if (!pvr2_hdw_dev_ok(hdw)) return; /* Make sure everything is up to date */ pvr2_i2c_core_sync(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; hdw->flag_init_ok = !0;}int pvr2_hdw_setup(struct pvr2_hdw *hdw){ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); LOCK_TAKE(hdw->big_lock); do { pvr2_hdw_setup_low(hdw); pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", hdw,hdw->flag_ok,hdw->flag_init_ok); if (pvr2_hdw_dev_ok(hdw)) { if (pvr2_hdw_init_ok(hdw)) { pvr2_trace( PVR2_TRACE_INFO, "Device initialization" " completed successfully."); break; } if (hdw->fw1_state == FW1_STATE_RELOAD) { pvr2_trace( PVR2_TRACE_INFO, "Device microcontroller firmware" " (re)loaded; it should now reset" " and reconnect."); break; } pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Device initialization was not successful."); if (hdw->fw1_state == FW1_STATE_MISSING) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Giving up since device" " microcontroller firmware" " appears to be missing."); break; } } if (procreload) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Attempting pvrusb2 recovery by reloading" " primary firmware."); pvr2_trace( PVR2_TRACE_ERROR_LEGS, "If this works, device should disconnect" " and reconnect in a sane state."); hdw->fw1_state = FW1_STATE_UNKNOWN; pvr2_upload_firmware1(hdw); } else { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "***WARNING*** pvrusb2 device hardware" " appears to be jammed" " and I can't clear it."); pvr2_trace( PVR2_TRACE_ERROR_LEGS, "You might need to power cycle" " the pvrusb2 device" " in order to recover."); } } while (0); LOCK_GIVE(hdw->big_lock); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); return hdw->flag_init_ok;}/* Create and return a structure for interacting with the underlying hardware */struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, const struct usb_device_id *devid){ unsigned int idx,cnt1,cnt2; struct pvr2_hdw *hdw; unsigned int hdw_type; int valid_std_mask; struct pvr2_ctrl *cptr; __u8 ifnum; struct v4l2_queryctrl qctrl; struct pvr2_ctl_info *ciptr; hdw_type = devid - pvr2_device_table; if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Bogus device type of %u reported",hdw_type); return NULL; } hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", hdw,pvr2_device_names[hdw_type]); if (!hdw) goto fail; hdw->tuner_signal_stale = !0; cx2341x_fill_defaults(&hdw->enc_ctl_state); hdw->control_cnt = CTRLDEF_COUNT; hdw->control_cnt += MPEGDEF_COUNT; hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, GFP_KERNEL); if (!hdw->controls) goto fail; hdw->hdw_type = hdw_type; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; } for (idx = 0; idx < 32; idx++) { hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx]; } for (idx = 0; idx < CTRLDEF_COUNT; idx++) { cptr = hdw->controls + idx; cptr->info = control_defs+idx; } /* Define and configure additional controls from cx2341x module. */ hdw->mpeg_ctrl_info = kzalloc( sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); if (!hdw->mpeg_ctrl_info) goto fail; for (idx = 0; idx < MPEGDEF_COUNT; idx++) { cptr = hdw->controls + idx + CTRLDEF_COUNT; ciptr = &(hdw->mpeg_ctrl_info[idx].info); ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; ciptr->name = mpeg_ids[idx].strid; ciptr->v4l_id = mpeg_ids[idx].id; ciptr->skip_init = !0; ciptr->get_value = ctrl_cx2341x_get; ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; ciptr->is_dirty = ctrl_cx2341x_is_dirty; if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; qctrl.id = ciptr->v4l_id; cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { ciptr->set_value = ctrl_cx2341x_set; } strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, PVR2_CTLD_INFO_DESC_SIZE); hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; ciptr->default_value = qctrl.default_value; switch (qctrl.type) { default: case V4L2_CTRL_TYPE_INTEGER: ciptr->type = pvr2_ctl_int; ciptr->def.type_int.min_value = qctrl.minimum; ciptr->def.type_int.max_value = qctrl.maximum; break; case V4L2_CTRL_TYPE_BOOLEAN: ciptr->type = pvr2_ctl_bool; break; case V4L2_CTRL_TYPE_MENU: ciptr->type = pvr2_ctl_enum; ciptr->def.type_enum.value_names = cx2341x_ctrl_get_menu(ciptr->v4l_id); for (cnt1 = 0; ciptr->def.type_enum.value_names[cnt1] != NULL; cnt1++) { } ciptr->def.type_enum.count = cnt1; break; } cptr->info = ciptr; } // Initialize video standard enum dynamic control cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM); if (cptr) { memcpy(&hdw->std_info_enum,cptr->info, sizeof(hdw->std_info_enum)); cptr->info = &hdw->std_info_enum; } // Initialize control data regarding video standard masks valid_std_mask = pvr2_std_get_usable(); for (idx = 0; idx < 32; idx++) { if (!(valid_std_mask & (1 << idx))) continue; cnt1 = pvr2_std_id_to_str( hdw->std_mask_names[idx], sizeof(hdw->std_mask_names[idx])-1, 1 << idx); hdw->std_mask_names[idx][cnt1] = 0; } cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); if (cptr) { memcpy(&hdw->std_info_avail,cptr->info, sizeof(hdw->std_info_avail)); cptr->info = &hdw->std_info_avail; hdw->std_info_avail.def.type_bitmask.bit_names = hdw->std_mask_ptrs; hdw->std_info_avail.def.type_bitmask.valid_bits = valid_std_mask; } cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR); if (cptr) { memcpy(&hdw->std_info_cur,cptr->info, sizeof(hdw->std_info_cur)); cptr->info = &hdw->std_info_cur; hdw->std_info_cur.def.type_bitmask.bit_names = hdw->std_mask_ptrs; hdw->std_info_avail.def.type_bitmask.valid_bits = valid_std_mask; } hdw->eeprom_addr = -1; hdw->unit_number = -1; hdw->v4l_minor_number_video = -1; hdw->v4l_minor_number_vbi = -1; hdw->v4l_minor_number_radio = -1; hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); if (!hdw->ctl_write_buffer) goto fail; hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); if (!hdw->ctl_read_buffer) goto fail; hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL); if (!hdw->ctl_write_urb) goto fail; hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL); if (!hdw->ctl_read_urb) goto fail; mutex_lock(&pvr2_unit_mtx); do { for (idx = 0; idx < PVR_NUM; idx++) { if (unit_pointers[idx]) continue; hdw->unit_number = idx; unit_pointers[idx] = hdw; break; } } while (0); mutex_unlock(&pvr2_unit_mtx); cnt1 = 0; cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); cnt1 += cnt2; if (hdw->unit_number >= 0) { cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c", ('a' + hdw->unit_number)); cnt1 += cnt2; } if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; hdw->name[cnt1] = 0; pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", hdw->unit_number,hdw->name); hdw->tuner_type = -1; hdw->flag_ok = !0; /* Initialize the mask of subsystems that we will shut down when we stop streaming. */ hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL; hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx", hdw->subsys_stream_mask); hdw->usb_intf = intf; hdw->usb_dev = interface_to_usbdev(intf); scnprintf(hdw->bus_info,sizeof(hdw->bus_info), "usb %s address %d", hdw->usb_dev->dev.bus_id, hdw->usb_dev->devnum); ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; usb_set_interface(hdw->usb_dev,ifnum,0); mutex_init(&hdw->ctl_lock_mutex); mutex_init(&hdw->big_lock_mutex); return hdw; fail: if (hdw) { usb_free_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_write_urb); kfree(hdw->ctl_read_buffer); kfree(hdw->ctl_write_buffer); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); kfree(hdw); } return NULL;}/* Remove _all_ associations between this driver and the underlying USB layer. */static 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 = NULL; } if (hdw->ctl_write_urb) { usb_kill_urb(hdw->ctl_write_urb); usb_free_urb(hdw->ctl_write_urb); hdw->ctl_write_urb = NULL; } if (hdw->ctl_read_buffer) { kfree(hdw->ctl_read_buffer); hdw->ctl_read_buffer = NULL; } if (hdw->ctl_write_buffer) { kfree(hdw->ctl_write_buffer); hdw->ctl_write_buffer = NULL; } pvr2_hdw_render_useless_unlocked(hdw); hdw->flag_disconnected = !0; hdw->usb_dev = NULL; hdw->usb_intf = NULL;}/* Destroy hardware interaction structure */void pvr2_hdw_destroy(struct pvr2_hdw *hdw){ if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); if (hdw->fw_buffer) { kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; } if (hdw->vid_stream) { pvr2_stream_destroy(hdw->vid_stream); hdw->vid_stream = NULL; } if (hdw->decoder_ctrl) { hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt); } pvr2_i2c_core_done(hdw); pvr2_hdw_remove_usb_stuff(hdw); mutex_lock(&pvr2_unit_mtx); do { if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM) && (unit_pointers[hdw->unit_number] == hdw)) { unit_pointers[hdw->unit_number] = NULL; } } while (0); mutex_unlock(&pvr2_unit_mtx); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); kfree(hdw->std_defs); kfree(hdw->std_enum_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);}// Attempt to autoselect an appropriate value for std_enum_cur given// whatever is currently in std_mask_curstatic void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw){ unsigned int idx; for (idx = 1; idx < hdw->std_enum_cnt; idx++) { if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) { hdw->std_enum_cur = idx; return; } } hdw->std_enum_cur = 0;}// Calculate correct set of enumerated standards based on currently known// set of available standards bits.static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw){ struct v4l2_standard *newstd; unsigned int std_cnt; unsigned int idx; newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail); if (hdw->std_defs) { kfree(hdw->std_defs); hdw->std_defs = NULL; } hdw->std_enum_cnt = 0; if (hdw->std_enum_names) { kfree(hdw->std_enum_names); hdw->std_enum_names = NULL; } if (!std_cnt) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, "WARNING: Failed to identify any viable standards"); } hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL); hdw->std_enum_names[0] = "none"; for (idx = 0; idx < std_cnt; idx++) { hdw->std_enum_names[idx+1] = newstd[idx].name; } // Set up the dynamic control for this standard hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names; hdw->std_info_enum.def.type_enum.count = std_cnt+1; hdw->std_defs = newstd; hdw->std_enum_cnt = std_cnt+1; hdw->std_enum_cur = 0; hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;}int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw, struct v4l2_standard *std, unsigned int idx){ int ret = -EINVAL; if (!idx) return ret; LOCK_TAKE(hdw->big_lock); do { if (idx >= hdw->std_enum_cnt) break; idx--; memcpy(std,hdw->std_defs+idx,sizeof(*std)); ret = 0; } while (0); LOCK_GIVE(hdw->big_lock); return ret;}/* Get the number of defined controls */unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw){ return hdw->control_cnt;}/* 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 >= hdw->control_cnt) return NULL; return hdw->controls + idx;}/* Retrieve a control handle given its index (0..count-1) */struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(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 < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; i = cptr->info->internal_id; if (i && (i == ctl_id)) return cptr; } return NULL;}/* Given a V4L ID, retrieve the control structure associated with it. */struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,u
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -