1 | /* $NetBSD: coram.c,v 1.13 2014/03/29 19:28:24 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2008, 2011 Jonathan A. Kollasch |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: coram.c,v 1.13 2014/03/29 19:28:24 christos Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/systm.h> |
34 | #include <sys/device.h> |
35 | #include <sys/kmem.h> |
36 | #include <sys/mutex.h> |
37 | #include <sys/module.h> |
38 | #include <sys/bus.h> |
39 | |
40 | #include <dev/dtv/dtvif.h> |
41 | |
42 | #include <dev/pci/cx23885reg.h> |
43 | #include <dev/pci/coramvar.h> |
44 | |
45 | #include <dev/pci/pcivar.h> |
46 | #include <dev/pci/pcireg.h> |
47 | #include <dev/pci/pcidevs.h> |
48 | #include <dev/i2c/i2cvar.h> |
49 | #include <dev/i2c/at24cxxvar.h> |
50 | |
51 | #include <dev/i2c/cx24227var.h> |
52 | #include <dev/i2c/mt2131var.h> |
53 | |
54 | /* #define CORAM_DEBUG */ |
55 | /* #define CORAM_ATTACH_I2C */ |
56 | |
57 | static const struct coram_board coram_boards[] = { |
58 | { PCI_VENDOR_HAUPPAUGE, 0x7911, "Hauppauge HVR-1250" }, |
59 | }; |
60 | |
61 | static int coram_match(device_t, cfdata_t, void *); |
62 | static void coram_attach(device_t, device_t, void *); |
63 | static int coram_detach(device_t, int); |
64 | static int coram_rescan(device_t, const char *, const int *); |
65 | static void coram_childdet(device_t, device_t); |
66 | static bool coram_resume(device_t, const pmf_qual_t *); |
67 | static int coram_intr(void *); |
68 | static const struct coram_board * coram_board_lookup(uint16_t, uint16_t); |
69 | |
70 | static int coram_iic_exec(void *, i2c_op_t, i2c_addr_t, |
71 | const void *, size_t, void *, size_t, int); |
72 | static int coram_iic_acquire_bus(void *, int); |
73 | static void coram_iic_release_bus(void *, int); |
74 | static int coram_iic_read(struct coram_iic_softc *, i2c_op_t, i2c_addr_t, |
75 | const void *, size_t, void *, size_t, int); |
76 | static int coram_iic_write(struct coram_iic_softc *, i2c_op_t, i2c_addr_t, |
77 | const void *, size_t, void *, size_t, int); |
78 | |
79 | static void coram_dtv_get_devinfo(void *, struct dvb_frontend_info *); |
80 | static int coram_dtv_open(void *, int); |
81 | static void coram_dtv_close(void *); |
82 | static int coram_dtv_set_tuner(void *, const struct dvb_frontend_parameters *); |
83 | static fe_status_t coram_dtv_get_status(void *); |
84 | static uint16_t coram_dtv_get_signal_strength(void *); |
85 | static uint16_t coram_dtv_get_snr(void *); |
86 | static int coram_dtv_start_transfer(void *, void (*)(void *, const struct dtv_payload *), void *); |
87 | static int coram_dtv_stop_transfer(void *); |
88 | |
89 | static int coram_mpeg_attach(struct coram_softc *); |
90 | static int coram_mpeg_detach(struct coram_softc *, int); |
91 | static int coram_mpeg_reset(struct coram_softc *); |
92 | static void * coram_mpeg_malloc(struct coram_softc *, size_t); |
93 | static int coram_allocmem(struct coram_softc *, size_t, size_t, struct coram_dma *); |
94 | static void coram_mpeg_free(struct coram_softc *, void *); |
95 | static int coram_mpeg_halt(struct coram_softc *); |
96 | static int coram_freemem(struct coram_softc *, struct coram_dma *); |
97 | static int coram_mpeg_trigger(struct coram_softc *, void *); |
98 | static int coram_risc_buffer(struct coram_softc *, uint32_t, uint32_t); |
99 | static int coram_risc_field(struct coram_softc *, uint32_t *, uint32_t); |
100 | static int coram_sram_ch_setup(struct coram_softc *, struct coram_sram_ch *, uint32_t); |
101 | static int coram_mpeg_intr(struct coram_softc *); |
102 | |
103 | CFATTACH_DECL2_NEW(coram, sizeof(struct coram_softc), |
104 | coram_match, coram_attach, coram_detach, NULL, |
105 | coram_rescan, coram_childdet); |
106 | |
107 | #define CORAM_SRAM_CH6 0 |
108 | |
109 | #define CORAM_TS_PKTSIZE (188 * 8) |
110 | |
111 | static struct coram_sram_ch coram_sram_chs[] = { |
112 | [CORAM_SRAM_CH6] = { |
113 | .csc_cmds= 0x10140, |
114 | .csc_iq = 0x10500, |
115 | .csc_iqsz = 0x40, |
116 | .csc_cdt = 0x10600, |
117 | .csc_cdtsz = 0x10, |
118 | .csc_fifo = 0x6000, |
119 | .csc_fifosz = 0x1000, |
120 | .csc_risc = 0x10800, |
121 | .csc_riscsz = 0x800, |
122 | .csc_ptr1 = DMA5_PTR1, |
123 | .csc_ptr2 = DMA5_PTR2, |
124 | .csc_cnt1 = DMA5_CNT1, |
125 | .csc_cnt2 = DMA5_CNT2, |
126 | }, |
127 | }; |
128 | |
129 | static const struct dtv_hw_if coram_dtv_if = { |
130 | .get_devinfo = coram_dtv_get_devinfo, |
131 | .open = coram_dtv_open, |
132 | .close = coram_dtv_close, |
133 | .set_tuner = coram_dtv_set_tuner, |
134 | .get_status = coram_dtv_get_status, |
135 | .get_signal_strength = coram_dtv_get_signal_strength, |
136 | .get_snr = coram_dtv_get_snr, |
137 | .start_transfer = coram_dtv_start_transfer, |
138 | .stop_transfer = coram_dtv_stop_transfer, |
139 | }; |
140 | |
141 | static int |
142 | coram_match(device_t parent, cfdata_t match, void *v) |
143 | { |
144 | const struct pci_attach_args *pa = v; |
145 | pcireg_t subid; |
146 | |
147 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CONEXANT) |
148 | return 0; |
149 | if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_CONEXANT_CX23885) |
150 | return 0; |
151 | |
152 | subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
153 | if (coram_board_lookup(PCI_VENDOR(subid), PCI_PRODUCT(subid)) == NULL) |
154 | return 0; |
155 | |
156 | return 1; |
157 | } |
158 | |
159 | static void |
160 | coram_attach(device_t parent, device_t self, void *aux) |
161 | { |
162 | struct coram_softc *sc = device_private(self); |
163 | const struct pci_attach_args *pa = aux; |
164 | pci_intr_handle_t ih; |
165 | pcireg_t reg; |
166 | const char *intrstr; |
167 | struct coram_iic_softc *cic; |
168 | uint32_t value; |
169 | int i; |
170 | #ifdef CORAM_ATTACH_I2C |
171 | struct i2cbus_attach_args iba; |
172 | #endif |
173 | char intrbuf[PCI_INTRSTR_LEN]; |
174 | |
175 | sc->sc_dev = self; |
176 | |
177 | pci_aprint_devinfo(pa, NULL); |
178 | |
179 | reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
180 | sc->sc_board = coram_board_lookup(PCI_VENDOR(reg), PCI_PRODUCT(reg)); |
181 | KASSERT(sc->sc_board != NULL); |
182 | |
183 | if (pci_mapreg_map(pa, CX23885_MMBASE, PCI_MAPREG_TYPE_MEM, 0, |
184 | &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems)) { |
185 | aprint_error_dev(self, "couldn't map memory space\n" ); |
186 | return; |
187 | } |
188 | |
189 | sc->sc_dmat = pa->pa_dmat; |
190 | sc->sc_pc = pa->pa_pc; |
191 | |
192 | if (pci_intr_map(pa, &ih)) { |
193 | aprint_error_dev(self, "couldn't map interrupt\n" ); |
194 | return; |
195 | } |
196 | intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); |
197 | sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_VM, coram_intr, self); |
198 | if (sc->sc_ih == NULL) { |
199 | aprint_error_dev(self, "couldn't establish interrupt" ); |
200 | if (intrstr != NULL) |
201 | aprint_error(" at %s" , intrstr); |
202 | aprint_error("\n" ); |
203 | return; |
204 | } |
205 | aprint_normal_dev(self, "interrupting at %s\n" , intrstr); |
206 | |
207 | /* set master */ |
208 | reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
209 | reg |= PCI_COMMAND_MASTER_ENABLE; |
210 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg); |
211 | |
212 | /* I2C */ |
213 | for(i = 0; i < I2C_NUM; i++) { |
214 | cic = &sc->sc_iic[i]; |
215 | |
216 | cic->cic_sc = sc; |
217 | if (bus_space_subregion(sc->sc_memt, sc->sc_memh, |
218 | I2C_BASE + (I2C_SIZE * i), I2C_SIZE, &cic->cic_regh)) |
219 | panic("failed to subregion i2c" ); |
220 | |
221 | mutex_init(&cic->cic_busmutex, MUTEX_DRIVER, IPL_NONE); |
222 | cic->cic_i2c.ic_cookie = cic; |
223 | cic->cic_i2c.ic_acquire_bus = coram_iic_acquire_bus; |
224 | cic->cic_i2c.ic_release_bus = coram_iic_release_bus; |
225 | cic->cic_i2c.ic_exec = coram_iic_exec; |
226 | |
227 | #ifdef CORAM_ATTACH_I2C |
228 | /* attach iic(4) */ |
229 | memset(&iba, 0, sizeof(iba)); |
230 | iba.iba_tag = &cic->cic_i2c; |
231 | iba.iba_type = I2C_TYPE_SMBUS; |
232 | cic->cic_i2cdev = config_found_ia(self, "i2cbus" , &iba, |
233 | iicbus_print); |
234 | #endif |
235 | } |
236 | |
237 | /* HVR1250 GPIO */ |
238 | value = bus_space_read_4(sc->sc_memt, sc->sc_memh, 0x110010); |
239 | #if 1 |
240 | value &= ~0x00010001; |
241 | bus_space_write_4(sc->sc_memt, sc->sc_memh, 0x110010, value); |
242 | delay(5000); |
243 | #endif |
244 | value |= 0x00010001; |
245 | bus_space_write_4(sc->sc_memt, sc->sc_memh, 0x110010, value); |
246 | |
247 | #if 0 |
248 | int i; |
249 | uint8_t foo[256]; |
250 | uint8_t bar; |
251 | bar = 0; |
252 | // seeprom_bootstrap_read(&sc->sc_i2c, 0x50, 0, 256, foo, 256); |
253 | |
254 | iic_acquire_bus(&sc->sc_i2c, I2C_F_POLL); |
255 | iic_exec(&sc->sc_i2c, I2C_OP_READ_WITH_STOP, 0x50, &bar, 1, foo, 256, |
256 | I2C_F_POLL); |
257 | iic_release_bus(&sc->sc_i2c, I2C_F_POLL); |
258 | |
259 | printf("\n" ); |
260 | for ( i = 0; i < 256; i++) { |
261 | if ( (i % 8) == 0 ) |
262 | printf("%02x: " , i); |
263 | |
264 | printf("%02x" , foo[i]); |
265 | |
266 | if ( (i % 8) == 7 ) |
267 | printf("\n" ); |
268 | else |
269 | printf(" " ); |
270 | } |
271 | printf("\n" ); |
272 | #endif |
273 | |
274 | sc->sc_demod = cx24227_open(sc->sc_dev, &sc->sc_iic[0].cic_i2c, 0x19); |
275 | if (sc->sc_demod == NULL) |
276 | aprint_error_dev(self, "couldn't open cx24227\n" ); |
277 | sc->sc_tuner = mt2131_open(sc->sc_dev, &sc->sc_iic[0].cic_i2c, 0x61); |
278 | if (sc->sc_tuner == NULL) |
279 | aprint_error_dev(self, "couldn't open mt2131\n" ); |
280 | |
281 | coram_mpeg_attach(sc); |
282 | |
283 | if (!pmf_device_register(self, NULL, coram_resume)) |
284 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
285 | |
286 | return; |
287 | } |
288 | |
289 | static int |
290 | coram_detach(device_t self, int flags) |
291 | { |
292 | struct coram_softc *sc = device_private(self); |
293 | struct coram_iic_softc *cic; |
294 | unsigned int i; |
295 | int error; |
296 | |
297 | error = coram_mpeg_detach(sc, flags); |
298 | if (error) |
299 | return error; |
300 | |
301 | if (sc->sc_tuner) |
302 | mt2131_close(sc->sc_tuner); |
303 | if (sc->sc_demod) |
304 | cx24227_close(sc->sc_demod); |
305 | for (i = 0; i < I2C_NUM; i++) { |
306 | cic = &sc->sc_iic[i]; |
307 | if (cic->cic_i2cdev) |
308 | config_detach(cic->cic_i2cdev, flags); |
309 | mutex_destroy(&cic->cic_busmutex); |
310 | } |
311 | pmf_device_deregister(self); |
312 | |
313 | if (sc->sc_mems) |
314 | bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); |
315 | if (sc->sc_ih) |
316 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static int |
322 | coram_rescan(device_t self, const char *ifattr, const int *locs) |
323 | { |
324 | struct coram_softc *sc = device_private(self); |
325 | struct dtv_attach_args daa; |
326 | |
327 | daa.hw = &coram_dtv_if; |
328 | daa.priv = sc; |
329 | |
330 | if (ifattr_match(ifattr, "dtvbus" ) && sc->sc_dtvdev == NULL) |
331 | sc->sc_dtvdev = config_found_ia(sc->sc_dev, "dtvbus" , |
332 | &daa, dtv_print); |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static void |
338 | coram_childdet(device_t self, device_t child) |
339 | { |
340 | struct coram_softc *sc = device_private(self); |
341 | struct coram_iic_softc *cic; |
342 | unsigned int i; |
343 | |
344 | if (sc->sc_dtvdev == child) |
345 | sc->sc_dtvdev = NULL; |
346 | |
347 | for (i = 0; i < I2C_NUM; i++) { |
348 | cic = &sc->sc_iic[i]; |
349 | if (cic->cic_i2cdev == child) |
350 | cic->cic_i2cdev = NULL; |
351 | } |
352 | } |
353 | |
354 | static int |
355 | coram_intr(void *v) |
356 | { |
357 | device_t self = v; |
358 | struct coram_softc *sc; |
359 | uint32_t val; |
360 | |
361 | sc = device_private(self); |
362 | |
363 | val = bus_space_read_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSTAT ); |
364 | if (val == 0) |
365 | return 0; /* not ours */ |
366 | |
367 | /* vid c */ |
368 | if (val & __BIT(2)) |
369 | coram_mpeg_intr(sc); |
370 | |
371 | if (val & ~__BIT(2)) |
372 | printf("%s %08x\n" , __func__, val); |
373 | |
374 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_STAT, val); |
375 | |
376 | return 1; |
377 | } |
378 | |
379 | static const struct coram_board * |
380 | coram_board_lookup(uint16_t vendor, uint16_t product) |
381 | { |
382 | unsigned int i; |
383 | |
384 | for (i = 0; i < __arraycount(coram_boards); i++) { |
385 | if (coram_boards[i].vendor == vendor && |
386 | coram_boards[i].product == product) { |
387 | return &coram_boards[i]; |
388 | } |
389 | } |
390 | |
391 | return NULL; |
392 | } |
393 | |
394 | #define CXDTV_TS_RISCI2 (1 << 4) |
395 | #define CXDTV_TS_RISCI1 (1 << 0) |
396 | |
397 | #define CXDTV_TS_RISCI (CXDTV_TS_RISCI1|CXDTV_TS_RISCI2) |
398 | |
399 | static int |
400 | coram_mpeg_intr(struct coram_softc *sc) |
401 | { |
402 | struct dtv_payload payload; |
403 | uint32_t s, m, v; |
404 | int i; |
405 | |
406 | s = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_INT_STAT); |
407 | m = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK); |
408 | |
409 | if ((s & m) == 0) |
410 | return 0; |
411 | |
412 | if ( (s & ~CXDTV_TS_RISCI) != 0 ) { |
413 | printf("%s: unexpected TS IS %08x\n" , |
414 | device_xname(sc->sc_dev), s); |
415 | |
416 | printf("cmds:\n" ); |
417 | for(i = 0; i < 20; i++) |
418 | { |
419 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, 0x10140 +(i*4)); |
420 | printf("%06x %08x\n" , 0x10140+(i*4), v); |
421 | } |
422 | } |
423 | |
424 | if (sc->sc_dtvsubmitcb == NULL) |
425 | goto done; |
426 | |
427 | if ((s & CXDTV_TS_RISCI1) == CXDTV_TS_RISCI1) { |
428 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma->map, |
429 | 0, CORAM_TS_PKTSIZE, |
430 | BUS_DMASYNC_POSTREAD); |
431 | payload.data = KERNADDR(sc->sc_dma); |
432 | payload.size = CORAM_TS_PKTSIZE; |
433 | sc->sc_dtvsubmitcb(sc->sc_dtvsubmitarg, &payload); |
434 | } |
435 | |
436 | if ((s & CXDTV_TS_RISCI2) == CXDTV_TS_RISCI2) { |
437 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma->map, |
438 | CORAM_TS_PKTSIZE, CORAM_TS_PKTSIZE, |
439 | BUS_DMASYNC_POSTREAD); |
440 | payload.data = (char *)(KERNADDR(sc->sc_dma)) + (uintptr_t)CORAM_TS_PKTSIZE; |
441 | payload.size = CORAM_TS_PKTSIZE; |
442 | sc->sc_dtvsubmitcb(sc->sc_dtvsubmitarg, &payload); |
443 | } |
444 | |
445 | done: |
446 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_INT_STAT, s); |
447 | |
448 | return 1; |
449 | } |
450 | |
451 | static bool |
452 | coram_resume(device_t dv, const pmf_qual_t *qual) |
453 | { |
454 | return true; |
455 | } |
456 | |
457 | static int |
458 | coram_iic_acquire_bus(void *cookie, int flags) |
459 | { |
460 | struct coram_iic_softc *cic; |
461 | |
462 | cic = cookie; |
463 | |
464 | if (flags & I2C_F_POLL) { |
465 | while (mutex_tryenter(&cic->cic_busmutex) == 0) |
466 | delay(50); |
467 | return 0; |
468 | } |
469 | |
470 | mutex_enter(&cic->cic_busmutex); |
471 | |
472 | return 0; |
473 | } |
474 | |
475 | static void |
476 | coram_iic_release_bus(void *cookie, int flags) |
477 | { |
478 | struct coram_iic_softc *cic; |
479 | |
480 | cic = cookie; |
481 | |
482 | mutex_exit(&cic->cic_busmutex); |
483 | |
484 | return; |
485 | } |
486 | |
487 | /* I2C Bus */ |
488 | |
489 | #define I2C_ADDR 0x0000 |
490 | #define I2C_WDATA 0x0004 |
491 | #define I2C_CTRL 0x0008 |
492 | #define I2C_RDATA 0x000c |
493 | #define I2C_STAT 0x0010 |
494 | |
495 | #define I2C_EXTEND (1 << 3) |
496 | #define I2C_NOSTOP (1 << 4) |
497 | |
498 | static int |
499 | coram_iic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, |
500 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
501 | { |
502 | struct coram_iic_softc *cic; |
503 | int ret; |
504 | |
505 | cic = cookie; |
506 | |
507 | if(cmdlen) { |
508 | ret = coram_iic_write(cic, op, addr, cmdbuf, cmdlen, buf, len, flags); |
509 | if(ret) |
510 | return ret; |
511 | } |
512 | |
513 | if(len) { |
514 | ret = coram_iic_read(cic, op, addr, cmdbuf, cmdlen, buf, len, flags); |
515 | if(ret) |
516 | return ret; |
517 | } |
518 | |
519 | |
520 | return 0; |
521 | |
522 | } |
523 | |
524 | static int |
525 | coram_iic_read(struct coram_iic_softc *cic, i2c_op_t op, i2c_addr_t addr, |
526 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
527 | { |
528 | uint8_t *rb; |
529 | uint32_t ctrl; |
530 | int bn; |
531 | |
532 | rb = buf; |
533 | |
534 | for ( bn = 0; bn < len; bn++) { |
535 | ctrl = (0x9d << 24) | (1 << 12) | (1 << 2) | 1; |
536 | if ( bn < len - 1 ) |
537 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
538 | |
539 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_ADDR, addr<<25); |
540 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_CTRL, ctrl); |
541 | |
542 | while((bus_space_read_4(cic->cic_sc->sc_memt, cic->cic_regh, |
543 | I2C_STAT) & 0x02)) { |
544 | delay(25); |
545 | } |
546 | if((bus_space_read_4(cic->cic_sc->sc_memt, cic->cic_regh, |
547 | I2C_STAT) & 0x01) == 0x00) { |
548 | // printf("%s %d no ack\n", __func__, bn); |
549 | return EIO; |
550 | } |
551 | |
552 | rb[bn] = bus_space_read_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_RDATA); |
553 | |
554 | } |
555 | |
556 | return 0; |
557 | } |
558 | |
559 | static int |
560 | coram_iic_write(struct coram_iic_softc *cic, i2c_op_t op, i2c_addr_t addr, |
561 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
562 | { |
563 | const uint8_t *wb; |
564 | uint32_t wdata, addrreg, ctrl; |
565 | int bn; |
566 | |
567 | wb = cmdbuf; |
568 | |
569 | addrreg = (addr << 25) | wb[0]; |
570 | wdata = wb[0]; |
571 | ctrl = (0x9d << 24) | (1 << 12) | (1 << 2); |
572 | |
573 | if ( cmdlen > 1 ) |
574 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
575 | else if (len) |
576 | ctrl |= I2C_NOSTOP; |
577 | |
578 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_ADDR, addrreg); |
579 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_WDATA, wdata); |
580 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_CTRL, ctrl); |
581 | |
582 | while((bus_space_read_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_STAT) & 0x02)) { |
583 | delay(25); } |
584 | |
585 | for ( bn = 1; bn < cmdlen; bn++) { |
586 | ctrl = (0x9d << 24) | (1 << 12) | (1 << 2); |
587 | wdata = wb[bn]; |
588 | |
589 | if ( bn < cmdlen - 1 ) |
590 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
591 | else if (len) |
592 | ctrl |= I2C_NOSTOP; |
593 | |
594 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_ADDR, addrreg); |
595 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_WDATA, wdata); |
596 | bus_space_write_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_CTRL, ctrl); |
597 | |
598 | while((bus_space_read_4(cic->cic_sc->sc_memt, cic->cic_regh, I2C_STAT) & 0x02)) { |
599 | delay(25); } |
600 | } |
601 | |
602 | return 0; |
603 | } |
604 | |
605 | static int |
606 | coram_mpeg_attach(struct coram_softc *sc) |
607 | { |
608 | struct coram_sram_ch *ch; |
609 | |
610 | ch = &coram_sram_chs[CORAM_SRAM_CH6]; |
611 | |
612 | sc->sc_riscbufsz = ch->csc_riscsz; |
613 | sc->sc_riscbuf = kmem_alloc(ch->csc_riscsz, KM_SLEEP); |
614 | |
615 | if ( sc->sc_riscbuf == NULL ) |
616 | panic("riscbuf null" ); |
617 | |
618 | coram_mpeg_reset(sc); |
619 | |
620 | sc->sc_tsbuf = NULL; |
621 | |
622 | coram_rescan(sc->sc_dev, NULL, NULL); |
623 | |
624 | return (sc->sc_dtvdev != NULL); |
625 | } |
626 | |
627 | static int |
628 | coram_mpeg_detach(struct coram_softc *sc, int flags) |
629 | { |
630 | struct coram_sram_ch *ch = &coram_sram_chs[CORAM_SRAM_CH6]; |
631 | int error; |
632 | |
633 | if (sc->sc_dtvdev) { |
634 | error = config_detach(sc->sc_dtvdev, flags); |
635 | if (error) |
636 | return error; |
637 | } |
638 | if (sc->sc_riscbuf) { |
639 | kmem_free(sc->sc_riscbuf, ch->csc_riscsz); |
640 | } |
641 | |
642 | return 0; |
643 | } |
644 | |
645 | static void |
646 | coram_dtv_get_devinfo(void *cookie, struct dvb_frontend_info *info) |
647 | { |
648 | struct coram_softc *sc = cookie; |
649 | |
650 | memset(info, 0, sizeof(*info)); |
651 | strlcpy(info->name, sc->sc_board->name, sizeof(info->name)); |
652 | info->type = FE_ATSC; |
653 | info->frequency_min = 54000000; |
654 | info->frequency_max = 858000000; |
655 | info->frequency_stepsize = 62500; |
656 | info->caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB; |
657 | } |
658 | |
659 | static int |
660 | coram_dtv_open(void *cookie, int flags) |
661 | { |
662 | struct coram_softc *sc = cookie; |
663 | |
664 | #ifdef CORAM_DEBUG |
665 | device_printf(sc->sc_dev, "%s\n" , __func__); |
666 | #endif |
667 | |
668 | //KASSERT(sc->sc_tsbuf == NULL); |
669 | |
670 | if (sc->sc_tuner == NULL || sc->sc_demod == NULL) |
671 | return ENXIO; |
672 | |
673 | coram_mpeg_reset(sc); |
674 | |
675 | /* allocate two alternating DMA areas for MPEG TS packets */ |
676 | sc->sc_tsbuf = coram_mpeg_malloc(sc, CORAM_TS_PKTSIZE * 2); |
677 | |
678 | if (sc->sc_tsbuf == NULL) |
679 | return ENOMEM; |
680 | |
681 | return 0; |
682 | } |
683 | |
684 | static void |
685 | coram_dtv_close(void *cookie) |
686 | { |
687 | struct coram_softc *sc = cookie; |
688 | |
689 | #ifdef CORAM_DEBUG |
690 | device_printf(sc->sc_dev, "%s\n" , __func__); |
691 | #endif |
692 | |
693 | coram_mpeg_halt(sc); |
694 | |
695 | if (sc->sc_tsbuf != NULL) { |
696 | coram_mpeg_free(sc, sc->sc_tsbuf); |
697 | sc->sc_tsbuf = NULL; |
698 | } |
699 | } |
700 | |
701 | static int |
702 | coram_dtv_set_tuner(void *cookie, const struct dvb_frontend_parameters *params) |
703 | { |
704 | struct coram_softc *sc = cookie; |
705 | |
706 | KASSERT(sc->sc_tuner != NULL); |
707 | mt2131_tune_dtv(sc->sc_tuner, params); |
708 | KASSERT(sc->sc_demod != NULL); |
709 | return cx24227_set_modulation(sc->sc_demod, params->u.vsb.modulation); |
710 | } |
711 | |
712 | static fe_status_t |
713 | coram_dtv_get_status(void *cookie) |
714 | { |
715 | struct coram_softc *sc = cookie; |
716 | |
717 | if (sc->sc_demod == NULL) |
718 | return ENXIO; |
719 | |
720 | return cx24227_get_dtv_status(sc->sc_demod);; |
721 | } |
722 | |
723 | static uint16_t |
724 | coram_dtv_get_signal_strength(void *cookie) |
725 | { |
726 | return 0; |
727 | } |
728 | |
729 | static uint16_t |
730 | coram_dtv_get_snr(void *cookie) |
731 | { |
732 | return 0; |
733 | } |
734 | |
735 | static int |
736 | coram_dtv_start_transfer(void *cookie, |
737 | void (*cb)(void *, const struct dtv_payload *), void *arg) |
738 | { |
739 | struct coram_softc *sc = cookie; |
740 | |
741 | #ifdef CORAM_DEBUG |
742 | device_printf(sc->sc_dev, "%s\n" , __func__); |
743 | #endif |
744 | |
745 | sc->sc_dtvsubmitcb = cb; |
746 | sc->sc_dtvsubmitarg = arg; |
747 | |
748 | coram_mpeg_trigger(sc, sc->sc_tsbuf); |
749 | |
750 | return 0; |
751 | } |
752 | |
753 | static int |
754 | coram_dtv_stop_transfer(void *cookie) |
755 | { |
756 | struct coram_softc *sc = cookie; |
757 | |
758 | #ifdef CORAM_DEBUG |
759 | device_printf(sc->sc_dev, "%s\n" , __func__); |
760 | #endif |
761 | |
762 | coram_mpeg_halt(sc); |
763 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK, 0); |
764 | |
765 | sc->sc_dtvsubmitcb = NULL; |
766 | sc->sc_dtvsubmitarg = NULL; |
767 | |
768 | return 0; |
769 | } |
770 | |
771 | |
772 | static int |
773 | coram_mpeg_reset(struct coram_softc *sc) |
774 | { |
775 | /* hold RISC in reset */ |
776 | bus_space_write_4(sc->sc_memt, sc->sc_memh, DEV_CNTRL2, 0); |
777 | |
778 | /* disable fifo + risc */ |
779 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_DMA_CTL, 0); |
780 | |
781 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK, 0); |
782 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK, 0); |
783 | |
784 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_STAT, 0); |
785 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_INT_STAT, 0); |
786 | |
787 | memset(sc->sc_riscbuf, 0, sc->sc_riscbufsz); |
788 | |
789 | return 0; |
790 | } |
791 | |
792 | static void * |
793 | coram_mpeg_malloc(struct coram_softc *sc, size_t size) |
794 | { |
795 | struct coram_dma *p; |
796 | int err; |
797 | |
798 | p = kmem_alloc(sizeof(struct coram_dma), KM_SLEEP); |
799 | if ( p == NULL ) |
800 | return NULL; |
801 | err = coram_allocmem(sc, size, 16, p); |
802 | if (err) { |
803 | kmem_free(p, sizeof(struct coram_dma)); |
804 | return NULL; |
805 | } |
806 | |
807 | p->next = sc->sc_dma; |
808 | sc->sc_dma = p; |
809 | |
810 | return KERNADDR(p); |
811 | } |
812 | |
813 | static int |
814 | coram_allocmem(struct coram_softc *sc, size_t size, size_t align, |
815 | struct coram_dma *p) |
816 | { |
817 | int err; |
818 | |
819 | p->size = size; |
820 | err = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0, |
821 | p->segs, sizeof(p->segs) / sizeof(p->segs[0]), |
822 | &p->nsegs, BUS_DMA_NOWAIT); |
823 | if (err) |
824 | return err; |
825 | err = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, |
826 | &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); |
827 | if (err) |
828 | goto free; |
829 | err = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0, |
830 | BUS_DMA_NOWAIT, &p->map); |
831 | if (err) |
832 | goto unmap; |
833 | err = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL, |
834 | BUS_DMA_NOWAIT); |
835 | if (err) |
836 | goto destroy; |
837 | |
838 | return 0; |
839 | destroy: |
840 | bus_dmamap_destroy(sc->sc_dmat, p->map); |
841 | unmap: |
842 | bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); |
843 | free: |
844 | bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); |
845 | |
846 | return err; |
847 | } |
848 | |
849 | static int |
850 | coram_mpeg_halt(struct coram_softc *sc) |
851 | { |
852 | uint32_t v; |
853 | |
854 | #ifdef CORAM_DEBUG |
855 | device_printf(sc->sc_dev, "%s\n" , __func__); |
856 | #endif |
857 | |
858 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_DMA_CTL, 0); |
859 | |
860 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK); |
861 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK, |
862 | v & __BIT(2)); |
863 | |
864 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK); |
865 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK, |
866 | v & 0); |
867 | |
868 | return 0; |
869 | } |
870 | |
871 | static void |
872 | coram_mpeg_free(struct coram_softc *sc, void *addr) |
873 | { |
874 | struct coram_dma *p; |
875 | struct coram_dma **pp; |
876 | |
877 | for (pp = &sc->sc_dma; (p = *pp) != NULL; pp = &p->next) |
878 | if (KERNADDR(p) == addr) { |
879 | coram_freemem(sc, p); |
880 | *pp = p->next; |
881 | kmem_free(p, sizeof(struct coram_dma)); |
882 | return; |
883 | } |
884 | |
885 | printf("%s: %p is already free\n" , device_xname(sc->sc_dev), addr); |
886 | return; |
887 | } |
888 | |
889 | static int |
890 | coram_freemem(struct coram_softc *sc, struct coram_dma *p) |
891 | { |
892 | bus_dmamap_unload(sc->sc_dmat, p->map); |
893 | bus_dmamap_destroy(sc->sc_dmat, p->map); |
894 | bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); |
895 | bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); |
896 | |
897 | return 0; |
898 | } |
899 | |
900 | static int |
901 | coram_mpeg_trigger(struct coram_softc *sc, void *buf) |
902 | { |
903 | struct coram_dma *p; |
904 | struct coram_sram_ch *ch; |
905 | uint32_t v; |
906 | |
907 | ch = &coram_sram_chs[CORAM_SRAM_CH6]; |
908 | |
909 | for (p = sc->sc_dma; p && KERNADDR(p) != buf; p = p->next) |
910 | continue; |
911 | if (p == NULL) { |
912 | printf("%s: coram_mpeg_trigger: bad addr %p\n" , |
913 | device_xname(sc->sc_dev), buf); |
914 | return ENOENT; |
915 | } |
916 | |
917 | /* disable fifo + risc */ |
918 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_DMA_CTL, 0); |
919 | |
920 | coram_risc_buffer(sc, CORAM_TS_PKTSIZE, 1); |
921 | coram_sram_ch_setup(sc, ch, CORAM_TS_PKTSIZE); |
922 | |
923 | /* let me hope this bit is the same as on the 2388[0-3] */ |
924 | /* software reset */ |
925 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_GEN_CTL, 0x0040); |
926 | delay (100*1000); |
927 | |
928 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_LNGTH, CORAM_TS_PKTSIZE); |
929 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_HW_SOP_CTL, 0x47 << 16 | 188 << 4); |
930 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_TS_CLK_EN, 1); |
931 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_VLD_MISC, 0); |
932 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_GEN_CTL, 12); |
933 | delay (100*1000); |
934 | |
935 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, PAD_CTRL); |
936 | v &= ~0x4; /* Clear TS2_SOP_OE */ |
937 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PAD_CTRL, v); |
938 | |
939 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK); |
940 | v |= 0x111111; |
941 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_INT_MSK, v); |
942 | |
943 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_DMA_CTL); |
944 | v |= 0x11; /* Enable RISC controller and FIFO */ |
945 | bus_space_write_4(sc->sc_memt, sc->sc_memh, VID_C_DMA_CTL, v); |
946 | |
947 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, DEV_CNTRL2); |
948 | v |= __BIT(5); /* Enable RISC controller */ |
949 | bus_space_write_4(sc->sc_memt, sc->sc_memh, DEV_CNTRL2, v); |
950 | |
951 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK); |
952 | v |= 0x001f00; |
953 | v |= 0x04; |
954 | bus_space_write_4(sc->sc_memt, sc->sc_memh, PCI_INT_MSK, v); |
955 | |
956 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_GEN_CTL); |
957 | #ifdef CORAM_DEBUG |
958 | printf("%s, %06x %08x\n" , __func__, VID_C_GEN_CTL, v); |
959 | #endif |
960 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_SOP_STATUS); |
961 | #ifdef CORAM_DEBUG |
962 | printf("%s, %06x %08x\n" , __func__, VID_C_SOP_STATUS, v); |
963 | #endif |
964 | delay(100*1000); |
965 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_GEN_CTL); |
966 | #ifdef CORAM_DEBUG |
967 | printf("%s, %06x %08x\n" , __func__, VID_C_GEN_CTL, v); |
968 | #endif |
969 | v = bus_space_read_4(sc->sc_memt, sc->sc_memh, VID_C_SOP_STATUS); |
970 | #ifdef CORAM_DEBUG |
971 | printf("%s, %06x %08x\n" , __func__, VID_C_SOP_STATUS, v); |
972 | #endif |
973 | |
974 | return 0; |
975 | } |
976 | |
977 | static int |
978 | coram_risc_buffer(struct coram_softc *sc, uint32_t bpl, uint32_t lines) |
979 | { |
980 | uint32_t *rm; |
981 | uint32_t size; |
982 | |
983 | size = 1 + (bpl * lines) / PAGE_SIZE + lines; |
984 | size += 2; |
985 | |
986 | if (sc->sc_riscbuf == NULL) { |
987 | return ENOMEM; |
988 | } |
989 | |
990 | rm = (uint32_t *)sc->sc_riscbuf; |
991 | coram_risc_field(sc, rm, bpl); |
992 | |
993 | return 0; |
994 | } |
995 | |
996 | static int |
997 | coram_risc_field(struct coram_softc *sc, uint32_t *rm, uint32_t bpl) |
998 | { |
999 | struct coram_dma *p; |
1000 | |
1001 | for (p = sc->sc_dma; p && KERNADDR(p) != sc->sc_tsbuf; p = p->next) |
1002 | continue; |
1003 | if (p == NULL) { |
1004 | printf("%s: coram_risc_field: bad addr %p\n" , |
1005 | device_xname(sc->sc_dev), sc->sc_tsbuf); |
1006 | return ENOENT; |
1007 | } |
1008 | |
1009 | memset(sc->sc_riscbuf, 0, sc->sc_riscbufsz); |
1010 | |
1011 | rm = sc->sc_riscbuf; |
1012 | |
1013 | /* htole32 will be done when program is copied to chip sram */ |
1014 | |
1015 | /* XXX */ |
1016 | *(rm++) = (CX_RISC_SYNC|0); |
1017 | |
1018 | *(rm++) = (CX_RISC_WRITE|CX_RISC_SOL|CX_RISC_EOL|CX_RISC_IRQ1|bpl); |
1019 | *(rm++) = (DMAADDR(p) + 0 * bpl); |
1020 | *(rm++) = 0; /* high dword */ |
1021 | |
1022 | *(rm++) = (CX_RISC_WRITE|CX_RISC_SOL|CX_RISC_EOL|CX_RISC_IRQ2|bpl); |
1023 | *(rm++) = (DMAADDR(p) + 1 * bpl); |
1024 | *(rm++) = 0; |
1025 | |
1026 | *(rm++) = (CX_RISC_JUMP|1); |
1027 | *(rm++) = (coram_sram_chs[CORAM_SRAM_CH6].csc_risc + 4); |
1028 | *(rm++) = 0; |
1029 | |
1030 | return 0; |
1031 | } |
1032 | |
1033 | static int |
1034 | coram_sram_ch_setup(struct coram_softc *sc, struct coram_sram_ch *csc, |
1035 | uint32_t bpl) |
1036 | { |
1037 | unsigned int i, lines; |
1038 | uint32_t cdt; |
1039 | |
1040 | /* XXX why round? */ |
1041 | bpl = (bpl + 7) & ~7; |
1042 | cdt = csc->csc_cdt; |
1043 | lines = csc->csc_fifosz / bpl; |
1044 | #ifdef CORAM_DEBUG |
1045 | printf("%s %d lines\n" , __func__, lines); |
1046 | #endif |
1047 | |
1048 | /* fill in CDT */ |
1049 | for (i = 0; i < lines; i++) { |
1050 | #ifdef CORAM_DEBUG |
1051 | printf("CDT ent %08x, %08x\n" , cdt + (16 * i), |
1052 | csc->csc_fifo + (bpl * i)); |
1053 | #endif |
1054 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1055 | cdt + (16 * i), csc->csc_fifo + (bpl * i)); |
1056 | } |
1057 | |
1058 | /* copy program */ |
1059 | /* converts program to little endian as it goes into sram */ |
1060 | bus_space_write_region_4(sc->sc_memt, sc->sc_memh, |
1061 | csc->csc_risc, (void *)sc->sc_riscbuf, sc->sc_riscbufsz >> 2); |
1062 | |
1063 | /* fill in CMDS */ |
1064 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1065 | csc->csc_cmds + CMDS_O_IRPC, csc->csc_risc); |
1066 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1067 | csc->csc_cmds + CMDS_O_IRPC + 4, 0); |
1068 | |
1069 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1070 | csc->csc_cmds + CMDS_O_CDTB, csc->csc_cdt); |
1071 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1072 | csc->csc_cmds + CMDS_O_CDTS, (lines * 16) >> 3); /* XXX magic */ |
1073 | |
1074 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1075 | csc->csc_cmds + CMDS_O_IQB, csc->csc_iq); |
1076 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1077 | csc->csc_cmds + CMDS_O_IQS, |
1078 | CMDS_IQS_ISRP | (csc->csc_iqsz >> 2) ); |
1079 | |
1080 | /* zero rest of CMDS */ |
1081 | bus_space_set_region_4(sc->sc_memt, sc->sc_memh, 0x18, 0, 20); |
1082 | |
1083 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1084 | csc->csc_ptr1, csc->csc_fifo); |
1085 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1086 | csc->csc_ptr2, cdt); |
1087 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1088 | csc->csc_cnt2, (lines * 16) >> 3); |
1089 | bus_space_write_4(sc->sc_memt, sc->sc_memh, |
1090 | csc->csc_cnt1, (bpl >> 3) - 1); |
1091 | |
1092 | return 0; |
1093 | } |
1094 | |
1095 | MODULE(MODULE_CLASS_DRIVER, coram, "cx24227,mt2131,pci" ); |
1096 | |
1097 | #ifdef _MODULE |
1098 | #include "ioconf.c" |
1099 | #endif |
1100 | |
1101 | static int |
1102 | coram_modcmd(modcmd_t cmd, void *v) |
1103 | { |
1104 | int error = 0; |
1105 | |
1106 | switch (cmd) { |
1107 | case MODULE_CMD_INIT: |
1108 | #ifdef _MODULE |
1109 | error = config_init_component(cfdriver_ioconf_coram, |
1110 | cfattach_ioconf_coram, cfdata_ioconf_coram); |
1111 | #endif |
1112 | return error; |
1113 | case MODULE_CMD_FINI: |
1114 | #ifdef _MODULE |
1115 | error = config_fini_component(cfdriver_ioconf_coram, |
1116 | cfattach_ioconf_coram, cfdata_ioconf_coram); |
1117 | #endif |
1118 | return error; |
1119 | default: |
1120 | return ENOTTY; |
1121 | } |
1122 | } |
1123 | |