]>
Commit | Line | Data |
---|---|---|
866b8695 GKH |
1 | /* |
2 | * Copyright (C) 2005-2006 Micronas USA Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License (Version 2) as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software Foundation, | |
15 | * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/kernel.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/spinlock.h> | |
22 | #include <linux/wait.h> | |
23 | #include <linux/list.h> | |
24 | #include <linux/slab.h> | |
25 | #include <linux/time.h> | |
26 | #include <linux/mm.h> | |
27 | #include <linux/usb.h> | |
28 | #include <linux/i2c.h> | |
29 | #include <asm/byteorder.h> | |
d73f822c | 30 | #include <media/v4l2-common.h> |
866b8695 GKH |
31 | |
32 | #include "saa7134-reg.h" | |
33 | #include "saa7134.h" | |
34 | #include "go7007-priv.h" | |
35 | ||
36 | #define GO7007_HPI_DEBUG | |
37 | ||
38 | enum hpi_address { | |
39 | HPI_ADDR_VIDEO_BUFFER = 0xe4, | |
40 | HPI_ADDR_INIT_BUFFER = 0xea, | |
41 | HPI_ADDR_INTR_RET_VALUE = 0xee, | |
42 | HPI_ADDR_INTR_RET_DATA = 0xec, | |
43 | HPI_ADDR_INTR_STATUS = 0xf4, | |
44 | HPI_ADDR_INTR_WR_PARAM = 0xf6, | |
45 | HPI_ADDR_INTR_WR_INDEX = 0xf8, | |
46 | }; | |
47 | ||
48 | enum gpio_command { | |
49 | GPIO_COMMAND_RESET = 0x00, /* 000b */ | |
50 | GPIO_COMMAND_REQ1 = 0x04, /* 001b */ | |
51 | GPIO_COMMAND_WRITE = 0x20, /* 010b */ | |
52 | GPIO_COMMAND_REQ2 = 0x24, /* 011b */ | |
53 | GPIO_COMMAND_READ = 0x80, /* 100b */ | |
54 | GPIO_COMMAND_VIDEO = 0x84, /* 101b */ | |
55 | GPIO_COMMAND_IDLE = 0xA0, /* 110b */ | |
56 | GPIO_COMMAND_ADDR = 0xA4, /* 111b */ | |
57 | }; | |
58 | ||
59 | struct saa7134_go7007 { | |
60 | struct saa7134_dev *dev; | |
61 | u8 *top; | |
62 | u8 *bottom; | |
63 | dma_addr_t top_dma; | |
64 | dma_addr_t bottom_dma; | |
65 | }; | |
66 | ||
67 | static struct go7007_board_info board_voyager = { | |
68 | .firmware = "go7007tv.bin", | |
69 | .flags = 0, | |
70 | .sensor_flags = GO7007_SENSOR_656 | | |
71 | GO7007_SENSOR_VALID_ENABLE | | |
72 | GO7007_SENSOR_TV | | |
73 | GO7007_SENSOR_VBI, | |
74 | .audio_flags = GO7007_AUDIO_I2S_MODE_1 | | |
75 | GO7007_AUDIO_WORD_16, | |
76 | .audio_rate = 48000, | |
77 | .audio_bclk_div = 8, | |
78 | .audio_main_div = 2, | |
79 | .hpi_buffer_cap = 7, | |
80 | .num_inputs = 1, | |
81 | .inputs = { | |
82 | { | |
83 | .name = "SAA7134", | |
84 | }, | |
85 | }, | |
86 | }; | |
5d929a71 | 87 | MODULE_FIRMWARE("go7007tv.bin"); |
866b8695 GKH |
88 | |
89 | /********************* Driver for GPIO HPI interface *********************/ | |
90 | ||
91 | static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) | |
92 | { | |
93 | saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
94 | ||
95 | /* Write HPI address */ | |
96 | saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); | |
97 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
98 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
99 | ||
100 | /* Write low byte */ | |
101 | saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); | |
102 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
103 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
104 | ||
105 | /* Write high byte */ | |
106 | saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); | |
107 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
108 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) | |
114 | { | |
115 | saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
116 | ||
117 | /* Write HPI address */ | |
118 | saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); | |
119 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
120 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
121 | ||
122 | saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); | |
123 | ||
124 | /* Read low byte */ | |
125 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); | |
126 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
127 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
128 | *data = saa_readb(SAA7134_GPIO_GPSTATUS0); | |
129 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
130 | ||
131 | /* Read high byte */ | |
132 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); | |
133 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
134 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
135 | *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; | |
136 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
141 | static int saa7134_go7007_interface_reset(struct go7007 *go) | |
142 | { | |
143 | struct saa7134_go7007 *saa = go->hpi_context; | |
144 | struct saa7134_dev *dev = saa->dev; | |
145 | u32 status; | |
146 | u16 intr_val, intr_data; | |
147 | int count = 20; | |
148 | ||
149 | saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ | |
150 | saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); | |
151 | saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
152 | ||
153 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
154 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); | |
155 | msleep(1); | |
156 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
157 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); | |
158 | msleep(10); | |
159 | ||
160 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
161 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
162 | ||
163 | status = saa_readb(SAA7134_GPIO_GPSTATUS2); | |
164 | /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */ | |
165 | ||
166 | /* enter command mode...(?) */ | |
167 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); | |
168 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); | |
169 | ||
170 | do { | |
171 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
172 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | |
173 | status = saa_readb(SAA7134_GPIO_GPSTATUS2); | |
174 | /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ | |
175 | } while (--count > 0); | |
176 | ||
177 | /* Wait for an interrupt to indicate successful hardware reset */ | |
178 | if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || | |
179 | (intr_val & ~0x1) != 0x55aa) { | |
180 | printk(KERN_ERR | |
181 | "saa7134-go7007: unable to reset the GO7007\n"); | |
182 | return -1; | |
183 | } | |
184 | return 0; | |
185 | } | |
186 | ||
187 | static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) | |
188 | { | |
189 | struct saa7134_go7007 *saa = go->hpi_context; | |
190 | struct saa7134_dev *dev = saa->dev; | |
191 | int i; | |
192 | u16 status_reg; | |
193 | ||
194 | #ifdef GO7007_HPI_DEBUG | |
195 | printk(KERN_DEBUG | |
196 | "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); | |
197 | #endif | |
198 | ||
199 | for (i = 0; i < 100; ++i) { | |
200 | gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); | |
201 | if (!(status_reg & 0x0010)) | |
202 | break; | |
203 | msleep(10); | |
204 | } | |
205 | if (i == 100) { | |
206 | printk(KERN_ERR | |
207 | "saa7134-go7007: device is hung, status reg = 0x%04x\n", | |
208 | status_reg); | |
209 | return -1; | |
210 | } | |
211 | gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); | |
212 | gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
217 | static int saa7134_go7007_read_interrupt(struct go7007 *go) | |
218 | { | |
219 | struct saa7134_go7007 *saa = go->hpi_context; | |
220 | struct saa7134_dev *dev = saa->dev; | |
221 | ||
222 | /* XXX we need to wait if there is no interrupt available */ | |
223 | go->interrupt_available = 1; | |
224 | gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); | |
225 | gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); | |
226 | #ifdef GO7007_HPI_DEBUG | |
227 | printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n", | |
228 | go->interrupt_value, go->interrupt_data); | |
229 | #endif | |
230 | return 0; | |
231 | } | |
232 | ||
233 | static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, | |
234 | unsigned long status) | |
235 | { | |
236 | struct go7007 *go = video_get_drvdata(dev->empress_dev); | |
237 | struct saa7134_go7007 *saa = go->hpi_context; | |
238 | ||
239 | if (!go->streaming) | |
240 | return; | |
241 | if (0 != (status & 0x000f0000)) | |
242 | printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n", | |
243 | (status >> 16) & 0x0f); | |
244 | if (status & 0x100000) { | |
245 | dma_sync_single(&dev->pci->dev, | |
246 | saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); | |
247 | go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); | |
248 | saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); | |
249 | } else { | |
250 | dma_sync_single(&dev->pci->dev, | |
251 | saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); | |
252 | go7007_parse_video_stream(go, saa->top, PAGE_SIZE); | |
253 | saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); | |
254 | } | |
255 | } | |
256 | ||
257 | static int saa7134_go7007_stream_start(struct go7007 *go) | |
258 | { | |
259 | struct saa7134_go7007 *saa = go->hpi_context; | |
260 | struct saa7134_dev *dev = saa->dev; | |
261 | ||
262 | saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), | |
263 | 0, PAGE_SIZE, DMA_FROM_DEVICE); | |
264 | if (!saa->top_dma) | |
265 | return -ENOMEM; | |
266 | saa->bottom_dma = dma_map_page(&dev->pci->dev, | |
267 | virt_to_page(saa->bottom), | |
268 | 0, PAGE_SIZE, DMA_FROM_DEVICE); | |
269 | if (!saa->bottom_dma) { | |
270 | dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, | |
271 | DMA_FROM_DEVICE); | |
272 | return -ENOMEM; | |
273 | } | |
274 | ||
275 | saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); | |
276 | saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); | |
277 | ||
278 | /* Set HPI interface for video */ | |
279 | saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
280 | saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); | |
281 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
282 | saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); | |
283 | ||
284 | /* Enable TS interface */ | |
285 | saa_writeb(SAA7134_TS_PARALLEL, 0xe6); | |
286 | ||
287 | /* Reset TS interface */ | |
288 | saa_setb(SAA7134_TS_SERIAL1, 0x01); | |
289 | saa_clearb(SAA7134_TS_SERIAL1, 0x01); | |
290 | ||
291 | /* Set up transfer block size */ | |
292 | saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); | |
293 | saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); | |
294 | saa_writeb(SAA7134_TS_DMA1, 0); | |
295 | saa_writeb(SAA7134_TS_DMA2, 0); | |
296 | ||
297 | /* Enable video streaming mode */ | |
298 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); | |
299 | ||
300 | saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); | |
301 | saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); | |
302 | saa_writel(SAA7134_RS_PITCH(5), 128); | |
303 | saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); | |
304 | ||
305 | /* Enable TS FIFO */ | |
306 | saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); | |
307 | ||
308 | /* Enable DMA IRQ */ | |
309 | saa_setl(SAA7134_IRQ1, | |
310 | SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | static int saa7134_go7007_stream_stop(struct go7007 *go) | |
316 | { | |
317 | struct saa7134_go7007 *saa = go->hpi_context; | |
d73f822c PE |
318 | struct saa7134_dev *dev; |
319 | ||
320 | if (!saa) | |
321 | return -EINVAL; | |
322 | dev = saa->dev; | |
323 | if (!dev) | |
324 | return -EINVAL; | |
866b8695 GKH |
325 | |
326 | /* Shut down TS FIFO */ | |
327 | saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); | |
328 | ||
329 | /* Disable DMA IRQ */ | |
330 | saa_clearl(SAA7134_IRQ1, | |
331 | SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); | |
332 | ||
333 | /* Disable TS interface */ | |
334 | saa_clearb(SAA7134_TS_PARALLEL, 0x80); | |
335 | ||
336 | dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, | |
337 | DMA_FROM_DEVICE); | |
338 | dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, | |
339 | DMA_FROM_DEVICE); | |
340 | ||
341 | return 0; | |
342 | } | |
343 | ||
344 | static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) | |
345 | { | |
346 | struct saa7134_go7007 *saa = go->hpi_context; | |
347 | struct saa7134_dev *dev = saa->dev; | |
348 | u16 status_reg; | |
349 | int i; | |
350 | ||
351 | #ifdef GO7007_HPI_DEBUG | |
352 | printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer " | |
353 | "sending %d bytes\n", len); | |
354 | #endif | |
355 | ||
356 | while (len > 0) { | |
357 | i = len > 64 ? 64 : len; | |
358 | saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); | |
359 | saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); | |
360 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); | |
361 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
362 | while (i-- > 0) { | |
363 | saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); | |
364 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); | |
365 | saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); | |
366 | ++data; | |
367 | --len; | |
368 | } | |
369 | for (i = 0; i < 100; ++i) { | |
370 | gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); | |
371 | if (!(status_reg & 0x0002)) | |
372 | break; | |
373 | } | |
374 | if (i == 100) { | |
375 | printk(KERN_ERR "saa7134-go7007: device is hung, " | |
376 | "status reg = 0x%04x\n", status_reg); | |
377 | return -1; | |
378 | } | |
379 | } | |
380 | return 0; | |
381 | } | |
382 | ||
d73f822c PE |
383 | static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd, |
384 | void *arg) | |
385 | { | |
386 | struct saa7134_go7007 *saa = go->hpi_context; | |
387 | struct saa7134_dev *dev = saa->dev; | |
388 | ||
389 | switch (cmd) { | |
390 | case VIDIOC_S_STD: | |
391 | { | |
392 | v4l2_std_id *std = arg; | |
393 | return saa7134_s_std_internal(dev, NULL, std); | |
394 | } | |
395 | case VIDIOC_G_STD: | |
396 | { | |
397 | v4l2_std_id *std = arg; | |
398 | *std = dev->tvnorm->id; | |
399 | return 0; | |
400 | } | |
401 | case VIDIOC_QUERYCTRL: | |
402 | { | |
403 | struct v4l2_queryctrl *ctrl = arg; | |
404 | if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) | |
405 | return saa7134_queryctrl(NULL, NULL, ctrl); | |
406 | } | |
407 | case VIDIOC_G_CTRL: | |
408 | { | |
409 | struct v4l2_control *ctrl = arg; | |
410 | if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) | |
411 | return saa7134_g_ctrl_internal(dev, NULL, ctrl); | |
412 | } | |
413 | case VIDIOC_S_CTRL: | |
414 | { | |
415 | struct v4l2_control *ctrl = arg; | |
416 | if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) | |
417 | return saa7134_s_ctrl_internal(dev, NULL, ctrl); | |
418 | } | |
419 | } | |
420 | return -EINVAL; | |
421 | ||
422 | } | |
423 | ||
866b8695 GKH |
424 | static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { |
425 | .interface_reset = saa7134_go7007_interface_reset, | |
426 | .write_interrupt = saa7134_go7007_write_interrupt, | |
427 | .read_interrupt = saa7134_go7007_read_interrupt, | |
428 | .stream_start = saa7134_go7007_stream_start, | |
429 | .stream_stop = saa7134_go7007_stream_stop, | |
430 | .send_firmware = saa7134_go7007_send_firmware, | |
d73f822c | 431 | .send_command = saa7134_go7007_send_command, |
866b8695 GKH |
432 | }; |
433 | ||
434 | /********************* Add/remove functions *********************/ | |
435 | ||
436 | static int saa7134_go7007_init(struct saa7134_dev *dev) | |
437 | { | |
438 | struct go7007 *go; | |
439 | struct saa7134_go7007 *saa; | |
440 | ||
441 | printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); | |
442 | ||
443 | saa = kmalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); | |
444 | if (saa == NULL) | |
445 | return -ENOMEM; | |
446 | memset(saa, 0, sizeof(struct saa7134_go7007)); | |
447 | ||
448 | /* Allocate a couple pages for receiving the compressed stream */ | |
449 | saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); | |
450 | if (!saa->top) | |
451 | goto allocfail; | |
452 | saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); | |
453 | if (!saa->bottom) | |
454 | goto allocfail; | |
455 | ||
456 | go = go7007_alloc(&board_voyager, &dev->pci->dev); | |
457 | if (go == NULL) | |
458 | goto allocfail; | |
459 | go->board_id = GO7007_BOARDID_PCI_VOYAGER; | |
460 | strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); | |
461 | go->hpi_ops = &saa7134_go7007_hpi_ops; | |
462 | go->hpi_context = saa; | |
463 | saa->dev = dev; | |
464 | ||
465 | /* Boot the GO7007 */ | |
466 | if (go7007_boot_encoder(go, go->board_info->flags & | |
467 | GO7007_BOARD_USE_ONBOARD_I2C) < 0) | |
468 | goto initfail; | |
469 | ||
470 | /* Do any final GO7007 initialization, then register the | |
471 | * V4L2 and ALSA interfaces */ | |
472 | if (go7007_register_encoder(go) < 0) | |
473 | goto initfail; | |
474 | dev->empress_dev = go->video_dev; | |
475 | video_set_drvdata(dev->empress_dev, go); | |
476 | ||
477 | go->status = STATUS_ONLINE; | |
478 | return 0; | |
479 | ||
480 | initfail: | |
481 | go->status = STATUS_SHUTDOWN; | |
482 | return 0; | |
483 | ||
484 | allocfail: | |
485 | if (saa->top) | |
486 | free_page((unsigned long)saa->top); | |
487 | if (saa->bottom) | |
488 | free_page((unsigned long)saa->bottom); | |
489 | kfree(saa); | |
490 | return -ENOMEM; | |
491 | } | |
492 | ||
493 | static int saa7134_go7007_fini(struct saa7134_dev *dev) | |
494 | { | |
495 | struct go7007 *go; | |
496 | struct saa7134_go7007 *saa; | |
497 | ||
498 | if (NULL == dev->empress_dev) | |
499 | return 0; | |
500 | ||
501 | go = video_get_drvdata(dev->empress_dev); | |
502 | saa = go->hpi_context; | |
503 | go->status = STATUS_SHUTDOWN; | |
504 | free_page((unsigned long)saa->top); | |
505 | free_page((unsigned long)saa->bottom); | |
506 | kfree(saa); | |
507 | go7007_remove(go); | |
508 | dev->empress_dev = NULL; | |
509 | ||
510 | return 0; | |
511 | } | |
512 | ||
513 | static struct saa7134_mpeg_ops saa7134_go7007_ops = { | |
514 | .type = SAA7134_MPEG_GO7007, | |
515 | .init = saa7134_go7007_init, | |
516 | .fini = saa7134_go7007_fini, | |
517 | .irq_ts_done = saa7134_go7007_irq_ts_done, | |
518 | }; | |
519 | ||
520 | static int __init saa7134_go7007_mod_init(void) | |
521 | { | |
522 | return saa7134_ts_register(&saa7134_go7007_ops); | |
523 | } | |
524 | ||
525 | static void __exit saa7134_go7007_mod_cleanup(void) | |
526 | { | |
527 | saa7134_ts_unregister(&saa7134_go7007_ops); | |
528 | } | |
529 | ||
530 | module_init(saa7134_go7007_mod_init); | |
531 | module_exit(saa7134_go7007_mod_cleanup); | |
532 | ||
533 | MODULE_LICENSE("GPL v2"); |