.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* DVB USB framework compliant Linux driver for the |
---|
2 | 3 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, |
---|
3 | 4 | * TeVii S421, S480, S482, S600, S630, S632, S650, S660, S662, |
---|
.. | .. |
---|
7 | 8 | * Terratec Cinergy S2 cards |
---|
8 | 9 | * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by) |
---|
9 | 10 | * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify it |
---|
11 | | - * under the terms of the GNU General Public License as published by the |
---|
12 | | - * Free Software Foundation, version 2. |
---|
13 | | - * |
---|
14 | | - * see Documentation/media/dvb-drivers/dvb-usb.rst for more information |
---|
| 11 | + * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information |
---|
15 | 12 | */ |
---|
16 | 13 | #include <media/dvb-usb-ids.h> |
---|
17 | 14 | #include "dw2102.h" |
---|
.. | .. |
---|
131 | 128 | |
---|
132 | 129 | switch (num) { |
---|
133 | 130 | case 2: |
---|
| 131 | + if (msg[0].len < 1) { |
---|
| 132 | + num = -EOPNOTSUPP; |
---|
| 133 | + break; |
---|
| 134 | + } |
---|
134 | 135 | /* read stv0299 register */ |
---|
135 | 136 | value = msg[0].buf[0];/* register */ |
---|
136 | 137 | for (i = 0; i < msg[1].len; i++) { |
---|
.. | .. |
---|
142 | 143 | case 1: |
---|
143 | 144 | switch (msg[0].addr) { |
---|
144 | 145 | case 0x68: |
---|
| 146 | + if (msg[0].len < 2) { |
---|
| 147 | + num = -EOPNOTSUPP; |
---|
| 148 | + break; |
---|
| 149 | + } |
---|
145 | 150 | /* write to stv0299 register */ |
---|
146 | 151 | buf6[0] = 0x2a; |
---|
147 | 152 | buf6[1] = msg[0].buf[0]; |
---|
.. | .. |
---|
151 | 156 | break; |
---|
152 | 157 | case 0x60: |
---|
153 | 158 | if (msg[0].flags == 0) { |
---|
| 159 | + if (msg[0].len < 4) { |
---|
| 160 | + num = -EOPNOTSUPP; |
---|
| 161 | + break; |
---|
| 162 | + } |
---|
154 | 163 | /* write to tuner pll */ |
---|
155 | 164 | buf6[0] = 0x2c; |
---|
156 | 165 | buf6[1] = 5; |
---|
.. | .. |
---|
162 | 171 | dw210x_op_rw(d->udev, 0xb2, 0, 0, |
---|
163 | 172 | buf6, 7, DW210X_WRITE_MSG); |
---|
164 | 173 | } else { |
---|
| 174 | + if (msg[0].len < 1) { |
---|
| 175 | + num = -EOPNOTSUPP; |
---|
| 176 | + break; |
---|
| 177 | + } |
---|
165 | 178 | /* read from tuner */ |
---|
166 | 179 | dw210x_op_rw(d->udev, 0xb5, 0, 0, |
---|
167 | 180 | buf6, 1, DW210X_READ_MSG); |
---|
.. | .. |
---|
169 | 182 | } |
---|
170 | 183 | break; |
---|
171 | 184 | case (DW2102_RC_QUERY): |
---|
| 185 | + if (msg[0].len < 2) { |
---|
| 186 | + num = -EOPNOTSUPP; |
---|
| 187 | + break; |
---|
| 188 | + } |
---|
172 | 189 | dw210x_op_rw(d->udev, 0xb8, 0, 0, |
---|
173 | 190 | buf6, 2, DW210X_READ_MSG); |
---|
174 | 191 | msg[0].buf[0] = buf6[0]; |
---|
175 | 192 | msg[0].buf[1] = buf6[1]; |
---|
176 | 193 | break; |
---|
177 | 194 | case (DW2102_VOLTAGE_CTRL): |
---|
| 195 | + if (msg[0].len < 1) { |
---|
| 196 | + num = -EOPNOTSUPP; |
---|
| 197 | + break; |
---|
| 198 | + } |
---|
178 | 199 | buf6[0] = 0x30; |
---|
179 | 200 | buf6[1] = msg[0].buf[0]; |
---|
180 | 201 | dw210x_op_rw(d->udev, 0xb2, 0, 0, |
---|
.. | .. |
---|
949 | 970 | for (i = 0; i < 6; i++) { |
---|
950 | 971 | obuf[1] = 0xf0 + i; |
---|
951 | 972 | if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) |
---|
952 | | - break; |
---|
| 973 | + return -1; |
---|
953 | 974 | else |
---|
954 | 975 | mac[i] = ibuf[0]; |
---|
955 | 976 | } |
---|
.. | .. |
---|
958 | 979 | } |
---|
959 | 980 | |
---|
960 | 981 | static int su3000_identify_state(struct usb_device *udev, |
---|
961 | | - struct dvb_usb_device_properties *props, |
---|
962 | | - struct dvb_usb_device_description **desc, |
---|
| 982 | + const struct dvb_usb_device_properties *props, |
---|
| 983 | + const struct dvb_usb_device_description **desc, |
---|
963 | 984 | int *cold) |
---|
964 | 985 | { |
---|
965 | 986 | info("%s", __func__); |
---|
.. | .. |
---|
1527 | 1548 | return -EIO; |
---|
1528 | 1549 | } |
---|
1529 | 1550 | |
---|
| 1551 | +static int tt_s2_4600_frontend_attach_probe_demod(struct dvb_usb_device *d, |
---|
| 1552 | + const int probe_addr) |
---|
| 1553 | +{ |
---|
| 1554 | + struct dw2102_state *state = d->priv; |
---|
| 1555 | + |
---|
| 1556 | + state->data[0] = 0x9; |
---|
| 1557 | + state->data[1] = 0x1; |
---|
| 1558 | + state->data[2] = 0x1; |
---|
| 1559 | + state->data[3] = probe_addr; |
---|
| 1560 | + state->data[4] = 0x0; |
---|
| 1561 | + |
---|
| 1562 | + if (dvb_usb_generic_rw(d, state->data, 5, state->data, 2, 0) < 0) { |
---|
| 1563 | + err("i2c probe for address 0x%x failed.", probe_addr); |
---|
| 1564 | + return 0; |
---|
| 1565 | + } |
---|
| 1566 | + |
---|
| 1567 | + if (state->data[0] != 8) /* fail(7) or error, no device at address */ |
---|
| 1568 | + return 0; |
---|
| 1569 | + |
---|
| 1570 | + /* probing successful */ |
---|
| 1571 | + return 1; |
---|
| 1572 | +} |
---|
| 1573 | + |
---|
1530 | 1574 | static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) |
---|
1531 | 1575 | { |
---|
1532 | 1576 | struct dvb_usb_device *d = adap->dev; |
---|
.. | .. |
---|
1536 | 1580 | struct i2c_board_info board_info; |
---|
1537 | 1581 | struct m88ds3103_platform_data m88ds3103_pdata = {}; |
---|
1538 | 1582 | struct ts2020_config ts2020_config = {}; |
---|
| 1583 | + int demod_addr; |
---|
1539 | 1584 | |
---|
1540 | 1585 | mutex_lock(&d->data_mutex); |
---|
1541 | 1586 | |
---|
.. | .. |
---|
1573 | 1618 | if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0) |
---|
1574 | 1619 | err("command 0x51 transfer failed."); |
---|
1575 | 1620 | |
---|
| 1621 | + /* probe for demodulator i2c address */ |
---|
| 1622 | + demod_addr = -1; |
---|
| 1623 | + if (tt_s2_4600_frontend_attach_probe_demod(d, 0x68)) |
---|
| 1624 | + demod_addr = 0x68; |
---|
| 1625 | + else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x69)) |
---|
| 1626 | + demod_addr = 0x69; |
---|
| 1627 | + else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x6a)) |
---|
| 1628 | + demod_addr = 0x6a; |
---|
| 1629 | + |
---|
1576 | 1630 | mutex_unlock(&d->data_mutex); |
---|
| 1631 | + |
---|
| 1632 | + if (demod_addr < 0) { |
---|
| 1633 | + err("probing for demodulator failed. Is the external power switched on?"); |
---|
| 1634 | + return -ENODEV; |
---|
| 1635 | + } |
---|
1577 | 1636 | |
---|
1578 | 1637 | /* attach demod */ |
---|
1579 | 1638 | m88ds3103_pdata.clk = 27000000; |
---|
.. | .. |
---|
1589 | 1648 | m88ds3103_pdata.lnb_hv_pol = 1; |
---|
1590 | 1649 | m88ds3103_pdata.lnb_en_pol = 0; |
---|
1591 | 1650 | memset(&board_info, 0, sizeof(board_info)); |
---|
1592 | | - strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); |
---|
1593 | | - board_info.addr = 0x68; |
---|
| 1651 | + if (demod_addr == 0x6a) |
---|
| 1652 | + strscpy(board_info.type, "m88ds3103b", I2C_NAME_SIZE); |
---|
| 1653 | + else |
---|
| 1654 | + strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); |
---|
| 1655 | + board_info.addr = demod_addr; |
---|
1594 | 1656 | board_info.platform_data = &m88ds3103_pdata; |
---|
1595 | 1657 | request_module("m88ds3103"); |
---|
1596 | | - client = i2c_new_device(&d->i2c_adap, &board_info); |
---|
1597 | | - if (client == NULL || client->dev.driver == NULL) |
---|
| 1658 | + client = i2c_new_client_device(&d->i2c_adap, &board_info); |
---|
| 1659 | + if (!i2c_client_has_driver(client)) |
---|
1598 | 1660 | return -ENODEV; |
---|
1599 | 1661 | if (!try_module_get(client->dev.driver->owner)) { |
---|
1600 | 1662 | i2c_unregister_device(client); |
---|
.. | .. |
---|
1608 | 1670 | /* attach tuner */ |
---|
1609 | 1671 | ts2020_config.fe = adap->fe_adap[0].fe; |
---|
1610 | 1672 | memset(&board_info, 0, sizeof(board_info)); |
---|
1611 | | - strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); |
---|
| 1673 | + strscpy(board_info.type, "ts2022", I2C_NAME_SIZE); |
---|
1612 | 1674 | board_info.addr = 0x60; |
---|
1613 | 1675 | board_info.platform_data = &ts2020_config; |
---|
1614 | 1676 | request_module("ts2020"); |
---|
1615 | | - client = i2c_new_device(i2c_adapter, &board_info); |
---|
| 1677 | + client = i2c_new_client_device(i2c_adapter, &board_info); |
---|
1616 | 1678 | |
---|
1617 | | - if (client == NULL || client->dev.driver == NULL) { |
---|
| 1679 | + if (!i2c_client_has_driver(client)) { |
---|
1618 | 1680 | dvb_frontend_detach(adap->fe_adap[0].fe); |
---|
1619 | 1681 | return -ENODEV; |
---|
1620 | 1682 | } |
---|
.. | .. |
---|
1741 | 1803 | TERRATEC_CINERGY_S2_R2, |
---|
1742 | 1804 | TERRATEC_CINERGY_S2_R3, |
---|
1743 | 1805 | TERRATEC_CINERGY_S2_R4, |
---|
| 1806 | + TERRATEC_CINERGY_S2_1, |
---|
| 1807 | + TERRATEC_CINERGY_S2_2, |
---|
1744 | 1808 | GOTVIEW_SAT_HD, |
---|
1745 | 1809 | GENIATECH_T220, |
---|
1746 | 1810 | TECHNOTREND_S2_4600, |
---|
.. | .. |
---|
1768 | 1832 | [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, |
---|
1769 | 1833 | [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, |
---|
1770 | 1834 | [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, |
---|
1771 | | - [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R2)}, |
---|
1772 | | - [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R3)}, |
---|
1773 | | - [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4)}, |
---|
| 1835 | + [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, |
---|
| 1836 | + USB_PID_TERRATEC_CINERGY_S2_R2)}, |
---|
| 1837 | + [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, |
---|
| 1838 | + USB_PID_TERRATEC_CINERGY_S2_R3)}, |
---|
| 1839 | + [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, |
---|
| 1840 | + USB_PID_TERRATEC_CINERGY_S2_R4)}, |
---|
| 1841 | + [TERRATEC_CINERGY_S2_1] = {USB_DEVICE(USB_VID_TERRATEC_2, |
---|
| 1842 | + USB_PID_TERRATEC_CINERGY_S2_1)}, |
---|
| 1843 | + [TERRATEC_CINERGY_S2_2] = {USB_DEVICE(USB_VID_TERRATEC_2, |
---|
| 1844 | + USB_PID_TERRATEC_CINERGY_S2_2)}, |
---|
1774 | 1845 | [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, |
---|
1775 | 1846 | [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, |
---|
1776 | 1847 | [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, |
---|
.. | .. |
---|
1839 | 1910 | switch (le16_to_cpu(dev->descriptor.idProduct)) { |
---|
1840 | 1911 | case USB_PID_TEVII_S650: |
---|
1841 | 1912 | dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC; |
---|
1842 | | - /* fall through */ |
---|
| 1913 | + fallthrough; |
---|
1843 | 1914 | case USB_PID_DW2104: |
---|
1844 | 1915 | reset = 1; |
---|
1845 | 1916 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, |
---|
1846 | 1917 | DW210X_WRITE_MSG); |
---|
1847 | | - /* fall through */ |
---|
| 1918 | + fallthrough; |
---|
1848 | 1919 | case USB_PID_DW3101: |
---|
1849 | 1920 | reset = 0; |
---|
1850 | 1921 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
---|
.. | .. |
---|
1877 | 1948 | break; |
---|
1878 | 1949 | } |
---|
1879 | 1950 | } |
---|
1880 | | - /* fall through */ |
---|
| 1951 | + fallthrough; |
---|
1881 | 1952 | case 0x2101: |
---|
1882 | 1953 | dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, |
---|
1883 | 1954 | DW210X_READ_MSG); |
---|
.. | .. |
---|
2290 | 2361 | }}, |
---|
2291 | 2362 | } |
---|
2292 | 2363 | }, |
---|
2293 | | - .num_device_descs = 6, |
---|
| 2364 | + .num_device_descs = 8, |
---|
2294 | 2365 | .devices = { |
---|
2295 | 2366 | { "SU3000HD DVB-S USB2.0", |
---|
2296 | 2367 | { &dw2102_table[GENIATECH_SU3000], NULL }, |
---|
.. | .. |
---|
2312 | 2383 | { &dw2102_table[TERRATEC_CINERGY_S2_R3], NULL }, |
---|
2313 | 2384 | { NULL }, |
---|
2314 | 2385 | }, |
---|
| 2386 | + { "Terratec Cinergy S2 PCIe Dual Port 1", |
---|
| 2387 | + { &dw2102_table[TERRATEC_CINERGY_S2_1], NULL }, |
---|
| 2388 | + { NULL }, |
---|
| 2389 | + }, |
---|
| 2390 | + { "Terratec Cinergy S2 PCIe Dual Port 2", |
---|
| 2391 | + { &dw2102_table[TERRATEC_CINERGY_S2_2], NULL }, |
---|
| 2392 | + { NULL }, |
---|
| 2393 | + }, |
---|
2315 | 2394 | { "GOTVIEW Satellite HD", |
---|
2316 | 2395 | { &dw2102_table[GOTVIEW_SAT_HD], NULL }, |
---|
2317 | 2396 | { NULL }, |
---|