diff options
Diffstat (limited to 'drivers/media/video/pvrusb2')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-context.c | 113 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-context.h | 7 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-debug.h | 2 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 1 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.c | 20 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.h | 6 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 115 |
7 files changed, 137 insertions, 127 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 953784c08abb..22bd8302c4aa 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "pvrusb2-ioread.h" | 23 | #include "pvrusb2-ioread.h" |
24 | #include "pvrusb2-hdw.h" | 24 | #include "pvrusb2-hdw.h" |
25 | #include "pvrusb2-debug.h" | 25 | #include "pvrusb2-debug.h" |
26 | #include <linux/kthread.h> | ||
26 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
27 | #include <linux/string.h> | 28 | #include <linux/string.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -30,32 +31,65 @@ | |||
30 | 31 | ||
31 | static void pvr2_context_destroy(struct pvr2_context *mp) | 32 | static void pvr2_context_destroy(struct pvr2_context *mp) |
32 | { | 33 | { |
33 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); | 34 | pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp); |
34 | if (mp->hdw) pvr2_hdw_destroy(mp->hdw); | 35 | if (mp->hdw) pvr2_hdw_destroy(mp->hdw); |
35 | kfree(mp); | 36 | kfree(mp); |
36 | } | 37 | } |
37 | 38 | ||
38 | 39 | ||
39 | static void pvr2_context_state_check(struct pvr2_context *mp) | 40 | static void pvr2_context_notify(struct pvr2_context *mp) |
40 | { | 41 | { |
41 | if (mp->init_flag) return; | 42 | mp->notify_flag = !0; |
42 | 43 | wake_up(&mp->wait_data); | |
43 | switch (pvr2_hdw_get_state(mp->hdw)) { | 44 | } |
44 | case PVR2_STATE_WARM: break; | 45 | |
45 | case PVR2_STATE_ERROR: break; | 46 | |
46 | case PVR2_STATE_READY: break; | 47 | static int pvr2_context_thread(void *_mp) |
47 | case PVR2_STATE_RUN: break; | 48 | { |
48 | default: return; | 49 | struct pvr2_channel *ch1,*ch2; |
50 | struct pvr2_context *mp = _mp; | ||
51 | pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread start)",mp); | ||
52 | |||
53 | /* Finish hardware initialization */ | ||
54 | if (pvr2_hdw_initialize(mp->hdw, | ||
55 | (void (*)(void *))pvr2_context_notify,mp)) { | ||
56 | mp->video_stream.stream = | ||
57 | pvr2_hdw_get_video_stream(mp->hdw); | ||
58 | /* Trigger interface initialization. By doing this here | ||
59 | initialization runs in our own safe and cozy thread | ||
60 | context. */ | ||
61 | if (mp->setup_func) mp->setup_func(mp); | ||
62 | } else { | ||
63 | pvr2_trace(PVR2_TRACE_CTXT, | ||
64 | "pvr2_context %p (thread skipping setup)",mp); | ||
65 | /* Even though initialization did not succeed, we're still | ||
66 | going to enter the wait loop anyway. We need to do this | ||
67 | in order to await the expected disconnect (which we will | ||
68 | detect in the normal course of operation). */ | ||
49 | } | 69 | } |
50 | 70 | ||
51 | pvr2_context_enter(mp); do { | 71 | /* Now just issue callbacks whenever hardware state changes or if |
52 | mp->init_flag = !0; | 72 | there is a disconnect. If there is a disconnect and there are |
53 | mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); | 73 | no channels left, then there's no reason to stick around anymore |
54 | if (mp->setup_func) { | 74 | so we'll self-destruct - tearing down the rest of this driver |
55 | mp->setup_func(mp); | 75 | instance along the way. */ |
76 | pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread enter loop)",mp); | ||
77 | while (!mp->disconnect_flag || mp->mc_first) { | ||
78 | if (mp->notify_flag) { | ||
79 | mp->notify_flag = 0; | ||
80 | pvr2_trace(PVR2_TRACE_CTXT, | ||
81 | "pvr2_context %p (thread notify)",mp); | ||
82 | for (ch1 = mp->mc_first; ch1; ch1 = ch2) { | ||
83 | ch2 = ch1->mc_next; | ||
84 | if (ch1->check_func) ch1->check_func(ch1); | ||
85 | } | ||
56 | } | 86 | } |
57 | } while (0); pvr2_context_exit(mp); | 87 | wait_event_interruptible(mp->wait_data, mp->notify_flag); |
58 | } | 88 | } |
89 | pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread end)",mp); | ||
90 | pvr2_context_destroy(mp); | ||
91 | return 0; | ||
92 | } | ||
59 | 93 | ||
60 | 94 | ||
61 | struct pvr2_context *pvr2_context_create( | 95 | struct pvr2_context *pvr2_context_create( |
@@ -63,10 +97,12 @@ struct pvr2_context *pvr2_context_create( | |||
63 | const struct usb_device_id *devid, | 97 | const struct usb_device_id *devid, |
64 | void (*setup_func)(struct pvr2_context *)) | 98 | void (*setup_func)(struct pvr2_context *)) |
65 | { | 99 | { |
100 | struct task_struct *thread; | ||
66 | struct pvr2_context *mp = NULL; | 101 | struct pvr2_context *mp = NULL; |
67 | mp = kzalloc(sizeof(*mp),GFP_KERNEL); | 102 | mp = kzalloc(sizeof(*mp),GFP_KERNEL); |
68 | if (!mp) goto done; | 103 | if (!mp) goto done; |
69 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); | 104 | pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp); |
105 | init_waitqueue_head(&mp->wait_data); | ||
70 | mp->setup_func = setup_func; | 106 | mp->setup_func = setup_func; |
71 | mutex_init(&mp->mutex); | 107 | mutex_init(&mp->mutex); |
72 | mp->hdw = pvr2_hdw_create(intf,devid); | 108 | mp->hdw = pvr2_hdw_create(intf,devid); |
@@ -75,57 +111,45 @@ struct pvr2_context *pvr2_context_create( | |||
75 | mp = NULL; | 111 | mp = NULL; |
76 | goto done; | 112 | goto done; |
77 | } | 113 | } |
78 | pvr2_hdw_initialize(mp->hdw, | 114 | thread = kthread_run(pvr2_context_thread, mp, "pvrusb2-context"); |
79 | (void (*)(void *))pvr2_context_state_check, | 115 | if (!thread) { |
80 | mp); | 116 | pvr2_context_destroy(mp); |
117 | mp = NULL; | ||
118 | goto done; | ||
119 | } | ||
81 | done: | 120 | done: |
82 | return mp; | 121 | return mp; |
83 | } | 122 | } |
84 | 123 | ||
85 | 124 | ||
86 | void pvr2_context_enter(struct pvr2_context *mp) | 125 | static void pvr2_context_enter(struct pvr2_context *mp) |
87 | { | 126 | { |
88 | mutex_lock(&mp->mutex); | 127 | mutex_lock(&mp->mutex); |
89 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp); | ||
90 | } | 128 | } |
91 | 129 | ||
92 | 130 | ||
93 | void pvr2_context_exit(struct pvr2_context *mp) | 131 | static void pvr2_context_exit(struct pvr2_context *mp) |
94 | { | 132 | { |
95 | int destroy_flag = 0; | 133 | int destroy_flag = 0; |
96 | if (!(mp->mc_first || !mp->disconnect_flag)) { | 134 | if (!(mp->mc_first || !mp->disconnect_flag)) { |
97 | destroy_flag = !0; | 135 | destroy_flag = !0; |
98 | } | 136 | } |
99 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp); | ||
100 | mutex_unlock(&mp->mutex); | 137 | mutex_unlock(&mp->mutex); |
101 | if (destroy_flag) pvr2_context_destroy(mp); | 138 | if (destroy_flag) pvr2_context_notify(mp); |
102 | } | ||
103 | |||
104 | |||
105 | static void pvr2_context_run_checks(struct pvr2_context *mp) | ||
106 | { | ||
107 | struct pvr2_channel *ch1,*ch2; | ||
108 | for (ch1 = mp->mc_first; ch1; ch1 = ch2) { | ||
109 | ch2 = ch1->mc_next; | ||
110 | if (ch1->check_func) { | ||
111 | ch1->check_func(ch1); | ||
112 | } | ||
113 | } | ||
114 | } | 139 | } |
115 | 140 | ||
116 | 141 | ||
117 | void pvr2_context_disconnect(struct pvr2_context *mp) | 142 | void pvr2_context_disconnect(struct pvr2_context *mp) |
118 | { | 143 | { |
119 | pvr2_context_enter(mp); do { | 144 | pvr2_hdw_disconnect(mp->hdw); |
120 | pvr2_hdw_disconnect(mp->hdw); | 145 | mp->disconnect_flag = !0; |
121 | mp->disconnect_flag = !0; | 146 | pvr2_context_notify(mp); |
122 | pvr2_context_run_checks(mp); | ||
123 | } while (0); pvr2_context_exit(mp); | ||
124 | } | 147 | } |
125 | 148 | ||
126 | 149 | ||
127 | void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) | 150 | void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) |
128 | { | 151 | { |
152 | pvr2_context_enter(mp); | ||
129 | cp->hdw = mp->hdw; | 153 | cp->hdw = mp->hdw; |
130 | cp->mc_head = mp; | 154 | cp->mc_head = mp; |
131 | cp->mc_next = NULL; | 155 | cp->mc_next = NULL; |
@@ -136,6 +160,7 @@ void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) | |||
136 | mp->mc_first = cp; | 160 | mp->mc_first = cp; |
137 | } | 161 | } |
138 | mp->mc_last = cp; | 162 | mp->mc_last = cp; |
163 | pvr2_context_exit(mp); | ||
139 | } | 164 | } |
140 | 165 | ||
141 | 166 | ||
@@ -151,6 +176,7 @@ static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) | |||
151 | void pvr2_channel_done(struct pvr2_channel *cp) | 176 | void pvr2_channel_done(struct pvr2_channel *cp) |
152 | { | 177 | { |
153 | struct pvr2_context *mp = cp->mc_head; | 178 | struct pvr2_context *mp = cp->mc_head; |
179 | pvr2_context_enter(mp); | ||
154 | pvr2_channel_disclaim_stream(cp); | 180 | pvr2_channel_disclaim_stream(cp); |
155 | if (cp->mc_next) { | 181 | if (cp->mc_next) { |
156 | cp->mc_next->mc_prev = cp->mc_prev; | 182 | cp->mc_next->mc_prev = cp->mc_prev; |
@@ -163,6 +189,7 @@ void pvr2_channel_done(struct pvr2_channel *cp) | |||
163 | mp->mc_first = cp->mc_next; | 189 | mp->mc_first = cp->mc_next; |
164 | } | 190 | } |
165 | cp->hdw = NULL; | 191 | cp->hdw = NULL; |
192 | pvr2_context_exit(mp); | ||
166 | } | 193 | } |
167 | 194 | ||
168 | 195 | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 96b255f02381..127ec53e0913 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h | |||
@@ -43,8 +43,10 @@ struct pvr2_context { | |||
43 | struct pvr2_hdw *hdw; | 43 | struct pvr2_hdw *hdw; |
44 | struct pvr2_context_stream video_stream; | 44 | struct pvr2_context_stream video_stream; |
45 | struct mutex mutex; | 45 | struct mutex mutex; |
46 | int notify_flag; | ||
46 | int disconnect_flag; | 47 | int disconnect_flag; |
47 | int init_flag; | 48 | |
49 | wait_queue_head_t wait_data; | ||
48 | 50 | ||
49 | /* Called after pvr2_context initialization is complete */ | 51 | /* Called after pvr2_context initialization is complete */ |
50 | void (*setup_func)(struct pvr2_context *); | 52 | void (*setup_func)(struct pvr2_context *); |
@@ -60,9 +62,6 @@ struct pvr2_channel { | |||
60 | void (*check_func)(struct pvr2_channel *); | 62 | void (*check_func)(struct pvr2_channel *); |
61 | }; | 63 | }; |
62 | 64 | ||
63 | void pvr2_context_enter(struct pvr2_context *); | ||
64 | void pvr2_context_exit(struct pvr2_context *); | ||
65 | |||
66 | struct pvr2_context *pvr2_context_create(struct usb_interface *intf, | 65 | struct pvr2_context *pvr2_context_create(struct usb_interface *intf, |
67 | const struct usb_device_id *devid, | 66 | const struct usb_device_id *devid, |
68 | void (*setup_func)(struct pvr2_context *)); | 67 | void (*setup_func)(struct pvr2_context *)); |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index fca49d8a9311..11537ddf8aa3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h | |||
@@ -39,7 +39,7 @@ extern int pvrusb2_debug; | |||
39 | #define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ | 39 | #define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ |
40 | #define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ | 40 | #define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ |
41 | #define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ | 41 | #define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ |
42 | #define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */ | 42 | #define PVR2_TRACE_CTXT (1 << 13) /* Main context tracking */ |
43 | #define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ | 43 | #define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ |
44 | #define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ | 44 | #define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ |
45 | #define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ | 45 | #define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index bc341ae5c79a..c725495826ce 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -187,7 +187,6 @@ struct pvr2_hdw { | |||
187 | struct workqueue_struct *workqueue; | 187 | struct workqueue_struct *workqueue; |
188 | struct work_struct workpoll; /* Update driver state */ | 188 | struct work_struct workpoll; /* Update driver state */ |
189 | struct work_struct worki2csync; /* Update i2c clients */ | 189 | struct work_struct worki2csync; /* Update i2c clients */ |
190 | struct work_struct workinit; /* Driver initialization sequence */ | ||
191 | 190 | ||
192 | /* Video spigot */ | 191 | /* Video spigot */ |
193 | struct pvr2_stream *vid_stream; | 192 | struct pvr2_stream *vid_stream; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1dff2d04a5d9..7e7c570cf830 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -221,7 +221,6 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *); | |||
221 | static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); | 221 | static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); |
222 | static void pvr2_hdw_worker_i2c(struct work_struct *work); | 222 | static void pvr2_hdw_worker_i2c(struct work_struct *work); |
223 | static void pvr2_hdw_worker_poll(struct work_struct *work); | 223 | static void pvr2_hdw_worker_poll(struct work_struct *work); |
224 | static void pvr2_hdw_worker_init(struct work_struct *work); | ||
225 | static int pvr2_hdw_wait(struct pvr2_hdw *,int state); | 224 | static int pvr2_hdw_wait(struct pvr2_hdw *,int state); |
226 | static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); | 225 | static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); |
227 | static void pvr2_hdw_state_log_state(struct pvr2_hdw *); | 226 | static void pvr2_hdw_state_log_state(struct pvr2_hdw *); |
@@ -1816,15 +1815,16 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw) | |||
1816 | /* Perform second stage initialization. Set callback pointer first so that | 1815 | /* Perform second stage initialization. Set callback pointer first so that |
1817 | we can avoid a possible initialization race (if the kernel thread runs | 1816 | we can avoid a possible initialization race (if the kernel thread runs |
1818 | before the callback has been set). */ | 1817 | before the callback has been set). */ |
1819 | void pvr2_hdw_initialize(struct pvr2_hdw *hdw, | 1818 | int pvr2_hdw_initialize(struct pvr2_hdw *hdw, |
1820 | void (*callback_func)(void *), | 1819 | void (*callback_func)(void *), |
1821 | void *callback_data) | 1820 | void *callback_data) |
1822 | { | 1821 | { |
1823 | LOCK_TAKE(hdw->big_lock); do { | 1822 | LOCK_TAKE(hdw->big_lock); do { |
1824 | hdw->state_data = callback_data; | 1823 | hdw->state_data = callback_data; |
1825 | hdw->state_func = callback_func; | 1824 | hdw->state_func = callback_func; |
1826 | } while (0); LOCK_GIVE(hdw->big_lock); | 1825 | } while (0); LOCK_GIVE(hdw->big_lock); |
1827 | queue_work(hdw->workqueue,&hdw->workinit); | 1826 | pvr2_hdw_setup(hdw); |
1827 | return hdw->flag_init_ok; | ||
1828 | } | 1828 | } |
1829 | 1829 | ||
1830 | 1830 | ||
@@ -2032,7 +2032,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
2032 | hdw->workqueue = create_singlethread_workqueue(hdw->name); | 2032 | hdw->workqueue = create_singlethread_workqueue(hdw->name); |
2033 | INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); | 2033 | INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); |
2034 | INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c); | 2034 | INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c); |
2035 | INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init); | ||
2036 | 2035 | ||
2037 | pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", | 2036 | pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", |
2038 | hdw->unit_number,hdw->name); | 2037 | hdw->unit_number,hdw->name); |
@@ -2517,15 +2516,6 @@ static void pvr2_hdw_worker_poll(struct work_struct *work) | |||
2517 | } | 2516 | } |
2518 | 2517 | ||
2519 | 2518 | ||
2520 | static void pvr2_hdw_worker_init(struct work_struct *work) | ||
2521 | { | ||
2522 | struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit); | ||
2523 | LOCK_TAKE(hdw->big_lock); do { | ||
2524 | pvr2_hdw_setup(hdw); | ||
2525 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2526 | } | ||
2527 | |||
2528 | |||
2529 | static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) | 2519 | static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) |
2530 | { | 2520 | { |
2531 | return wait_event_interruptible( | 2521 | return wait_event_interruptible( |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 597ee5033149..a868e52a73a3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h | |||
@@ -103,9 +103,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
103 | 103 | ||
104 | /* Perform second stage initialization, passing in a notification callback | 104 | /* Perform second stage initialization, passing in a notification callback |
105 | for when the master state changes. */ | 105 | for when the master state changes. */ |
106 | void pvr2_hdw_initialize(struct pvr2_hdw *, | 106 | int pvr2_hdw_initialize(struct pvr2_hdw *, |
107 | void (*callback_func)(void *), | 107 | void (*callback_func)(void *), |
108 | void *callback_data); | 108 | void *callback_data); |
109 | 109 | ||
110 | /* Destroy hardware interaction structure */ | 110 | /* Destroy hardware interaction structure */ |
111 | void pvr2_hdw_destroy(struct pvr2_hdw *); | 111 | void pvr2_hdw_destroy(struct pvr2_hdw *); |
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; |