aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2008-04-22 13:45:45 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:48 -0400
commit794b16072e00d0a40a8c773dd4319fb1e460a632 (patch)
tree4ce7b55af0ae1208d72bee673c16311acf085f66 /drivers/media/video/pvrusb2/pvrusb2-v4l2.c
parent8f59100a42576c49e2170e9dc04f8b7ac922a74d (diff)
V4L/DVB (7321): pvrusb2: Rework context handling and initialization
This change significantly rearranges pvr2_context level initialization and operation: 1. A new kernel thread is set up for management of the context. 2. Destruction of the pvr2_context instance is moved into the kernel thread. No other context is able to remove the instance; doing this simplifies lock handling. 3. The callback into pvrusb2-main, which is used to trigger initialization of each interface, is now issued from this kernel thread. Previously it had been indirectly issued out of the work queue thread in pvr2_hdw, which led to deadlock issues if the interface needed to change a control setting (which in turn requires dispatch of another work queue entry). 4. Callbacks into the interfaces (via the pvr2_channel structure) are now issued strictly from this thread. The net result of this is that such callback functions can now also safely operate driver controls without deadlocking the work queue. (At the moment this is not actually a problem, but I'm anticipating issues with this in the future). 5. There is no longer any need for anyone to enter / exit the pvr2_context structure. Implementation of the kernel thread here allows this all to be internal now, simplifying other logic. 6. A very very longstanding issue involving a mutex deadlock between the pvrusb2 driver and v4l should now be solved. The deadlock involved the pvr2_context mutex and a globals-protecting mutex in v4l. During initialization the driver would take the pvr2_context mutex first then the v4l2 interface would register with v4l and implicitly take the v4l mutex. Later when v4l would call back into the driver, the two mutexes could possibly be taken in the opposite order, a situation that can lead to deadlock. In practice this really wasn't an issue unless a v4l app tried to start VERY early after the driver appeared. However it still needed to be solved, and with the use of the kernel thread relieving need for pvr2_context mutex, the problem should be finally solved. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-v4l2.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c115
1 files changed, 55 insertions, 60 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index e878c6445ae2..249d7488e482 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -884,7 +884,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
884{ 884{
885 struct pvr2_v4l2_fh *fhp = file->private_data; 885 struct pvr2_v4l2_fh *fhp = file->private_data;
886 struct pvr2_v4l2 *vp = fhp->vhead; 886 struct pvr2_v4l2 *vp = fhp->vhead;
887 struct pvr2_context *mp = fhp->vhead->channel.mc_head;
888 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; 887 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
889 888
890 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); 889 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
@@ -901,42 +900,40 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
901 v4l2_prio_close(&vp->prio, &fhp->prio); 900 v4l2_prio_close(&vp->prio, &fhp->prio);
902 file->private_data = NULL; 901 file->private_data = NULL;
903 902
904 pvr2_context_enter(mp); do { 903 /* Restore the previous input selection, if it makes sense
905 /* Restore the previous input selection, if it makes sense 904 to do so. */
906 to do so. */ 905 if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
907 if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) { 906 struct pvr2_ctrl *cp;
908 struct pvr2_ctrl *cp; 907 int pval;
909 int pval; 908 cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
910 cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); 909 pvr2_ctrl_get_value(cp,&pval);
911 pvr2_ctrl_get_value(cp,&pval); 910 /* Only restore if we're still selecting the radio */
912 /* Only restore if we're still selecting the radio */ 911 if (pval == PVR2_CVAL_INPUT_RADIO) {
913 if (pval == PVR2_CVAL_INPUT_RADIO) { 912 pvr2_ctrl_set_value(cp,fhp->prev_input_val);
914 pvr2_ctrl_set_value(cp,fhp->prev_input_val); 913 pvr2_hdw_commit_ctl(hdw);
915 pvr2_hdw_commit_ctl(hdw);
916 }
917 } 914 }
915 }
918 916
919 if (fhp->vnext) { 917 if (fhp->vnext) {
920 fhp->vnext->vprev = fhp->vprev; 918 fhp->vnext->vprev = fhp->vprev;
921 } else { 919 } else {
922 vp->vlast = fhp->vprev; 920 vp->vlast = fhp->vprev;
923 } 921 }
924 if (fhp->vprev) { 922 if (fhp->vprev) {
925 fhp->vprev->vnext = fhp->vnext; 923 fhp->vprev->vnext = fhp->vnext;
926 } else { 924 } else {
927 vp->vfirst = fhp->vnext; 925 vp->vfirst = fhp->vnext;
928 } 926 }
929 fhp->vnext = NULL; 927 fhp->vnext = NULL;
930 fhp->vprev = NULL; 928 fhp->vprev = NULL;
931 fhp->vhead = NULL; 929 fhp->vhead = NULL;
932 pvr2_channel_done(&fhp->channel); 930 pvr2_channel_done(&fhp->channel);
933 pvr2_trace(PVR2_TRACE_STRUCT, 931 pvr2_trace(PVR2_TRACE_STRUCT,
934 "Destroying pvr_v4l2_fh id=%p",fhp); 932 "Destroying pvr_v4l2_fh id=%p",fhp);
935 kfree(fhp); 933 kfree(fhp);
936 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) { 934 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
937 pvr2_v4l2_destroy_no_lock(vp); 935 pvr2_v4l2_destroy_no_lock(vp);
938 } 936 }
939 } while (0); pvr2_context_exit(mp);
940 return 0; 937 return 0;
941} 938}
942 939
@@ -969,32 +966,30 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
969 init_waitqueue_head(&fhp->wait_data); 966 init_waitqueue_head(&fhp->wait_data);
970 fhp->dev_info = dip; 967 fhp->dev_info = dip;
971 968
972 pvr2_context_enter(vp->channel.mc_head); do { 969 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
973 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); 970 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
974 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
975 971
976 fhp->vnext = NULL; 972 fhp->vnext = NULL;
977 fhp->vprev = vp->vlast; 973 fhp->vprev = vp->vlast;
978 if (vp->vlast) { 974 if (vp->vlast) {
979 vp->vlast->vnext = fhp; 975 vp->vlast->vnext = fhp;
980 } else { 976 } else {
981 vp->vfirst = fhp; 977 vp->vfirst = fhp;
982 } 978 }
983 vp->vlast = fhp; 979 vp->vlast = fhp;
984 fhp->vhead = vp; 980 fhp->vhead = vp;
985 981
986 /* Opening the /dev/radioX device implies a mode switch. 982 /* Opening the /dev/radioX device implies a mode switch.
987 So execute that here. Note that you can get the 983 So execute that here. Note that you can get the
988 IDENTICAL effect merely by opening the normal video 984 IDENTICAL effect merely by opening the normal video
989 device and setting the input appropriately. */ 985 device and setting the input appropriately. */
990 if (dip->v4l_type == VFL_TYPE_RADIO) { 986 if (dip->v4l_type == VFL_TYPE_RADIO) {
991 struct pvr2_ctrl *cp; 987 struct pvr2_ctrl *cp;
992 cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); 988 cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
993 pvr2_ctrl_get_value(cp,&fhp->prev_input_val); 989 pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
994 pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO); 990 pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
995 pvr2_hdw_commit_ctl(hdw); 991 pvr2_hdw_commit_ctl(hdw);
996 } 992 }
997 } while (0); pvr2_context_exit(vp->channel.mc_head);
998 993
999 fhp->file = file; 994 fhp->file = file;
1000 file->private_data = fhp; 995 file->private_data = fhp;