18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cx18 driver initialization and card probing 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Derived from ivtv-driver.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 88c2ecf20Sopenharmony_ci * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "cx18-driver.h" 128c2ecf20Sopenharmony_ci#include "cx18-io.h" 138c2ecf20Sopenharmony_ci#include "cx18-version.h" 148c2ecf20Sopenharmony_ci#include "cx18-cards.h" 158c2ecf20Sopenharmony_ci#include "cx18-i2c.h" 168c2ecf20Sopenharmony_ci#include "cx18-irq.h" 178c2ecf20Sopenharmony_ci#include "cx18-gpio.h" 188c2ecf20Sopenharmony_ci#include "cx18-firmware.h" 198c2ecf20Sopenharmony_ci#include "cx18-queue.h" 208c2ecf20Sopenharmony_ci#include "cx18-streams.h" 218c2ecf20Sopenharmony_ci#include "cx18-av-core.h" 228c2ecf20Sopenharmony_ci#include "cx18-scb.h" 238c2ecf20Sopenharmony_ci#include "cx18-mailbox.h" 248c2ecf20Sopenharmony_ci#include "cx18-ioctl.h" 258c2ecf20Sopenharmony_ci#include "cx18-controls.h" 268c2ecf20Sopenharmony_ci#include "tuner-xc2028.h" 278c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 288c2ecf20Sopenharmony_ci#include <media/tveeprom.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* If you have already X v4l cards, then set this to X. This way 318c2ecf20Sopenharmony_ci the device numbers stay matched. Example: you have a WinTV card 328c2ecf20Sopenharmony_ci without radio and a Compro H900 with. Normally this would give a 338c2ecf20Sopenharmony_ci video1 device together with a radio0 device for the Compro. By 348c2ecf20Sopenharmony_ci setting this to 1 you ensure that radio0 is now also radio1. */ 358c2ecf20Sopenharmony_ciint cx18_first_minor; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Callback for registering extensions */ 388c2ecf20Sopenharmony_ciint (*cx18_ext_init)(struct cx18 *); 398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx18_ext_init); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* add your revision and whatnot here */ 428c2ecf20Sopenharmony_cistatic const struct pci_device_id cx18_pci_tbl[] = { 438c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, 448c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 458c2ecf20Sopenharmony_ci {0,} 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cx18_pci_tbl); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic atomic_t cx18_instance = ATOMIC_INIT(0); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Parameter declarations */ 538c2ecf20Sopenharmony_cistatic int cardtype[CX18_MAX_CARDS]; 548c2ecf20Sopenharmony_cistatic int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, 558c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 568c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 578c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 }; 588c2ecf20Sopenharmony_cistatic int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, 598c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 608c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 618c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1 }; 628c2ecf20Sopenharmony_cistatic unsigned cardtype_c = 1; 638c2ecf20Sopenharmony_cistatic unsigned tuner_c = 1; 648c2ecf20Sopenharmony_cistatic unsigned radio_c = 1; 658c2ecf20Sopenharmony_cistatic char pal[] = "--"; 668c2ecf20Sopenharmony_cistatic char secam[] = "--"; 678c2ecf20Sopenharmony_cistatic char ntsc[] = "-"; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Buffers */ 708c2ecf20Sopenharmony_cistatic int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; 718c2ecf20Sopenharmony_cistatic int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; 728c2ecf20Sopenharmony_cistatic int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; 738c2ecf20Sopenharmony_cistatic int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; 748c2ecf20Sopenharmony_cistatic int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; 758c2ecf20Sopenharmony_cistatic int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; 788c2ecf20Sopenharmony_cistatic int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; 798c2ecf20Sopenharmony_cistatic int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; 808c2ecf20Sopenharmony_cistatic int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; 818c2ecf20Sopenharmony_cistatic int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int enc_ts_bufs = -1; 848c2ecf20Sopenharmony_cistatic int enc_mpg_bufs = -1; 858c2ecf20Sopenharmony_cistatic int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM; 868c2ecf20Sopenharmony_cistatic int enc_yuv_bufs = -1; 878c2ecf20Sopenharmony_cistatic int enc_vbi_bufs = -1; 888c2ecf20Sopenharmony_cistatic int enc_pcm_bufs = -1; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int cx18_pci_latency = 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int mmio_ndelay; 948c2ecf20Sopenharmony_cistatic int retry_mmio = 1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint cx18_debug; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cimodule_param_array(tuner, int, &tuner_c, 0644); 998c2ecf20Sopenharmony_cimodule_param_array(radio, int, &radio_c, 0644); 1008c2ecf20Sopenharmony_cimodule_param_array(cardtype, int, &cardtype_c, 0644); 1018c2ecf20Sopenharmony_cimodule_param_string(pal, pal, sizeof(pal), 0644); 1028c2ecf20Sopenharmony_cimodule_param_string(secam, secam, sizeof(secam), 0644); 1038c2ecf20Sopenharmony_cimodule_param_string(ntsc, ntsc, sizeof(ntsc), 0644); 1048c2ecf20Sopenharmony_cimodule_param_named(debug, cx18_debug, int, 0644); 1058c2ecf20Sopenharmony_cimodule_param(mmio_ndelay, int, 0644); 1068c2ecf20Sopenharmony_cimodule_param(retry_mmio, int, 0644); 1078c2ecf20Sopenharmony_cimodule_param(cx18_pci_latency, int, 0644); 1088c2ecf20Sopenharmony_cimodule_param(cx18_first_minor, int, 0644); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cimodule_param(enc_ts_buffers, int, 0644); 1118c2ecf20Sopenharmony_cimodule_param(enc_mpg_buffers, int, 0644); 1128c2ecf20Sopenharmony_cimodule_param(enc_idx_buffers, int, 0644); 1138c2ecf20Sopenharmony_cimodule_param(enc_yuv_buffers, int, 0644); 1148c2ecf20Sopenharmony_cimodule_param(enc_vbi_buffers, int, 0644); 1158c2ecf20Sopenharmony_cimodule_param(enc_pcm_buffers, int, 0644); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cimodule_param(enc_ts_bufsize, int, 0644); 1188c2ecf20Sopenharmony_cimodule_param(enc_mpg_bufsize, int, 0644); 1198c2ecf20Sopenharmony_cimodule_param(enc_idx_bufsize, int, 0644); 1208c2ecf20Sopenharmony_cimodule_param(enc_yuv_bufsize, int, 0644); 1218c2ecf20Sopenharmony_cimodule_param(enc_pcm_bufsize, int, 0644); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cimodule_param(enc_ts_bufs, int, 0644); 1248c2ecf20Sopenharmony_cimodule_param(enc_mpg_bufs, int, 0644); 1258c2ecf20Sopenharmony_cimodule_param(enc_idx_bufs, int, 0644); 1268c2ecf20Sopenharmony_cimodule_param(enc_yuv_bufs, int, 0644); 1278c2ecf20Sopenharmony_cimodule_param(enc_vbi_bufs, int, 0644); 1288c2ecf20Sopenharmony_cimodule_param(enc_pcm_bufs, int, 0644); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tuner, "Tuner type selection,\n" 1318c2ecf20Sopenharmony_ci "\t\t\tsee tuner.h for values"); 1328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(radio, 1338c2ecf20Sopenharmony_ci "Enable or disable the radio. Use only if autodetection\n" 1348c2ecf20Sopenharmony_ci "\t\t\tfails. 0 = disable, 1 = enable"); 1358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cardtype, 1368c2ecf20Sopenharmony_ci "Only use this option if your card is not detected properly.\n" 1378c2ecf20Sopenharmony_ci "\t\tSpecify card type:\n" 1388c2ecf20Sopenharmony_ci "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" 1398c2ecf20Sopenharmony_ci "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" 1408c2ecf20Sopenharmony_ci "\t\t\t 3 = Compro VideoMate H900\n" 1418c2ecf20Sopenharmony_ci "\t\t\t 4 = Yuan MPC718\n" 1428c2ecf20Sopenharmony_ci "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" 1438c2ecf20Sopenharmony_ci "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" 1448c2ecf20Sopenharmony_ci "\t\t\t 7 = Leadtek WinFast PVR2100\n" 1458c2ecf20Sopenharmony_ci "\t\t\t 8 = Leadtek WinFast DVR3100 H\n" 1468c2ecf20Sopenharmony_ci "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n" 1478c2ecf20Sopenharmony_ci "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n" 1488c2ecf20Sopenharmony_ci "\t\t\t 0 = Autodetect (default)\n" 1498c2ecf20Sopenharmony_ci "\t\t\t-1 = Ignore this card\n\t\t"); 1508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); 1518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); 1528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); 1538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, 1548c2ecf20Sopenharmony_ci "Debug level (bitmask). Default: 0\n" 1558c2ecf20Sopenharmony_ci "\t\t\t 1/0x0001: warning\n" 1568c2ecf20Sopenharmony_ci "\t\t\t 2/0x0002: info\n" 1578c2ecf20Sopenharmony_ci "\t\t\t 4/0x0004: mailbox\n" 1588c2ecf20Sopenharmony_ci "\t\t\t 8/0x0008: dma\n" 1598c2ecf20Sopenharmony_ci "\t\t\t 16/0x0010: ioctl\n" 1608c2ecf20Sopenharmony_ci "\t\t\t 32/0x0020: file\n" 1618c2ecf20Sopenharmony_ci "\t\t\t 64/0x0040: i2c\n" 1628c2ecf20Sopenharmony_ci "\t\t\t128/0x0080: irq\n" 1638c2ecf20Sopenharmony_ci "\t\t\t256/0x0100: high volume\n"); 1648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cx18_pci_latency, 1658c2ecf20Sopenharmony_ci "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" 1668c2ecf20Sopenharmony_ci "\t\t\tDefault: Yes"); 1678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(retry_mmio, 1688c2ecf20Sopenharmony_ci "(Deprecated) MMIO writes are now always checked and retried\n" 1698c2ecf20Sopenharmony_ci "\t\t\tEffectively: 1 [Yes]"); 1708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mmio_ndelay, 1718c2ecf20Sopenharmony_ci "(Deprecated) MMIO accesses are now never purposely delayed\n" 1728c2ecf20Sopenharmony_ci "\t\t\tEffectively: 0 ns"); 1738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_ts_buffers, 1748c2ecf20Sopenharmony_ci "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" 1758c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); 1768c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_ts_bufsize, 1778c2ecf20Sopenharmony_ci "Size of an encoder TS buffer (kB)\n" 1788c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); 1798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_ts_bufs, 1808c2ecf20Sopenharmony_ci "Number of encoder TS buffers\n" 1818c2ecf20Sopenharmony_ci "\t\t\tDefault is computed from other enc_ts_* parameters"); 1828c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_mpg_buffers, 1838c2ecf20Sopenharmony_ci "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" 1848c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); 1858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_mpg_bufsize, 1868c2ecf20Sopenharmony_ci "Size of an encoder MPG buffer (kB)\n" 1878c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); 1888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_mpg_bufs, 1898c2ecf20Sopenharmony_ci "Number of encoder MPG buffers\n" 1908c2ecf20Sopenharmony_ci "\t\t\tDefault is computed from other enc_mpg_* parameters"); 1918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_idx_buffers, 1928c2ecf20Sopenharmony_ci "(Deprecated) Encoder IDX buffer memory (MB)\n" 1938c2ecf20Sopenharmony_ci "\t\t\tIgnored, except 0 disables IDX buffer allocations\n" 1948c2ecf20Sopenharmony_ci "\t\t\tDefault: 1 [Enabled]"); 1958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_idx_bufsize, 1968c2ecf20Sopenharmony_ci "Size of an encoder IDX buffer (kB)\n" 1978c2ecf20Sopenharmony_ci "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n" 1988c2ecf20Sopenharmony_ci "\t\t\t(multiples of size required for 64 index entries)\n" 1998c2ecf20Sopenharmony_ci "\t\t\tDefault: 2"); 2008c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_idx_bufs, 2018c2ecf20Sopenharmony_ci "Number of encoder IDX buffers\n" 2028c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM)); 2038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_yuv_buffers, 2048c2ecf20Sopenharmony_ci "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" 2058c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); 2068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_yuv_bufsize, 2078c2ecf20Sopenharmony_ci "Size of an encoder YUV buffer (kB)\n" 2088c2ecf20Sopenharmony_ci "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n" 2098c2ecf20Sopenharmony_ci "\t\t\t(multiples of size required for 32 screen lines)\n" 2108c2ecf20Sopenharmony_ci "\t\t\tDefault: 102"); 2118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_yuv_bufs, 2128c2ecf20Sopenharmony_ci "Number of encoder YUV buffers\n" 2138c2ecf20Sopenharmony_ci "\t\t\tDefault is computed from other enc_yuv_* parameters"); 2148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_vbi_buffers, 2158c2ecf20Sopenharmony_ci "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" 2168c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); 2178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_vbi_bufs, 2188c2ecf20Sopenharmony_ci "Number of encoder VBI buffers\n" 2198c2ecf20Sopenharmony_ci "\t\t\tDefault is computed from enc_vbi_buffers"); 2208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_pcm_buffers, 2218c2ecf20Sopenharmony_ci "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" 2228c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); 2238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_pcm_bufsize, 2248c2ecf20Sopenharmony_ci "Size of an encoder PCM buffer (kB)\n" 2258c2ecf20Sopenharmony_ci "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); 2268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enc_pcm_bufs, 2278c2ecf20Sopenharmony_ci "Number of encoder PCM buffers\n" 2288c2ecf20Sopenharmony_ci "\t\t\tDefault is computed from other enc_pcm_* parameters"); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cx18_first_minor, 2318c2ecf20Sopenharmony_ci "Set device node number assigned to first card"); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hans Verkuil"); 2348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CX23418 driver"); 2358c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); 2368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciMODULE_VERSION(CX18_VERSION); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#if defined(CONFIG_MODULES) && defined(MODULE) 2418c2ecf20Sopenharmony_cistatic void request_module_async(struct work_struct *work) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct cx18 *dev = container_of(work, struct cx18, request_module_wk); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Make sure cx18-alsa module is loaded */ 2468c2ecf20Sopenharmony_ci request_module("cx18-alsa"); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Initialize cx18-alsa for this instance of the cx18 device */ 2498c2ecf20Sopenharmony_ci if (cx18_ext_init) 2508c2ecf20Sopenharmony_ci cx18_ext_init(dev); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void request_modules(struct cx18 *dev) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci INIT_WORK(&dev->request_module_wk, request_module_async); 2568c2ecf20Sopenharmony_ci schedule_work(&dev->request_module_wk); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void flush_request_modules(struct cx18 *dev) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci flush_work(&dev->request_module_wk); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci#else 2648c2ecf20Sopenharmony_ci#define request_modules(dev) 2658c2ecf20Sopenharmony_ci#define flush_request_modules(dev) 2668c2ecf20Sopenharmony_ci#endif /* CONFIG_MODULES */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* Generic utility functions */ 2698c2ecf20Sopenharmony_ciint cx18_msleep_timeout(unsigned int msecs, int intr) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci long int timeout = msecs_to_jiffies(msecs); 2728c2ecf20Sopenharmony_ci int sig; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci do { 2758c2ecf20Sopenharmony_ci set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 2768c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 2778c2ecf20Sopenharmony_ci sig = intr ? signal_pending(current) : 0; 2788c2ecf20Sopenharmony_ci } while (!sig && timeout); 2798c2ecf20Sopenharmony_ci return sig; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* Release ioremapped memory */ 2838c2ecf20Sopenharmony_cistatic void cx18_iounmap(struct cx18 *cx) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci if (!cx) 2868c2ecf20Sopenharmony_ci return; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Release io memory */ 2898c2ecf20Sopenharmony_ci if (cx->enc_mem) { 2908c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("releasing enc_mem\n"); 2918c2ecf20Sopenharmony_ci iounmap(cx->enc_mem); 2928c2ecf20Sopenharmony_ci cx->enc_mem = NULL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int i; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci CX18_INFO("eeprom dump:\n"); 3018c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 3028c2ecf20Sopenharmony_ci if (0 == (i % 16)) 3038c2ecf20Sopenharmony_ci CX18_INFO("eeprom %02x:", i); 3048c2ecf20Sopenharmony_ci printk(KERN_CONT " %02x", eedata[i]); 3058c2ecf20Sopenharmony_ci if (15 == (i % 16)) 3068c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/* Hauppauge card? get values from tveeprom */ 3118c2ecf20Sopenharmony_civoid cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct i2c_client *c; 3148c2ecf20Sopenharmony_ci u8 eedata[256]; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci memset(tv, 0, sizeof(*tv)); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci c = kzalloc(sizeof(*c), GFP_KERNEL); 3198c2ecf20Sopenharmony_ci if (!c) 3208c2ecf20Sopenharmony_ci return; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci strscpy(c->name, "cx18 tveeprom tmp", sizeof(c->name)); 3238c2ecf20Sopenharmony_ci c->adapter = &cx->i2c_adap[0]; 3248c2ecf20Sopenharmony_ci c->addr = 0xa0 >> 1; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (tveeprom_read(c, eedata, sizeof(eedata))) 3278c2ecf20Sopenharmony_ci goto ret; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci switch (cx->card->type) { 3308c2ecf20Sopenharmony_ci case CX18_CARD_HVR_1600_ESMT: 3318c2ecf20Sopenharmony_ci case CX18_CARD_HVR_1600_SAMSUNG: 3328c2ecf20Sopenharmony_ci case CX18_CARD_HVR_1600_S5H1411: 3338c2ecf20Sopenharmony_ci tveeprom_hauppauge_analog(tv, eedata); 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case CX18_CARD_YUAN_MPC718: 3368c2ecf20Sopenharmony_ci case CX18_CARD_GOTVIEW_PCI_DVD3: 3378c2ecf20Sopenharmony_ci tv->model = 0x718; 3388c2ecf20Sopenharmony_ci cx18_eeprom_dump(cx, eedata, sizeof(eedata)); 3398c2ecf20Sopenharmony_ci CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n", 3408c2ecf20Sopenharmony_ci eedata[2], eedata[1], eedata[4], eedata[3]); 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci tv->model = 0xffffffff; 3448c2ecf20Sopenharmony_ci cx18_eeprom_dump(cx, eedata, sizeof(eedata)); 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciret: 3498c2ecf20Sopenharmony_ci kfree(c); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void cx18_process_eeprom(struct cx18 *cx) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct tveeprom tv; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci cx18_read_eeprom(cx, &tv); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Many thanks to Steven Toth from Hauppauge for providing the 3598c2ecf20Sopenharmony_ci model numbers */ 3608c2ecf20Sopenharmony_ci /* Note: the Samsung memory models cannot be reliably determined 3618c2ecf20Sopenharmony_ci from the model number. Use the cardtype module option if you 3628c2ecf20Sopenharmony_ci have one of these preproduction models. */ 3638c2ecf20Sopenharmony_ci switch (tv.model) { 3648c2ecf20Sopenharmony_ci case 74301: /* Retail models */ 3658c2ecf20Sopenharmony_ci case 74321: 3668c2ecf20Sopenharmony_ci case 74351: /* OEM models */ 3678c2ecf20Sopenharmony_ci case 74361: 3688c2ecf20Sopenharmony_ci /* Digital side is s5h1411/tda18271 */ 3698c2ecf20Sopenharmony_ci cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411); 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case 74021: /* Retail models */ 3728c2ecf20Sopenharmony_ci case 74031: 3738c2ecf20Sopenharmony_ci case 74041: 3748c2ecf20Sopenharmony_ci case 74141: 3758c2ecf20Sopenharmony_ci case 74541: /* OEM models */ 3768c2ecf20Sopenharmony_ci case 74551: 3778c2ecf20Sopenharmony_ci case 74591: 3788c2ecf20Sopenharmony_ci case 74651: 3798c2ecf20Sopenharmony_ci case 74691: 3808c2ecf20Sopenharmony_ci case 74751: 3818c2ecf20Sopenharmony_ci case 74891: 3828c2ecf20Sopenharmony_ci /* Digital side is s5h1409/mxl5005s */ 3838c2ecf20Sopenharmony_ci cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case 0x718: 3868c2ecf20Sopenharmony_ci return; 3878c2ecf20Sopenharmony_ci case 0xffffffff: 3888c2ecf20Sopenharmony_ci CX18_INFO("Unknown EEPROM encoding\n"); 3898c2ecf20Sopenharmony_ci return; 3908c2ecf20Sopenharmony_ci case 0: 3918c2ecf20Sopenharmony_ci CX18_ERR("Invalid EEPROM\n"); 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci CX18_ERR("Unknown model %d, defaulting to original HVR-1600 (cardtype=1)\n", 3958c2ecf20Sopenharmony_ci tv.model); 3968c2ecf20Sopenharmony_ci cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci cx->v4l2_cap = cx->card->v4l2_capabilities; 4018c2ecf20Sopenharmony_ci cx->card_name = cx->card->name; 4028c2ecf20Sopenharmony_ci cx->card_i2c = cx->card->i2c; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci CX18_INFO("Autodetected %s\n", cx->card_name); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (tv.tuner_type == TUNER_ABSENT) 4078c2ecf20Sopenharmony_ci CX18_ERR("tveeprom cannot autodetect tuner!\n"); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (cx->options.tuner == -1) 4108c2ecf20Sopenharmony_ci cx->options.tuner = tv.tuner_type; 4118c2ecf20Sopenharmony_ci if (cx->options.radio == -1) 4128c2ecf20Sopenharmony_ci cx->options.radio = (tv.has_radio != 0); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (cx->std != 0) 4158c2ecf20Sopenharmony_ci /* user specified tuner standard */ 4168c2ecf20Sopenharmony_ci return; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* autodetect tuner standard */ 4198c2ecf20Sopenharmony_ci#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ 4208c2ecf20Sopenharmony_ci V4L2_STD_MN | \ 4218c2ecf20Sopenharmony_ci V4L2_STD_PAL_I | \ 4228c2ecf20Sopenharmony_ci V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ 4238c2ecf20Sopenharmony_ci V4L2_STD_DK) 4248c2ecf20Sopenharmony_ci if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) 4258c2ecf20Sopenharmony_ci == TVEEPROM_TUNER_FORMAT_ALL) { 4268c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("Worldwide tuner detected\n"); 4278c2ecf20Sopenharmony_ci cx->std = V4L2_STD_ALL; 4288c2ecf20Sopenharmony_ci } else if (tv.tuner_formats & V4L2_STD_PAL) { 4298c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("PAL tuner detected\n"); 4308c2ecf20Sopenharmony_ci cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; 4318c2ecf20Sopenharmony_ci } else if (tv.tuner_formats & V4L2_STD_NTSC) { 4328c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("NTSC tuner detected\n"); 4338c2ecf20Sopenharmony_ci cx->std |= V4L2_STD_NTSC_M; 4348c2ecf20Sopenharmony_ci } else if (tv.tuner_formats & V4L2_STD_SECAM) { 4358c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("SECAM tuner detected\n"); 4368c2ecf20Sopenharmony_ci cx->std |= V4L2_STD_SECAM_L; 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci CX18_INFO("No tuner detected, default to NTSC-M\n"); 4398c2ecf20Sopenharmony_ci cx->std |= V4L2_STD_NTSC_M; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic v4l2_std_id cx18_parse_std(struct cx18 *cx) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci switch (pal[0]) { 4468c2ecf20Sopenharmony_ci case '6': 4478c2ecf20Sopenharmony_ci return V4L2_STD_PAL_60; 4488c2ecf20Sopenharmony_ci case 'b': 4498c2ecf20Sopenharmony_ci case 'B': 4508c2ecf20Sopenharmony_ci case 'g': 4518c2ecf20Sopenharmony_ci case 'G': 4528c2ecf20Sopenharmony_ci return V4L2_STD_PAL_BG; 4538c2ecf20Sopenharmony_ci case 'h': 4548c2ecf20Sopenharmony_ci case 'H': 4558c2ecf20Sopenharmony_ci return V4L2_STD_PAL_H; 4568c2ecf20Sopenharmony_ci case 'n': 4578c2ecf20Sopenharmony_ci case 'N': 4588c2ecf20Sopenharmony_ci if (pal[1] == 'c' || pal[1] == 'C') 4598c2ecf20Sopenharmony_ci return V4L2_STD_PAL_Nc; 4608c2ecf20Sopenharmony_ci return V4L2_STD_PAL_N; 4618c2ecf20Sopenharmony_ci case 'i': 4628c2ecf20Sopenharmony_ci case 'I': 4638c2ecf20Sopenharmony_ci return V4L2_STD_PAL_I; 4648c2ecf20Sopenharmony_ci case 'd': 4658c2ecf20Sopenharmony_ci case 'D': 4668c2ecf20Sopenharmony_ci case 'k': 4678c2ecf20Sopenharmony_ci case 'K': 4688c2ecf20Sopenharmony_ci return V4L2_STD_PAL_DK; 4698c2ecf20Sopenharmony_ci case 'M': 4708c2ecf20Sopenharmony_ci case 'm': 4718c2ecf20Sopenharmony_ci return V4L2_STD_PAL_M; 4728c2ecf20Sopenharmony_ci case '-': 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci default: 4758c2ecf20Sopenharmony_ci CX18_WARN("pal= argument not recognised\n"); 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci switch (secam[0]) { 4808c2ecf20Sopenharmony_ci case 'b': 4818c2ecf20Sopenharmony_ci case 'B': 4828c2ecf20Sopenharmony_ci case 'g': 4838c2ecf20Sopenharmony_ci case 'G': 4848c2ecf20Sopenharmony_ci case 'h': 4858c2ecf20Sopenharmony_ci case 'H': 4868c2ecf20Sopenharmony_ci return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; 4878c2ecf20Sopenharmony_ci case 'd': 4888c2ecf20Sopenharmony_ci case 'D': 4898c2ecf20Sopenharmony_ci case 'k': 4908c2ecf20Sopenharmony_ci case 'K': 4918c2ecf20Sopenharmony_ci return V4L2_STD_SECAM_DK; 4928c2ecf20Sopenharmony_ci case 'l': 4938c2ecf20Sopenharmony_ci case 'L': 4948c2ecf20Sopenharmony_ci if (secam[1] == 'C' || secam[1] == 'c') 4958c2ecf20Sopenharmony_ci return V4L2_STD_SECAM_LC; 4968c2ecf20Sopenharmony_ci return V4L2_STD_SECAM_L; 4978c2ecf20Sopenharmony_ci case '-': 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci default: 5008c2ecf20Sopenharmony_ci CX18_WARN("secam= argument not recognised\n"); 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci switch (ntsc[0]) { 5058c2ecf20Sopenharmony_ci case 'm': 5068c2ecf20Sopenharmony_ci case 'M': 5078c2ecf20Sopenharmony_ci return V4L2_STD_NTSC_M; 5088c2ecf20Sopenharmony_ci case 'j': 5098c2ecf20Sopenharmony_ci case 'J': 5108c2ecf20Sopenharmony_ci return V4L2_STD_NTSC_M_JP; 5118c2ecf20Sopenharmony_ci case 'k': 5128c2ecf20Sopenharmony_ci case 'K': 5138c2ecf20Sopenharmony_ci return V4L2_STD_NTSC_M_KR; 5148c2ecf20Sopenharmony_ci case '-': 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci default: 5178c2ecf20Sopenharmony_ci CX18_WARN("ntsc= argument not recognised\n"); 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* no match found */ 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void cx18_process_options(struct cx18 *cx) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci int i, j; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; 5308c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; 5318c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; 5328c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; 5338c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; 5348c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; 5358c2ecf20Sopenharmony_ci cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; 5388c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; 5398c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; 5408c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; 5418c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; 5428c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; 5438c2ecf20Sopenharmony_ci cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; 5468c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; 5478c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; 5488c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; 5498c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = VBI_ACTIVE_SAMPLES * 36; 5508c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; 5518c2ecf20Sopenharmony_ci cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Ensure stream_buffers & stream_buf_size are valid */ 5548c2ecf20Sopenharmony_ci for (i = 0; i < CX18_MAX_STREAMS; i++) { 5558c2ecf20Sopenharmony_ci if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */ 5568c2ecf20Sopenharmony_ci cx->options.megabytes[i] <= 0 || /* User said 0 MB total */ 5578c2ecf20Sopenharmony_ci cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */ 5588c2ecf20Sopenharmony_ci cx->options.megabytes[i] = 0; 5598c2ecf20Sopenharmony_ci cx->stream_buffers[i] = 0; 5608c2ecf20Sopenharmony_ci cx->stream_buf_size[i] = 0; 5618c2ecf20Sopenharmony_ci continue; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * YUV is a special case where the stream_buf_size needs to be 5658c2ecf20Sopenharmony_ci * an integral multiple of 33.75 kB (storage for 32 screens 5668c2ecf20Sopenharmony_ci * lines to maintain alignment in case of lost buffers). 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * IDX is a special case where the stream_buf_size should be 5698c2ecf20Sopenharmony_ci * an integral multiple of 1.5 kB (storage for 64 index entries 5708c2ecf20Sopenharmony_ci * to maintain alignment in case of lost buffers). 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci if (i == CX18_ENC_STREAM_TYPE_YUV) { 5748c2ecf20Sopenharmony_ci cx->stream_buf_size[i] *= 1024; 5758c2ecf20Sopenharmony_ci cx->stream_buf_size[i] -= 5768c2ecf20Sopenharmony_ci (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) 5798c2ecf20Sopenharmony_ci cx->stream_buf_size[i] = 5808c2ecf20Sopenharmony_ci CX18_UNIT_ENC_YUV_BUFSIZE; 5818c2ecf20Sopenharmony_ci } else if (i == CX18_ENC_STREAM_TYPE_IDX) { 5828c2ecf20Sopenharmony_ci cx->stream_buf_size[i] *= 1024; 5838c2ecf20Sopenharmony_ci cx->stream_buf_size[i] -= 5848c2ecf20Sopenharmony_ci (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE) 5878c2ecf20Sopenharmony_ci cx->stream_buf_size[i] = 5888c2ecf20Sopenharmony_ci CX18_UNIT_ENC_IDX_BUFSIZE; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci /* 5918c2ecf20Sopenharmony_ci * YUV and IDX are special cases where the stream_buf_size is 5928c2ecf20Sopenharmony_ci * now in bytes. 5938c2ecf20Sopenharmony_ci * VBI is a special case where the stream_buf_size is fixed 5948c2ecf20Sopenharmony_ci * and already in bytes 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci if (i == CX18_ENC_STREAM_TYPE_VBI || 5978c2ecf20Sopenharmony_ci i == CX18_ENC_STREAM_TYPE_YUV || 5988c2ecf20Sopenharmony_ci i == CX18_ENC_STREAM_TYPE_IDX) { 5998c2ecf20Sopenharmony_ci if (cx->stream_buffers[i] < 0) { 6008c2ecf20Sopenharmony_ci cx->stream_buffers[i] = 6018c2ecf20Sopenharmony_ci cx->options.megabytes[i] * 1024 * 1024 6028c2ecf20Sopenharmony_ci / cx->stream_buf_size[i]; 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci /* N.B. This might round down to 0 */ 6058c2ecf20Sopenharmony_ci cx->options.megabytes[i] = 6068c2ecf20Sopenharmony_ci cx->stream_buffers[i] 6078c2ecf20Sopenharmony_ci * cx->stream_buf_size[i]/(1024 * 1024); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci } else { 6108c2ecf20Sopenharmony_ci /* All other streams have stream_buf_size in kB here */ 6118c2ecf20Sopenharmony_ci if (cx->stream_buffers[i] < 0) { 6128c2ecf20Sopenharmony_ci cx->stream_buffers[i] = 6138c2ecf20Sopenharmony_ci cx->options.megabytes[i] * 1024 6148c2ecf20Sopenharmony_ci / cx->stream_buf_size[i]; 6158c2ecf20Sopenharmony_ci } else { 6168c2ecf20Sopenharmony_ci /* N.B. This might round down to 0 */ 6178c2ecf20Sopenharmony_ci cx->options.megabytes[i] = 6188c2ecf20Sopenharmony_ci cx->stream_buffers[i] 6198c2ecf20Sopenharmony_ci * cx->stream_buf_size[i] / 1024; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci /* convert from kB to bytes */ 6228c2ecf20Sopenharmony_ci cx->stream_buf_size[i] *= 1024; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, %d bytes\n", 6258c2ecf20Sopenharmony_ci i, cx->options.megabytes[i], 6268c2ecf20Sopenharmony_ci cx->stream_buffers[i], cx->stream_buf_size[i]); 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci cx->options.cardtype = cardtype[cx->instance]; 6308c2ecf20Sopenharmony_ci cx->options.tuner = tuner[cx->instance]; 6318c2ecf20Sopenharmony_ci cx->options.radio = radio[cx->instance]; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci cx->std = cx18_parse_std(cx); 6348c2ecf20Sopenharmony_ci if (cx->options.cardtype == -1) { 6358c2ecf20Sopenharmony_ci CX18_INFO("Ignore card\n"); 6368c2ecf20Sopenharmony_ci return; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci cx->card = cx18_get_card(cx->options.cardtype - 1); 6398c2ecf20Sopenharmony_ci if (cx->card) 6408c2ecf20Sopenharmony_ci CX18_INFO("User specified %s card\n", cx->card->name); 6418c2ecf20Sopenharmony_ci else if (cx->options.cardtype != 0) 6428c2ecf20Sopenharmony_ci CX18_ERR("Unknown user specified type, trying to autodetect card\n"); 6438c2ecf20Sopenharmony_ci if (!cx->card) { 6448c2ecf20Sopenharmony_ci if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { 6458c2ecf20Sopenharmony_ci cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); 6468c2ecf20Sopenharmony_ci CX18_INFO("Autodetected Hauppauge card\n"); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci if (!cx->card) { 6508c2ecf20Sopenharmony_ci for (i = 0; (cx->card = cx18_get_card(i)); i++) { 6518c2ecf20Sopenharmony_ci if (!cx->card->pci_list) 6528c2ecf20Sopenharmony_ci continue; 6538c2ecf20Sopenharmony_ci for (j = 0; cx->card->pci_list[j].device; j++) { 6548c2ecf20Sopenharmony_ci if (cx->pci_dev->device != 6558c2ecf20Sopenharmony_ci cx->card->pci_list[j].device) 6568c2ecf20Sopenharmony_ci continue; 6578c2ecf20Sopenharmony_ci if (cx->pci_dev->subsystem_vendor != 6588c2ecf20Sopenharmony_ci cx->card->pci_list[j].subsystem_vendor) 6598c2ecf20Sopenharmony_ci continue; 6608c2ecf20Sopenharmony_ci if (cx->pci_dev->subsystem_device != 6618c2ecf20Sopenharmony_ci cx->card->pci_list[j].subsystem_device) 6628c2ecf20Sopenharmony_ci continue; 6638c2ecf20Sopenharmony_ci CX18_INFO("Autodetected %s card\n", cx->card->name); 6648c2ecf20Sopenharmony_ci goto done; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_cidone: 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (!cx->card) { 6718c2ecf20Sopenharmony_ci cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); 6728c2ecf20Sopenharmony_ci CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", 6738c2ecf20Sopenharmony_ci cx->pci_dev->vendor, cx->pci_dev->device); 6748c2ecf20Sopenharmony_ci CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", 6758c2ecf20Sopenharmony_ci cx->pci_dev->subsystem_vendor, 6768c2ecf20Sopenharmony_ci cx->pci_dev->subsystem_device); 6778c2ecf20Sopenharmony_ci CX18_ERR("Defaulting to %s card\n", cx->card->name); 6788c2ecf20Sopenharmony_ci CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); 6798c2ecf20Sopenharmony_ci CX18_ERR("card you have to the linux-media mailinglist (www.linuxtv.org)\n"); 6808c2ecf20Sopenharmony_ci CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci cx->v4l2_cap = cx->card->v4l2_capabilities; 6838c2ecf20Sopenharmony_ci cx->card_name = cx->card->name; 6848c2ecf20Sopenharmony_ci cx->card_i2c = cx->card->i2c; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int cx18_create_in_workq(struct cx18 *cx) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", 6908c2ecf20Sopenharmony_ci cx->v4l2_dev.name); 6918c2ecf20Sopenharmony_ci cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name); 6928c2ecf20Sopenharmony_ci if (!cx->in_work_queue) { 6938c2ecf20Sopenharmony_ci CX18_ERR("Unable to create incoming mailbox handler thread\n"); 6948c2ecf20Sopenharmony_ci return -ENOMEM; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci return 0; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void cx18_init_in_work_orders(struct cx18 *cx) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci int i; 7028c2ecf20Sopenharmony_ci for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { 7038c2ecf20Sopenharmony_ci cx->in_work_order[i].cx = cx; 7048c2ecf20Sopenharmony_ci cx->in_work_order[i].str = cx->epu_debug_str; 7058c2ecf20Sopenharmony_ci INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci/* Precondition: the cx18 structure has been memset to 0. Only 7108c2ecf20Sopenharmony_ci the dev and instance fields have been filled in. 7118c2ecf20Sopenharmony_ci No assumptions on the card type may be made here (see cx18_init_struct2 7128c2ecf20Sopenharmony_ci for that). 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_cistatic int cx18_init_struct1(struct cx18 *cx) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci int ret; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci cx->base_addr = pci_resource_start(cx->pci_dev, 0); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci mutex_init(&cx->serialize_lock); 7218c2ecf20Sopenharmony_ci mutex_init(&cx->gpio_lock); 7228c2ecf20Sopenharmony_ci mutex_init(&cx->epu2apu_mb_lock); 7238c2ecf20Sopenharmony_ci mutex_init(&cx->epu2cpu_mb_lock); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ret = cx18_create_in_workq(cx); 7268c2ecf20Sopenharmony_ci if (ret) 7278c2ecf20Sopenharmony_ci return ret; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci cx18_init_in_work_orders(cx); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* start counting open_id at 1 */ 7328c2ecf20Sopenharmony_ci cx->open_id = 1; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Initial settings */ 7358c2ecf20Sopenharmony_ci cx->cxhdl.port = CX2341X_PORT_MEMORY; 7368c2ecf20Sopenharmony_ci cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; 7378c2ecf20Sopenharmony_ci cx->cxhdl.ops = &cx18_cxhdl_ops; 7388c2ecf20Sopenharmony_ci cx->cxhdl.func = cx18_api_func; 7398c2ecf20Sopenharmony_ci cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; 7408c2ecf20Sopenharmony_ci ret = cx2341x_handler_init(&cx->cxhdl, 50); 7418c2ecf20Sopenharmony_ci if (ret) 7428c2ecf20Sopenharmony_ci return ret; 7438c2ecf20Sopenharmony_ci cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; 7468c2ecf20Sopenharmony_ci cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; 7478c2ecf20Sopenharmony_ci cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | 7488c2ecf20Sopenharmony_ci (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | 7498c2ecf20Sopenharmony_ci (cx->cxhdl.video_median_filter_type->cur.val << 2); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci init_waitqueue_head(&cx->cap_w); 7528c2ecf20Sopenharmony_ci init_waitqueue_head(&cx->mb_apu_waitq); 7538c2ecf20Sopenharmony_ci init_waitqueue_head(&cx->mb_cpu_waitq); 7548c2ecf20Sopenharmony_ci init_waitqueue_head(&cx->dma_waitq); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* VBI */ 7578c2ecf20Sopenharmony_ci cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; 7588c2ecf20Sopenharmony_ci cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* IVTV style VBI insertion into MPEG streams */ 7618c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); 7628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); 7638c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); 7648c2ecf20Sopenharmony_ci list_add(&cx->vbi.sliced_mpeg_buf.list, 7658c2ecf20Sopenharmony_ci &cx->vbi.sliced_mpeg_mdl.buf_list); 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/* Second initialization part. Here the card type has been 7708c2ecf20Sopenharmony_ci autodetected. */ 7718c2ecf20Sopenharmony_cistatic void cx18_init_struct2(struct cx18 *cx) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci int i; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS - 1; i++) 7768c2ecf20Sopenharmony_ci if (cx->card->video_inputs[i].video_type == 0) 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci cx->nof_inputs = i; 7798c2ecf20Sopenharmony_ci for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS - 1; i++) 7808c2ecf20Sopenharmony_ci if (cx->card->audio_inputs[i].audio_type == 0) 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci cx->nof_audio_inputs = i; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Find tuner input */ 7858c2ecf20Sopenharmony_ci for (i = 0; i < cx->nof_inputs; i++) { 7868c2ecf20Sopenharmony_ci if (cx->card->video_inputs[i].video_type == 7878c2ecf20Sopenharmony_ci CX18_CARD_INPUT_VID_TUNER) 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci if (i == cx->nof_inputs) 7918c2ecf20Sopenharmony_ci i = 0; 7928c2ecf20Sopenharmony_ci cx->active_input = i; 7938c2ecf20Sopenharmony_ci cx->audio_input = cx->card->video_inputs[i].audio_index; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, 7978c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci u16 cmd; 8008c2ecf20Sopenharmony_ci unsigned char pci_latency; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("Enabling pci device\n"); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (pci_enable_device(pci_dev)) { 8058c2ecf20Sopenharmony_ci CX18_ERR("Can't enable device %d!\n", cx->instance); 8068c2ecf20Sopenharmony_ci return -EIO; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { 8098c2ecf20Sopenharmony_ci CX18_ERR("No suitable DMA available, card %d\n", cx->instance); 8108c2ecf20Sopenharmony_ci return -EIO; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { 8138c2ecf20Sopenharmony_ci CX18_ERR("Cannot request encoder memory region, card %d\n", 8148c2ecf20Sopenharmony_ci cx->instance); 8158c2ecf20Sopenharmony_ci return -EIO; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* Enable bus mastering and memory mapped IO for the CX23418 */ 8198c2ecf20Sopenharmony_ci pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); 8208c2ecf20Sopenharmony_ci cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; 8218c2ecf20Sopenharmony_ci pci_write_config_word(pci_dev, PCI_COMMAND, cmd); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci cx->card_rev = pci_dev->revision; 8248c2ecf20Sopenharmony_ci pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (pci_latency < 64 && cx18_pci_latency) { 8278c2ecf20Sopenharmony_ci CX18_INFO("Unreasonably low latency timer, setting to 64 (was %d)\n", 8288c2ecf20Sopenharmony_ci pci_latency); 8298c2ecf20Sopenharmony_ci pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); 8308c2ecf20Sopenharmony_ci pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, irq: %d, latency: %d, memory: 0x%llx\n", 8348c2ecf20Sopenharmony_ci cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, 8358c2ecf20Sopenharmony_ci PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), 8368c2ecf20Sopenharmony_ci cx->pci_dev->irq, pci_latency, (u64)cx->base_addr); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic void cx18_init_subdevs(struct cx18 *cx) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci u32 hw = cx->card->hw_all; 8448c2ecf20Sopenharmony_ci u32 device; 8458c2ecf20Sopenharmony_ci int i; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = 0, device = 1; i < 32; i++, device <<= 1) { 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (!(device & hw)) 8508c2ecf20Sopenharmony_ci continue; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci switch (device) { 8538c2ecf20Sopenharmony_ci case CX18_HW_DVB: 8548c2ecf20Sopenharmony_ci case CX18_HW_TVEEPROM: 8558c2ecf20Sopenharmony_ci /* These subordinate devices do not use probing */ 8568c2ecf20Sopenharmony_ci cx->hw_flags |= device; 8578c2ecf20Sopenharmony_ci break; 8588c2ecf20Sopenharmony_ci case CX18_HW_418_AV: 8598c2ecf20Sopenharmony_ci /* The A/V decoder gets probed earlier to set PLLs */ 8608c2ecf20Sopenharmony_ci /* Just note that the card uses it (i.e. has analog) */ 8618c2ecf20Sopenharmony_ci cx->hw_flags |= device; 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci case CX18_HW_GPIO_RESET_CTRL: 8648c2ecf20Sopenharmony_ci /* 8658c2ecf20Sopenharmony_ci * The Reset Controller gets probed and added to 8668c2ecf20Sopenharmony_ci * hw_flags earlier for i2c adapter/bus initialization 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci case CX18_HW_GPIO_MUX: 8708c2ecf20Sopenharmony_ci if (cx18_gpio_register(cx, device) == 0) 8718c2ecf20Sopenharmony_ci cx->hw_flags |= device; 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci default: 8748c2ecf20Sopenharmony_ci if (cx18_i2c_register(cx, i) == 0) 8758c2ecf20Sopenharmony_ci cx->hw_flags |= device; 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (cx->hw_flags & CX18_HW_418_AV) 8818c2ecf20Sopenharmony_ci cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (cx->card->hw_muxer != 0) 8848c2ecf20Sopenharmony_ci cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int cx18_probe(struct pci_dev *pci_dev, 8888c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci int retval = 0; 8918c2ecf20Sopenharmony_ci int i; 8928c2ecf20Sopenharmony_ci u32 devtype; 8938c2ecf20Sopenharmony_ci struct cx18 *cx; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* FIXME - module parameter arrays constrain max instances */ 8968c2ecf20Sopenharmony_ci i = atomic_inc_return(&cx18_instance) - 1; 8978c2ecf20Sopenharmony_ci if (i >= CX18_MAX_CARDS) { 8988c2ecf20Sopenharmony_ci printk(KERN_ERR "cx18: cannot manage card %d, driver has a limit of 0 - %d\n", 8998c2ecf20Sopenharmony_ci i, CX18_MAX_CARDS - 1); 9008c2ecf20Sopenharmony_ci return -ENOMEM; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci cx = kzalloc(sizeof(*cx), GFP_ATOMIC); 9048c2ecf20Sopenharmony_ci if (!cx) 9058c2ecf20Sopenharmony_ci return -ENOMEM; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci cx->pci_dev = pci_dev; 9088c2ecf20Sopenharmony_ci cx->instance = i; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); 9118c2ecf20Sopenharmony_ci if (retval) { 9128c2ecf20Sopenharmony_ci printk(KERN_ERR "cx18: v4l2_device_register of card %d failed\n", 9138c2ecf20Sopenharmony_ci cx->instance); 9148c2ecf20Sopenharmony_ci kfree(cx); 9158c2ecf20Sopenharmony_ci return retval; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", 9188c2ecf20Sopenharmony_ci cx->instance); 9198c2ecf20Sopenharmony_ci CX18_INFO("Initializing card %d\n", cx->instance); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci cx18_process_options(cx); 9228c2ecf20Sopenharmony_ci if (cx->options.cardtype == -1) { 9238c2ecf20Sopenharmony_ci retval = -ENODEV; 9248c2ecf20Sopenharmony_ci goto err; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci retval = cx18_init_struct1(cx); 9288c2ecf20Sopenharmony_ci if (retval) 9298c2ecf20Sopenharmony_ci goto err; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* PCI Device Setup */ 9348c2ecf20Sopenharmony_ci retval = cx18_setup_pci(cx, pci_dev, pci_id); 9358c2ecf20Sopenharmony_ci if (retval != 0) 9368c2ecf20Sopenharmony_ci goto free_workqueues; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* map io memory */ 9398c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", 9408c2ecf20Sopenharmony_ci (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); 9418c2ecf20Sopenharmony_ci cx->enc_mem = ioremap(cx->base_addr + CX18_MEM_OFFSET, 9428c2ecf20Sopenharmony_ci CX18_MEM_SIZE); 9438c2ecf20Sopenharmony_ci if (!cx->enc_mem) { 9448c2ecf20Sopenharmony_ci CX18_ERR("ioremap failed. Can't get a window into CX23418 memory and register space\n"); 9458c2ecf20Sopenharmony_ci CX18_ERR("Each capture card with a CX23418 needs 64 MB of vmalloc address space for the window\n"); 9468c2ecf20Sopenharmony_ci CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); 9478c2ecf20Sopenharmony_ci CX18_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); 9488c2ecf20Sopenharmony_ci retval = -ENOMEM; 9498c2ecf20Sopenharmony_ci goto free_mem; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; 9528c2ecf20Sopenharmony_ci devtype = cx18_read_reg(cx, 0xC72028); 9538c2ecf20Sopenharmony_ci switch (devtype & 0xff000000) { 9548c2ecf20Sopenharmony_ci case 0xff000000: 9558c2ecf20Sopenharmony_ci CX18_INFO("cx23418 revision %08x (A)\n", devtype); 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci case 0x01000000: 9588c2ecf20Sopenharmony_ci CX18_INFO("cx23418 revision %08x (B)\n", devtype); 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci default: 9618c2ecf20Sopenharmony_ci CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci cx18_init_power(cx, 1); 9668c2ecf20Sopenharmony_ci cx18_init_memory(cx); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); 9698c2ecf20Sopenharmony_ci cx18_init_scb(cx); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci cx18_gpio_init(cx); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* Initialize integrated A/V decoder early to set PLLs, just in case */ 9748c2ecf20Sopenharmony_ci retval = cx18_av_probe(cx); 9758c2ecf20Sopenharmony_ci if (retval) { 9768c2ecf20Sopenharmony_ci CX18_ERR("Could not register A/V decoder subdevice\n"); 9778c2ecf20Sopenharmony_ci goto free_map; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Initialize GPIO Reset Controller to do chip resets during i2c init */ 9818c2ecf20Sopenharmony_ci if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { 9828c2ecf20Sopenharmony_ci if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) 9838c2ecf20Sopenharmony_ci CX18_WARN("Could not register GPIO reset controllersubdevice; proceeding anyway.\n"); 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* active i2c */ 9898c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("activating i2c...\n"); 9908c2ecf20Sopenharmony_ci retval = init_cx18_i2c(cx); 9918c2ecf20Sopenharmony_ci if (retval) { 9928c2ecf20Sopenharmony_ci CX18_ERR("Could not initialize i2c\n"); 9938c2ecf20Sopenharmony_ci goto free_map; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (cx->card->hw_all & CX18_HW_TVEEPROM) { 9978c2ecf20Sopenharmony_ci /* Based on the model number the cardtype may be changed. 9988c2ecf20Sopenharmony_ci The PCI IDs are not always reliable. */ 9998c2ecf20Sopenharmony_ci const struct cx18_card *orig_card = cx->card; 10008c2ecf20Sopenharmony_ci cx18_process_eeprom(cx); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (cx->card != orig_card) { 10038c2ecf20Sopenharmony_ci /* Changed the cardtype; re-reset the I2C chips */ 10048c2ecf20Sopenharmony_ci cx18_gpio_init(cx); 10058c2ecf20Sopenharmony_ci cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, 10068c2ecf20Sopenharmony_ci core, reset, (u32) CX18_GPIO_RESET_I2C); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci if (cx->card->comment) 10108c2ecf20Sopenharmony_ci CX18_INFO("%s", cx->card->comment); 10118c2ecf20Sopenharmony_ci if (cx->card->v4l2_capabilities == 0) { 10128c2ecf20Sopenharmony_ci retval = -ENODEV; 10138c2ecf20Sopenharmony_ci goto free_i2c; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci cx18_init_memory(cx); 10168c2ecf20Sopenharmony_ci cx18_init_scb(cx); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* Register IRQ */ 10198c2ecf20Sopenharmony_ci retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, 10208c2ecf20Sopenharmony_ci IRQF_SHARED, cx->v4l2_dev.name, (void *)cx); 10218c2ecf20Sopenharmony_ci if (retval) { 10228c2ecf20Sopenharmony_ci CX18_ERR("Failed to register irq %d\n", retval); 10238c2ecf20Sopenharmony_ci goto free_i2c; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (cx->std == 0) 10278c2ecf20Sopenharmony_ci cx->std = V4L2_STD_NTSC_M; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (cx->options.tuner == -1) { 10308c2ecf20Sopenharmony_ci for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { 10318c2ecf20Sopenharmony_ci if ((cx->std & cx->card->tuners[i].std) == 0) 10328c2ecf20Sopenharmony_ci continue; 10338c2ecf20Sopenharmony_ci cx->options.tuner = cx->card->tuners[i].tuner; 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci /* if no tuner was found, then pick the first tuner in the card list */ 10388c2ecf20Sopenharmony_ci if (cx->options.tuner == -1 && cx->card->tuners[0].std) { 10398c2ecf20Sopenharmony_ci cx->std = cx->card->tuners[0].std; 10408c2ecf20Sopenharmony_ci if (cx->std & V4L2_STD_PAL) 10418c2ecf20Sopenharmony_ci cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; 10428c2ecf20Sopenharmony_ci else if (cx->std & V4L2_STD_NTSC) 10438c2ecf20Sopenharmony_ci cx->std = V4L2_STD_NTSC_M; 10448c2ecf20Sopenharmony_ci else if (cx->std & V4L2_STD_SECAM) 10458c2ecf20Sopenharmony_ci cx->std = V4L2_STD_SECAM_L; 10468c2ecf20Sopenharmony_ci cx->options.tuner = cx->card->tuners[0].tuner; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci if (cx->options.radio == -1) 10498c2ecf20Sopenharmony_ci cx->options.radio = (cx->card->radio_input.audio_type != 0); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* The card is now fully identified, continue with card-specific 10528c2ecf20Sopenharmony_ci initialization. */ 10538c2ecf20Sopenharmony_ci cx18_init_struct2(cx); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci cx18_init_subdevs(cx); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (cx->std & V4L2_STD_525_60) 10588c2ecf20Sopenharmony_ci cx->is_60hz = 1; 10598c2ecf20Sopenharmony_ci else 10608c2ecf20Sopenharmony_ci cx->is_50hz = 1; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (cx->options.radio > 0) 10658c2ecf20Sopenharmony_ci cx->v4l2_cap |= V4L2_CAP_RADIO; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (cx->options.tuner > -1) { 10688c2ecf20Sopenharmony_ci struct tuner_setup setup; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci setup.addr = ADDR_UNSET; 10718c2ecf20Sopenharmony_ci setup.type = cx->options.tuner; 10728c2ecf20Sopenharmony_ci setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ 10738c2ecf20Sopenharmony_ci setup.config = NULL; 10748c2ecf20Sopenharmony_ci if (cx->options.radio > 0) 10758c2ecf20Sopenharmony_ci setup.mode_mask |= T_RADIO; 10768c2ecf20Sopenharmony_ci setup.tuner_callback = (setup.type == TUNER_XC2028) ? 10778c2ecf20Sopenharmony_ci cx18_reset_tuner_gpio : NULL; 10788c2ecf20Sopenharmony_ci cx18_call_all(cx, tuner, s_type_addr, &setup); 10798c2ecf20Sopenharmony_ci if (setup.type == TUNER_XC2028) { 10808c2ecf20Sopenharmony_ci static struct xc2028_ctrl ctrl = { 10818c2ecf20Sopenharmony_ci .fname = XC2028_DEFAULT_FIRMWARE, 10828c2ecf20Sopenharmony_ci .max_len = 64, 10838c2ecf20Sopenharmony_ci }; 10848c2ecf20Sopenharmony_ci struct v4l2_priv_tun_config cfg = { 10858c2ecf20Sopenharmony_ci .tuner = cx->options.tuner, 10868c2ecf20Sopenharmony_ci .priv = &ctrl, 10878c2ecf20Sopenharmony_ci }; 10888c2ecf20Sopenharmony_ci cx18_call_all(cx, tuner, s_config, &cfg); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) 10938c2ecf20Sopenharmony_ci are not. */ 10948c2ecf20Sopenharmony_ci cx->tuner_std = cx->std; 10958c2ecf20Sopenharmony_ci if (cx->std == V4L2_STD_ALL) 10968c2ecf20Sopenharmony_ci cx->std = V4L2_STD_NTSC_M; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci retval = cx18_streams_setup(cx); 10998c2ecf20Sopenharmony_ci if (retval) { 11008c2ecf20Sopenharmony_ci CX18_ERR("Error %d setting up streams\n", retval); 11018c2ecf20Sopenharmony_ci goto free_irq; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci retval = cx18_streams_register(cx); 11048c2ecf20Sopenharmony_ci if (retval) { 11058c2ecf20Sopenharmony_ci CX18_ERR("Error %d registering devices\n", retval); 11068c2ecf20Sopenharmony_ci goto free_streams; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci CX18_INFO("Initialized card: %s\n", cx->card_name); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Load cx18 submodules (cx18-alsa) */ 11128c2ecf20Sopenharmony_ci request_modules(cx); 11138c2ecf20Sopenharmony_ci return 0; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cifree_streams: 11168c2ecf20Sopenharmony_ci cx18_streams_cleanup(cx, 1); 11178c2ecf20Sopenharmony_cifree_irq: 11188c2ecf20Sopenharmony_ci free_irq(cx->pci_dev->irq, (void *)cx); 11198c2ecf20Sopenharmony_cifree_i2c: 11208c2ecf20Sopenharmony_ci exit_cx18_i2c(cx); 11218c2ecf20Sopenharmony_cifree_map: 11228c2ecf20Sopenharmony_ci cx18_iounmap(cx); 11238c2ecf20Sopenharmony_cifree_mem: 11248c2ecf20Sopenharmony_ci release_mem_region(cx->base_addr, CX18_MEM_SIZE); 11258c2ecf20Sopenharmony_cifree_workqueues: 11268c2ecf20Sopenharmony_ci destroy_workqueue(cx->in_work_queue); 11278c2ecf20Sopenharmony_cierr: 11288c2ecf20Sopenharmony_ci CX18_ERR("Error %d on initialization\n", retval); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci v4l2_device_unregister(&cx->v4l2_dev); 11318c2ecf20Sopenharmony_ci kfree(cx); 11328c2ecf20Sopenharmony_ci return retval; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciint cx18_init_on_first_open(struct cx18 *cx) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci int video_input; 11388c2ecf20Sopenharmony_ci int fw_retry_count = 3; 11398c2ecf20Sopenharmony_ci struct v4l2_frequency vf; 11408c2ecf20Sopenharmony_ci struct cx18_open_id fh; 11418c2ecf20Sopenharmony_ci v4l2_std_id std; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci fh.cx = cx; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) 11468c2ecf20Sopenharmony_ci return -ENXIO; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) 11498c2ecf20Sopenharmony_ci return 0; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci while (--fw_retry_count > 0) { 11528c2ecf20Sopenharmony_ci /* load firmware */ 11538c2ecf20Sopenharmony_ci if (cx18_firmware_init(cx) == 0) 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci if (fw_retry_count > 1) 11568c2ecf20Sopenharmony_ci CX18_WARN("Retry loading firmware\n"); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (fw_retry_count == 0) { 11608c2ecf20Sopenharmony_ci set_bit(CX18_F_I_FAILED, &cx->i_flags); 11618c2ecf20Sopenharmony_ci return -ENXIO; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* 11668c2ecf20Sopenharmony_ci * Init the firmware twice to work around a silicon bug 11678c2ecf20Sopenharmony_ci * with the digital TS. 11688c2ecf20Sopenharmony_ci * 11698c2ecf20Sopenharmony_ci * The second firmware load requires us to normalize the APU state, 11708c2ecf20Sopenharmony_ci * or the audio for the first analog capture will be badly incorrect. 11718c2ecf20Sopenharmony_ci * 11728c2ecf20Sopenharmony_ci * I can't seem to call APU_RESETAI and have it succeed without the 11738c2ecf20Sopenharmony_ci * APU capturing audio, so we start and stop it here to do the reset 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ 11778c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); 11788c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_RESETAI, 0); 11798c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci fw_retry_count = 3; 11828c2ecf20Sopenharmony_ci while (--fw_retry_count > 0) { 11838c2ecf20Sopenharmony_ci /* load firmware */ 11848c2ecf20Sopenharmony_ci if (cx18_firmware_init(cx) == 0) 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci if (fw_retry_count > 1) 11878c2ecf20Sopenharmony_ci CX18_WARN("Retry loading firmware\n"); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (fw_retry_count == 0) { 11918c2ecf20Sopenharmony_ci set_bit(CX18_F_I_FAILED, &cx->i_flags); 11928c2ecf20Sopenharmony_ci return -ENXIO; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* 11968c2ecf20Sopenharmony_ci * The second firmware load requires us to normalize the APU state, 11978c2ecf20Sopenharmony_ci * or the audio for the first analog capture will be badly incorrect. 11988c2ecf20Sopenharmony_ci * 11998c2ecf20Sopenharmony_ci * I can't seem to call APU_RESETAI and have it succeed without the 12008c2ecf20Sopenharmony_ci * APU capturing audio, so we start and stop it here to do the reset 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ 12048c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); 12058c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_RESETAI, 0); 12068c2ecf20Sopenharmony_ci cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* Init the A/V decoder, if it hasn't been already */ 12098c2ecf20Sopenharmony_ci v4l2_subdev_call(cx->sd_av, core, load_fw); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci vf.tuner = 0; 12128c2ecf20Sopenharmony_ci vf.type = V4L2_TUNER_ANALOG_TV; 12138c2ecf20Sopenharmony_ci vf.frequency = 6400; /* the tuner 'baseline' frequency */ 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* Set initial frequency. For PAL/SECAM broadcasts no 12168c2ecf20Sopenharmony_ci 'default' channel exists AFAIK. */ 12178c2ecf20Sopenharmony_ci if (cx->std == V4L2_STD_NTSC_M_JP) 12188c2ecf20Sopenharmony_ci vf.frequency = 1460; /* ch. 1 91250*16/1000 */ 12198c2ecf20Sopenharmony_ci else if (cx->std & V4L2_STD_NTSC_M) 12208c2ecf20Sopenharmony_ci vf.frequency = 1076; /* ch. 4 67250*16/1000 */ 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci video_input = cx->active_input; 12238c2ecf20Sopenharmony_ci cx->active_input++; /* Force update of input */ 12248c2ecf20Sopenharmony_ci cx18_s_input(NULL, &fh, video_input); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code 12278c2ecf20Sopenharmony_ci in one place. */ 12288c2ecf20Sopenharmony_ci cx->std++; /* Force full standard initialization */ 12298c2ecf20Sopenharmony_ci std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; 12308c2ecf20Sopenharmony_ci cx18_s_std(NULL, &fh, std); 12318c2ecf20Sopenharmony_ci cx18_s_frequency(NULL, &fh, &vf); 12328c2ecf20Sopenharmony_ci return 0; 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic void cx18_cancel_in_work_orders(struct cx18 *cx) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci int i; 12388c2ecf20Sopenharmony_ci for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) 12398c2ecf20Sopenharmony_ci cancel_work_sync(&cx->in_work_order[i].work); 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic void cx18_cancel_out_work_orders(struct cx18 *cx) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci int i; 12458c2ecf20Sopenharmony_ci for (i = 0; i < CX18_MAX_STREAMS; i++) 12468c2ecf20Sopenharmony_ci if (cx->streams[i].video_dev.v4l2_dev) 12478c2ecf20Sopenharmony_ci cancel_work_sync(&cx->streams[i].out_work_order); 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic void cx18_remove(struct pci_dev *pci_dev) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); 12538c2ecf20Sopenharmony_ci struct cx18 *cx = to_cx18(v4l2_dev); 12548c2ecf20Sopenharmony_ci int i; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("Removing Card\n"); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci flush_request_modules(cx); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* Stop all captures */ 12618c2ecf20Sopenharmony_ci CX18_DEBUG_INFO("Stopping all streams\n"); 12628c2ecf20Sopenharmony_ci if (atomic_read(&cx->tot_capturing) > 0) 12638c2ecf20Sopenharmony_ci cx18_stop_all_captures(cx); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* Stop interrupts that cause incoming work to be queued */ 12668c2ecf20Sopenharmony_ci cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Incoming work can cause outgoing work, so clean up incoming first */ 12698c2ecf20Sopenharmony_ci cx18_cancel_in_work_orders(cx); 12708c2ecf20Sopenharmony_ci cx18_cancel_out_work_orders(cx); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* Stop ack interrupts that may have been needed for work to finish */ 12738c2ecf20Sopenharmony_ci cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci cx18_halt_firmware(cx); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci destroy_workqueue(cx->in_work_queue); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci cx18_streams_cleanup(cx, 1); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci exit_cx18_i2c(cx); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci free_irq(cx->pci_dev->irq, (void *)cx); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci cx18_iounmap(cx); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci release_mem_region(cx->base_addr, CX18_MEM_SIZE); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci pci_disable_device(cx->pci_dev); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (cx->vbi.sliced_mpeg_data[0]) 12928c2ecf20Sopenharmony_ci for (i = 0; i < CX18_VBI_FRAMES; i++) 12938c2ecf20Sopenharmony_ci kfree(cx->vbi.sliced_mpeg_data[i]); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&cx->av_state.hdl); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci CX18_INFO("Removed %s\n", cx->card_name); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci v4l2_device_unregister(v4l2_dev); 13008c2ecf20Sopenharmony_ci kfree(cx); 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci/* define a pci_driver for card detection */ 13058c2ecf20Sopenharmony_cistatic struct pci_driver cx18_pci_driver = { 13068c2ecf20Sopenharmony_ci .name = "cx18", 13078c2ecf20Sopenharmony_ci .id_table = cx18_pci_tbl, 13088c2ecf20Sopenharmony_ci .probe = cx18_probe, 13098c2ecf20Sopenharmony_ci .remove = cx18_remove, 13108c2ecf20Sopenharmony_ci}; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic int __init module_start(void) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci printk(KERN_INFO "cx18: Start initialization, version %s\n", 13158c2ecf20Sopenharmony_ci CX18_VERSION); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* Validate parameters */ 13188c2ecf20Sopenharmony_ci if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { 13198c2ecf20Sopenharmony_ci printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n", 13208c2ecf20Sopenharmony_ci CX18_MAX_CARDS - 1); 13218c2ecf20Sopenharmony_ci return -1; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (cx18_debug < 0 || cx18_debug > 511) { 13258c2ecf20Sopenharmony_ci cx18_debug = 0; 13268c2ecf20Sopenharmony_ci printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (pci_register_driver(&cx18_pci_driver)) { 13308c2ecf20Sopenharmony_ci printk(KERN_ERR "cx18: Error detecting PCI card\n"); 13318c2ecf20Sopenharmony_ci return -ENODEV; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci printk(KERN_INFO "cx18: End initialization\n"); 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic void __exit module_cleanup(void) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci pci_unregister_driver(&cx18_pci_driver); 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cimodule_init(module_start); 13438c2ecf20Sopenharmony_cimodule_exit(module_cleanup); 13448c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); 1345