blob: e7b1811e3567bbeb27fecac815b230b990db26a4 [file] [log] [blame]
Antti Palosaari831e0b72011-07-08 23:36:07 -03001/*
2 * Realtek RTL28xxU DVB USB driver
3 *
4 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
5 * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include "rtl28xxu.h"
23
24#include "rtl2830.h"
25
26#include "qt1010.h"
27#include "mt2060.h"
28#include "mxl5005s.h"
29
30/* debug */
31static int dvb_usb_rtl28xxu_debug;
32module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644);
33MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
34DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
35
36static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
37{
38 int ret;
39 unsigned int pipe;
40 u8 requesttype;
41 u8 *buf;
42
43 buf = kmalloc(req->size, GFP_KERNEL);
44 if (!buf) {
45 ret = -ENOMEM;
46 goto err;
47 }
48
49 if (req->index & CMD_WR_FLAG) {
50 /* write */
51 memcpy(buf, req->data, req->size);
52 requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
53 pipe = usb_sndctrlpipe(d->udev, 0);
54 } else {
55 /* read */
56 requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
57 pipe = usb_rcvctrlpipe(d->udev, 0);
58 }
59
60 ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
61 req->index, buf, req->size, 1000);
62
63 deb_dump(0, requesttype, req->value, req->index, buf, req->size,
64 deb_xfer);
65
66 if (ret < 0)
67 goto err_dealloc;
68 else
69 ret = 0;
70
71 /* read request, copy returned data to return buf */
72 if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
73 memcpy(req->data, buf, req->size);
74
75 kfree(buf);
76 return ret;
77
78err_dealloc:
79 kfree(buf);
80err:
81 deb_info("%s: failed=%d\n", __func__, ret);
82 return ret;
83}
84
85static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
86{
87 struct rtl28xxu_req req;
88
89 if (reg < 0x3000)
90 req.index = CMD_USB_WR;
91 else
92 req.index = CMD_SYS_WR;
93
94 req.value = reg;
95 req.size = len;
96 req.data = val;
97
98 return rtl28xxu_ctrl_msg(d, &req);
99}
100
101static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
102{
103 struct rtl28xxu_req req;
104
105 if (reg < 0x3000)
106 req.index = CMD_USB_RD;
107 else
108 req.index = CMD_SYS_RD;
109
110 req.value = reg;
111 req.size = len;
112 req.data = val;
113
114 return rtl28xxu_ctrl_msg(d, &req);
115}
116
117static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
118{
119 return rtl2831_wr_regs(d, reg, &val, 1);
120}
121
122static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
123{
124 return rtl2831_rd_regs(d, reg, val, 1);
125}
126
127/* I2C */
128static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
129 int num)
130{
131 int ret;
132 struct dvb_usb_device *d = i2c_get_adapdata(adap);
133 struct rtl28xxu_req req;
134
135 /*
136 * It is not known which are real I2C bus xfer limits, but testing
137 * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
138 */
139
140 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
141 return -EAGAIN;
142
143 if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
144 (msg[1].flags & I2C_M_RD)) {
145 if (msg[0].len > 2 || msg[1].len > 24) {
146 ret = -EOPNOTSUPP;
147 goto err_unlock;
148 }
149 if (msg[0].addr == 0x10) {
150 /* integrated demod */
151 req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1);
152 req.index = CMD_DEMOD_RD | msg[0].buf[0];
153 req.size = msg[1].len;
154 req.data = &msg[1].buf[0];
155 ret = rtl28xxu_ctrl_msg(d, &req);
156 } else {
157 /* real I2C */
158 req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
159 req.index = CMD_I2C_RD;
160 req.size = msg[1].len;
161 req.data = &msg[1].buf[0];
162 ret = rtl28xxu_ctrl_msg(d, &req);
163 }
164 } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
165 if (msg[0].len > 22) {
166 ret = -EOPNOTSUPP;
167 goto err_unlock;
168 }
169 if (msg[0].addr == 0x10) {
170 /* integrated demod */
171 req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1);
172 req.index = CMD_DEMOD_WR | msg[0].buf[0];
173 req.size = msg[0].len-2;
174 req.data = &msg[0].buf[2];
175 ret = rtl28xxu_ctrl_msg(d, &req);
176 } else {
177 /* real I2C */
178 req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
179 req.index = CMD_I2C_WR;
180 req.size = msg[0].len-1;
181 req.data = &msg[0].buf[1];
182 ret = rtl28xxu_ctrl_msg(d, &req);
183 }
184 } else {
185 ret = -EINVAL;
186 }
187
188err_unlock:
189 mutex_unlock(&d->i2c_mutex);
190
191 return ret ? ret : num;
192}
193
194static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
195{
196 return I2C_FUNC_I2C;
197}
198
199static struct i2c_algorithm rtl28xxu_i2c_algo = {
200 .master_xfer = rtl28xxu_i2c_xfer,
201 .functionality = rtl28xxu_i2c_func,
202};
203
204static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
205 .i2c_addr = 0x10, /* 0x20 */
206 .xtal = 28800000,
207 .ts_mode = 0,
208 .spec_inv = 1,
209 .if_dvbt = 36150000,
210 .vtop = 0x20,
211 .krf = 0x04,
212 .agc_targ_val = 0x2d,
213
214};
215
216static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
217 .i2c_addr = 0x10, /* 0x20 */
218 .xtal = 28800000,
219 .ts_mode = 0,
220 .spec_inv = 1,
221 .if_dvbt = 36125000,
222 .vtop = 0x20,
223 .krf = 0x04,
224 .agc_targ_val = 0x2d,
225};
226
227static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
228 .i2c_addr = 0x10, /* 0x20 */
229 .xtal = 28800000,
230 .ts_mode = 0,
231 .spec_inv = 0,
232 .if_dvbt = 4570000,
233 .vtop = 0x3f,
234 .krf = 0x04,
235 .agc_targ_val = 0x3e,
236};
237
238static int rtl28xxu_frontend_attach(struct dvb_usb_adapter *adap)
239{
240 int ret;
241 struct rtl28xxu_priv *priv = adap->dev->priv;
242 u8 buf[1];
243 struct rtl2830_config *rtl2830_config;
244 /* for MT2060 tuner probe */
245 struct rtl28xxu_req req_mt2060 = {0x00c0, CMD_I2C_RD, 1, buf};
246 /* for QT1010 tuner probe */
247 struct rtl28xxu_req req_qt1010 = {0x0fc4, CMD_I2C_RD, 1, buf};
248 /* open RTL2831U/RTL2830 I2C gate */
249 struct rtl28xxu_req req_gate = {0x0120, 0x0011, 0x0001, "\x08"};
250
251 deb_info("%s:\n", __func__);
252
253 /*
254 * RTL2831U GPIOs
255 * =========================================================
256 * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?)
257 * GPIO2 | LED | 0 off | 1 on |
258 * GPIO4 | tuner#1 | 0 on | 1 off | MT2060
259 */
260
261 /* GPIO direction */
262 ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
263 if (ret)
264 goto err;
265
266 /* enable as output GPIO0, GPIO2, GPIO4 */
267 ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
268 if (ret)
269 goto err;
270
271 /*
272 * Probe used tuner. We need to know used tuner before demod attach
273 * since there is some demod params needed to set according to tuner.
274 */
275
276 /* open demod I2C gate */
277 ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
278 if (ret)
279 goto err;
280
281 /* check QT1010 ID(?) register; reg=0f val=2c */
282 ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
283 if (ret == 0 && buf[0] == 0x2c) {
284 priv->tuner = TUNER_RTL2830_QT1010;
285 rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
286 deb_info("%s: QT1010\n", __func__);
287 goto found;
288 } else {
289 deb_info("%s: QT1010 probe failed=%d - %02x\n",
290 __func__, ret, buf[0]);
291 }
292
293 /* open demod I2C gate */
294 ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
295 if (ret)
296 goto err;
297
298 /* check MT2060 ID register; reg=00 val=63 */
299 ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
300 if (ret == 0 && buf[0] == 0x63) {
301 priv->tuner = TUNER_RTL2830_MT2060;
302 rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
303 deb_info("%s: MT2060\n", __func__);
304 goto found;
305 } else {
306 deb_info("%s: MT2060 probe failed=%d - %02x\n",
307 __func__, ret, buf[0]);
308 }
309
310 /* assume MXL5005S */
311 priv->tuner = TUNER_RTL2830_MXL5005S;
312 rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
313 deb_info("%s: MXL5005S\n", __func__);
314 goto found;
315
316found:
317 /* attach demodulator */
318 adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config,
319 &adap->dev->i2c_adap);
320 if (adap->fe[0] == NULL) {
321 ret = -ENODEV;
322 goto err;
323 }
324
325 return ret;
326err:
327 deb_info("%s: failed=%d\n", __func__, ret);
328 return ret;
329}
330
331static struct qt1010_config rtl28xxu_qt1010_config = {
332 .i2c_address = 0x62, /* 0xc4 */
333};
334
335static struct mt2060_config rtl28xxu_mt2060_config = {
336 .i2c_address = 0x60, /* 0xc0 */
337 .clock_out = 0,
338};
339
340static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
341 .i2c_address = 0x63, /* 0xc6 */
342 .if_freq = IF_FREQ_4570000HZ,
343 .xtal_freq = CRYSTAL_FREQ_16000000HZ,
344 .agc_mode = MXL_SINGLE_AGC,
345 .tracking_filter = MXL_TF_C_H,
346 .rssi_enable = MXL_RSSI_ENABLE,
347 .cap_select = MXL_CAP_SEL_ENABLE,
348 .div_out = MXL_DIV_OUT_4,
349 .clock_out = MXL_CLOCK_OUT_DISABLE,
350 .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
351 .top = MXL5005S_TOP_25P2,
352 .mod_mode = MXL_DIGITAL_MODE,
353 .if_mode = MXL_ZERO_IF,
354 .AgcMasterByte = 0x00,
355};
356
357static int rtl28xxu_tuner_attach(struct dvb_usb_adapter *adap)
358{
359 int ret;
360 struct rtl28xxu_priv *priv = adap->dev->priv;
361 struct i2c_adapter *rtl2830_tuner_i2c;
362 struct dvb_frontend *fe = NULL;
363
364 deb_info("%s:\n", __func__);
365
366 /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
367 rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]);
368
369 switch (priv->tuner) {
370 case TUNER_RTL2830_QT1010:
371 fe = dvb_attach(qt1010_attach, adap->fe[0], rtl2830_tuner_i2c,
372 &rtl28xxu_qt1010_config);
373 break;
374 case TUNER_RTL2830_MT2060:
375 fe = dvb_attach(mt2060_attach, adap->fe[0], rtl2830_tuner_i2c,
376 &rtl28xxu_mt2060_config, 1220);
377 break;
378 case TUNER_RTL2830_MXL5005S:
379 fe = dvb_attach(mxl5005s_attach, adap->fe[0], rtl2830_tuner_i2c,
380 &rtl28xxu_mxl5005s_config);
381 break;
382 default:
383 err("unknown tuner=%d", priv->tuner);
384 }
385
386 if (fe == NULL) {
387 ret = -ENODEV;
388 goto err;
389 }
390
391 return 0;
392err:
393 deb_info("%s: failed=%d\n", __func__, ret);
394 return ret;
395}
396
397static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
398{
399 int ret;
400 u8 buf[2], gpio;
401
402 deb_info("%s: onoff=%d\n", __func__, onoff);
403
404 ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
405 if (ret)
406 goto err;
407
408 if (onoff) {
409 buf[0] = 0x00;
410 buf[1] = 0x00;
411 gpio |= 0x04; /* LED on */
412 } else {
413 buf[0] = 0x10; /* stall EPA */
414 buf[1] = 0x02; /* reset EPA */
415 gpio &= (~0x04); /* LED off */
416 }
417
418 ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
419 if (ret)
420 goto err;
421
422 ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
423 if (ret)
424 goto err;
425
426 return ret;
427err:
428 deb_info("%s: failed=%d\n", __func__, ret);
429 return ret;
430}
431
432static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
433{
434 int ret;
435 u8 gpio, sys0;
436
437 deb_info("%s: onoff=%d\n", __func__, onoff);
438
439 /* demod adc */
440 ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
441 if (ret)
442 goto err;
443
444 /* tuner power, read GPIOs */
445 ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
446 if (ret)
447 goto err;
448
449 deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
450
451 if (onoff) {
452 gpio |= 0x01; /* GPIO0 = 1 */
453 gpio &= (~0x10); /* GPIO4 = 0 */
454 sys0 = sys0 & 0x0f;
455 sys0 |= 0xe0;
456 } else {
457
458#if 0 /* keep */
459 /*
460 * FIXME: Use .fe_ioctl_override() to prevent demod
461 * IOCTLs in case of device is powered off.
462 *
463 * For now we cannot power off device because most FE IOCTLs
464 * can be performed only when device is powered.
465 * Using IOCTLs when device is powered off will result errors
466 * because register access to demod fails.
467 */
468 gpio &= (~0x01); /* GPIO0 = 0 */
469 gpio |= 0x10; /* GPIO4 = 1 */
470 sys0 = sys0 & (~0xc0);
471#endif
472 }
473
474 deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
475
476 /* demod adc */
477 ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
478 if (ret)
479 goto err;
480
481 /* tuner power, write GPIOs */
482 ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
483 if (ret)
484 goto err;
485
486 return ret;
487err:
488 deb_info("%s: failed=%d\n", __func__, ret);
489 return ret;
490}
491
492static int rtl28xxu_rc_query(struct dvb_usb_device *d)
493{
494 int ret;
495 u8 buf[5];
496 u32 rc_code;
497
498 ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
499 if (ret)
500 goto err;
501
502 if (buf[4] & 0x01) {
503 if (buf[2] == (u8) ~buf[3]) {
504 if (buf[0] == (u8) ~buf[1]) {
505 /* NEC standard (16 bit) */
506 rc_code = buf[0] << 8 | buf[2];
507 } else {
508 /* NEC extended (24 bit) */
509 rc_code = buf[0] << 16 |
510 buf[1] << 8 | buf[2];
511 }
512 } else {
513 /* NEC full (32 bit) */
514 rc_code = buf[0] << 24 | buf[1] << 16 |
515 buf[2] << 8 | buf[3];
516 }
517
518 rc_keydown(d->rc_dev, rc_code, 0);
519
520 ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
521 if (ret)
522 goto err;
523
524 /* repeated intentionally to avoid extra keypress */
525 ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
526 if (ret)
527 goto err;
528 }
529
530 return ret;
531err:
532 deb_info("%s: failed=%d\n", __func__, ret);
533 return ret;
534}
535
536/* DVB USB Driver stuff */
537#define USB_VID_REALTEK 0x0bda
538#define USB_PID_RTL2831U 0x2831
539#define USB_PID_FREECOM 0x0160
540
541#define RTL2831U_0BDA_2831 0
542#define RTL2831U_14AA_0160 1
543
544static struct usb_device_id rtl28xxu_table[] = {
545 [RTL2831U_0BDA_2831] = {
546 USB_DEVICE(USB_VID_REALTEK, USB_PID_RTL2831U)},
547 [RTL2831U_14AA_0160] = {
548 USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM)},
549 {} /* terminating entry */
550};
551
552MODULE_DEVICE_TABLE(usb, rtl28xxu_table);
553
554static struct dvb_usb_device_properties rtl28xxu_properties[] = {
555 {
556 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
557
558 .usb_ctrl = DEVICE_SPECIFIC,
559 .no_reconnect = 1,
560
561 .size_of_priv = sizeof(struct rtl28xxu_priv),
562
563 .num_adapters = 1,
564 .adapter = {
565 {
566 .frontend_attach = rtl28xxu_frontend_attach,
567 .tuner_attach = rtl28xxu_tuner_attach,
568 .streaming_ctrl = rtl28xxu_streaming_ctrl,
569 .stream = {
570 .type = USB_BULK,
571 .count = 6,
572 .endpoint = 0x81,
573 .u = {
574 .bulk = {
575 .buffersize = 4096,
576 }
577 }
578 },
579 }
580 },
581
582 .power_ctrl = rtl28xxu_power_ctrl,
583
584 .rc.core = {
585 .protocol = RC_TYPE_NEC,
586 .module_name = "rtl28xxu",
587 .rc_query = rtl28xxu_rc_query,
588 .rc_interval = 400,
589 .allowed_protos = RC_TYPE_NEC,
590 .rc_codes = RC_MAP_EMPTY,
591 },
592
593 .i2c_algo = &rtl28xxu_i2c_algo,
594
595 .num_device_descs = 2,
596 .devices = {
597 {
598 .name = "Realtek RTL2831U reference design",
599 .cold_ids = {NULL},
600 .warm_ids = {
601 &rtl28xxu_table[RTL2831U_0BDA_2831], NULL},
602 },
603 {
604 .name = "Freecom USB2.0 DVB-T",
605 .cold_ids = {NULL},
606 .warm_ids = {
607 &rtl28xxu_table[RTL2831U_14AA_0160], NULL},
608 },
609 }
610 },
611};
612
613static int rtl28xxu_probe(struct usb_interface *intf,
614 const struct usb_device_id *id)
615{
616 int ret, i;
617 int properties_count = ARRAY_SIZE(rtl28xxu_properties);
618 struct dvb_usb_device *d = NULL;
619 struct rtl28xxu_reg_val rc_nec_tab[] = {
620 { 0x3033, 0x80 },
621 { 0x3020, 0x43 },
622 { 0x3021, 0x16 },
623 { 0x3022, 0x16 },
624 { 0x3023, 0x5a },
625 { 0x3024, 0x2d },
626 { 0x3025, 0x16 },
627 { 0x3026, 0x01 },
628 { 0x3028, 0xb0 },
629 { 0x3029, 0x04 },
630 { 0x302c, 0x88 },
631 { 0x302e, 0x13 },
632 { 0x3030, 0xdf },
633 { 0x3031, 0x05 },
634 };
635
636 deb_info("%s: interface=%d\n", __func__,
637 intf->cur_altsetting->desc.bInterfaceNumber);
638
639 if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
640 return 0;
641
642 for (i = 0; i < properties_count; i++) {
643 ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
644 THIS_MODULE, &d, adapter_nr);
645 if (ret == 0 || ret != -ENODEV)
646 break;
647 }
648
649 if (ret)
650 goto err;
651
652 /* init USB endpoints */
653 ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
654 if (ret)
655 goto err;
656
657 ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
658 if (ret)
659 goto err;
660
661 ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
662 if (ret)
663 goto err;
664
665 /* init remote controller */
666 for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
667 ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, rc_nec_tab[i].val);
668 if (ret)
669 goto err;
670 }
671
672 return ret;
673err:
674 deb_info("%s: failed=%d\n", __func__, ret);
675 return ret;
676}
677
678static struct usb_driver rtl28xxu_driver = {
679 .name = "dvb_usb_rtl28xxu",
680 .probe = rtl28xxu_probe,
681 .disconnect = dvb_usb_device_exit,
682 .id_table = rtl28xxu_table,
683};
684
685/* module stuff */
686static int __init rtl28xxu_module_init(void)
687{
688 int ret;
689 deb_info("%s:\n", __func__);
690 ret = usb_register(&rtl28xxu_driver);
691 if (ret)
692 err("usb_register failed=%d", ret);
693
694 return ret;
695}
696
697static void __exit rtl28xxu_module_exit(void)
698{
699 deb_info("%s:\n", __func__);
700 /* deregister this driver from the USB subsystem */
701 usb_deregister(&rtl28xxu_driver);
702}
703
704module_init(rtl28xxu_module_init);
705module_exit(rtl28xxu_module_exit);
706
707MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
708MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
709MODULE_LICENSE("GPL");