diff options
author | Mike Isely <isely@isely.net> | 2006-06-26 19:58:46 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-26 23:17:15 -0400 |
commit | d855497edbfbf9e19a17f4a1154bca69cb4bd9ba (patch) | |
tree | b39bef23fc00c91dac73ae171ad6ba7261170918 /drivers/media/video/pvrusb2/pvrusb2-context.c | |
parent | eb99adde31b7d85c67a5e1c2fa5e098e1056dd79 (diff) |
V4L/DVB (4228a): pvrusb2 to kernel 2.6.18
Implement V4L2 driver for the Hauppauge PVR USB2 TV tuner.
The Hauppauge PVR USB2 is a USB connected TV tuner with an embedded
cx23416 hardware MPEG2 encoder. There are two major variants of this
device; this driver handles both. Any V4L2 application which
understands MPEG2 video stream data should be able to work with this
device.
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-context.c')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-context.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c new file mode 100644 index 000000000000..40dc59871a45 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include "pvrusb2-context.h" | ||
22 | #include "pvrusb2-io.h" | ||
23 | #include "pvrusb2-ioread.h" | ||
24 | #include "pvrusb2-hdw.h" | ||
25 | #include "pvrusb2-debug.h" | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <asm/semaphore.h> | ||
30 | |||
31 | |||
32 | static void pvr2_context_destroy(struct pvr2_context *mp) | ||
33 | { | ||
34 | if (mp->hdw) pvr2_hdw_destroy(mp->hdw); | ||
35 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); | ||
36 | flush_workqueue(mp->workqueue); | ||
37 | destroy_workqueue(mp->workqueue); | ||
38 | kfree(mp); | ||
39 | } | ||
40 | |||
41 | |||
42 | static void pvr2_context_trigger_poll(struct pvr2_context *mp) | ||
43 | { | ||
44 | queue_work(mp->workqueue,&mp->workpoll); | ||
45 | } | ||
46 | |||
47 | |||
48 | static void pvr2_context_poll(struct pvr2_context *mp) | ||
49 | { | ||
50 | pvr2_context_enter(mp); do { | ||
51 | pvr2_hdw_poll(mp->hdw); | ||
52 | } while (0); pvr2_context_exit(mp); | ||
53 | } | ||
54 | |||
55 | |||
56 | static void pvr2_context_setup(struct pvr2_context *mp) | ||
57 | { | ||
58 | pvr2_context_enter(mp); do { | ||
59 | if (!pvr2_hdw_dev_ok(mp->hdw)) break; | ||
60 | pvr2_hdw_setup(mp->hdw); | ||
61 | pvr2_hdw_setup_poll_trigger( | ||
62 | mp->hdw, | ||
63 | (void (*)(void *))pvr2_context_trigger_poll, | ||
64 | mp); | ||
65 | if (!pvr2_hdw_dev_ok(mp->hdw)) break; | ||
66 | if (!pvr2_hdw_init_ok(mp->hdw)) break; | ||
67 | mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); | ||
68 | if (mp->setup_func) { | ||
69 | mp->setup_func(mp); | ||
70 | } | ||
71 | } while (0); pvr2_context_exit(mp); | ||
72 | } | ||
73 | |||
74 | |||
75 | struct pvr2_context *pvr2_context_create( | ||
76 | struct usb_interface *intf, | ||
77 | const struct usb_device_id *devid, | ||
78 | void (*setup_func)(struct pvr2_context *)) | ||
79 | { | ||
80 | struct pvr2_context *mp = 0; | ||
81 | mp = kmalloc(sizeof(*mp),GFP_KERNEL); | ||
82 | if (!mp) goto done; | ||
83 | memset(mp,0,sizeof(*mp)); | ||
84 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); | ||
85 | mp->setup_func = setup_func; | ||
86 | mutex_init(&mp->mutex); | ||
87 | mp->hdw = pvr2_hdw_create(intf,devid); | ||
88 | if (!mp->hdw) { | ||
89 | pvr2_context_destroy(mp); | ||
90 | mp = 0; | ||
91 | goto done; | ||
92 | } | ||
93 | |||
94 | mp->workqueue = create_singlethread_workqueue("pvrusb2"); | ||
95 | INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); | ||
96 | INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); | ||
97 | queue_work(mp->workqueue,&mp->workinit); | ||
98 | done: | ||
99 | return mp; | ||
100 | } | ||
101 | |||
102 | |||
103 | void pvr2_context_enter(struct pvr2_context *mp) | ||
104 | { | ||
105 | mutex_lock(&mp->mutex); | ||
106 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp); | ||
107 | } | ||
108 | |||
109 | |||
110 | void pvr2_context_exit(struct pvr2_context *mp) | ||
111 | { | ||
112 | int destroy_flag = 0; | ||
113 | if (!(mp->mc_first || !mp->disconnect_flag)) { | ||
114 | destroy_flag = !0; | ||
115 | } | ||
116 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp); | ||
117 | mutex_unlock(&mp->mutex); | ||
118 | if (destroy_flag) pvr2_context_destroy(mp); | ||
119 | } | ||
120 | |||
121 | |||
122 | static void pvr2_context_run_checks(struct pvr2_context *mp) | ||
123 | { | ||
124 | struct pvr2_channel *ch1,*ch2; | ||
125 | for (ch1 = mp->mc_first; ch1; ch1 = ch2) { | ||
126 | ch2 = ch1->mc_next; | ||
127 | if (ch1->check_func) { | ||
128 | ch1->check_func(ch1); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | |||
134 | void pvr2_context_disconnect(struct pvr2_context *mp) | ||
135 | { | ||
136 | pvr2_context_enter(mp); do { | ||
137 | pvr2_hdw_disconnect(mp->hdw); | ||
138 | mp->disconnect_flag = !0; | ||
139 | pvr2_context_run_checks(mp); | ||
140 | } while (0); pvr2_context_exit(mp); | ||
141 | } | ||
142 | |||
143 | |||
144 | void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) | ||
145 | { | ||
146 | cp->hdw = mp->hdw; | ||
147 | cp->mc_head = mp; | ||
148 | cp->mc_next = 0; | ||
149 | cp->mc_prev = mp->mc_last; | ||
150 | if (mp->mc_last) { | ||
151 | mp->mc_last->mc_next = cp; | ||
152 | } else { | ||
153 | mp->mc_first = cp; | ||
154 | } | ||
155 | mp->mc_last = cp; | ||
156 | } | ||
157 | |||
158 | |||
159 | static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) | ||
160 | { | ||
161 | if (!cp->stream) return; | ||
162 | pvr2_stream_kill(cp->stream->stream); | ||
163 | cp->stream->user = 0; | ||
164 | cp->stream = 0; | ||
165 | } | ||
166 | |||
167 | |||
168 | void pvr2_channel_done(struct pvr2_channel *cp) | ||
169 | { | ||
170 | struct pvr2_context *mp = cp->mc_head; | ||
171 | pvr2_channel_disclaim_stream(cp); | ||
172 | if (cp->mc_next) { | ||
173 | cp->mc_next->mc_prev = cp->mc_prev; | ||
174 | } else { | ||
175 | mp->mc_last = cp->mc_prev; | ||
176 | } | ||
177 | if (cp->mc_prev) { | ||
178 | cp->mc_prev->mc_next = cp->mc_next; | ||
179 | } else { | ||
180 | mp->mc_first = cp->mc_next; | ||
181 | } | ||
182 | cp->hdw = 0; | ||
183 | } | ||
184 | |||
185 | |||
186 | int pvr2_channel_claim_stream(struct pvr2_channel *cp, | ||
187 | struct pvr2_context_stream *sp) | ||
188 | { | ||
189 | int code = 0; | ||
190 | pvr2_context_enter(cp->mc_head); do { | ||
191 | if (sp == cp->stream) break; | ||
192 | if (sp->user) { | ||
193 | code = -EBUSY; | ||
194 | break; | ||
195 | } | ||
196 | pvr2_channel_disclaim_stream(cp); | ||
197 | if (!sp) break; | ||
198 | sp->user = cp; | ||
199 | cp->stream = sp; | ||
200 | } while (0); pvr2_context_exit(cp->mc_head); | ||
201 | return code; | ||
202 | } | ||
203 | |||
204 | |||
205 | // This is the marker for the real beginning of a legitimate mpeg2 stream. | ||
206 | static char stream_sync_key[] = { | ||
207 | 0x00, 0x00, 0x01, 0xba, | ||
208 | }; | ||
209 | |||
210 | struct pvr2_ioread *pvr2_channel_create_mpeg_stream( | ||
211 | struct pvr2_context_stream *sp) | ||
212 | { | ||
213 | struct pvr2_ioread *cp; | ||
214 | cp = pvr2_ioread_create(); | ||
215 | if (!cp) return 0; | ||
216 | pvr2_ioread_setup(cp,sp->stream); | ||
217 | pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); | ||
218 | return cp; | ||
219 | } | ||
220 | |||
221 | |||
222 | /* | ||
223 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
224 | *** Local Variables: *** | ||
225 | *** mode: c *** | ||
226 | *** fill-column: 75 *** | ||
227 | *** tab-width: 8 *** | ||
228 | *** c-basic-offset: 8 *** | ||
229 | *** End: *** | ||
230 | */ | ||