PNP: stop using the subsystem rwsem
[linux/fpc-iii.git] / drivers / media / video / cx88 / cx88-core.c
blobd86813be56de33fa8df22e3402ba94fa669af524
1 /*
3 * device driver for Conexant 2388x based TV cards
4 * driver core
6 * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
8 * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
9 * - Multituner support
10 * - video_ioctl2 conversion
11 * - PAL/M fixes
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <linux/init.h>
29 #include <linux/list.h>
30 #include <linux/module.h>
31 #include <linux/moduleparam.h>
32 #include <linux/kernel.h>
33 #include <linux/slab.h>
34 #include <linux/kmod.h>
35 #include <linux/sound.h>
36 #include <linux/interrupt.h>
37 #include <linux/pci.h>
38 #include <linux/delay.h>
39 #include <linux/videodev2.h>
40 #include <linux/mutex.h>
42 #include "cx88.h"
43 #include <media/v4l2-common.h>
45 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
46 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
47 MODULE_LICENSE("GPL");
49 /* ------------------------------------------------------------------ */
51 static unsigned int core_debug = 0;
52 module_param(core_debug,int,0644);
53 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
55 static unsigned int latency = UNSET;
56 module_param(latency,int,0444);
57 MODULE_PARM_DESC(latency,"pci latency timer");
59 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
60 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
61 static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
63 module_param_array(tuner, int, NULL, 0444);
64 module_param_array(radio, int, NULL, 0444);
65 module_param_array(card, int, NULL, 0444);
67 MODULE_PARM_DESC(tuner,"tuner type");
68 MODULE_PARM_DESC(radio,"radio tuner type");
69 MODULE_PARM_DESC(card,"card type");
71 static unsigned int nicam = 0;
72 module_param(nicam,int,0644);
73 MODULE_PARM_DESC(nicam,"tv audio is nicam");
75 static unsigned int nocomb = 0;
76 module_param(nocomb,int,0644);
77 MODULE_PARM_DESC(nocomb,"disable comb filter");
79 #define dprintk(level,fmt, arg...) if (core_debug >= level) \
80 printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
82 static unsigned int cx88_devcount;
83 static LIST_HEAD(cx88_devlist);
84 static DEFINE_MUTEX(devlist);
86 #define NO_SYNC_LINE (-1U)
88 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
89 unsigned int offset, u32 sync_line,
90 unsigned int bpl, unsigned int padding,
91 unsigned int lines)
93 struct scatterlist *sg;
94 unsigned int line,todo;
96 /* sync instruction */
97 if (sync_line != NO_SYNC_LINE)
98 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
100 /* scan lines */
101 sg = sglist;
102 for (line = 0; line < lines; line++) {
103 while (offset && offset >= sg_dma_len(sg)) {
104 offset -= sg_dma_len(sg);
105 sg++;
107 if (bpl <= sg_dma_len(sg)-offset) {
108 /* fits into current chunk */
109 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
110 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
111 offset+=bpl;
112 } else {
113 /* scanline needs to be split */
114 todo = bpl;
115 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
116 (sg_dma_len(sg)-offset));
117 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
118 todo -= (sg_dma_len(sg)-offset);
119 offset = 0;
120 sg++;
121 while (todo > sg_dma_len(sg)) {
122 *(rp++)=cpu_to_le32(RISC_WRITE|
123 sg_dma_len(sg));
124 *(rp++)=cpu_to_le32(sg_dma_address(sg));
125 todo -= sg_dma_len(sg);
126 sg++;
128 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
129 *(rp++)=cpu_to_le32(sg_dma_address(sg));
130 offset += todo;
132 offset += padding;
135 return rp;
138 int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
139 struct scatterlist *sglist,
140 unsigned int top_offset, unsigned int bottom_offset,
141 unsigned int bpl, unsigned int padding, unsigned int lines)
143 u32 instructions,fields;
144 u32 *rp;
145 int rc;
147 fields = 0;
148 if (UNSET != top_offset)
149 fields++;
150 if (UNSET != bottom_offset)
151 fields++;
153 /* estimate risc mem: worst case is one write per page border +
154 one write per scan line + syncs + jump (all 2 dwords). Padding
155 can cause next bpl to start close to a page border. First DMA
156 region may be smaller than PAGE_SIZE */
157 instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
158 instructions += 2;
159 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
160 return rc;
162 /* write risc instructions */
163 rp = risc->cpu;
164 if (UNSET != top_offset)
165 rp = cx88_risc_field(rp, sglist, top_offset, 0,
166 bpl, padding, lines);
167 if (UNSET != bottom_offset)
168 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
169 bpl, padding, lines);
171 /* save pointer to jmp instruction address */
172 risc->jmp = rp;
173 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
174 return 0;
177 int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
178 struct scatterlist *sglist, unsigned int bpl,
179 unsigned int lines)
181 u32 instructions;
182 u32 *rp;
183 int rc;
185 /* estimate risc mem: worst case is one write per page border +
186 one write per scan line + syncs + jump (all 2 dwords). Here
187 there is no padding and no sync. First DMA region may be smaller
188 than PAGE_SIZE */
189 instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
190 instructions += 1;
191 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
192 return rc;
194 /* write risc instructions */
195 rp = risc->cpu;
196 rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
198 /* save pointer to jmp instruction address */
199 risc->jmp = rp;
200 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
201 return 0;
204 int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
205 u32 reg, u32 mask, u32 value)
207 u32 *rp;
208 int rc;
210 if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
211 return rc;
213 /* write risc instructions */
214 rp = risc->cpu;
215 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
216 *(rp++) = cpu_to_le32(reg);
217 *(rp++) = cpu_to_le32(value);
218 *(rp++) = cpu_to_le32(mask);
219 *(rp++) = cpu_to_le32(RISC_JUMP);
220 *(rp++) = cpu_to_le32(risc->dma);
221 return 0;
224 void
225 cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
227 BUG_ON(in_interrupt());
228 videobuf_waiton(&buf->vb,0,0);
229 videobuf_dma_unmap(q, &buf->vb.dma);
230 videobuf_dma_free(&buf->vb.dma);
231 btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
232 buf->vb.state = STATE_NEEDS_INIT;
235 /* ------------------------------------------------------------------ */
236 /* our SRAM memory layout */
238 /* we are going to put all thr risc programs into host memory, so we
239 * can use the whole SDRAM for the DMA fifos. To simplify things, we
240 * use a static memory layout. That surely will waste memory in case
241 * we don't use all DMA channels at the same time (which will be the
242 * case most of the time). But that still gives us enougth FIFO space
243 * to be able to deal with insane long pci latencies ...
245 * FIFO space allocations:
246 * channel 21 (y video) - 10.0k
247 * channel 22 (u video) - 2.0k
248 * channel 23 (v video) - 2.0k
249 * channel 24 (vbi) - 4.0k
250 * channels 25+26 (audio) - 4.0k
251 * channel 28 (mpeg) - 4.0k
252 * TOTAL = 29.0k
254 * Every channel has 160 bytes control data (64 bytes instruction
255 * queue and 6 CDT entries), which is close to 2k total.
257 * Address layout:
258 * 0x0000 - 0x03ff CMDs / reserved
259 * 0x0400 - 0x0bff instruction queues + CDs
260 * 0x0c00 - FIFOs
263 struct sram_channel cx88_sram_channels[] = {
264 [SRAM_CH21] = {
265 .name = "video y / packed",
266 .cmds_start = 0x180040,
267 .ctrl_start = 0x180400,
268 .cdt = 0x180400 + 64,
269 .fifo_start = 0x180c00,
270 .fifo_size = 0x002800,
271 .ptr1_reg = MO_DMA21_PTR1,
272 .ptr2_reg = MO_DMA21_PTR2,
273 .cnt1_reg = MO_DMA21_CNT1,
274 .cnt2_reg = MO_DMA21_CNT2,
276 [SRAM_CH22] = {
277 .name = "video u",
278 .cmds_start = 0x180080,
279 .ctrl_start = 0x1804a0,
280 .cdt = 0x1804a0 + 64,
281 .fifo_start = 0x183400,
282 .fifo_size = 0x000800,
283 .ptr1_reg = MO_DMA22_PTR1,
284 .ptr2_reg = MO_DMA22_PTR2,
285 .cnt1_reg = MO_DMA22_CNT1,
286 .cnt2_reg = MO_DMA22_CNT2,
288 [SRAM_CH23] = {
289 .name = "video v",
290 .cmds_start = 0x1800c0,
291 .ctrl_start = 0x180540,
292 .cdt = 0x180540 + 64,
293 .fifo_start = 0x183c00,
294 .fifo_size = 0x000800,
295 .ptr1_reg = MO_DMA23_PTR1,
296 .ptr2_reg = MO_DMA23_PTR2,
297 .cnt1_reg = MO_DMA23_CNT1,
298 .cnt2_reg = MO_DMA23_CNT2,
300 [SRAM_CH24] = {
301 .name = "vbi",
302 .cmds_start = 0x180100,
303 .ctrl_start = 0x1805e0,
304 .cdt = 0x1805e0 + 64,
305 .fifo_start = 0x184400,
306 .fifo_size = 0x001000,
307 .ptr1_reg = MO_DMA24_PTR1,
308 .ptr2_reg = MO_DMA24_PTR2,
309 .cnt1_reg = MO_DMA24_CNT1,
310 .cnt2_reg = MO_DMA24_CNT2,
312 [SRAM_CH25] = {
313 .name = "audio from",
314 .cmds_start = 0x180140,
315 .ctrl_start = 0x180680,
316 .cdt = 0x180680 + 64,
317 .fifo_start = 0x185400,
318 .fifo_size = 0x001000,
319 .ptr1_reg = MO_DMA25_PTR1,
320 .ptr2_reg = MO_DMA25_PTR2,
321 .cnt1_reg = MO_DMA25_CNT1,
322 .cnt2_reg = MO_DMA25_CNT2,
324 [SRAM_CH26] = {
325 .name = "audio to",
326 .cmds_start = 0x180180,
327 .ctrl_start = 0x180720,
328 .cdt = 0x180680 + 64, /* same as audio IN */
329 .fifo_start = 0x185400, /* same as audio IN */
330 .fifo_size = 0x001000, /* same as audio IN */
331 .ptr1_reg = MO_DMA26_PTR1,
332 .ptr2_reg = MO_DMA26_PTR2,
333 .cnt1_reg = MO_DMA26_CNT1,
334 .cnt2_reg = MO_DMA26_CNT2,
336 [SRAM_CH28] = {
337 .name = "mpeg",
338 .cmds_start = 0x180200,
339 .ctrl_start = 0x1807C0,
340 .cdt = 0x1807C0 + 64,
341 .fifo_start = 0x186400,
342 .fifo_size = 0x001000,
343 .ptr1_reg = MO_DMA28_PTR1,
344 .ptr2_reg = MO_DMA28_PTR2,
345 .cnt1_reg = MO_DMA28_CNT1,
346 .cnt2_reg = MO_DMA28_CNT2,
350 int cx88_sram_channel_setup(struct cx88_core *core,
351 struct sram_channel *ch,
352 unsigned int bpl, u32 risc)
354 unsigned int i,lines;
355 u32 cdt;
357 bpl = (bpl + 7) & ~7; /* alignment */
358 cdt = ch->cdt;
359 lines = ch->fifo_size / bpl;
360 if (lines > 6)
361 lines = 6;
362 BUG_ON(lines < 2);
364 /* write CDT */
365 for (i = 0; i < lines; i++)
366 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
368 /* write CMDS */
369 cx_write(ch->cmds_start + 0, risc);
370 cx_write(ch->cmds_start + 4, cdt);
371 cx_write(ch->cmds_start + 8, (lines*16) >> 3);
372 cx_write(ch->cmds_start + 12, ch->ctrl_start);
373 cx_write(ch->cmds_start + 16, 64 >> 2);
374 for (i = 20; i < 64; i += 4)
375 cx_write(ch->cmds_start + i, 0);
377 /* fill registers */
378 cx_write(ch->ptr1_reg, ch->fifo_start);
379 cx_write(ch->ptr2_reg, cdt);
380 cx_write(ch->cnt1_reg, (bpl >> 3) -1);
381 cx_write(ch->cnt2_reg, (lines*16) >> 3);
383 dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
384 return 0;
387 /* ------------------------------------------------------------------ */
388 /* debug helper code */
390 static int cx88_risc_decode(u32 risc)
392 static char *instr[16] = {
393 [ RISC_SYNC >> 28 ] = "sync",
394 [ RISC_WRITE >> 28 ] = "write",
395 [ RISC_WRITEC >> 28 ] = "writec",
396 [ RISC_READ >> 28 ] = "read",
397 [ RISC_READC >> 28 ] = "readc",
398 [ RISC_JUMP >> 28 ] = "jump",
399 [ RISC_SKIP >> 28 ] = "skip",
400 [ RISC_WRITERM >> 28 ] = "writerm",
401 [ RISC_WRITECM >> 28 ] = "writecm",
402 [ RISC_WRITECR >> 28 ] = "writecr",
404 static int incr[16] = {
405 [ RISC_WRITE >> 28 ] = 2,
406 [ RISC_JUMP >> 28 ] = 2,
407 [ RISC_WRITERM >> 28 ] = 3,
408 [ RISC_WRITECM >> 28 ] = 3,
409 [ RISC_WRITECR >> 28 ] = 4,
411 static char *bits[] = {
412 "12", "13", "14", "resync",
413 "cnt0", "cnt1", "18", "19",
414 "20", "21", "22", "23",
415 "irq1", "irq2", "eol", "sol",
417 int i;
419 printk("0x%08x [ %s", risc,
420 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
421 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
422 if (risc & (1 << (i + 12)))
423 printk(" %s",bits[i]);
424 printk(" count=%d ]\n", risc & 0xfff);
425 return incr[risc >> 28] ? incr[risc >> 28] : 1;
429 void cx88_sram_channel_dump(struct cx88_core *core,
430 struct sram_channel *ch)
432 static char *name[] = {
433 "initial risc",
434 "cdt base",
435 "cdt size",
436 "iq base",
437 "iq size",
438 "risc pc",
439 "iq wr ptr",
440 "iq rd ptr",
441 "cdt current",
442 "pci target",
443 "line / byte",
445 u32 risc;
446 unsigned int i,j,n;
448 printk("%s: %s - dma channel status dump\n",
449 core->name,ch->name);
450 for (i = 0; i < ARRAY_SIZE(name); i++)
451 printk("%s: cmds: %-12s: 0x%08x\n",
452 core->name,name[i],
453 cx_read(ch->cmds_start + 4*i));
454 for (i = 0; i < 4; i++) {
455 risc = cx_read(ch->cmds_start + 4 * (i+11));
456 printk("%s: risc%d: ", core->name, i);
457 cx88_risc_decode(risc);
459 for (i = 0; i < 16; i += n) {
460 risc = cx_read(ch->ctrl_start + 4 * i);
461 printk("%s: iq %x: ", core->name, i);
462 n = cx88_risc_decode(risc);
463 for (j = 1; j < n; j++) {
464 risc = cx_read(ch->ctrl_start + 4 * (i+j));
465 printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
466 core->name, i+j, risc, j);
470 printk("%s: fifo: 0x%08x -> 0x%x\n",
471 core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
472 printk("%s: ctrl: 0x%08x -> 0x%x\n",
473 core->name, ch->ctrl_start, ch->ctrl_start+6*16);
474 printk("%s: ptr1_reg: 0x%08x\n",
475 core->name,cx_read(ch->ptr1_reg));
476 printk("%s: ptr2_reg: 0x%08x\n",
477 core->name,cx_read(ch->ptr2_reg));
478 printk("%s: cnt1_reg: 0x%08x\n",
479 core->name,cx_read(ch->cnt1_reg));
480 printk("%s: cnt2_reg: 0x%08x\n",
481 core->name,cx_read(ch->cnt2_reg));
484 static char *cx88_pci_irqs[32] = {
485 "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
486 "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
487 "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
488 "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
491 void cx88_print_irqbits(char *name, char *tag, char **strings,
492 u32 bits, u32 mask)
494 unsigned int i;
496 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
497 for (i = 0; i < 32; i++) {
498 if (!(bits & (1 << i)))
499 continue;
500 if (strings[i])
501 printk(" %s", strings[i]);
502 else
503 printk(" %d", i);
504 if (!(mask & (1 << i)))
505 continue;
506 printk("*");
508 printk("\n");
511 /* ------------------------------------------------------------------ */
513 int cx88_core_irq(struct cx88_core *core, u32 status)
515 int handled = 0;
517 if (status & (1<<18)) {
518 cx88_ir_irq(core);
519 handled++;
521 if (!handled)
522 cx88_print_irqbits(core->name, "irq pci",
523 cx88_pci_irqs, status,
524 core->pci_irqmask);
525 return handled;
528 void cx88_wakeup(struct cx88_core *core,
529 struct cx88_dmaqueue *q, u32 count)
531 struct cx88_buffer *buf;
532 int bc;
534 for (bc = 0;; bc++) {
535 if (list_empty(&q->active))
536 break;
537 buf = list_entry(q->active.next,
538 struct cx88_buffer, vb.queue);
539 /* count comes from the hw and is is 16bit wide --
540 * this trick handles wrap-arounds correctly for
541 * up to 32767 buffers in flight... */
542 if ((s16) (count - buf->count) < 0)
543 break;
544 do_gettimeofday(&buf->vb.ts);
545 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
546 count, buf->count);
547 buf->vb.state = STATE_DONE;
548 list_del(&buf->vb.queue);
549 wake_up(&buf->vb.done);
551 if (list_empty(&q->active)) {
552 del_timer(&q->timeout);
553 } else {
554 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
556 if (bc != 1)
557 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
560 void cx88_shutdown(struct cx88_core *core)
562 /* disable RISC controller + IRQs */
563 cx_write(MO_DEV_CNTRL2, 0);
565 /* stop dma transfers */
566 cx_write(MO_VID_DMACNTRL, 0x0);
567 cx_write(MO_AUD_DMACNTRL, 0x0);
568 cx_write(MO_TS_DMACNTRL, 0x0);
569 cx_write(MO_VIP_DMACNTRL, 0x0);
570 cx_write(MO_GPHST_DMACNTRL, 0x0);
572 /* stop interrupts */
573 cx_write(MO_PCI_INTMSK, 0x0);
574 cx_write(MO_VID_INTMSK, 0x0);
575 cx_write(MO_AUD_INTMSK, 0x0);
576 cx_write(MO_TS_INTMSK, 0x0);
577 cx_write(MO_VIP_INTMSK, 0x0);
578 cx_write(MO_GPHST_INTMSK, 0x0);
580 /* stop capturing */
581 cx_write(VID_CAPTURE_CONTROL, 0);
584 int cx88_reset(struct cx88_core *core)
586 dprintk(1,"%s\n",__FUNCTION__);
587 cx88_shutdown(core);
589 /* clear irq status */
590 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
591 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
592 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
594 /* wait a bit */
595 msleep(100);
597 /* init sram */
598 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
599 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
600 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
601 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
602 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
603 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
604 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
606 /* misc init ... */
607 cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
608 (1 << 12) | // agc gain
609 (1 << 11) | // adaptibe agc
610 (0 << 10) | // chroma agc
611 (0 << 9) | // ckillen
612 (7)));
614 /* setup image format */
615 cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
617 /* setup FIFO Threshholds */
618 cx_write(MO_PDMA_STHRSH, 0x0807);
619 cx_write(MO_PDMA_DTHRSH, 0x0807);
621 /* fixes flashing of image */
622 cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
623 cx_write(MO_AGC_BACK_VBI, 0x00E00555);
625 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
626 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
627 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
629 /* Reset on-board parts */
630 cx_write(MO_SRST_IO, 0);
631 msleep(10);
632 cx_write(MO_SRST_IO, 1);
634 return 0;
637 /* ------------------------------------------------------------------ */
639 static unsigned int inline norm_swidth(v4l2_std_id norm)
641 return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
644 static unsigned int inline norm_hdelay(v4l2_std_id norm)
646 return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
649 static unsigned int inline norm_vdelay(v4l2_std_id norm)
651 return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
654 static unsigned int inline norm_fsc8(v4l2_std_id norm)
656 if (norm & V4L2_STD_PAL_M)
657 return 28604892; // 3.575611 MHz
659 if (norm & (V4L2_STD_PAL_Nc))
660 return 28656448; // 3.582056 MHz
662 if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
663 return 28636360; // 3.57954545 MHz +/- 10 Hz
665 /* SECAM have also different sub carrier for chroma,
666 but step_db and step_dr, at cx88_set_tvnorm already handles that.
668 The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
671 return 35468950; // 4.43361875 MHz +/- 5 Hz
674 static unsigned int inline norm_htotal(v4l2_std_id norm)
677 unsigned int fsc4=norm_fsc8(norm)/2;
679 /* returns 4*FSC / vtotal / frames per seconds */
680 return (norm & V4L2_STD_625_50) ?
681 ((fsc4+312)/625+12)/25 :
682 ((fsc4+262)/525*1001+15000)/30000;
685 static unsigned int inline norm_vbipack(v4l2_std_id norm)
687 return (norm & V4L2_STD_625_50) ? 511 : 400;
690 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
691 enum v4l2_field field)
693 unsigned int swidth = norm_swidth(core->tvnorm);
694 unsigned int sheight = norm_maxh(core->tvnorm);
695 u32 value;
697 dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
698 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
699 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
700 v4l2_norm_to_name(core->tvnorm));
701 if (!V4L2_FIELD_HAS_BOTH(field))
702 height *= 2;
704 // recalc H delay and scale registers
705 value = (width * norm_hdelay(core->tvnorm)) / swidth;
706 value &= 0x3fe;
707 cx_write(MO_HDELAY_EVEN, value);
708 cx_write(MO_HDELAY_ODD, value);
709 dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
711 value = (swidth * 4096 / width) - 4096;
712 cx_write(MO_HSCALE_EVEN, value);
713 cx_write(MO_HSCALE_ODD, value);
714 dprintk(1,"set_scale: hscale 0x%04x\n", value);
716 cx_write(MO_HACTIVE_EVEN, width);
717 cx_write(MO_HACTIVE_ODD, width);
718 dprintk(1,"set_scale: hactive 0x%04x\n", width);
720 // recalc V scale Register (delay is constant)
721 cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
722 cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
723 dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
725 value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
726 cx_write(MO_VSCALE_EVEN, value);
727 cx_write(MO_VSCALE_ODD, value);
728 dprintk(1,"set_scale: vscale 0x%04x\n", value);
730 cx_write(MO_VACTIVE_EVEN, sheight);
731 cx_write(MO_VACTIVE_ODD, sheight);
732 dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
734 // setup filters
735 value = 0;
736 value |= (1 << 19); // CFILT (default)
737 if (core->tvnorm & V4L2_STD_SECAM) {
738 value |= (1 << 15);
739 value |= (1 << 16);
741 if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
742 value |= (1 << 13) | (1 << 5);
743 if (V4L2_FIELD_INTERLACED == field)
744 value |= (1 << 3); // VINT (interlaced vertical scaling)
745 if (width < 385)
746 value |= (1 << 0); // 3-tap interpolation
747 if (width < 193)
748 value |= (1 << 1); // 5-tap interpolation
749 if (nocomb)
750 value |= (3 << 5); // disable comb filter
752 cx_write(MO_FILTER_EVEN, value);
753 cx_write(MO_FILTER_ODD, value);
754 dprintk(1,"set_scale: filter 0x%04x\n", value);
756 return 0;
759 static const u32 xtal = 28636363;
761 static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
763 static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
764 u64 pll;
765 u32 reg;
766 int i;
768 if (prescale < 2)
769 prescale = 2;
770 if (prescale > 5)
771 prescale = 5;
773 pll = ofreq * 8 * prescale * (u64)(1 << 20);
774 do_div(pll,xtal);
775 reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
776 if (((reg >> 20) & 0x3f) < 14) {
777 printk("%s/0: pll out of range\n",core->name);
778 return -1;
781 dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
782 reg, cx_read(MO_PLL_REG), ofreq);
783 cx_write(MO_PLL_REG, reg);
784 for (i = 0; i < 100; i++) {
785 reg = cx_read(MO_DEVICE_STATUS);
786 if (reg & (1<<2)) {
787 dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
788 prescale,ofreq);
789 return 0;
791 dprintk(1,"pll not locked yet, waiting ...\n");
792 msleep(10);
794 dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
795 return -1;
798 int cx88_start_audio_dma(struct cx88_core *core)
800 /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
801 int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
803 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
804 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
805 return 0;
807 /* setup fifo + format */
808 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
809 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
811 cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
812 cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
814 /* start dma */
815 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
817 return 0;
820 int cx88_stop_audio_dma(struct cx88_core *core)
822 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
823 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
824 return 0;
826 /* stop dma */
827 cx_write(MO_AUD_DMACNTRL, 0x0000);
829 return 0;
832 static int set_tvaudio(struct cx88_core *core)
834 v4l2_std_id norm = core->tvnorm;
836 if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
837 return 0;
839 if (V4L2_STD_PAL_BG & norm) {
840 core->tvaudio = WW_BG;
842 } else if (V4L2_STD_PAL_DK & norm) {
843 core->tvaudio = WW_DK;
845 } else if (V4L2_STD_PAL_I & norm) {
846 core->tvaudio = WW_I;
848 } else if (V4L2_STD_SECAM_L & norm) {
849 core->tvaudio = WW_L;
851 } else if (V4L2_STD_SECAM_DK & norm) {
852 core->tvaudio = WW_DK;
854 } else if ((V4L2_STD_NTSC_M & norm) ||
855 (V4L2_STD_PAL_M & norm)) {
856 core->tvaudio = WW_BTSC;
858 } else if (V4L2_STD_NTSC_M_JP & norm) {
859 core->tvaudio = WW_EIAJ;
861 } else {
862 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
863 core->name, v4l2_norm_to_name(core->tvnorm));
864 core->tvaudio = 0;
865 return 0;
868 cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
869 cx88_set_tvaudio(core);
870 /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
873 This should be needed only on cx88-alsa. It seems that some cx88 chips have
874 bugs and does require DMA enabled for it to work.
876 cx88_start_audio_dma(core);
877 return 0;
882 int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
884 u32 fsc8;
885 u32 adc_clock;
886 u32 vdec_clock;
887 u32 step_db,step_dr;
888 u64 tmp64;
889 u32 bdelay,agcdelay,htotal;
890 u32 cxiformat, cxoformat;
892 core->tvnorm = norm;
893 fsc8 = norm_fsc8(norm);
894 adc_clock = xtal;
895 vdec_clock = fsc8;
896 step_db = fsc8;
897 step_dr = fsc8;
899 if (norm & V4L2_STD_NTSC_M_JP) {
900 cxiformat = VideoFormatNTSCJapan;
901 cxoformat = 0x181f0008;
902 } else if (norm & V4L2_STD_NTSC_443) {
903 cxiformat = VideoFormatNTSC443;
904 cxoformat = 0x181f0008;
905 } else if (norm & V4L2_STD_PAL_M) {
906 cxiformat = VideoFormatPALM;
907 cxoformat = 0x1c1f0008;
908 } else if (norm & V4L2_STD_PAL_N) {
909 cxiformat = VideoFormatPALN;
910 cxoformat = 0x1c1f0008;
911 } else if (norm & V4L2_STD_PAL_Nc) {
912 cxiformat = VideoFormatPALNC;
913 cxoformat = 0x1c1f0008;
914 } else if (norm & V4L2_STD_PAL_60) {
915 cxiformat = VideoFormatPAL60;
916 cxoformat = 0x181f0008;
917 } else if (norm & V4L2_STD_NTSC) {
918 cxiformat = VideoFormatNTSC;
919 cxoformat = 0x181f0008;
920 } else if (norm & V4L2_STD_SECAM) {
921 step_db = 4250000 * 8;
922 step_dr = 4406250 * 8;
924 cxiformat = VideoFormatSECAM;
925 cxoformat = 0x181f0008;
926 } else { /* PAL */
927 cxiformat = VideoFormatPAL;
928 cxoformat = 0x181f0008;
931 dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
932 v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
933 step_db, step_dr);
934 set_pll(core,2,vdec_clock);
936 dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
937 cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
938 cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
940 // FIXME: as-is from DScaler
941 dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
942 cxoformat, cx_read(MO_OUTPUT_FORMAT));
943 cx_write(MO_OUTPUT_FORMAT, cxoformat);
945 // MO_SCONV_REG = adc clock / video dec clock * 2^17
946 tmp64 = adc_clock * (u64)(1 << 17);
947 do_div(tmp64, vdec_clock);
948 dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
949 (u32)tmp64, cx_read(MO_SCONV_REG));
950 cx_write(MO_SCONV_REG, (u32)tmp64);
952 // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
953 tmp64 = step_db * (u64)(1 << 22);
954 do_div(tmp64, vdec_clock);
955 dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
956 (u32)tmp64, cx_read(MO_SUB_STEP));
957 cx_write(MO_SUB_STEP, (u32)tmp64);
959 // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
960 tmp64 = step_dr * (u64)(1 << 22);
961 do_div(tmp64, vdec_clock);
962 dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
963 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
964 cx_write(MO_SUB_STEP_DR, (u32)tmp64);
966 // bdelay + agcdelay
967 bdelay = vdec_clock * 65 / 20000000 + 21;
968 agcdelay = vdec_clock * 68 / 20000000 + 15;
969 dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
970 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
971 cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
973 // htotal
974 tmp64 = norm_htotal(norm) * (u64)vdec_clock;
975 do_div(tmp64, fsc8);
976 htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
977 dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
978 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
979 cx_write(MO_HTOTAL, htotal);
981 // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
982 // the effective vbi offset ~244 samples, the same as the Bt8x8
983 cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
985 // this is needed as well to set all tvnorm parameter
986 cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
988 // audio
989 set_tvaudio(core);
991 // tell i2c chips
992 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
994 // done
995 return 0;
998 /* ------------------------------------------------------------------ */
1000 static int cx88_pci_quirks(char *name, struct pci_dev *pci)
1002 unsigned int lat = UNSET;
1003 u8 ctrl = 0;
1004 u8 value;
1006 /* check pci quirks */
1007 if (pci_pci_problems & PCIPCI_TRITON) {
1008 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
1009 name);
1010 ctrl |= CX88X_EN_TBFX;
1012 if (pci_pci_problems & PCIPCI_NATOMA) {
1013 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
1014 name);
1015 ctrl |= CX88X_EN_TBFX;
1017 if (pci_pci_problems & PCIPCI_VIAETBF) {
1018 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
1019 name);
1020 ctrl |= CX88X_EN_TBFX;
1022 if (pci_pci_problems & PCIPCI_VSFX) {
1023 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
1024 name);
1025 ctrl |= CX88X_EN_VSFX;
1027 #ifdef PCIPCI_ALIMAGIK
1028 if (pci_pci_problems & PCIPCI_ALIMAGIK) {
1029 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
1030 name);
1031 lat = 0x0A;
1033 #endif
1035 /* check insmod options */
1036 if (UNSET != latency)
1037 lat = latency;
1039 /* apply stuff */
1040 if (ctrl) {
1041 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
1042 value |= ctrl;
1043 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
1045 if (UNSET != lat) {
1046 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
1047 name, latency);
1048 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1050 return 0;
1053 /* ------------------------------------------------------------------ */
1055 struct video_device *cx88_vdev_init(struct cx88_core *core,
1056 struct pci_dev *pci,
1057 struct video_device *template,
1058 char *type)
1060 struct video_device *vfd;
1062 vfd = video_device_alloc();
1063 if (NULL == vfd)
1064 return NULL;
1065 *vfd = *template;
1066 vfd->minor = -1;
1067 vfd->dev = &pci->dev;
1068 vfd->release = video_device_release;
1069 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1070 core->name, type, cx88_boards[core->board].name);
1071 return vfd;
1074 static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1076 if (request_mem_region(pci_resource_start(pci,0),
1077 pci_resource_len(pci,0),
1078 core->name))
1079 return 0;
1080 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
1081 core->name,(unsigned long long)pci_resource_start(pci,0));
1082 return -EBUSY;
1085 struct cx88_core* cx88_core_get(struct pci_dev *pci)
1087 struct cx88_core *core;
1088 struct list_head *item;
1089 int i;
1091 mutex_lock(&devlist);
1092 list_for_each(item,&cx88_devlist) {
1093 core = list_entry(item, struct cx88_core, devlist);
1094 if (pci->bus->number != core->pci_bus)
1095 continue;
1096 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1097 continue;
1099 if (0 != get_ressources(core,pci))
1100 goto fail_unlock;
1101 atomic_inc(&core->refcount);
1102 mutex_unlock(&devlist);
1103 return core;
1105 core = kzalloc(sizeof(*core),GFP_KERNEL);
1106 if (NULL == core)
1107 goto fail_unlock;
1109 atomic_inc(&core->refcount);
1110 core->pci_bus = pci->bus->number;
1111 core->pci_slot = PCI_SLOT(pci->devfn);
1112 core->pci_irqmask = 0x00fc00;
1113 mutex_init(&core->lock);
1115 core->nr = cx88_devcount++;
1116 sprintf(core->name,"cx88[%d]",core->nr);
1117 if (0 != get_ressources(core,pci)) {
1118 printk(KERN_ERR "CORE %s No more PCI ressources for "
1119 "subsystem: %04x:%04x, board: %s\n",
1120 core->name,pci->subsystem_vendor,
1121 pci->subsystem_device,
1122 cx88_boards[core->board].name);
1124 cx88_devcount--;
1125 goto fail_free;
1127 list_add_tail(&core->devlist,&cx88_devlist);
1129 /* PCI stuff */
1130 cx88_pci_quirks(core->name, pci);
1131 core->lmmio = ioremap(pci_resource_start(pci,0),
1132 pci_resource_len(pci,0));
1133 core->bmmio = (u8 __iomem *)core->lmmio;
1135 /* board config */
1136 core->board = UNSET;
1137 if (card[core->nr] < cx88_bcount)
1138 core->board = card[core->nr];
1139 for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
1140 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1141 pci->subsystem_device == cx88_subids[i].subdevice)
1142 core->board = cx88_subids[i].card;
1143 if (UNSET == core->board) {
1144 core->board = CX88_BOARD_UNKNOWN;
1145 cx88_card_list(core,pci);
1147 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1148 core->name,pci->subsystem_vendor,
1149 pci->subsystem_device,cx88_boards[core->board].name,
1150 core->board, card[core->nr] == core->board ?
1151 "insmod option" : "autodetected");
1153 core->tuner_type = tuner[core->nr];
1154 core->radio_type = radio[core->nr];
1155 if (UNSET == core->tuner_type)
1156 core->tuner_type = cx88_boards[core->board].tuner_type;
1157 if (UNSET == core->radio_type)
1158 core->radio_type = cx88_boards[core->board].radio_type;
1159 if (!core->tuner_addr)
1160 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1161 if (!core->radio_addr)
1162 core->radio_addr = cx88_boards[core->board].radio_addr;
1164 printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
1165 core->tuner_type, core->tuner_addr<<1,
1166 core->radio_type, core->radio_addr<<1);
1168 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1170 /* init hardware */
1171 cx88_reset(core);
1172 cx88_card_setup_pre_i2c(core);
1173 cx88_i2c_init(core,pci);
1174 cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
1175 cx88_card_setup(core);
1176 cx88_ir_init(core,pci);
1178 mutex_unlock(&devlist);
1179 return core;
1181 fail_free:
1182 kfree(core);
1183 fail_unlock:
1184 mutex_unlock(&devlist);
1185 return NULL;
1188 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1190 release_mem_region(pci_resource_start(pci,0),
1191 pci_resource_len(pci,0));
1193 if (!atomic_dec_and_test(&core->refcount))
1194 return;
1196 mutex_lock(&devlist);
1197 cx88_ir_fini(core);
1198 if (0 == core->i2c_rc)
1199 i2c_del_adapter(&core->i2c_adap);
1200 list_del(&core->devlist);
1201 iounmap(core->lmmio);
1202 cx88_devcount--;
1203 mutex_unlock(&devlist);
1204 kfree(core);
1207 /* ------------------------------------------------------------------ */
1209 EXPORT_SYMBOL(cx88_print_irqbits);
1211 EXPORT_SYMBOL(cx88_core_irq);
1212 EXPORT_SYMBOL(cx88_wakeup);
1213 EXPORT_SYMBOL(cx88_reset);
1214 EXPORT_SYMBOL(cx88_shutdown);
1216 EXPORT_SYMBOL(cx88_risc_buffer);
1217 EXPORT_SYMBOL(cx88_risc_databuffer);
1218 EXPORT_SYMBOL(cx88_risc_stopper);
1219 EXPORT_SYMBOL(cx88_free_buffer);
1221 EXPORT_SYMBOL(cx88_sram_channels);
1222 EXPORT_SYMBOL(cx88_sram_channel_setup);
1223 EXPORT_SYMBOL(cx88_sram_channel_dump);
1225 EXPORT_SYMBOL(cx88_set_tvnorm);
1226 EXPORT_SYMBOL(cx88_set_scale);
1228 EXPORT_SYMBOL(cx88_vdev_init);
1229 EXPORT_SYMBOL(cx88_core_get);
1230 EXPORT_SYMBOL(cx88_core_put);
1233 * Local variables:
1234 * c-basic-offset: 8
1235 * End:
1236 * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off