blob: 9cd161c409efb2e272b21b76ec5c52182cf57aae [file] [log] [blame]
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001/*
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03002 * driver for Earthsoft PT1/PT2
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03003 *
4 * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
5 *
6 * based on pt1dvr - http://pt1dvr.sourceforge.jp/
7 * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/kernel.h>
25#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Andrew Morton2a20b052009-09-21 17:00:58 -070027#include <linux/vmalloc.h>
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -030028#include <linux/pci.h>
29#include <linux/kthread.h>
30#include <linux/freezer.h>
Akihiro Tsukada69881112012-03-10 11:38:14 -030031#include <linux/ratelimit.h>
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -030032
33#include "dvbdev.h"
34#include "dvb_demux.h"
35#include "dmxdev.h"
36#include "dvb_net.h"
37#include "dvb_frontend.h"
38
39#include "va1j5jf8007t.h"
40#include "va1j5jf8007s.h"
41
42#define DRIVER_NAME "earth-pt1"
43
44#define PT1_PAGE_SHIFT 12
45#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
46#define PT1_NR_UPACKETS 1024
47#define PT1_NR_BUFS 511
48
49struct pt1_buffer_page {
50 __le32 upackets[PT1_NR_UPACKETS];
51};
52
53struct pt1_table_page {
54 __le32 next_pfn;
55 __le32 buf_pfns[PT1_NR_BUFS];
56};
57
58struct pt1_buffer {
59 struct pt1_buffer_page *page;
60 dma_addr_t addr;
61};
62
63struct pt1_table {
64 struct pt1_table_page *page;
65 dma_addr_t addr;
66 struct pt1_buffer bufs[PT1_NR_BUFS];
67};
68
69#define PT1_NR_ADAPS 4
70
71struct pt1_adapter;
72
73struct pt1 {
74 struct pci_dev *pdev;
75 void __iomem *regs;
76 struct i2c_adapter i2c_adap;
77 int i2c_running;
78 struct pt1_adapter *adaps[PT1_NR_ADAPS];
79 struct pt1_table *tables;
80 struct task_struct *kthread;
Akihiro Tsukada847e8762012-03-10 11:38:13 -030081 int table_index;
82 int buf_index;
HIRANO Takahito4d1f4132010-04-07 11:48:48 -030083
84 struct mutex lock;
85 int power;
86 int reset;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -030087};
88
89struct pt1_adapter {
90 struct pt1 *pt1;
91 int index;
92
93 u8 *buf;
94 int upacket_count;
95 int packet_count;
Akihiro Tsukada69881112012-03-10 11:38:14 -030096 int st_count;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -030097
98 struct dvb_adapter adap;
99 struct dvb_demux demux;
100 int users;
101 struct dmxdev dmxdev;
102 struct dvb_net net;
103 struct dvb_frontend *fe;
104 int (*orig_set_voltage)(struct dvb_frontend *fe,
105 fe_sec_voltage_t voltage);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300106 int (*orig_sleep)(struct dvb_frontend *fe);
107 int (*orig_init)(struct dvb_frontend *fe);
108
109 fe_sec_voltage_t voltage;
110 int sleep;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300111};
112
113#define pt1_printk(level, pt1, format, arg...) \
114 dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
115
116static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
117{
118 writel(data, pt1->regs + reg * 4);
119}
120
121static u32 pt1_read_reg(struct pt1 *pt1, int reg)
122{
123 return readl(pt1->regs + reg * 4);
124}
125
Akihiro Tsukada7ff04762012-03-10 11:38:15 -0300126static int pt1_nr_tables = 8;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300127module_param_named(nr_tables, pt1_nr_tables, int, 0);
128
129static void pt1_increment_table_count(struct pt1 *pt1)
130{
131 pt1_write_reg(pt1, 0, 0x00000020);
132}
133
134static void pt1_init_table_count(struct pt1 *pt1)
135{
136 pt1_write_reg(pt1, 0, 0x00000010);
137}
138
139static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
140{
141 pt1_write_reg(pt1, 5, first_pfn);
142 pt1_write_reg(pt1, 0, 0x0c000040);
143}
144
145static void pt1_unregister_tables(struct pt1 *pt1)
146{
147 pt1_write_reg(pt1, 0, 0x08080000);
148}
149
150static int pt1_sync(struct pt1 *pt1)
151{
152 int i;
153 for (i = 0; i < 57; i++) {
154 if (pt1_read_reg(pt1, 0) & 0x20000000)
155 return 0;
156 pt1_write_reg(pt1, 0, 0x00000008);
157 }
158 pt1_printk(KERN_ERR, pt1, "could not sync\n");
159 return -EIO;
160}
161
162static u64 pt1_identify(struct pt1 *pt1)
163{
164 int i;
165 u64 id;
166 id = 0;
167 for (i = 0; i < 57; i++) {
168 id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
169 pt1_write_reg(pt1, 0, 0x00000008);
170 }
171 return id;
172}
173
174static int pt1_unlock(struct pt1 *pt1)
175{
176 int i;
177 pt1_write_reg(pt1, 0, 0x00000008);
178 for (i = 0; i < 3; i++) {
179 if (pt1_read_reg(pt1, 0) & 0x80000000)
180 return 0;
181 schedule_timeout_uninterruptible((HZ + 999) / 1000);
182 }
183 pt1_printk(KERN_ERR, pt1, "could not unlock\n");
184 return -EIO;
185}
186
187static int pt1_reset_pci(struct pt1 *pt1)
188{
189 int i;
190 pt1_write_reg(pt1, 0, 0x01010000);
191 pt1_write_reg(pt1, 0, 0x01000000);
192 for (i = 0; i < 10; i++) {
193 if (pt1_read_reg(pt1, 0) & 0x00000001)
194 return 0;
195 schedule_timeout_uninterruptible((HZ + 999) / 1000);
196 }
197 pt1_printk(KERN_ERR, pt1, "could not reset PCI\n");
198 return -EIO;
199}
200
201static int pt1_reset_ram(struct pt1 *pt1)
202{
203 int i;
204 pt1_write_reg(pt1, 0, 0x02020000);
205 pt1_write_reg(pt1, 0, 0x02000000);
206 for (i = 0; i < 10; i++) {
207 if (pt1_read_reg(pt1, 0) & 0x00000002)
208 return 0;
209 schedule_timeout_uninterruptible((HZ + 999) / 1000);
210 }
211 pt1_printk(KERN_ERR, pt1, "could not reset RAM\n");
212 return -EIO;
213}
214
215static int pt1_do_enable_ram(struct pt1 *pt1)
216{
217 int i, j;
218 u32 status;
219 status = pt1_read_reg(pt1, 0) & 0x00000004;
220 pt1_write_reg(pt1, 0, 0x00000002);
221 for (i = 0; i < 10; i++) {
222 for (j = 0; j < 1024; j++) {
223 if ((pt1_read_reg(pt1, 0) & 0x00000004) != status)
224 return 0;
225 }
226 schedule_timeout_uninterruptible((HZ + 999) / 1000);
227 }
228 pt1_printk(KERN_ERR, pt1, "could not enable RAM\n");
229 return -EIO;
230}
231
232static int pt1_enable_ram(struct pt1 *pt1)
233{
234 int i, ret;
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300235 int phase;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300236 schedule_timeout_uninterruptible((HZ + 999) / 1000);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300237 phase = pt1->pdev->device == 0x211a ? 128 : 166;
238 for (i = 0; i < phase; i++) {
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300239 ret = pt1_do_enable_ram(pt1);
240 if (ret < 0)
241 return ret;
242 }
243 return 0;
244}
245
246static void pt1_disable_ram(struct pt1 *pt1)
247{
248 pt1_write_reg(pt1, 0, 0x0b0b0000);
249}
250
251static void pt1_set_stream(struct pt1 *pt1, int index, int enabled)
252{
253 pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index);
254}
255
256static void pt1_init_streams(struct pt1 *pt1)
257{
258 int i;
259 for (i = 0; i < PT1_NR_ADAPS; i++)
260 pt1_set_stream(pt1, i, 0);
261}
262
263static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
264{
265 u32 upacket;
266 int i;
267 int index;
268 struct pt1_adapter *adap;
269 int offset;
270 u8 *buf;
Akihiro Tsukada69881112012-03-10 11:38:14 -0300271 int sc;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300272
273 if (!page->upackets[PT1_NR_UPACKETS - 1])
274 return 0;
275
276 for (i = 0; i < PT1_NR_UPACKETS; i++) {
277 upacket = le32_to_cpu(page->upackets[i]);
278 index = (upacket >> 29) - 1;
279 if (index < 0 || index >= PT1_NR_ADAPS)
280 continue;
281
282 adap = pt1->adaps[index];
283 if (upacket >> 25 & 1)
284 adap->upacket_count = 0;
285 else if (!adap->upacket_count)
286 continue;
287
Akihiro Tsukada69881112012-03-10 11:38:14 -0300288 if (upacket >> 24 & 1)
289 printk_ratelimited(KERN_INFO "earth-pt1: device "
290 "buffer overflowing. table[%d] buf[%d]\n",
291 pt1->table_index, pt1->buf_index);
292 sc = upacket >> 26 & 0x7;
293 if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
294 printk_ratelimited(KERN_INFO "earth-pt1: data loss"
295 " in streamID(adapter)[%d]\n", index);
296 adap->st_count = sc;
297
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300298 buf = adap->buf;
299 offset = adap->packet_count * 188 + adap->upacket_count * 3;
300 buf[offset] = upacket >> 16;
301 buf[offset + 1] = upacket >> 8;
302 if (adap->upacket_count != 62)
303 buf[offset + 2] = upacket;
304
305 if (++adap->upacket_count >= 63) {
306 adap->upacket_count = 0;
307 if (++adap->packet_count >= 21) {
308 dvb_dmx_swfilter_packets(&adap->demux, buf, 21);
309 adap->packet_count = 0;
310 }
311 }
312 }
313
314 page->upackets[PT1_NR_UPACKETS - 1] = 0;
315 return 1;
316}
317
318static int pt1_thread(void *data)
319{
320 struct pt1 *pt1;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300321 struct pt1_buffer_page *page;
322
323 pt1 = data;
324 set_freezable();
325
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300326 while (!kthread_should_stop()) {
327 try_to_freeze();
328
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300329 page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300330 if (!pt1_filter(pt1, page)) {
331 schedule_timeout_interruptible((HZ + 999) / 1000);
332 continue;
333 }
334
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300335 if (++pt1->buf_index >= PT1_NR_BUFS) {
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300336 pt1_increment_table_count(pt1);
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300337 pt1->buf_index = 0;
338 if (++pt1->table_index >= pt1_nr_tables)
339 pt1->table_index = 0;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300340 }
341 }
342
343 return 0;
344}
345
346static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr)
347{
348 dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr);
349}
350
351static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp)
352{
353 void *page;
354 dma_addr_t addr;
355
356 page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr,
357 GFP_KERNEL);
358 if (page == NULL)
359 return NULL;
360
361 BUG_ON(addr & (PT1_PAGE_SIZE - 1));
362 BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1);
363
364 *addrp = addr;
365 *pfnp = addr >> PT1_PAGE_SHIFT;
366 return page;
367}
368
369static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf)
370{
371 pt1_free_page(pt1, buf->page, buf->addr);
372}
373
374static int
375pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp)
376{
377 struct pt1_buffer_page *page;
378 dma_addr_t addr;
379
380 page = pt1_alloc_page(pt1, &addr, pfnp);
381 if (page == NULL)
382 return -ENOMEM;
383
384 page->upackets[PT1_NR_UPACKETS - 1] = 0;
385
386 buf->page = page;
387 buf->addr = addr;
388 return 0;
389}
390
391static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table)
392{
393 int i;
394
395 for (i = 0; i < PT1_NR_BUFS; i++)
396 pt1_cleanup_buffer(pt1, &table->bufs[i]);
397
398 pt1_free_page(pt1, table->page, table->addr);
399}
400
401static int
402pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp)
403{
404 struct pt1_table_page *page;
405 dma_addr_t addr;
406 int i, ret;
407 u32 buf_pfn;
408
409 page = pt1_alloc_page(pt1, &addr, pfnp);
410 if (page == NULL)
411 return -ENOMEM;
412
413 for (i = 0; i < PT1_NR_BUFS; i++) {
414 ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn);
415 if (ret < 0)
416 goto err;
417
418 page->buf_pfns[i] = cpu_to_le32(buf_pfn);
419 }
420
421 pt1_increment_table_count(pt1);
422 table->page = page;
423 table->addr = addr;
424 return 0;
425
426err:
427 while (i--)
428 pt1_cleanup_buffer(pt1, &table->bufs[i]);
429
430 pt1_free_page(pt1, page, addr);
431 return ret;
432}
433
434static void pt1_cleanup_tables(struct pt1 *pt1)
435{
436 struct pt1_table *tables;
437 int i;
438
439 tables = pt1->tables;
440 pt1_unregister_tables(pt1);
441
442 for (i = 0; i < pt1_nr_tables; i++)
443 pt1_cleanup_table(pt1, &tables[i]);
444
445 vfree(tables);
446}
447
448static int pt1_init_tables(struct pt1 *pt1)
449{
450 struct pt1_table *tables;
451 int i, ret;
452 u32 first_pfn, pfn;
453
454 tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables);
455 if (tables == NULL)
456 return -ENOMEM;
457
458 pt1_init_table_count(pt1);
459
460 i = 0;
461 if (pt1_nr_tables) {
462 ret = pt1_init_table(pt1, &tables[0], &first_pfn);
463 if (ret)
464 goto err;
465 i++;
466 }
467
468 while (i < pt1_nr_tables) {
469 ret = pt1_init_table(pt1, &tables[i], &pfn);
470 if (ret)
471 goto err;
472 tables[i - 1].page->next_pfn = cpu_to_le32(pfn);
473 i++;
474 }
475
476 tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn);
477
478 pt1_register_tables(pt1, first_pfn);
479 pt1->tables = tables;
480 return 0;
481
482err:
483 while (i--)
484 pt1_cleanup_table(pt1, &tables[i]);
485
486 vfree(tables);
487 return ret;
488}
489
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300490static int pt1_start_polling(struct pt1 *pt1)
491{
492 int ret = 0;
493
494 mutex_lock(&pt1->lock);
495 if (!pt1->kthread) {
496 pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
497 if (IS_ERR(pt1->kthread)) {
498 ret = PTR_ERR(pt1->kthread);
499 pt1->kthread = NULL;
500 }
501 }
502 mutex_unlock(&pt1->lock);
503 return ret;
504}
505
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300506static int pt1_start_feed(struct dvb_demux_feed *feed)
507{
508 struct pt1_adapter *adap;
509 adap = container_of(feed->demux, struct pt1_adapter, demux);
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300510 if (!adap->users++) {
511 int ret;
512
513 ret = pt1_start_polling(adap->pt1);
514 if (ret)
515 return ret;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300516 pt1_set_stream(adap->pt1, adap->index, 1);
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300517 }
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300518 return 0;
519}
520
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300521static void pt1_stop_polling(struct pt1 *pt1)
522{
523 int i, count;
524
525 mutex_lock(&pt1->lock);
526 for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
527 count += pt1->adaps[i]->users;
528
529 if (count == 0 && pt1->kthread) {
530 kthread_stop(pt1->kthread);
531 pt1->kthread = NULL;
532 }
533 mutex_unlock(&pt1->lock);
534}
535
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300536static int pt1_stop_feed(struct dvb_demux_feed *feed)
537{
538 struct pt1_adapter *adap;
539 adap = container_of(feed->demux, struct pt1_adapter, demux);
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300540 if (!--adap->users) {
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300541 pt1_set_stream(adap->pt1, adap->index, 0);
Akihiro Tsukada847e8762012-03-10 11:38:13 -0300542 pt1_stop_polling(adap->pt1);
543 }
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300544 return 0;
545}
546
547static void
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300548pt1_update_power(struct pt1 *pt1)
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300549{
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300550 int bits;
551 int i;
552 struct pt1_adapter *adap;
553 static const int sleep_bits[] = {
554 1 << 4,
555 1 << 6 | 1 << 7,
556 1 << 5,
557 1 << 6 | 1 << 8,
558 };
559
560 bits = pt1->power | !pt1->reset << 3;
561 mutex_lock(&pt1->lock);
562 for (i = 0; i < PT1_NR_ADAPS; i++) {
563 adap = pt1->adaps[i];
564 switch (adap->voltage) {
565 case SEC_VOLTAGE_13: /* actually 11V */
566 bits |= 1 << 1;
567 break;
568 case SEC_VOLTAGE_18: /* actually 15V */
569 bits |= 1 << 1 | 1 << 2;
570 break;
571 default:
572 break;
573 }
574
575 /* XXX: The bits should be changed depending on adap->sleep. */
576 bits |= sleep_bits[i];
577 }
578 pt1_write_reg(pt1, 1, bits);
579 mutex_unlock(&pt1->lock);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300580}
581
582static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
583{
584 struct pt1_adapter *adap;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300585
586 adap = container_of(fe->dvb, struct pt1_adapter, adap);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300587 adap->voltage = voltage;
588 pt1_update_power(adap->pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300589
590 if (adap->orig_set_voltage)
591 return adap->orig_set_voltage(fe, voltage);
592 else
593 return 0;
594}
595
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300596static int pt1_sleep(struct dvb_frontend *fe)
597{
598 struct pt1_adapter *adap;
599
600 adap = container_of(fe->dvb, struct pt1_adapter, adap);
601 adap->sleep = 1;
602 pt1_update_power(adap->pt1);
603
604 if (adap->orig_sleep)
605 return adap->orig_sleep(fe);
606 else
607 return 0;
608}
609
610static int pt1_wakeup(struct dvb_frontend *fe)
611{
612 struct pt1_adapter *adap;
613
614 adap = container_of(fe->dvb, struct pt1_adapter, adap);
615 adap->sleep = 0;
616 pt1_update_power(adap->pt1);
617 schedule_timeout_uninterruptible((HZ + 999) / 1000);
618
619 if (adap->orig_init)
620 return adap->orig_init(fe);
621 else
622 return 0;
623}
624
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300625static void pt1_free_adapter(struct pt1_adapter *adap)
626{
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300627 dvb_net_release(&adap->net);
628 adap->demux.dmx.close(&adap->demux.dmx);
629 dvb_dmxdev_release(&adap->dmxdev);
630 dvb_dmx_release(&adap->demux);
631 dvb_unregister_adapter(&adap->adap);
632 free_page((unsigned long)adap->buf);
633 kfree(adap);
634}
635
636DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
637
638static struct pt1_adapter *
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300639pt1_alloc_adapter(struct pt1 *pt1)
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300640{
641 struct pt1_adapter *adap;
642 void *buf;
643 struct dvb_adapter *dvb_adap;
644 struct dvb_demux *demux;
645 struct dmxdev *dmxdev;
646 int ret;
647
648 adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL);
649 if (!adap) {
650 ret = -ENOMEM;
651 goto err;
652 }
653
654 adap->pt1 = pt1;
655
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300656 adap->voltage = SEC_VOLTAGE_OFF;
657 adap->sleep = 1;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300658
659 buf = (u8 *)__get_free_page(GFP_KERNEL);
660 if (!buf) {
661 ret = -ENOMEM;
662 goto err_kfree;
663 }
664
665 adap->buf = buf;
666 adap->upacket_count = 0;
667 adap->packet_count = 0;
Akihiro Tsukada69881112012-03-10 11:38:14 -0300668 adap->st_count = -1;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300669
670 dvb_adap = &adap->adap;
671 dvb_adap->priv = adap;
672 ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE,
673 &pt1->pdev->dev, adapter_nr);
674 if (ret < 0)
675 goto err_free_page;
676
677 demux = &adap->demux;
678 demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
679 demux->priv = adap;
680 demux->feednum = 256;
681 demux->filternum = 256;
682 demux->start_feed = pt1_start_feed;
683 demux->stop_feed = pt1_stop_feed;
684 demux->write_to_decoder = NULL;
685 ret = dvb_dmx_init(demux);
686 if (ret < 0)
687 goto err_unregister_adapter;
688
689 dmxdev = &adap->dmxdev;
690 dmxdev->filternum = 256;
691 dmxdev->demux = &demux->dmx;
692 dmxdev->capabilities = 0;
693 ret = dvb_dmxdev_init(dmxdev, dvb_adap);
694 if (ret < 0)
695 goto err_dmx_release;
696
697 dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
698
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300699 return adap;
700
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300701err_dmx_release:
702 dvb_dmx_release(demux);
703err_unregister_adapter:
704 dvb_unregister_adapter(dvb_adap);
705err_free_page:
706 free_page((unsigned long)buf);
707err_kfree:
708 kfree(adap);
709err:
710 return ERR_PTR(ret);
711}
712
713static void pt1_cleanup_adapters(struct pt1 *pt1)
714{
715 int i;
716 for (i = 0; i < PT1_NR_ADAPS; i++)
717 pt1_free_adapter(pt1->adaps[i]);
718}
719
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300720static int pt1_init_adapters(struct pt1 *pt1)
721{
722 int i;
723 struct pt1_adapter *adap;
724 int ret;
725
726 for (i = 0; i < PT1_NR_ADAPS; i++) {
727 adap = pt1_alloc_adapter(pt1);
728 if (IS_ERR(adap)) {
729 ret = PTR_ERR(adap);
730 goto err;
731 }
732
733 adap->index = i;
734 pt1->adaps[i] = adap;
735 }
736 return 0;
737
738err:
739 while (i--)
740 pt1_free_adapter(pt1->adaps[i]);
741
742 return ret;
743}
744
745static void pt1_cleanup_frontend(struct pt1_adapter *adap)
746{
747 dvb_unregister_frontend(adap->fe);
748}
749
750static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
751{
752 int ret;
753
754 adap->orig_set_voltage = fe->ops.set_voltage;
755 adap->orig_sleep = fe->ops.sleep;
756 adap->orig_init = fe->ops.init;
757 fe->ops.set_voltage = pt1_set_voltage;
758 fe->ops.sleep = pt1_sleep;
759 fe->ops.init = pt1_wakeup;
760
761 ret = dvb_register_frontend(&adap->adap, fe);
762 if (ret < 0)
763 return ret;
764
765 adap->fe = fe;
766 return 0;
767}
768
769static void pt1_cleanup_frontends(struct pt1 *pt1)
770{
771 int i;
772 for (i = 0; i < PT1_NR_ADAPS; i++)
773 pt1_cleanup_frontend(pt1->adaps[i]);
774}
775
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300776struct pt1_config {
777 struct va1j5jf8007s_config va1j5jf8007s_config;
778 struct va1j5jf8007t_config va1j5jf8007t_config;
779};
780
781static const struct pt1_config pt1_configs[2] = {
782 {
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300783 {
784 .demod_address = 0x1b,
785 .frequency = VA1J5JF8007S_20MHZ,
786 },
787 {
788 .demod_address = 0x1a,
789 .frequency = VA1J5JF8007T_20MHZ,
790 },
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300791 }, {
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300792 {
793 .demod_address = 0x19,
794 .frequency = VA1J5JF8007S_20MHZ,
795 },
796 {
797 .demod_address = 0x18,
798 .frequency = VA1J5JF8007T_20MHZ,
799 },
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300800 },
801};
802
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300803static const struct pt1_config pt2_configs[2] = {
804 {
805 {
806 .demod_address = 0x1b,
807 .frequency = VA1J5JF8007S_25MHZ,
808 },
809 {
810 .demod_address = 0x1a,
811 .frequency = VA1J5JF8007T_25MHZ,
812 },
813 }, {
814 {
815 .demod_address = 0x19,
816 .frequency = VA1J5JF8007S_25MHZ,
817 },
818 {
819 .demod_address = 0x18,
820 .frequency = VA1J5JF8007T_25MHZ,
821 },
822 },
823};
824
825static int pt1_init_frontends(struct pt1 *pt1)
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300826{
827 int i, j;
828 struct i2c_adapter *i2c_adap;
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300829 const struct pt1_config *configs, *config;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300830 struct dvb_frontend *fe[4];
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300831 int ret;
832
833 i = 0;
834 j = 0;
835
836 i2c_adap = &pt1->i2c_adap;
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300837 configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300838 do {
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300839 config = &configs[i / 2];
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300840
841 fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
842 i2c_adap);
843 if (!fe[i]) {
844 ret = -ENODEV; /* This does not sound nice... */
845 goto err;
846 }
847 i++;
848
849 fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config,
850 i2c_adap);
851 if (!fe[i]) {
852 ret = -ENODEV;
853 goto err;
854 }
855 i++;
856
857 ret = va1j5jf8007s_prepare(fe[i - 2]);
858 if (ret < 0)
859 goto err;
860
861 ret = va1j5jf8007t_prepare(fe[i - 1]);
862 if (ret < 0)
863 goto err;
864
865 } while (i < 4);
866
867 do {
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300868 ret = pt1_init_frontend(pt1->adaps[j], fe[j]);
869 if (ret < 0)
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300870 goto err;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300871 } while (++j < 4);
872
873 return 0;
874
875err:
876 while (i-- > j)
877 fe[i]->ops.release(fe[i]);
878
879 while (j--)
HIRANO Takahito4d1f4132010-04-07 11:48:48 -0300880 dvb_unregister_frontend(fe[j]);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -0300881
882 return ret;
883}
884
885static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable,
886 int clock, int data, int next_addr)
887{
888 pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 |
889 !clock << 11 | !data << 10 | next_addr);
890}
891
892static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data)
893{
894 pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1);
895 pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2);
896 pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3);
897 *addrp = addr + 3;
898}
899
900static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp)
901{
902 pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1);
903 pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2);
904 pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3);
905 pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4);
906 *addrp = addr + 4;
907}
908
909static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data)
910{
911 int i;
912 for (i = 0; i < 8; i++)
913 pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1);
914 pt1_i2c_write_bit(pt1, addr, &addr, 1);
915 *addrp = addr;
916}
917
918static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last)
919{
920 int i;
921 for (i = 0; i < 8; i++)
922 pt1_i2c_read_bit(pt1, addr, &addr);
923 pt1_i2c_write_bit(pt1, addr, &addr, last);
924 *addrp = addr;
925}
926
927static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp)
928{
929 pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1);
930 pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
931 pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3);
932 *addrp = addr + 3;
933}
934
935static void
936pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
937{
938 int i;
939 pt1_i2c_prepare(pt1, addr, &addr);
940 pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1);
941 for (i = 0; i < msg->len; i++)
942 pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]);
943 *addrp = addr;
944}
945
946static void
947pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
948{
949 int i;
950 pt1_i2c_prepare(pt1, addr, &addr);
951 pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1);
952 for (i = 0; i < msg->len; i++)
953 pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1);
954 *addrp = addr;
955}
956
957static int pt1_i2c_end(struct pt1 *pt1, int addr)
958{
959 pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1);
960 pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
961 pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0);
962
963 pt1_write_reg(pt1, 0, 0x00000004);
964 do {
965 if (signal_pending(current))
966 return -EINTR;
967 schedule_timeout_interruptible((HZ + 999) / 1000);
968 } while (pt1_read_reg(pt1, 0) & 0x00000080);
969 return 0;
970}
971
972static void pt1_i2c_begin(struct pt1 *pt1, int *addrp)
973{
974 int addr;
975 addr = 0;
976
977 pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */);
978 addr = addr + 1;
979
980 if (!pt1->i2c_running) {
981 pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1);
982 pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
983 addr = addr + 2;
984 pt1->i2c_running = 1;
985 }
986 *addrp = addr;
987}
988
989static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
990{
991 struct pt1 *pt1;
992 int i;
993 struct i2c_msg *msg, *next_msg;
994 int addr, ret;
995 u16 len;
996 u32 word;
997
998 pt1 = i2c_get_adapdata(adap);
999
1000 for (i = 0; i < num; i++) {
1001 msg = &msgs[i];
1002 if (msg->flags & I2C_M_RD)
1003 return -ENOTSUPP;
1004
1005 if (i + 1 < num)
1006 next_msg = &msgs[i + 1];
1007 else
1008 next_msg = NULL;
1009
1010 if (next_msg && next_msg->flags & I2C_M_RD) {
1011 i++;
1012
1013 len = next_msg->len;
1014 if (len > 4)
1015 return -ENOTSUPP;
1016
1017 pt1_i2c_begin(pt1, &addr);
1018 pt1_i2c_write_msg(pt1, addr, &addr, msg);
1019 pt1_i2c_read_msg(pt1, addr, &addr, next_msg);
1020 ret = pt1_i2c_end(pt1, addr);
1021 if (ret < 0)
1022 return ret;
1023
1024 word = pt1_read_reg(pt1, 2);
1025 while (len--) {
1026 next_msg->buf[len] = word;
1027 word >>= 8;
1028 }
1029 } else {
1030 pt1_i2c_begin(pt1, &addr);
1031 pt1_i2c_write_msg(pt1, addr, &addr, msg);
1032 ret = pt1_i2c_end(pt1, addr);
1033 if (ret < 0)
1034 return ret;
1035 }
1036 }
1037
1038 return num;
1039}
1040
1041static u32 pt1_i2c_func(struct i2c_adapter *adap)
1042{
1043 return I2C_FUNC_I2C;
1044}
1045
1046static const struct i2c_algorithm pt1_i2c_algo = {
1047 .master_xfer = pt1_i2c_xfer,
1048 .functionality = pt1_i2c_func,
1049};
1050
1051static void pt1_i2c_wait(struct pt1 *pt1)
1052{
1053 int i;
1054 for (i = 0; i < 128; i++)
1055 pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0);
1056}
1057
1058static void pt1_i2c_init(struct pt1 *pt1)
1059{
1060 int i;
1061 for (i = 0; i < 1024; i++)
1062 pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
1063}
1064
1065static void __devexit pt1_remove(struct pci_dev *pdev)
1066{
1067 struct pt1 *pt1;
1068 void __iomem *regs;
1069
1070 pt1 = pci_get_drvdata(pdev);
1071 regs = pt1->regs;
1072
Akihiro Tsukada847e8762012-03-10 11:38:13 -03001073 if (pt1->kthread)
1074 kthread_stop(pt1->kthread);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001075 pt1_cleanup_tables(pt1);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001076 pt1_cleanup_frontends(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001077 pt1_disable_ram(pt1);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001078 pt1->power = 0;
1079 pt1->reset = 1;
1080 pt1_update_power(pt1);
1081 pt1_cleanup_adapters(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001082 i2c_del_adapter(&pt1->i2c_adap);
1083 pci_set_drvdata(pdev, NULL);
1084 kfree(pt1);
1085 pci_iounmap(pdev, regs);
1086 pci_release_regions(pdev);
1087 pci_disable_device(pdev);
1088}
1089
1090static int __devinit
1091pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1092{
1093 int ret;
1094 void __iomem *regs;
1095 struct pt1 *pt1;
1096 struct i2c_adapter *i2c_adap;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001097
1098 ret = pci_enable_device(pdev);
1099 if (ret < 0)
1100 goto err;
1101
Mauro Carvalho Chehab84d6ae42009-09-19 01:01:26 -03001102 ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001103 if (ret < 0)
1104 goto err_pci_disable_device;
1105
1106 pci_set_master(pdev);
1107
1108 ret = pci_request_regions(pdev, DRIVER_NAME);
1109 if (ret < 0)
1110 goto err_pci_disable_device;
1111
1112 regs = pci_iomap(pdev, 0, 0);
1113 if (!regs) {
1114 ret = -EIO;
1115 goto err_pci_release_regions;
1116 }
1117
1118 pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL);
1119 if (!pt1) {
1120 ret = -ENOMEM;
1121 goto err_pci_iounmap;
1122 }
1123
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001124 mutex_init(&pt1->lock);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001125 pt1->pdev = pdev;
1126 pt1->regs = regs;
1127 pci_set_drvdata(pdev, pt1);
1128
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001129 ret = pt1_init_adapters(pt1);
1130 if (ret < 0)
1131 goto err_kfree;
1132
1133 mutex_init(&pt1->lock);
1134
1135 pt1->power = 0;
1136 pt1->reset = 1;
1137 pt1_update_power(pt1);
1138
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001139 i2c_adap = &pt1->i2c_adap;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001140 i2c_adap->algo = &pt1_i2c_algo;
1141 i2c_adap->algo_data = NULL;
1142 i2c_adap->dev.parent = &pdev->dev;
HIRANO Takahitocae72c72011-05-01 02:29:40 -03001143 strcpy(i2c_adap->name, DRIVER_NAME);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001144 i2c_set_adapdata(i2c_adap, pt1);
1145 ret = i2c_add_adapter(i2c_adap);
1146 if (ret < 0)
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001147 goto err_pt1_cleanup_adapters;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001148
1149 pt1_i2c_init(pt1);
1150 pt1_i2c_wait(pt1);
1151
1152 ret = pt1_sync(pt1);
1153 if (ret < 0)
1154 goto err_i2c_del_adapter;
1155
1156 pt1_identify(pt1);
1157
1158 ret = pt1_unlock(pt1);
1159 if (ret < 0)
1160 goto err_i2c_del_adapter;
1161
1162 ret = pt1_reset_pci(pt1);
1163 if (ret < 0)
1164 goto err_i2c_del_adapter;
1165
1166 ret = pt1_reset_ram(pt1);
1167 if (ret < 0)
1168 goto err_i2c_del_adapter;
1169
1170 ret = pt1_enable_ram(pt1);
1171 if (ret < 0)
1172 goto err_i2c_del_adapter;
1173
1174 pt1_init_streams(pt1);
1175
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001176 pt1->power = 1;
1177 pt1_update_power(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001178 schedule_timeout_uninterruptible((HZ + 49) / 50);
1179
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001180 pt1->reset = 0;
1181 pt1_update_power(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001182 schedule_timeout_uninterruptible((HZ + 999) / 1000);
1183
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001184 ret = pt1_init_frontends(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001185 if (ret < 0)
1186 goto err_pt1_disable_ram;
1187
1188 ret = pt1_init_tables(pt1);
1189 if (ret < 0)
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001190 goto err_pt1_cleanup_frontends;
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001191
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001192 return 0;
1193
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001194err_pt1_cleanup_frontends:
1195 pt1_cleanup_frontends(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001196err_pt1_disable_ram:
1197 pt1_disable_ram(pt1);
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001198 pt1->power = 0;
1199 pt1->reset = 1;
1200 pt1_update_power(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001201err_i2c_del_adapter:
1202 i2c_del_adapter(i2c_adap);
HIRANO Takahitocae72c72011-05-01 02:29:40 -03001203err_pt1_cleanup_adapters:
1204 pt1_cleanup_adapters(pt1);
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001205err_kfree:
1206 pci_set_drvdata(pdev, NULL);
1207 kfree(pt1);
1208err_pci_iounmap:
1209 pci_iounmap(pdev, regs);
1210err_pci_release_regions:
1211 pci_release_regions(pdev);
1212err_pci_disable_device:
1213 pci_disable_device(pdev);
1214err:
1215 return ret;
1216
1217}
1218
1219static struct pci_device_id pt1_id_table[] = {
1220 { PCI_DEVICE(0x10ee, 0x211a) },
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001221 { PCI_DEVICE(0x10ee, 0x222a) },
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001222 { },
1223};
1224MODULE_DEVICE_TABLE(pci, pt1_id_table);
1225
1226static struct pci_driver pt1_driver = {
1227 .name = DRIVER_NAME,
1228 .probe = pt1_probe,
1229 .remove = __devexit_p(pt1_remove),
1230 .id_table = pt1_id_table,
1231};
1232
1233
1234static int __init pt1_init(void)
1235{
1236 return pci_register_driver(&pt1_driver);
1237}
1238
1239
1240static void __exit pt1_cleanup(void)
1241{
1242 pci_unregister_driver(&pt1_driver);
1243}
1244
1245module_init(pt1_init);
1246module_exit(pt1_cleanup);
1247
1248MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
HIRANO Takahito4d1f4132010-04-07 11:48:48 -03001249MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
Mauro Carvalho Chehab3d17fb12009-08-23 00:51:22 -03001250MODULE_LICENSE("GPL");