| .. | .. |
|---|
| 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 }, |
|---|