├── .gitignore ├── CXADC-Compression-Scripts └── Windows │ ├── CXADC_14.3msps_to_FLAC.bat │ ├── CXADC_17.8msps_to_FLAC.bat │ ├── CXADC_20msps_to_FLAC.bat │ ├── CXADC_28.6msps_to_FLAC.bat │ ├── CXADC_40msps_to_FLAC.bat │ └── Flac-Windows-Install.md ├── Kbuild ├── Makefile ├── README.md ├── Tips-&-Notes.md ├── cx88-reg.h ├── cxadc.c ├── cxadc.conf ├── cxadc.rules ├── cxadcnc.service ├── dkms.conf ├── leveladj.c └── utils ├── README.md ├── cx10fsc ├── cx16bit ├── cx6off ├── cx6on ├── cx8bit ├── cx8fsc ├── cxfreq ├── cxlevel ├── cxlvlcavdd ├── cxvalues ├── cxvx0 ├── cxvx1 ├── cxvx2 └── inst_scripts /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.cmd 3 | *.o 4 | *.ko 5 | *.mod 6 | *.mod.c 7 | modules.order 8 | Module.symvers 9 | built-in.a 10 | .vscode/ 11 | .directory 12 | leveladj 13 | -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/CXADC_14.3msps_to_FLAC.bat: -------------------------------------------------------------------------------- 1 | :: Create FLAC file from an stock CX Card 14.3msps (10-bit) 16-bit sample capture .u16 file. 2 | pushd %~dp0 3 | echo Encoding Unsinged 16-bit to FLAC Compressed ... 4 | flac.exe -f "%~1" --threads 64 --best --sample-rate=14318 --sign=unsigned --channels=1 --endian=little --bps=16 "%~n1.flac" 5 | echo Done. 6 | PAUSE -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/CXADC_17.8msps_to_FLAC.bat: -------------------------------------------------------------------------------- 1 | :: Create FLAC file from an stock CX Card 17.8msps (10-bit) 16-bit sample capture .u16 file. 2 | pushd %~dp0 3 | echo Encoding Unsinged 16-bit to FLAC Compressed ... 4 | flac.exe -f "%~1" --threads 64 --best --sample-rate=17898 --sign=unsigned --channels=1 --endian=little --bps=16 "%~n1.flac" 5 | echo Done. 6 | PAUSE -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/CXADC_20msps_to_FLAC.bat: -------------------------------------------------------------------------------- 1 | :: Create FLAC file from an Modified CX Card 20msps (10-bit) 16-bit sample capture .u16 file. 2 | pushd %~dp0 3 | echo Encoding Unsinged 16-bit to FLAC Compressed ... 4 | flac.exe -f "%~1" --threads 64 --best --sample-rate=20000 --sign=unsigned --channels=1 --endian=little --bps=16 "%~n1.flac" 5 | echo Done. 6 | PAUSE -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/CXADC_28.6msps_to_FLAC.bat: -------------------------------------------------------------------------------- 1 | :: Create FLAC file from an stock CX Card 28.6msps 8-bit capture .u8 file. 2 | pushd %~dp0 3 | echo Encoding Unsinged 8-bit to FLAC Compressed ... 4 | flac.exe -f "%~1" --threads 64 --best --sample-rate=28636 --sign=unsigned --channels=1 --endian=little --bps=8 "%~n1.flac" 5 | echo Done. 6 | PAUSE -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/CXADC_40msps_to_FLAC.bat: -------------------------------------------------------------------------------- 1 | :: Create FLAC file from an modifyed 40msps CX Card 8-bit .u8 file. 2 | pushd %~dp0 3 | echo Encoding Unsinged 8-bit to FLAC Compressed ... 4 | flac.exe -f "%~1" --threads 64 --best --sample-rate=40000 --sign=unsigned --channels=1 --endian=little --bps=8 "%~n1.flac" 5 | echo Done. 6 | PAUSE -------------------------------------------------------------------------------- /CXADC-Compression-Scripts/Windows/Flac-Windows-Install.md: -------------------------------------------------------------------------------- 1 | ## Install FFmpeg/SoX/FLAC inside windows 2 | 3 | These commands will install these in `PATH` so the tools are available system-wide. 4 | 5 | Open a PowerShell Terminal as administrator. 6 | 7 | Install Choco (chocolatey package manager) 8 | 9 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) 10 | 11 | Then you can install the following system-wide without any hassle. 12 | 13 | Install FFmpeg 14 | 15 | choco install ffmpeg 16 | 17 | Install FLAC 18 | 19 | choco install flac 20 | 21 | Install SoX 22 | 23 | choco install sox.portable 24 | 25 | 26 | ## Manually Build FLAC 27 | 28 | 29 | For Windows users replace the x86 binary parts from the current [release builds](https://github.com/xiph/flac/releases/tag/1.5.0). 30 | 31 | For Ubuntu/Mint users this should get you sorted as the current packages use an older build. 32 | 33 | For MacOS users it should be available on Brew soon. 34 | 35 | 36 | ### Installation and Build Steps 37 | 38 | 1. **Remove Existing FLAC Installation**: 39 | 40 | ``` 41 | sudo apt-get remove flac libflac-dev 42 | ``` 43 | 44 | 2. **Clone the FLAC Repository**: 45 | 46 | ``` 47 | git clone https://github.com/xiph/flac.git 48 | cd flac 49 | git checkout tags/1.5.0 -b 1.5.0 50 | ``` 51 | 52 | 3. **Install Required Dependencies**: 53 | 54 | ``` 55 | sudo apt-get install build-essential autoconf automake libtool pkg-config cmake curl pandoc graphviz 56 | ``` 57 | 58 | 4. **Create a Build Directory**: 59 | 60 | ``` 61 | mkdir build 62 | cd build 63 | ``` 64 | 65 | 5. **Configure the Build with `cmake`**: 66 | 67 | - If you want to include man pages: 68 | ``` 69 | cmake .. 70 | ``` 71 | - If you want to build without man pages: 72 | ``` 73 | cmake -DINSTALL_MANPAGES=OFF .. 74 | ``` 75 | 76 | 6. **Compile the Code**: 77 | 78 | ``` 79 | make 80 | ``` 81 | 82 | 7. **Install FLAC**: 83 | 84 | ``` 85 | sudo make install 86 | ``` -------------------------------------------------------------------------------- /Kbuild: -------------------------------------------------------------------------------- 1 | obj-m := cxadc.o 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CONFIG_MODULE_SIG=n 2 | KDIR ?= /lib/modules/`uname -r`/build 3 | 4 | default: 5 | $(MAKE) -C $(KDIR) M=$$PWD 6 | cc leveladj.c -o leveladj 7 | 8 | %: 9 | $(MAKE) -C $(KDIR) M=$$PWD $@ 10 | 11 | clean: 12 | $(MAKE) -C $(KDIR) M=$$PWD clean 13 | rm -f leveladj 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CXADC (CX - Analogue-Digital Converter) 2 | 3 | 4 | cxadc is an alternative Linux driver for the Conexant CX2388x series of video decoder/encoder chips used on many PCI TV tuner and capture cards. 5 | 6 | The new driver configures the CX2388x to capture in its raw output mode in 8-bit or 16-bit unsigned samples from the video input ports, allowing these cards to be used as a low-cost 28-54mhz 10bit ADC for SDR and similar applications. 7 | 8 | > [!NOTE] 9 | > `CX23885-xx` & `CX23888-xx` are incompatible chips, however the `CX25800` is a compatible chip. 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Today the cheap PCIe (with 1x bridge chip) capture card market uses these chips at 16-35USD prices per card, directly from China. 18 | 19 | The regular cx88 driver in Linux provides support for capturing composite 20 | video, digital video, audio and the other normal features of these chips. 21 | 22 | > [!WARNING] 23 | > You shouldn't load both drivers at the same time. 24 | 25 | 26 | # Wiki 27 | 28 | 29 | There is now a [wiki](https://github.com/happycube/cxadc-linux3/wiki) about the cards variants and helpful information on modifications cabling and amplification. 30 | 31 | 32 | ## Where to find current PCIe 1x CX2388x cards & notes: 33 | 34 | 35 | 36 | Links to buy a CX Card: 37 | 38 | - Current CX White CX25800 Card Order Links [Link 1](https://s.click.aliexpress.com/e/_olUXYFh) / [Link 2](https://s.click.aliexpress.com/e/_DBBRKPR) / [Link 3](https://s.click.aliexpress.com/e/_Dkhwebf) (16~30 USD) (Recommended as it has the better CX25800 IC) 39 | - [Blue Variant](https://s.click.aliexpress.com/e/_DFDQaJh) 40 | 41 | **Note 00:** While `Mhz` is used and is accurate due to the crystal used, in reality, it should be called `MSPS` (million samples per second) as the actual effective sampled is half the Mhz number of the defined crystal/clock rate. 42 | 43 | **Note 01:** The CX chip variant with the least self-noise is the CX25800, mostly found on the White Variation card; most clean captures are at 6dB off, and Digital Gain at 0-10 with external amplification and or proper impedance matching. 44 | 45 | **Note 02:** For reliable 40mhz 8-bit & 20mhz 16-bit samples, it is recommended to replace the stock crystal with a `ABLS2-40.000MHZ-D4YF-T` or equivalent fundamental crystal. 46 | 47 | [For the full list of working crystal replacements, check the wiki page here!](https://github.com/happycube/cxadc-linux3/wiki/Crystal-Upgrades) 48 | 49 | **Note 03:** Asmedia PCI to PCIe 1x bridge chips may have support issues on some older PCH chipsets based on Intel 3rd gen; for example, white cards use ITE chips which might not have said issue. 50 | 51 | **Note 04:** Added cooling can provide additional stability, more so with 40-54mhz crystal mods, but within 10° Celsius of room temperature is always preferable for silicone hardware. Currently, only 40-54mhz crystal mods have been broadly viable in testing for current white PCIe cards. 52 | 53 | **Note 05:** For crystals over 54mhz: it might be possible to use higher crystals with self-temperature regulated isolated chamber models, but this is still to have proper testing. 54 | 55 | **Note 06:** While the term Mhz is used and is hardware accurate, to be clear with Nyquist sampling the crystal frequency should be noted as the MSPS or million samples per second rating, the number is always halved to equal its effective bandwidth of whatever its sampling i.e 28mhz is 28msps with 14mhz of bandwidth and so on you want a 2:1 ratio or higher of whatever your capturing to correctly sample it. 56 | 57 | **Note 07:** When using lower-end older systems (Pentium 4 and before era), if there are not enough system resources, you may have dropped samples, this also applies to any use of SoX or FLAC in real-time. 58 | 59 | 60 | # Getting Started & Installation 61 | 62 | 63 | ## Install Dependencies 64 | 65 | 66 | 67 | 68 |
69 | Ubuntu 22.04 70 |
71 | 72 | Update your package manager 73 | 74 | sudo apt update 75 | 76 | Install build essentials 77 | 78 | sudo apt install build-essential 79 | 80 | Install Linux Headers 81 | 82 | sudo apt install linux-headers-generic 83 | 84 | Install PV for real-time monitoring of the runtime & datarate output: 85 | 86 | sudo apt install pv 87 | 88 | Install Sox key for manipulating data in real-time or more usefully after captures: 89 | 90 | sudo apt install sox 91 | 92 | Install FFmpeg (If you don't already have it!) 93 | 94 | sudo apt install ffmpeg 95 | 96 | Install FLAC (If you don't already have it!) 97 | 98 | sudo apt install flac 99 | 100 |
101 | 102 |
103 | Raspberry Pi OS on Raspberry Pi 4 or 5 with PCIe adapter 104 |
105 | 106 | As Ubuntu 22.04, but install `raspberrypi-kernel-headers` instead of `linux-headers-generic`, 107 | and then add the following to the end of `/boot/firmware/config.txt`: 108 | 109 | [all] 110 | dtoverlay=pcie-32bit-dma 111 | 112 | 113 |
114 | 115 | 116 | ## Install CXADC 117 | 118 | 119 | Pull the driver via terminal 120 | 121 | Open a terminal window and git clone the repository: 122 | 123 | git clone https://github.com/happycube/cxadc-linux3 cxadc 124 | 125 | For offline install simply, click `Code` on the GitHub page and then download the zip. 126 | 127 | Move the zip to your home directory into a folder called `cxadc` and extract the files. 128 | 129 | Afterward, open a terminal in the said directory and continue below. 130 | 131 | 132 | ## How to Update 133 | 134 | 135 | You can then use `git pull` inside the directory to update later and then re-build the driver with the steps below again or likewise manually re-download the files. 136 | 137 | 138 | ## Build The Driver 139 | 140 | 141 | If not already inside of the CXADC directory 142 | 143 | cd cxadc 144 | 145 | Build and install the out-of-tree module: 146 | 147 | make && sudo make modules_install && sudo depmod -a 148 | 149 | If you see the following error, ignore it: 150 | 151 | At main.c:160: 152 | - SSL error:02001002:system library:fopen:No such file or directory: ../crypto/bio/bss_file.c:69 153 | - SSL error:2006D080:BIO routines:BIO_new_file:no such file: ../crypto/bio/bss_file.c:76 154 | sign-file: certs/signing_key.pem: No such file or directory 155 | Warning: modules_install: missing 'System.map' file. Skipping depmod. 156 | 157 | This error just means the module could not be signed. It will still be installed. 158 | 159 | Install configuration files: 160 | 161 | sudo cp cxadc.rules /etc/udev/rules.d 162 | sudo cp cxadc.conf /etc/modprobe.d 163 | 164 | Now reboot and the modules will be loaded automatically. The device node will 165 | be called `/dev/cxadc0`. The default cx88 driver will be blacklisted by cxadc.conf. 166 | Module parameters can also be configured in that file. 167 | 168 | If there is an issue just re-load the CXADC module from the install directory via terminal 169 | 170 | sudo rmmod cxadc 171 | make 172 | sudo make modules_install 173 | sudo depmod -a 174 | 175 | `depmod -a` enables auto load on start-up 176 | 177 | You can then install scripted commands to help operate and verify your configuration. 178 | 179 | Check the `utils folder` and the associated README for quicker and more simplified commands. 180 | 181 | To enable short system wide commands, first change into the utils directory from the cxadc source folder: 182 | 183 | cd utils 184 | 185 | Then install the system links with: 186 | 187 | sudo ./inst_scripts 188 | 189 | 190 | ## Troubleshooting 191 | 192 | > [!WARNING] 193 | > Secure boot is the most common issue with many PCI/PCIe devices on Linux very much so video class devices such as BMD SDI hardware. 194 | 195 | If the kernal is updated, the driver will need a re-install unless [DKMS](https://askubuntu.com/questions/408605/what-does-dkms-do-how-do-i-use-it) is setup. 196 | 197 | If you see this error: 198 | 199 | arch/x86/Makefile:142: CONFIG_X86_X32 enabled but no binutils support 200 | INSTALL /lib/modules/5.15.0-92-generic/extra/cxadc.ko 201 | SIGN /lib/modules/5.15.0-92-generic/extra/cxadc.ko 202 | DEPMOD /lib/modules/5.15.0-92-generic 203 | Warning: modules_install: missing 'System.map' file. Skipping depmod. 204 | make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-92-generic' 205 | 206 | 207 | > [!CAUTION] 208 | > Ensure secure boot is disabled before doing anything else. 209 | 210 | Try Install Binutils 211 | 212 | apt install binutils 213 | 214 | If issues with binutills persists just use a different Kernel like [Xanmod](https://xanmod.org/) has been tested as a fix to the issue. 215 | 216 | 217 | # Configuration of Capture Settings 218 | 219 | 220 | Most of these parameters (except `latency`) can be changed using sysfs 221 | after the module has been loaded. Re-opening the device will update the 222 | CX2388x's registers. If you wish to be able to change module parameters 223 | as a regular users (e.g. without `sudo`), you need to run the command: 224 | 225 | sudo usermod -a -G video YourUbuntuUserName 226 | 227 | To change configuration open the terminal and use the following command to change driver config settings. 228 | 229 | 230 | ## Module Parameters 231 | 232 | 233 | > [!CAUTION] 234 | > - Configuration will reset on every re-boot of the system. 235 | > - If using a fixed input/gain configuration update the `cxadc.rules` file inside the `etc/udev/rules.d` directory, this will save you from having to manually copy-paste change values on each system restart. 236 | 237 | > [!NOTE] 238 | > You can use `cxvalues` to check your current configuration state at anytime globally on the terminal. 239 | 240 | X = Number Setting i.e `0` `1` `2` `3` etc 241 | 242 | Y = Parameter setting i.e `vmux`, `level` etc 243 | 244 | echo X >/sys/class/cxadc/cxadc0/device/parameters/Y 245 | 246 | Example: `echo 1 >/sys/class/cxadc/cxadc0/device/parameters/vmux` 247 | 248 | > [!WARNING] 249 | > Also see the `utils` folders for scripts to manipulate these values; sudo will be required unless you add your local user to the `video` group as mentioned above. 250 | 251 | 252 | ## `Multi Card Usage` 253 | 254 | 255 | In single card capture mode this is `cat /dev/cxadc0` 256 | 257 | With multi card this will be `cat /dev/cxadc1` and so on for card 2 and 3 etc 258 | 259 | Same for parameters 260 | 261 | `sudo echo 1 >/sys/class/cxadc/cxadc0/device/parameters/vmux` 262 | 263 | This changes to 264 | 265 | `sudo echo 1 >/sys/class/cxadc/cxadc1/device/parameters/vmux` 266 | 267 | This can go up to 256, but real world use we don't expect more then 8-16 per system. 268 | 269 | > [!NOTE] 270 | > Each card has a separate set of entries in the `cxadc.rules` file also. 271 | 272 | 273 | ## `vmux` (0 to 3, default 2) select physical input to capture. 274 | 275 | 276 | [Check the Wiki](https://github.com/happycube/cxadc-linux3/wiki/Types-Of-CX2388x-Cards) for the optimal way to connect your card type! 277 | 278 | A typical TV card has a tuner, a composite input with RCA or BNC ports and S-Video input, tied to three of these inputs; you 279 | may need to experiment with inputs. The quickest way is to attach a video signal and see a white flash on signal hook-up, and change vmux until you get something. 280 | 281 | 282 | > [!TIP] 283 | > On current White CX cards `VMUX 0 is S-Video` and `VMUX 1 is RCA input`. 284 | 285 | ## Commands to Check for Signal Burst 286 | 287 | 288 | Create a video preview of signal. Depending on the RF signal type, you will get an unstable video or just a white flash on cable connection. 289 | 290 | (Using video_size values to give approximately the correct resolution for the default 28.64 Mhz sample rate) 291 | 292 | PAL: 293 | 294 | `sudo ffplay -hide_banner -async 1 -f rawvideo -pixel_format gray8 -video_size 1832x625 -i /dev/cxadc0 -vf scale=1135x625,eq=gamma=0.5:contrast=1.5` 295 | 296 | NTSC: 297 | 298 | `sudo ffplay -hide_banner -async 1 -f rawvideo -pixel_format gray8 -video_size 1820x525 -i /dev/cxadc0 -vf scale=910x525,eq=gamma=0.5:contrast=1.5` 299 | 300 | 301 | ## `audsel` (0 to 3, default none) 302 | 303 | 304 | Some TV cards (e.g. the PixelView PlayTV Pro Ultra) have an external 305 | multiplexer attached to the CX2388x's GPIO pins to select an audio 306 | channel. If your card has one, you can select the input using this 307 | parameter. 308 | 309 | On the PlayTV Pro Ultra: 310 | - `audsel=0`: tuner tv audio out? 311 | - `audsel=1`: silence? 312 | - `audsel=2`: FM stereo tuner out? 313 | - `audsel=3`: audio in to audio out 314 | 315 | 316 | ## `latency` (0 to 255, default 255) 317 | 318 | 319 | The PCI latency timer value for the device. 320 | 321 | 322 | ## `sixdb` (0 or 1, default 1) 323 | 324 | 325 | Enables or disables a default 6db gain applied to the input signal (Disabling this can result in cleaner capture but may require an external amplifier) 326 | 327 | `1` = On 328 | 329 | `0` = Off 330 | 331 | 332 | ## `level` (0 to 31, default 16) 333 | 334 | 335 | The fixed digital gain to be applied by the CX2388x 336 | 337 | (`INT_VGA_VAL` in the datasheet). 338 | 339 | Adjust to minimise clipping; `./leveladj` will do this 340 | for you automatically. 341 | 342 | To change the card witch add the `-h` flag followed by the card so `./leveladj -h 1` for card 2 for example. 343 | 344 | 345 | ## `tenxfsc` (0 to 2, 10 to 99, or 10022728 to "see below", default 0) 346 | 347 | 348 | By default, cxadc captures at a rate of 8 x fsc (8 * 315 / 88 Mhz, approximately 28.6 MHz) 349 | 350 | tenxfsc - Sets sampling rate of the ADC based on the crystal's native frequency 351 | 352 | `0` = Native crystal frequency i.e 28MHz (default), 40, 50, 54, (if hardware modified) 353 | 354 | `1` = Native crystal frequency times 1.25 355 | 356 | 357 | With the Stock 28.6Mhz Crystal the modes are the following: 358 | 359 | `0` = 28.6 MHz 8-bit 360 | 361 | `1` = 35.8 MHz 8-bit (Upsampled) 362 | 363 | 364 | > [!NOTE] 365 | > For 40mhz 8-bit native or 20mhz 16-bit (10-bit scaled to 16-bits) sampling please use the [clockgen or crystal replacement](https://github.com/happycube/cxadc-linux3/wiki/Modifications) hardware mods for reliable results & lower noise. 366 | 367 | Alternatively, enter 2 digit values (like 20), that will then be 368 | multiplied by 1,000,000 (so 20 = 20,000,000sps), with the caveat 369 | that the lowest possible rate is a little more than 1/3 the actual 370 | `HW Crystal` rate (HW crystal / 40 * 14). For stock 28.6mhz crystal, 371 | this is about 10,022,728sps. 372 | 373 | For a 40mhz crystal card, the lowest 374 | rate will be 14,000,000sps. The highest rate is capped at the 375 | 10fsc rate, or: HW crystal / 8 * 10. 376 | 377 | Full-range sample values can also be entered: 14318181 for instance. 378 | Again, the caveat is that the lowest possible rate is: 379 | HW crystal / 40 * 14 and the highest allowed rate is: 380 | HW crystal / 8 * 10. 381 | 382 | Values outside the range will be converted to the lowest / highest 383 | value appropriately. Higher rates may work, with the max rate depending 384 | on individual card and cooling, but can cause system crash for others, 385 | so are prevented by the driver code (increase at your own risk). 386 | 387 | 388 | ## `tenbit` (0 or 1, default 0) 389 | 390 | 391 | By default, cxadc captures unsigned 8-bit samples. 392 | 393 | In mode 1, unsigned 16-bit mode, the data is resampled (down-converted) by 50% 394 | 395 | `0` = 8xFsc 8-bit data mode (Raw Unsigned Data) 396 | 397 | `1` = 4xFsc 16-bit data mode (Filtered Vertical Blanking Interval Data) 398 | 399 | When in 16bit sample modes, change to the following: 400 | 401 | `14.3 MHz 16-bit` - Stock Card 402 | 403 | `17.9 MHz 16-bit` - Stock Card 404 | 405 | 406 | ## `crystal` (? - 54000000, default 28636363) 407 | 408 | 409 | The Mhz of the physical XTAL crystal on your CX Card. 410 | The stock crystal is usually a 28636363 (28.6Mhz) fundamental type, but a 40mhz replacement crystal is easily available and crystals as high as 54mhz have been shown to work (with 411 | extra cooling required above 40mhz). 412 | 413 | This value is ONLY used to compute the sample rates entered for the tenxfsc parameters other than 0, 1, 2. 414 | 415 | 416 | ## `center_offset` (0 to 255, default 2) 417 | 418 | 419 | This option allows you to manually adjust DC center offset or the centering of the RF signal you wish to capture. 420 | 421 | > [!TIP] 422 | > You can visually adjust the DC offset line with this handy [GNURadio Script](https://github.com/tandersn/GNRC-Flowgraphs/tree/main/test_cxadc)! 423 | 424 | Manual calculation: If the "highest" and "lowest" values returned are equidistant from 0 and 255 respectively, it's cantered. 425 | 426 | Use leveladj to obtain level and centring information 427 | 428 | ./leveladj 429 | 430 | Example: 431 | 432 | `low 121 high 133 clipped 0 nsamp 2097152` 433 | 434 | 121-121=0 133+121 = 254 = centred, but: low 435 | 436 | `110 high 119 clipped 0 nsamp 2097152` 437 | 438 | 110-110=0 119+110 = 229 = not centred. 439 | 440 | 441 | # Capture 442 | 443 | 444 | ## Gain Adjustment 445 | 446 | 447 | Connect a live or playing signal to the input you've selected, and run `leveladj` to adjust the gain automatically: 448 | 449 | ./leveladj 450 | 451 | To use this on multiple different cards 452 | 453 | `./leveladj -d 1` (1 means for device 2/3/4 and so on device 0 is assumed when `-d` is not used) 454 | 455 | 456 | ### Fixed Gain & External Amplifyer Use 457 | 458 | 459 | You can manually set a fixed gain setting after centering the signal with 460 | 461 | `sudo echo 0 >/sys/class/cxadc/cxadc0/device/parameters/level` - Internal Gain (`0`~`31`) 462 | 463 | `sudo echo 0 >/sys/class/cxadc/cxadc0/device/parameters/sixdb` - Digital Gain Boost (`1` On / `0` Off) 464 | 465 | This is critical to note when trying capture [RAW CVBS](https://github.com/oyvindln/vhs-decode/wiki/CVBS-Composite-Decode) or using an [AD4857](https://github.com/happycube/cxadc-linux3/wiki/Modifications#external-amplification) amplifier with a videotape deck. 466 | 467 | 468 | ## Command Line Capture (CLI) 469 | 470 | 471 | Open a terminal in the directory you wish to write the data to, and use the following example command to capture 10 seconds of test samples. 472 | 473 | timeout 10s cat /dev/cxadc0 |pv > CX_Card_28msps_8-bit.u8 474 | 475 | Press Ctrl+C to copy then Ctrl+P to past the command use <+> to move edit position on the command line to edit the name or command and Enter to run the command. 476 | 477 | `cat` is the default due to user issues with `dd` 478 | 479 | To use the PV argument that enables data rate/runtime readout, modify the command with `|pv >` 480 | 481 | It will look like this when in use: 482 | 483 | cat /dev/cxadc0 |pv > CX_Card_28msps_8-bit.u8 484 | 0:00:04 [38.1MiB/s] [ <=> 485 | 486 | Ctrl+C Will kill the current process, use this to stop the capture manually. 487 | 488 | `timeout 10s` defines the capture duration of 10 seconds, this can be defined in `h`ours `m`inutes or `s`econds if a timeout duration is not set it will capture until storage space runs out or is stopped manually. 489 | 490 | `sox -r 28636363` etc can be used to resample to the sample rate specified, whereas cat/dd will just do whatever has been pre-defined by the parameters set above. 491 | 492 | Note: For use with the decode projects, filetypes `.u8` for 8-bit & `.u16` for 16-bit samples are used instead of `.raw` extension. 493 | 494 | This allows the software to correctly detect the data and use it for decoding or flac compression and renaming to `.vhs`/`.svhs` etc. 495 | 496 | 497 | ### Real-Time FLAC Compressed Capture 498 | 499 | 500 | Optional but **not optimal** due to risk of dropped samples even with high-end hardware, on the fly FLAC compressed captures are possible with the following commands; edit rates and modes as needed. 501 | 502 | > [!WARNING] 503 | > You need to be on FLAC 1.5.0 or newer to leverage multi-threading for higher reliability capture and real-time compression. 504 | 505 | 8-bit Mode (Stock 28.6 MSPS) 506 | 507 | cat /dev/cxadc0 | flac --threads 64 -6 --sample-rate=28636 --sign=unsigned --channels=1 --endian=little --bps=8 --blocksize=65535 --lax -f - -o media-name-28msps-8bit-cx-card.flac 508 | 509 | 16-bit Mode (Stock 17.8 MSPS) 510 | 511 | cat /dev/cxadc0 | flac --threads 64 -6 --sample-rate=17898 --sign=unsigned --channels=1 --endian=little --bps=16 --blocksize=65535 --lax -f - -o media-name-17.8msps-16bit-cx-card.flac 512 | 513 | 514 | # Issues & Debugging 515 | 516 | 517 | Secure boot can cause issues. 518 | 519 | Kernel updates will break the driver and require a full re-installation, unless DKMS is setup. 520 | 521 | `rules.config` - Inside this file are your defined base settings every time the driver loads. 522 | 523 | 524 | ## History 525 | 526 | 527 | ### 2005-09-25 - v0.2 528 | 529 | cxadc was originally written by Hew How Chee (). 530 | See [SDR using a CX2388x TV+FM card](http://web.archive.org/web/20091027150612/http://geocities.com/how_chee/cx23881fc6.htm) for more details. 531 | 532 | - added support for i2c, use `i2c.c` to tune 533 | - set registers to lower gain 534 | - set registers so that no signal is nearer to sample value 128 535 | - added `vmux` and `audsel` as params during driver loading 536 | (for 2nd IF hardware modification, load driver using `vmux=2`). 537 | By default `audsel=2` is to route tv tuner audio signal to 538 | audio out of TV card, `vmux=1` to use the signal from video in of tv card. 539 | 540 | ### 2007-03-24 - v0.3 541 | 542 | - change code to compile and run in kernel 2.6.18 (Fedora Core 6) 543 | for Intel 32 bit single processor only 544 | - clean up mess in version 0.2 code 545 | 546 | ### 2013-12-18 - v0.4 547 | 548 | This version has been retargeted for Ubuntu 13.10 Linux 3.11 by 549 | [Chad Page](https://github.com/happycube/) (Chad.Page@gmail.com). 550 | 551 | While still a mess, the driver has been simplified a bit. Data is now read 552 | using standard `read()` semantics, so no capture program is needed like the original 553 | version. 554 | 555 | For the first time, it also runs on 64-bit Linux, and *seems* to be OK under 556 | SMP. 557 | 558 | ### 2019-06-09 - v0.5 559 | 560 | - Update to work with Linux 5.1; older versions should still work. 561 | - Tidy up the code to get rid of most of the warnings from checkpatch, 562 | and bring it closer in style to the normal cx88 driver. 563 | - Make `audsel` optional. 564 | - Don't allow `/dev/cxadc` to be opened multiple times. 565 | - When unloading cxadc, reset the AGC registers to their default values. 566 | as cx88 expects. This lets you switch between cxadc and cx88 without 567 | rebooting. 568 | 569 | ### 2021-12-14 - Updated Documentation 570 | 571 | Information Additions Documentation Cleanup by [Harry Munday](https://github.com/harrypm) (harry@opcomedia.com) 572 | 573 | - Change 10bit to the correct 16bit as that's what's stated in RAW16 under the datasheet and that's what the actual samples are in format-wise. 574 | - Cleaned up and added examples for adjusting module parameters and basic real-time readout information. 575 | - Added notations of ABLS2-40.000MHZ-D4YF-T a drop-in replacement crystal that adds 40mhz ability at low cost for current market PCIe cards. 576 | - Added documentation for sixdb mode selection. 577 | - Added links to find current CX cards 578 | - Added issues that have been found 579 | - Added crystal list of working replacements 580 | 581 | ### 2022-01-21 - v0.6 - Usability Improvements 582 | 583 | New additions by [Tony Anderson](https://github.com/tandersn) (tandersn@uw.edu) 584 | 585 | - Fixed ./leveladj script from re-setting module parameters 586 | - Added new command scripts 587 | - Added new level adjustment tool cxlvlcavdd 588 | - Added dedicated readme for new scripts and future tools 589 | 590 | ### 2022-04-26 - More Usability Improvements & Tools 591 | 592 | - Documentation Cleanup 593 | - More utils additons 594 | - Added cxlevel (utils/README.md) 595 | - Added cxfreq (utils/README.md) 596 | - Added cxvalues shows the current configuration. 597 | - Added fortycryst 0 for no, 1 for yes, and then added sample rates 11-27 (14-27 on 40cryst) 598 | - Added warning messages for high & low gain states 599 | 600 | ### 2023-01-12 - v0.7 Multi Card Support 601 | 602 | New multi-card support added by [Adam R](https://github.com/AR1972) 603 | 604 | - Multi card support up to 256 cards per system 605 | - Individual card settings support 606 | - Documentation & Scripts updated 607 | 608 | ### 2024 - Hardware Notes 609 | 610 | [Clockgen Mod](https://github.com/happycube/cxadc-linux3/wiki/Modifications#clockgen-mod---external-clock) Established. 611 | 612 | - Software defined 20/28.6/40/50msps modes 613 | - Shared clock source synchronised capture 614 | - Raspberry Pi 4 & 5 support added by [Alistair Buxton](https://github.com/ali1234) 615 | 616 | ### 2024-12-11 617 | 618 | - [Windows Port](https://github.com/JuniorIsAJitterbug/cxadc-win) of CXADC established by Jitterbug 619 | 620 | ### 2025-02-11 621 | 622 | - [FLAC V1.5.0 released](https://github.com/xiph/flac/releases/tag/1.5.0) enabling CPU multi-threading for FM RF archival capture with FLAC. -------------------------------------------------------------------------------- /Tips-&-Notes.md: -------------------------------------------------------------------------------- 1 | ## Other Tips 2 | 3 | ### Change CXADC defaults 4 | 5 | Defaults cxadc3-linux/cxadc.c file to have the defaults you like. at stock, it will look like this: 6 | 7 | `static int latency = -1;` (leave this alone) 8 | 9 | `static int audsel = -1;` 10 | 11 | `static int vmux = 2;` 12 | 13 | `static int level = 16;` 14 | 15 | `static int tenbit;` 16 | 17 | `static int tenxfsc;` 18 | 19 | `static int sixdb = 1;` 20 | 21 | `static int crystal = 28636363;` 22 | 23 | But you could change it to: 24 | 25 | `static int latency = -1;` (leave this alone) 26 | 27 | `static int audsel = -1;` 28 | 29 | `static int vmux = 1;` 30 | 31 | `static int level = 0;` 32 | 33 | `static int tenbit = 1;` 34 | 35 | `static int tenxfsc = 1;` 36 | 37 | `static int sixdb = 0;` 38 | 39 | `static int crystal = 40000000;` 40 | 41 | Then redo the make and sudo make modules_install commands. Then next reboot, it will come up with those settings as the default. 42 | 43 | ### Accessing registers directly from userspace 44 | 45 | This can be done with the pcimem tool. Get it from here: 46 | 47 | https://github.com/billfarrow/pcimem 48 | 49 | Build it with `make`. To use, consult `lspci` for the PCI address of 50 | your card. This will be different depending on motherboard and slot. 51 | Example output: 52 | 53 | 03:00.0 Multimedia video controller: Conexant Systems, Inc. CX23880/1/2/3 PCI Video and Audio Decoder (rev 05) 54 | 03:00.4 Multimedia controller: Conexant Systems, Inc. CX23880/1/2/3 PCI Video and Audio Decoder [IR Port] (rev 05) 55 | 56 | Here we want the video controller at address `03:00.0` - not the 57 | IR port. Next you need to find that device in sysfs. Due to topology 58 | it can be nested under other devices. The quickest way to find it: 59 | 60 | find /sys/devices -iname '*03:00.0' 61 | 62 | Output: 63 | 64 | /sys/devices/pci0000:00/0000:00:1c.5/0000:02:00.0/0000:03:00.0 65 | 66 | To use pcimem we take that filename and add "/resource0" to the end. 67 | Then to read a register we do this: 68 | 69 | ./pcimem /sys/devices/pci0000:00/0000:00:1c.5/0000:02:00.0/0000:03:00.0/resource0 0x2f0000 70 | 71 | 0x2f0000 is the device ID register and it should begin with 0x88. 72 | Output: 73 | 74 | 0x2F0000: 0x880014F1 75 | 76 | To write to a register, specify a value after the address. -------------------------------------------------------------------------------- /cx88-reg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cx88x-hw.h - CX2388x register offsets 3 | * 4 | * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) 5 | * 2001 Michael Eskin 6 | * 2002 Yurij Sysoev 7 | * 2003 Gerd Knorr 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | */ 19 | 20 | #ifndef _CX88_REG_H_ 21 | #define _CX88_REG_H_ 22 | 23 | /* 24 | * PCI IDs and config space 25 | */ 26 | 27 | #ifndef PCI_VENDOR_ID_CONEXANT 28 | # define PCI_VENDOR_ID_CONEXANT 0x14F1 29 | #endif 30 | #ifndef PCI_DEVICE_ID_CX2300_VID 31 | # define PCI_DEVICE_ID_CX2300_VID 0x8800 32 | #endif 33 | 34 | #define CX88X_DEVCTRL 0x40 35 | #define CX88X_EN_TBFX 0x02 36 | #define CX88X_EN_VSFX 0x04 37 | 38 | /* 39 | * PCI controller registers 40 | */ 41 | 42 | /* Command and Status Register */ 43 | #define F0_CMD_STAT_MM 0x2f0004 44 | #define F1_CMD_STAT_MM 0x2f0104 45 | #define F2_CMD_STAT_MM 0x2f0204 46 | #define F3_CMD_STAT_MM 0x2f0304 47 | #define F4_CMD_STAT_MM 0x2f0404 48 | 49 | /* Device Control #1 */ 50 | #define F0_DEV_CNTRL1_MM 0x2f0040 51 | #define F1_DEV_CNTRL1_MM 0x2f0140 52 | #define F2_DEV_CNTRL1_MM 0x2f0240 53 | #define F3_DEV_CNTRL1_MM 0x2f0340 54 | #define F4_DEV_CNTRL1_MM 0x2f0440 55 | 56 | /* Device Control #1 */ 57 | #define F0_BAR0_MM 0x2f0010 58 | #define F1_BAR0_MM 0x2f0110 59 | #define F2_BAR0_MM 0x2f0210 60 | #define F3_BAR0_MM 0x2f0310 61 | #define F4_BAR0_MM 0x2f0410 62 | 63 | /* 64 | * DMA Controller registers 65 | */ 66 | 67 | #define MO_PDMA_STHRSH 0x200000 // Source threshold 68 | #define MO_PDMA_STADRS 0x200004 // Source target address 69 | #define MO_PDMA_SIADRS 0x200008 // Source internal address 70 | #define MO_PDMA_SCNTRL 0x20000C // Source control 71 | #define MO_PDMA_DTHRSH 0x200010 // Destination threshold 72 | #define MO_PDMA_DTADRS 0x200014 // Destination target address 73 | #define MO_PDMA_DIADRS 0x200018 // Destination internal address 74 | #define MO_PDMA_DCNTRL 0x20001C // Destination control 75 | #define MO_LD_SSID 0x200030 // Load subsystem ID 76 | #define MO_DEV_CNTRL2 0x200034 // Device control 77 | #define MO_PCI_INTMSK 0x200040 // PCI interrupt mask 78 | #define MO_PCI_INTSTAT 0x200044 // PCI interrupt status 79 | #define MO_PCI_INTMSTAT 0x200048 // PCI interrupt masked status 80 | #define MO_VID_INTMSK 0x200050 // Video interrupt mask 81 | #define MO_VID_INTSTAT 0x200054 // Video interrupt status 82 | #define MO_VID_INTMSTAT 0x200058 // Video interrupt masked status 83 | #define MO_VID_INTSSTAT 0x20005C // Video interrupt set status 84 | #define MO_AUD_INTMSK 0x200060 // Audio interrupt mask 85 | #define MO_AUD_INTSTAT 0x200064 // Audio interrupt status 86 | #define MO_AUD_INTMSTAT 0x200068 // Audio interrupt masked status 87 | #define MO_AUD_INTSSTAT 0x20006C // Audio interrupt set status 88 | #define MO_TS_INTMSK 0x200070 // Transport stream interrupt mask 89 | #define MO_TS_INTSTAT 0x200074 // Transport stream interrupt status 90 | #define MO_TS_INTMSTAT 0x200078 // Transport stream interrupt mask status 91 | #define MO_TS_INTSSTAT 0x20007C // Transport stream interrupt set status 92 | #define MO_VIP_INTMSK 0x200080 // VIP interrupt mask 93 | #define MO_VIP_INTSTAT 0x200084 // VIP interrupt status 94 | #define MO_VIP_INTMSTAT 0x200088 // VIP interrupt masked status 95 | #define MO_VIP_INTSSTAT 0x20008C // VIP interrupt set status 96 | #define MO_GPHST_INTMSK 0x200090 // Host interrupt mask 97 | #define MO_GPHST_INTSTAT 0x200094 // Host interrupt status 98 | #define MO_GPHST_INTMSTAT 0x200098 // Host interrupt masked status 99 | #define MO_GPHST_INTSSTAT 0x20009C // Host interrupt set status 100 | 101 | // DMA Channels 1-6 belong to SPIPE 102 | #define MO_DMA7_PTR1 0x300018 // {24}RW* DMA Current Ptr : Ch#7 103 | #define MO_DMA8_PTR1 0x30001C // {24}RW* DMA Current Ptr : Ch#8 104 | 105 | // DMA Channels 9-20 belong to SPIPE 106 | #define MO_DMA21_PTR1 0x300080 // {24}R0* DMA Current Ptr : Ch#21 107 | #define MO_DMA22_PTR1 0x300084 // {24}R0* DMA Current Ptr : Ch#22 108 | #define MO_DMA23_PTR1 0x300088 // {24}R0* DMA Current Ptr : Ch#23 109 | #define MO_DMA24_PTR1 0x30008C // {24}R0* DMA Current Ptr : Ch#24 110 | #define MO_DMA25_PTR1 0x300090 // {24}R0* DMA Current Ptr : Ch#25 111 | #define MO_DMA26_PTR1 0x300094 // {24}R0* DMA Current Ptr : Ch#26 112 | #define MO_DMA27_PTR1 0x300098 // {24}R0* DMA Current Ptr : Ch#27 113 | #define MO_DMA28_PTR1 0x30009C // {24}R0* DMA Current Ptr : Ch#28 114 | #define MO_DMA29_PTR1 0x3000A0 // {24}R0* DMA Current Ptr : Ch#29 115 | #define MO_DMA30_PTR1 0x3000A4 // {24}R0* DMA Current Ptr : Ch#30 116 | #define MO_DMA31_PTR1 0x3000A8 // {24}R0* DMA Current Ptr : Ch#31 117 | #define MO_DMA32_PTR1 0x3000AC // {24}R0* DMA Current Ptr : Ch#32 118 | 119 | #define MO_DMA21_PTR2 0x3000C0 // {24}RW* DMA Tab Ptr : Ch#21 120 | #define MO_DMA22_PTR2 0x3000C4 // {24}RW* DMA Tab Ptr : Ch#22 121 | #define MO_DMA23_PTR2 0x3000C8 // {24}RW* DMA Tab Ptr : Ch#23 122 | #define MO_DMA24_PTR2 0x3000CC // {24}RW* DMA Tab Ptr : Ch#24 123 | #define MO_DMA25_PTR2 0x3000D0 // {24}RW* DMA Tab Ptr : Ch#25 124 | #define MO_DMA26_PTR2 0x3000D4 // {24}RW* DMA Tab Ptr : Ch#26 125 | #define MO_DMA27_PTR2 0x3000D8 // {24}RW* DMA Tab Ptr : Ch#27 126 | #define MO_DMA28_PTR2 0x3000DC // {24}RW* DMA Tab Ptr : Ch#28 127 | #define MO_DMA29_PTR2 0x3000E0 // {24}RW* DMA Tab Ptr : Ch#29 128 | #define MO_DMA30_PTR2 0x3000E4 // {24}RW* DMA Tab Ptr : Ch#30 129 | #define MO_DMA31_PTR2 0x3000E8 // {24}RW* DMA Tab Ptr : Ch#31 130 | #define MO_DMA32_PTR2 0x3000EC // {24}RW* DMA Tab Ptr : Ch#32 131 | 132 | #define MO_DMA21_CNT1 0x300100 // {11}RW* DMA Buffer Size : Ch#21 133 | #define MO_DMA22_CNT1 0x300104 // {11}RW* DMA Buffer Size : Ch#22 134 | #define MO_DMA23_CNT1 0x300108 // {11}RW* DMA Buffer Size : Ch#23 135 | #define MO_DMA24_CNT1 0x30010C // {11}RW* DMA Buffer Size : Ch#24 136 | #define MO_DMA25_CNT1 0x300110 // {11}RW* DMA Buffer Size : Ch#25 137 | #define MO_DMA26_CNT1 0x300114 // {11}RW* DMA Buffer Size : Ch#26 138 | #define MO_DMA27_CNT1 0x300118 // {11}RW* DMA Buffer Size : Ch#27 139 | #define MO_DMA28_CNT1 0x30011C // {11}RW* DMA Buffer Size : Ch#28 140 | #define MO_DMA29_CNT1 0x300120 // {11}RW* DMA Buffer Size : Ch#29 141 | #define MO_DMA30_CNT1 0x300124 // {11}RW* DMA Buffer Size : Ch#30 142 | #define MO_DMA31_CNT1 0x300128 // {11}RW* DMA Buffer Size : Ch#31 143 | #define MO_DMA32_CNT1 0x30012C // {11}RW* DMA Buffer Size : Ch#32 144 | 145 | #define MO_DMA21_CNT2 0x300140 // {11}RW* DMA Table Size : Ch#21 146 | #define MO_DMA22_CNT2 0x300144 // {11}RW* DMA Table Size : Ch#22 147 | #define MO_DMA23_CNT2 0x300148 // {11}RW* DMA Table Size : Ch#23 148 | #define MO_DMA24_CNT2 0x30014C // {11}RW* DMA Table Size : Ch#24 149 | #define MO_DMA25_CNT2 0x300150 // {11}RW* DMA Table Size : Ch#25 150 | #define MO_DMA26_CNT2 0x300154 // {11}RW* DMA Table Size : Ch#26 151 | #define MO_DMA27_CNT2 0x300158 // {11}RW* DMA Table Size : Ch#27 152 | #define MO_DMA28_CNT2 0x30015C // {11}RW* DMA Table Size : Ch#28 153 | #define MO_DMA29_CNT2 0x300160 // {11}RW* DMA Table Size : Ch#29 154 | #define MO_DMA30_CNT2 0x300164 // {11}RW* DMA Table Size : Ch#30 155 | #define MO_DMA31_CNT2 0x300168 // {11}RW* DMA Table Size : Ch#31 156 | #define MO_DMA32_CNT2 0x30016C // {11}RW* DMA Table Size : Ch#32 157 | 158 | /* 159 | * Video registers 160 | */ 161 | 162 | #define MO_VIDY_DMA 0x310000 // {64}RWp Video Y 163 | #define MO_VIDU_DMA 0x310008 // {64}RWp Video U 164 | #define MO_VIDV_DMA 0x310010 // {64}RWp Video V 165 | #define MO_VBI_DMA 0x310018 // {64}RWp VBI (Vertical blanking interval) 166 | 167 | #define MO_DEVICE_STATUS 0x310100 168 | #define MO_INPUT_FORMAT 0x310104 169 | #define MO_AGC_BURST 0x31010c 170 | #define MO_CONTR_BRIGHT 0x310110 171 | #define MO_UV_SATURATION 0x310114 172 | #define MO_HUE 0x310118 173 | #define MO_WHITE_CRUSH 0x31011c 174 | #define MO_HTOTAL 0x310120 175 | #define MO_HDELAY_EVEN 0x310124 176 | #define MO_HDELAY_ODD 0x310128 177 | #define MO_VDELAY_ODD 0x31012c 178 | #define MO_VDELAY_EVEN 0x310130 179 | #define MO_HACTIVE_EVEN 0x31013c 180 | #define MO_HACTIVE_ODD 0x310140 181 | #define MO_VACTIVE_EVEN 0x310144 182 | #define MO_VACTIVE_ODD 0x310148 183 | #define MO_HSCALE_EVEN 0x31014c 184 | #define MO_HSCALE_ODD 0x310150 185 | #define MO_VSCALE_EVEN 0x310154 186 | #define MO_FILTER_EVEN 0x31015c 187 | #define MO_VSCALE_ODD 0x310158 188 | #define MO_FILTER_ODD 0x310160 189 | #define MO_OUTPUT_FORMAT 0x310164 190 | 191 | #define MO_PLL_REG 0x310168 // PLL register 192 | #define MO_PLL_ADJ_CTRL 0x31016c // PLL adjust control register 193 | #define MO_SCONV_REG 0x310170 // sample rate conversion register 194 | #define MO_SCONV_FIFO 0x310174 // sample rate conversion fifo 195 | #define MO_SUB_STEP 0x310178 // subcarrier step size 196 | #define MO_SUB_STEP_DR 0x31017c // subcarrier step size for DR line 197 | 198 | #define MO_CAPTURE_CTRL 0x310180 // capture control 199 | #define MO_COLOR_CTRL 0x310184 200 | #define MO_VBI_PACKET 0x310188 // vbi packet size / delay 201 | #define MO_FIELD_COUNT 0x310190 // field counter 202 | #define MO_VIP_CONFIG 0x310194 203 | #define MO_VBOS_CONTROL 0x3101a8 204 | 205 | #define MO_AGC_BACK_VBI 0x310200 206 | #define MO_AGC_SYNC_SLICER 0x310204 207 | #define MO_AGC_SYNC_TIP1 0x310208 208 | #define MO_AGC_SYNC_TIP2 0x31020c 209 | #define MO_AGC_SYNC_TIP3 0x310210 210 | #define MO_AGC_GAIN_ADJ1 0x310214 211 | #define MO_AGC_GAIN_ADJ2 0x310218 212 | #define MO_AGC_GAIN_ADJ3 0x31021c 213 | #define MO_AGC_GAIN_ADJ4 0x310220 214 | 215 | #define MO_VIDY_GPCNT 0x31C020 // {16}RO Video Y general purpose counter 216 | #define MO_VIDU_GPCNT 0x31C024 // {16}RO Video U general purpose counter 217 | #define MO_VIDV_GPCNT 0x31C028 // {16}RO Video V general purpose counter 218 | #define MO_VBI_GPCNT 0x31C02C // {16}RO VBI general purpose counter 219 | #define MO_VIDY_GPCNTRL 0x31C030 // {2}WO Video Y general purpose control 220 | #define MO_VIDU_GPCNTRL 0x31C034 // {2}WO Video U general purpose control 221 | #define MO_VIDV_GPCNTRL 0x31C038 // {2}WO Video V general purpose control 222 | #define MO_VBI_GPCNTRL 0x31C03C // {2}WO VBI general purpose counter 223 | #define MO_VID_DMACNTRL 0x31C040 // {8}RW Video DMA control 224 | #define MO_VID_XFR_STAT 0x31C044 // {1}RO Video transfer status 225 | 226 | /* 227 | * audio registers 228 | */ 229 | 230 | #define MO_AUDD_DMA 0x320000 // {64}RWp Audio downstream 231 | #define MO_AUDU_DMA 0x320008 // {64}RWp Audio upstream 232 | #define MO_AUDR_DMA 0x320010 // {64}RWp Audio RDS (downstream) 233 | #define MO_AUDD_GPCNT 0x32C020 // {16}RO Audio down general purpose counter 234 | #define MO_AUDU_GPCNT 0x32C024 // {16}RO Audio up general purpose counter 235 | #define MO_AUDR_GPCNT 0x32C028 // {16}RO Audio RDS general purpose counter 236 | #define MO_AUDD_GPCNTRL 0x32C030 // {2}WO Audio down general purpose control 237 | #define MO_AUDU_GPCNTRL 0x32C034 // {2}WO Audio up general purpose control 238 | #define MO_AUDR_GPCNTRL 0x32C038 // {2}WO Audio RDS general purpose control 239 | #define MO_AUD_DMACNTRL 0x32C040 // {6}RW Audio DMA control 240 | #define MO_AUD_XFR_STAT 0x32C044 // {1}RO Audio transfer status 241 | #define MO_AUDD_LNGTH 0x32C048 // {12}RW Audio down line length 242 | #define MO_AUDR_LNGTH 0x32C04C // {12}RW Audio RDS line length 243 | 244 | #define AUD_INIT 0x320100 245 | #define AUD_INIT_LD 0x320104 246 | #define AUD_SOFT_RESET 0x320108 247 | #define AUD_I2SINPUTCNTL 0x320120 248 | #define AUD_BAUDRATE 0x320124 249 | #define AUD_I2SOUTPUTCNTL 0x320128 250 | #define AAGC_HYST 0x320134 251 | #define AAGC_GAIN 0x320138 252 | #define AAGC_DEF 0x32013c 253 | #define AUD_IIR1_0_SEL 0x320150 254 | #define AUD_IIR1_0_SHIFT 0x320154 255 | #define AUD_IIR1_1_SEL 0x320158 256 | #define AUD_IIR1_1_SHIFT 0x32015c 257 | #define AUD_IIR1_2_SEL 0x320160 258 | #define AUD_IIR1_2_SHIFT 0x320164 259 | #define AUD_IIR1_3_SEL 0x320168 260 | #define AUD_IIR1_3_SHIFT 0x32016c 261 | #define AUD_IIR1_4_SEL 0x320170 262 | #define AUD_IIR1_4_SHIFT 0x32017c 263 | #define AUD_IIR1_5_SEL 0x320180 264 | #define AUD_IIR1_5_SHIFT 0x320184 265 | #define AUD_IIR2_0_SEL 0x320190 266 | #define AUD_IIR2_0_SHIFT 0x320194 267 | #define AUD_IIR2_1_SEL 0x320198 268 | #define AUD_IIR2_1_SHIFT 0x32019c 269 | #define AUD_IIR2_2_SEL 0x3201a0 270 | #define AUD_IIR2_2_SHIFT 0x3201a4 271 | #define AUD_IIR2_3_SEL 0x3201a8 272 | #define AUD_IIR2_3_SHIFT 0x3201ac 273 | #define AUD_IIR3_0_SEL 0x3201c0 274 | #define AUD_IIR3_0_SHIFT 0x3201c4 275 | #define AUD_IIR3_1_SEL 0x3201c8 276 | #define AUD_IIR3_1_SHIFT 0x3201cc 277 | #define AUD_IIR3_2_SEL 0x3201d0 278 | #define AUD_IIR3_2_SHIFT 0x3201d4 279 | #define AUD_IIR4_0_SEL 0x3201e0 280 | #define AUD_IIR4_0_SHIFT 0x3201e4 281 | #define AUD_IIR4_1_SEL 0x3201e8 282 | #define AUD_IIR4_1_SHIFT 0x3201ec 283 | #define AUD_IIR4_2_SEL 0x3201f0 284 | #define AUD_IIR4_2_SHIFT 0x3201f4 285 | #define AUD_IIR4_0_CA0 0x320200 286 | #define AUD_IIR4_0_CA1 0x320204 287 | #define AUD_IIR4_0_CA2 0x320208 288 | #define AUD_IIR4_0_CB0 0x32020c 289 | #define AUD_IIR4_0_CB1 0x320210 290 | #define AUD_IIR4_1_CA0 0x320214 291 | #define AUD_IIR4_1_CA1 0x320218 292 | #define AUD_IIR4_1_CA2 0x32021c 293 | #define AUD_IIR4_1_CB0 0x320220 294 | #define AUD_IIR4_1_CB1 0x320224 295 | #define AUD_IIR4_2_CA0 0x320228 296 | #define AUD_IIR4_2_CA1 0x32022c 297 | #define AUD_IIR4_2_CA2 0x320230 298 | #define AUD_IIR4_2_CB0 0x320234 299 | #define AUD_IIR4_2_CB1 0x320238 300 | #define AUD_HP_MD_IIR4_1 0x320250 301 | #define AUD_HP_PROG_IIR4_1 0x320254 302 | #define AUD_FM_MODE_ENABLE 0x320258 303 | #define AUD_POLY0_DDS_CONSTANT 0x320270 304 | #define AUD_DN0_FREQ 0x320274 305 | #define AUD_DN1_FREQ 0x320278 306 | #define AUD_DN1_FREQ_SHIFT 0x32027c 307 | #define AUD_DN1_AFC 0x320280 308 | #define AUD_DN1_SRC_SEL 0x320284 309 | #define AUD_DN1_SHFT 0x320288 310 | #define AUD_DN2_FREQ 0x32028c 311 | #define AUD_DN2_FREQ_SHIFT 0x320290 312 | #define AUD_DN2_AFC 0x320294 313 | #define AUD_DN2_SRC_SEL 0x320298 314 | #define AUD_DN2_SHFT 0x32029c 315 | #define AUD_CRDC0_SRC_SEL 0x320300 316 | #define AUD_CRDC0_SHIFT 0x320304 317 | #define AUD_CORDIC_SHIFT_0 0x320308 318 | #define AUD_CRDC1_SRC_SEL 0x32030c 319 | #define AUD_CRDC1_SHIFT 0x320310 320 | #define AUD_CORDIC_SHIFT_1 0x320314 321 | #define AUD_DCOC_0_SRC 0x320320 322 | #define AUD_DCOC0_SHIFT 0x320324 323 | #define AUD_DCOC_0_SHIFT_IN0 0x320328 324 | #define AUD_DCOC_0_SHIFT_IN1 0x32032c 325 | #define AUD_DCOC_1_SRC 0x320330 326 | #define AUD_DCOC1_SHIFT 0x320334 327 | #define AUD_DCOC_1_SHIFT_IN0 0x320338 328 | #define AUD_DCOC_1_SHIFT_IN1 0x32033c 329 | #define AUD_DCOC_2_SRC 0x320340 330 | #define AUD_DCOC2_SHIFT 0x320344 331 | #define AUD_DCOC_2_SHIFT_IN0 0x320348 332 | #define AUD_DCOC_2_SHIFT_IN1 0x32034c 333 | #define AUD_DCOC_PASS_IN 0x320350 334 | #define AUD_PDET_SRC 0x320370 335 | #define AUD_PDET_SHIFT 0x320374 336 | #define AUD_PILOT_BQD_1_K0 0x320380 337 | #define AUD_PILOT_BQD_1_K1 0x320384 338 | #define AUD_PILOT_BQD_1_K2 0x320388 339 | #define AUD_PILOT_BQD_1_K3 0x32038c 340 | #define AUD_PILOT_BQD_1_K4 0x320390 341 | #define AUD_PILOT_BQD_2_K0 0x320394 342 | #define AUD_PILOT_BQD_2_K1 0x320398 343 | #define AUD_PILOT_BQD_2_K2 0x32039c 344 | #define AUD_PILOT_BQD_2_K3 0x3203a0 345 | #define AUD_PILOT_BQD_2_K4 0x3203a4 346 | #define AUD_THR_FR 0x3203c0 347 | #define AUD_X_PROG 0x3203c4 348 | #define AUD_Y_PROG 0x3203c8 349 | #define AUD_HARMONIC_MULT 0x3203cc 350 | #define AUD_C1_UP_THR 0x3203d0 351 | #define AUD_C1_LO_THR 0x3203d4 352 | #define AUD_C2_UP_THR 0x3203d8 353 | #define AUD_C2_LO_THR 0x3203dc 354 | #define AUD_PLL_EN 0x320400 355 | #define AUD_PLL_SRC 0x320404 356 | #define AUD_PLL_SHIFT 0x320408 357 | #define AUD_PLL_IF_SEL 0x32040c 358 | #define AUD_PLL_IF_SHIFT 0x320410 359 | #define AUD_BIQUAD_PLL_K0 0x320414 360 | #define AUD_BIQUAD_PLL_K1 0x320418 361 | #define AUD_BIQUAD_PLL_K2 0x32041c 362 | #define AUD_BIQUAD_PLL_K3 0x320420 363 | #define AUD_BIQUAD_PLL_K4 0x320424 364 | #define AUD_DEEMPH0_SRC_SEL 0x320440 365 | #define AUD_DEEMPH0_SHIFT 0x320444 366 | #define AUD_DEEMPH0_G0 0x320448 367 | #define AUD_DEEMPH0_A0 0x32044c 368 | #define AUD_DEEMPH0_B0 0x320450 369 | #define AUD_DEEMPH0_A1 0x320454 370 | #define AUD_DEEMPH0_B1 0x320458 371 | #define AUD_DEEMPH1_SRC_SEL 0x32045c 372 | #define AUD_DEEMPH1_SHIFT 0x320460 373 | #define AUD_DEEMPH1_G0 0x320464 374 | #define AUD_DEEMPH1_A0 0x320468 375 | #define AUD_DEEMPH1_B0 0x32046c 376 | #define AUD_DEEMPH1_A1 0x320470 377 | #define AUD_DEEMPH1_B1 0x320474 378 | #define AUD_OUT0_SEL 0x320490 379 | #define AUD_OUT0_SHIFT 0x320494 380 | #define AUD_OUT1_SEL 0x320498 381 | #define AUD_OUT1_SHIFT 0x32049c 382 | #define AUD_RDSI_SEL 0x3204a0 383 | #define AUD_RDSI_SHIFT 0x3204a4 384 | #define AUD_RDSQ_SEL 0x3204a8 385 | #define AUD_RDSQ_SHIFT 0x3204ac 386 | #define AUD_DBX_IN_GAIN 0x320500 387 | #define AUD_DBX_WBE_GAIN 0x320504 388 | #define AUD_DBX_SE_GAIN 0x320508 389 | #define AUD_DBX_RMS_WBE 0x32050c 390 | #define AUD_DBX_RMS_SE 0x320510 391 | #define AUD_DBX_SE_BYPASS 0x320514 392 | #define AUD_FAWDETCTL 0x320530 393 | #define AUD_FAWDETWINCTL 0x320534 394 | #define AUD_DEEMPHGAIN_R 0x320538 395 | #define AUD_DEEMPHNUMER1_R 0x32053c 396 | #define AUD_DEEMPHNUMER2_R 0x320540 397 | #define AUD_DEEMPHDENOM1_R 0x320544 398 | #define AUD_DEEMPHDENOM2_R 0x320548 399 | #define AUD_ERRLOGPERIOD_R 0x32054c 400 | #define AUD_ERRINTRPTTHSHLD1_R 0x320550 401 | #define AUD_ERRINTRPTTHSHLD2_R 0x320554 402 | #define AUD_ERRINTRPTTHSHLD3_R 0x320558 403 | #define AUD_NICAM_STATUS1 0x32055c 404 | #define AUD_NICAM_STATUS2 0x320560 405 | #define AUD_ERRLOG1 0x320564 406 | #define AUD_ERRLOG2 0x320568 407 | #define AUD_ERRLOG3 0x32056c 408 | #define AUD_DAC_BYPASS_L 0x320580 409 | #define AUD_DAC_BYPASS_R 0x320584 410 | #define AUD_DAC_BYPASS_CTL 0x320588 411 | #define AUD_CTL 0x32058c 412 | #define AUD_STATUS 0x320590 413 | #define AUD_VOL_CTL 0x320594 414 | #define AUD_BAL_CTL 0x320598 415 | #define AUD_START_TIMER 0x3205b0 416 | #define AUD_MODE_CHG_TIMER 0x3205b4 417 | #define AUD_POLYPH80SCALEFAC 0x3205b8 418 | #define AUD_DMD_RA_DDS 0x3205bc 419 | #define AUD_I2S_RA_DDS 0x3205c0 420 | #define AUD_RATE_THRES_DMD 0x3205d0 421 | #define AUD_RATE_THRES_I2S 0x3205d4 422 | #define AUD_RATE_ADJ1 0x3205d8 423 | #define AUD_RATE_ADJ2 0x3205dc 424 | #define AUD_RATE_ADJ3 0x3205e0 425 | #define AUD_RATE_ADJ4 0x3205e4 426 | #define AUD_RATE_ADJ5 0x3205e8 427 | #define AUD_APB_IN_RATE_ADJ 0x3205ec 428 | #define AUD_I2SCNTL 0x3205ec 429 | #define AUD_PHASE_FIX_CTL 0x3205f0 430 | #define AUD_PLL_PRESCALE 0x320600 431 | #define AUD_PLL_DDS 0x320604 432 | #define AUD_PLL_INT 0x320608 433 | #define AUD_PLL_FRAC 0x32060c 434 | #define AUD_PLL_JTAG 0x320620 435 | #define AUD_PLL_SPMP 0x320624 436 | #define AUD_AFE_12DB_EN 0x320628 437 | 438 | // Audio QAM Register Addresses 439 | #define AUD_PDF_DDS_CNST_BYTE2 0x320d01 440 | #define AUD_PDF_DDS_CNST_BYTE1 0x320d02 441 | #define AUD_PDF_DDS_CNST_BYTE0 0x320d03 442 | #define AUD_PHACC_FREQ_8MSB 0x320d2a 443 | #define AUD_PHACC_FREQ_8LSB 0x320d2b 444 | #define AUD_QAM_MODE 0x320d04 445 | 446 | /* 447 | * transport stream registers 448 | */ 449 | 450 | #define MO_TS_DMA 0x330000 // {64}RWp Transport stream downstream 451 | #define MO_TS_GPCNT 0x33C020 // {16}RO TS general purpose counter 452 | #define MO_TS_GPCNTRL 0x33C030 // {2}WO TS general purpose control 453 | #define MO_TS_DMACNTRL 0x33C040 // {6}RW TS DMA control 454 | #define MO_TS_XFR_STAT 0x33C044 // {1}RO TS transfer status 455 | #define MO_TS_LNGTH 0x33C048 // {12}RW TS line length 456 | 457 | #define TS_HW_SOP_CNTRL 0x33C04C 458 | #define TS_GEN_CNTRL 0x33C050 459 | #define TS_BD_PKT_STAT 0x33C054 460 | #define TS_SOP_STAT 0x33C058 461 | #define TS_FIFO_OVFL_STAT 0x33C05C 462 | #define TS_VALERR_CNTRL 0x33C060 463 | 464 | /* 465 | * VIP registers 466 | */ 467 | 468 | #define MO_VIPD_DMA 0x340000 // {64}RWp VIP downstream 469 | #define MO_VIPU_DMA 0x340008 // {64}RWp VIP upstream 470 | #define MO_VIPD_GPCNT 0x34C020 // {16}RO VIP down general purpose counter 471 | #define MO_VIPU_GPCNT 0x34C024 // {16}RO VIP up general purpose counter 472 | #define MO_VIPD_GPCNTRL 0x34C030 // {2}WO VIP down general purpose control 473 | #define MO_VIPU_GPCNTRL 0x34C034 // {2}WO VIP up general purpose control 474 | #define MO_VIP_DMACNTRL 0x34C040 // {6}RW VIP DMA control 475 | #define MO_VIP_XFR_STAT 0x34C044 // {1}RO VIP transfer status 476 | #define MO_VIP_CFG 0x340048 // VIP configuration 477 | #define MO_VIPU_CNTRL 0x34004C // VIP upstream control #1 478 | #define MO_VIPD_CNTRL 0x340050 // VIP downstream control #2 479 | #define MO_VIPD_LNGTH 0x340054 // VIP downstream line length 480 | #define MO_VIP_BRSTLN 0x340058 // VIP burst length 481 | #define MO_VIP_INTCNTRL 0x34C05C // VIP Interrupt Control 482 | #define MO_VIP_XFTERM 0x340060 // VIP transfer terminate 483 | 484 | /* 485 | * misc registers 486 | */ 487 | 488 | #define MO_M2M_DMA 0x350000 // {64}RWp Mem2Mem DMA Bfr 489 | #define MO_GP0_IO 0x350010 // {32}RW* GPIOoutput enablesdata I/O 490 | #define MO_GP1_IO 0x350014 // {32}RW* GPIOoutput enablesdata I/O 491 | #define MO_GP2_IO 0x350018 // {32}RW* GPIOoutput enablesdata I/O 492 | #define MO_GP3_IO 0x35001C // {32}RW* GPIO Mode/Ctrloutput enables 493 | #define MO_GPIO 0x350020 // {32}RW* GPIO I2C Ctrldata I/O 494 | #define MO_GPOE 0x350024 // {32}RW GPIO I2C Ctrloutput enables 495 | #define MO_GP_ISM 0x350028 // {16}WO GPIO Intr Sens/Pol 496 | 497 | #define MO_PLL_B 0x35C008 // {32}RW* PLL Control for ASB bus clks 498 | #define MO_M2M_CNT 0x35C024 // {32}RW Mem2Mem DMA Cnt 499 | #define MO_M2M_XSUM 0x35C028 // {32}RO M2M XOR-Checksum 500 | #define MO_CRC 0x35C02C // {16}RW CRC16 init/result 501 | #define MO_CRC_D 0x35C030 // {32}WO CRC16 new data in 502 | #define MO_TM_CNT_LDW 0x35C034 // {32}RO Timer : Counter low dword 503 | #define MO_TM_CNT_UW 0x35C038 // {16}RO Timer : Counter high word 504 | #define MO_TM_LMT_LDW 0x35C03C // {32}RW Timer : Limit low dword 505 | #define MO_TM_LMT_UW 0x35C040 // {32}RW Timer : Limit high word 506 | #define MO_PINMUX_IO 0x35C044 // {8}RW Pin Mux Control 507 | #define MO_TSTSEL_IO 0x35C048 // {2}RW Pin Mux Control 508 | #define MO_AFECFG_IO 0x35C04C // AFE configuration reg 509 | #define MO_DDS_IO 0x35C050 // DDS Increment reg 510 | #define MO_DDSCFG_IO 0x35C054 // DDS Configuration reg 511 | #define MO_SAMPLE_IO 0x35C058 // IRIn sample reg 512 | #define MO_SRST_IO 0x35C05C // Output system reset reg 513 | 514 | #define MO_INT1_MSK 0x35C060 // DMA RISC interrupt mask 515 | #define MO_INT1_STAT 0x35C064 // DMA RISC interrupt status 516 | #define MO_INT1_MSTAT 0x35C068 // DMA RISC interrupt masked status 517 | 518 | /* 519 | * i2c bus registers 520 | */ 521 | 522 | #define MO_I2C 0x368000 // I2C data/control 523 | #define MO_I2C_DIV (0xf<<4) 524 | #define MO_I2C_SYNC (1<<3) 525 | #define MO_I2C_W3B (1<<2) 526 | #define MO_I2C_SCL (1<<1) 527 | #define MO_I2C_SDA (1<<0) 528 | 529 | 530 | /* 531 | * general purpose host registers 532 | * 533 | * FIXME: tyops? s/0x35/0x38/ ?? 534 | */ 535 | 536 | #define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream 537 | #define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream 538 | #define MO_GPHSTU_CNTRL 0x380048 // Host upstream control #1 539 | #define MO_GPHSTD_CNTRL 0x38004C // Host downstream control #2 540 | #define MO_GPHSTD_LNGTH 0x380050 // Host downstream line length 541 | #define MO_GPHST_WSC 0x380054 // Host wait state control 542 | #define MO_GPHST_XFR 0x380058 // Host transfer control 543 | #define MO_GPHST_WDTH 0x38005C // Host interface width 544 | #define MO_GPHST_HDSHK 0x380060 // Host peripheral handshake 545 | #define MO_GPHST_MUX16 0x380064 // Host muxed 16-bit transfer parameters 546 | #define MO_GPHST_MODE 0x380068 // Host mode select 547 | 548 | #define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter 549 | #define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter 550 | #define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control 551 | #define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control 552 | #define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control 553 | #define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status 554 | #define MO_GPHST_SOFT_RST 0x38C06C // Host software reset 555 | 556 | /* 557 | * RISC instructions 558 | */ 559 | 560 | #define RISC_SYNC 0x80000000 561 | #define RISC_SYNC_ODD 0x80000000 562 | #define RISC_SYNC_EVEN 0x80000200 563 | #define RISC_RESYNC 0x80008000 564 | #define RISC_RESYNC_ODD 0x80008000 565 | #define RISC_RESYNC_EVEN 0x80008200 566 | #define RISC_WRITE 0x10000000 567 | #define RISC_WRITEC 0x50000000 568 | #define RISC_READ 0x90000000 569 | #define RISC_READC 0xA0000000 570 | #define RISC_JUMP 0x70000000 571 | #define RISC_SKIP 0x20000000 572 | #define RISC_WRITERM 0xB0000000 573 | #define RISC_WRITECM 0xC0000000 574 | #define RISC_WRITECR 0xD0000000 575 | #define RISC_IMM 0x00000001 576 | 577 | #define RISC_SOL 0x08000000 578 | #define RISC_EOL 0x04000000 579 | 580 | #define RISC_IRQ2 0x02000000 581 | #define RISC_IRQ1 0x01000000 582 | 583 | #define RISC_CNT_NONE 0x00000000 584 | #define RISC_CNT_INC 0x00010000 585 | #define RISC_CNT_RSVR 0x00020000 586 | #define RISC_CNT_RESET 0x00030000 587 | #define RISC_JMP_SRP 0x01 588 | 589 | /* 590 | * various constants 591 | */ 592 | 593 | // DMA 594 | /* Interrupt mask/status */ 595 | #define PCI_INT_VIDINT (1 << 0) 596 | #define PCI_INT_AUDINT (1 << 1) 597 | #define PCI_INT_TSINT (1 << 2) 598 | #define PCI_INT_VIPINT (1 << 3) 599 | #define PCI_INT_HSTINT (1 << 4) 600 | #define PCI_INT_TM1INT (1 << 5) 601 | #define PCI_INT_SRCDMAINT (1 << 6) 602 | #define PCI_INT_DSTDMAINT (1 << 7) 603 | #define PCI_INT_RISC_RD_BERRINT (1 << 10) 604 | #define PCI_INT_RISC_WR_BERRINT (1 << 11) 605 | #define PCI_INT_BRDG_BERRINT (1 << 12) 606 | #define PCI_INT_SRC_DMA_BERRINT (1 << 13) 607 | #define PCI_INT_DST_DMA_BERRINT (1 << 14) 608 | #define PCI_INT_IPB_DMA_BERRINT (1 << 15) 609 | #define PCI_INT_I2CDONE (1 << 16) 610 | #define PCI_INT_I2CRACK (1 << 17) 611 | #define PCI_INT_IR_SMPINT (1 << 18) 612 | #define PCI_INT_GPIO_INT0 (1 << 19) 613 | #define PCI_INT_GPIO_INT1 (1 << 20) 614 | 615 | #define SEL_BTSC 0x01 616 | #define SEL_EIAJ 0x02 617 | #define SEL_A2 0x04 618 | #define SEL_SAP 0x08 619 | #define SEL_NICAM 0x10 620 | #define SEL_FMRADIO 0x20 621 | 622 | // AUD_CTL 623 | #define AUD_INT_DN_RISCI1 (1 << 0) 624 | #define AUD_INT_UP_RISCI1 (1 << 1) 625 | #define AUD_INT_RDS_DN_RISCI1 (1 << 2) 626 | #define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ 627 | #define AUD_INT_UP_RISCI2 (1 << 5) 628 | #define AUD_INT_RDS_DN_RISCI2 (1 << 6) 629 | #define AUD_INT_DN_SYNC (1 << 12) 630 | #define AUD_INT_UP_SYNC (1 << 13) 631 | #define AUD_INT_RDS_DN_SYNC (1 << 14) 632 | #define AUD_INT_OPC_ERR (1 << 16) 633 | #define AUD_INT_BER_IRQ (1 << 20) 634 | #define AUD_INT_MCHG_IRQ (1 << 21) 635 | 636 | #define EN_BTSC_FORCE_MONO 0 637 | #define EN_BTSC_FORCE_STEREO 1 638 | #define EN_BTSC_FORCE_SAP 2 639 | #define EN_BTSC_AUTO_STEREO 3 640 | #define EN_BTSC_AUTO_SAP 4 641 | 642 | #define EN_A2_FORCE_MONO1 8 643 | #define EN_A2_FORCE_MONO2 9 644 | #define EN_A2_FORCE_STEREO 10 645 | #define EN_A2_AUTO_MONO2 11 646 | #define EN_A2_AUTO_STEREO 12 647 | 648 | #define EN_EIAJ_FORCE_MONO1 16 649 | #define EN_EIAJ_FORCE_MONO2 17 650 | #define EN_EIAJ_FORCE_STEREO 18 651 | #define EN_EIAJ_AUTO_MONO2 19 652 | #define EN_EIAJ_AUTO_STEREO 20 653 | 654 | #define EN_NICAM_FORCE_MONO1 32 655 | #define EN_NICAM_FORCE_MONO2 33 656 | #define EN_NICAM_FORCE_STEREO 34 657 | #define EN_NICAM_AUTO_MONO2 35 658 | #define EN_NICAM_AUTO_STEREO 36 659 | 660 | #define EN_FMRADIO_FORCE_MONO 24 661 | #define EN_FMRADIO_FORCE_STEREO 25 662 | #define EN_FMRADIO_AUTO_STEREO 26 663 | 664 | #define EN_NICAM_AUTO_FALLBACK 0x00000040 665 | #define EN_FMRADIO_EN_RDS 0x00000200 666 | #define EN_NICAM_TRY_AGAIN_BIT 0x00000400 667 | #define EN_DAC_ENABLE 0x00001000 668 | #define EN_I2SOUT_ENABLE 0x00002000 669 | #define EN_I2SIN_STR2DAC 0x00004000 670 | #define EN_I2SIN_ENABLE 0x00008000 671 | 672 | #define EN_DMTRX_SUMDIFF (0 << 7) 673 | #define EN_DMTRX_SUMR (1 << 7) 674 | #define EN_DMTRX_LR (2 << 7) 675 | #define EN_DMTRX_MONO (3 << 7) 676 | #define EN_DMTRX_BYPASS (1 << 11) 677 | 678 | // Video 679 | #define VID_CAPTURE_CONTROL 0x310180 680 | 681 | #define CX23880_CAP_CTL_CAPTURE_VBI_ODD (1<<3) 682 | #define CX23880_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) 683 | #define CX23880_CAP_CTL_CAPTURE_ODD (1<<1) 684 | #define CX23880_CAP_CTL_CAPTURE_EVEN (1<<0) 685 | 686 | #define VideoInputMux0 0x0 687 | #define VideoInputMux1 0x1 688 | #define VideoInputMux2 0x2 689 | #define VideoInputMux3 0x3 690 | #define VideoInputTuner 0x0 691 | #define VideoInputComposite 0x1 692 | #define VideoInputSVideo 0x2 693 | #define VideoInputOther 0x3 694 | 695 | #define Xtal0 0x1 696 | #define Xtal1 0x2 697 | #define XtalAuto 0x3 698 | 699 | #define VideoFormatAuto 0x0 700 | #define VideoFormatNTSC 0x1 701 | #define VideoFormatNTSCJapan 0x2 702 | #define VideoFormatNTSC443 0x3 703 | #define VideoFormatPAL 0x4 704 | #define VideoFormatPALB 0x4 705 | #define VideoFormatPALD 0x4 706 | #define VideoFormatPALG 0x4 707 | #define VideoFormatPALH 0x4 708 | #define VideoFormatPALI 0x4 709 | #define VideoFormatPALBDGHI 0x4 710 | #define VideoFormatPALM 0x5 711 | #define VideoFormatPALN 0x6 712 | #define VideoFormatPALNC 0x7 713 | #define VideoFormatPAL60 0x8 714 | #define VideoFormatSECAM 0x9 715 | 716 | #define VideoFormatAuto27MHz 0x10 717 | #define VideoFormatNTSC27MHz 0x11 718 | #define VideoFormatNTSCJapan27MHz 0x12 719 | #define VideoFormatNTSC44327MHz 0x13 720 | #define VideoFormatPAL27MHz 0x14 721 | #define VideoFormatPALB27MHz 0x14 722 | #define VideoFormatPALD27MHz 0x14 723 | #define VideoFormatPALG27MHz 0x14 724 | #define VideoFormatPALH27MHz 0x14 725 | #define VideoFormatPALI27MHz 0x14 726 | #define VideoFormatPALBDGHI27MHz 0x14 727 | #define VideoFormatPALM27MHz 0x15 728 | #define VideoFormatPALN27MHz 0x16 729 | #define VideoFormatPALNC27MHz 0x17 730 | #define VideoFormatPAL6027MHz 0x18 731 | #define VideoFormatSECAM27MHz 0x19 732 | 733 | #define NominalUSECAM 0x87 734 | #define NominalVSECAM 0x85 735 | #define NominalUNTSC 0xFE 736 | #define NominalVNTSC 0xB4 737 | 738 | #define NominalContrast 0xD8 739 | 740 | #define HFilterAutoFormat 0x0 741 | #define HFilterCIF 0x1 742 | #define HFilterQCIF 0x2 743 | #define HFilterICON 0x3 744 | 745 | #define VFilter2TapInterpolate 0 746 | #define VFilter3TapInterpolate 1 747 | #define VFilter4TapInterpolate 2 748 | #define VFilter5TapInterpolate 3 749 | #define VFilter2TapNoInterpolate 4 750 | #define VFilter3TapNoInterpolate 5 751 | #define VFilter4TapNoInterpolate 6 752 | #define VFilter5TapNoInterpolate 7 753 | 754 | #define ColorFormatRGB32 0x0000 755 | #define ColorFormatRGB24 0x0011 756 | #define ColorFormatRGB16 0x0022 757 | #define ColorFormatRGB15 0x0033 758 | #define ColorFormatYUY2 0x0044 759 | #define ColorFormatBTYUV 0x0055 760 | #define ColorFormatY8 0x0066 761 | #define ColorFormatRGB8 0x0077 762 | #define ColorFormatPL422 0x0088 763 | #define ColorFormatPL411 0x0099 764 | #define ColorFormatYUV12 0x00AA 765 | #define ColorFormatYUV9 0x00BB 766 | #define ColorFormatRAW 0x00EE 767 | #define ColorFormatBSWAP 0x0300 768 | #define ColorFormatWSWAP 0x0c00 769 | #define ColorFormatEvenMask 0x050f 770 | #define ColorFormatOddMask 0x0af0 771 | #define ColorFormatGamma 0x1000 772 | 773 | #define Interlaced 0x1 774 | #define NonInterlaced 0x0 775 | 776 | #define FieldEven 0x1 777 | #define FieldOdd 0x0 778 | 779 | #define TGReadWriteMode 0x0 780 | #define TGEnableMode 0x1 781 | 782 | #define DV_CbAlign 0x0 783 | #define DV_Y0Align 0x1 784 | #define DV_CrAlign 0x2 785 | #define DV_Y1Align 0x3 786 | 787 | #define DVF_Analog 0x0 788 | #define DVF_CCIR656 0x1 789 | #define DVF_ByteStream 0x2 790 | #define DVF_ExtVSYNC 0x4 791 | #define DVF_ExtField 0x5 792 | 793 | #define CHANNEL_VID_Y 0x1 794 | #define CHANNEL_VID_U 0x2 795 | #define CHANNEL_VID_V 0x3 796 | #define CHANNEL_VID_VBI 0x4 797 | #define CHANNEL_AUD_DN 0x5 798 | #define CHANNEL_AUD_UP 0x6 799 | #define CHANNEL_AUD_RDS_DN 0x7 800 | #define CHANNEL_MPEG_DN 0x8 801 | #define CHANNEL_VIP_DN 0x9 802 | #define CHANNEL_VIP_UP 0xA 803 | #define CHANNEL_HOST_DN 0xB 804 | #define CHANNEL_HOST_UP 0xC 805 | #define CHANNEL_FIRST 0x1 806 | #define CHANNEL_LAST 0xC 807 | 808 | #define GP_COUNT_CONTROL_NONE 0x0 809 | #define GP_COUNT_CONTROL_INC 0x1 810 | #define GP_COUNT_CONTROL_RESERVED 0x2 811 | #define GP_COUNT_CONTROL_RESET 0x3 812 | 813 | #define PLL_PRESCALE_BY_2 2 814 | #define PLL_PRESCALE_BY_3 3 815 | #define PLL_PRESCALE_BY_4 4 816 | #define PLL_PRESCALE_BY_5 5 817 | 818 | #define HLNotchFilter4xFsc 0 819 | #define HLNotchFilterSquare 1 820 | #define HLNotchFilter135NTSC 2 821 | #define HLNotchFilter135PAL 3 822 | 823 | #define NTSC_8x_SUB_CARRIER 28.63636E6 824 | #define PAL_8x_SUB_CARRIER 35.46895E6 825 | 826 | // Default analog settings 827 | #define DEFAULT_HUE_NTSC 0x00 828 | #define DEFAULT_BRIGHTNESS_NTSC 0x00 829 | #define DEFAULT_CONTRAST_NTSC 0x39 830 | #define DEFAULT_SAT_U_NTSC 0x7F 831 | #define DEFAULT_SAT_V_NTSC 0x5A 832 | 833 | #endif /* _CX88_REG_H_ */ 834 | -------------------------------------------------------------------------------- /cxadc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * cxadc - CX2388x ADC DMA driver for Linux, version 0.5 4 | * 5 | * Copyright (C) 2005-2007 Hew How Chee 6 | * Copyright (C) 2013-2015 Chad Page 7 | * Copyright (C) 2019-2024 Adam Sampson 8 | * Copyright (C) 2020-2022 Tony Anderson 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | */ 20 | 21 | #include "cx88-reg.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /* 35 | * From Linux 4.21, dma_alloc_coherent always returns zeroed memory, 36 | * and dma_zalloc_coherent was removed later. 37 | */ 38 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 21, 0) 39 | #define dma_zalloc_coherent dma_alloc_coherent 40 | #endif 41 | 42 | #define default_latency -1 43 | #define default_audsel -1 44 | #define default_vmux 1 45 | #define default_level 16 46 | #define default_tenbit 0 47 | #define default_tenxfsc 0 48 | #define default_sixdb 0 49 | #define default_crystal 28636363 50 | #define default_center_offset 8 51 | 52 | #define cx_read(reg) readl(ctd->mmio + ((reg) >> 2)) 53 | #define cx_write(reg, value) writel((value), ctd->mmio + ((reg) >> 2)) 54 | 55 | #define cx_err(fmt, ...) \ 56 | dev_err(&ctd->pci->dev, fmt, ##__VA_ARGS__) 57 | #define cx_info(fmt, ...) \ 58 | dev_info(&ctd->pci->dev, fmt, ##__VA_ARGS__) 59 | 60 | /* 64 Mbytes VBI DMA BUFF */ 61 | #define VBI_DMA_BUFF_SIZE (1024*1024*64) 62 | /* corresponds to 8192 DMA pages of 4k bytes */ 63 | #define MAX_DMA_PAGE (VBI_DMA_BUFF_SIZE/PAGE_SIZE) 64 | 65 | #define CLUSTER_BUFFER_SIZE 2048 66 | 67 | /* Must be a power of 2 */ 68 | #define IRQ_PERIOD_IN_PAGES (0x200000 >> PAGE_SHIFT) 69 | 70 | struct cxadc { 71 | /* linked list */ 72 | struct cxadc *next; 73 | /* device info */ 74 | struct cdev cdev; 75 | struct pci_dev *pci; 76 | unsigned int irq; 77 | unsigned int mem; 78 | unsigned int *mmio; 79 | struct kref refcnt; 80 | 81 | /* locking */ 82 | bool in_use; 83 | struct mutex lock; 84 | 85 | unsigned int risc_inst_buff_size; 86 | unsigned int *risc_inst_virt; 87 | dma_addr_t risc_inst_phy; 88 | 89 | wait_queue_head_t readQ; 90 | 91 | void *pgvec_virt[MAX_DMA_PAGE+1]; 92 | dma_addr_t pgvec_phy[MAX_DMA_PAGE+1]; 93 | 94 | atomic_t lgpcnt; 95 | int initial_page; 96 | /* device attributes */ 97 | int latency; 98 | int audsel; 99 | int vmux; 100 | int level; 101 | int tenbit; 102 | int tenxfsc; 103 | int sixdb; 104 | int crystal; 105 | int center_offset; 106 | }; 107 | 108 | /* 109 | * boiler plate for device attributes 110 | * show/store for latency 111 | */ 112 | 113 | static ssize_t mycxadc_latency_show(struct device *dev, 114 | struct device_attribute *attr, char *buf) 115 | { 116 | struct cxadc *mycxadc = dev_get_drvdata(dev); 117 | int len; 118 | 119 | len = sprintf(buf, "%d\n", mycxadc->latency); 120 | if (len <= 0) 121 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 122 | return len; 123 | } 124 | 125 | static ssize_t mycxadc_latency_store(struct device *dev, 126 | struct device_attribute *attr, const char *buf, size_t count) 127 | { 128 | int ret; 129 | struct cxadc *mycxadc = dev_get_drvdata(dev); 130 | 131 | ret = kstrtoint(buf, 10, &mycxadc->latency); 132 | return count; 133 | } 134 | 135 | /* 136 | * show/store for audsel 137 | */ 138 | 139 | static ssize_t mycxadc_audsel_show(struct device *dev, 140 | struct device_attribute *attr, char *buf) 141 | { 142 | struct cxadc *mycxadc = dev_get_drvdata(dev); 143 | int len; 144 | 145 | len = sprintf(buf, "%d\n", mycxadc->audsel); 146 | if (len <= 0) 147 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 148 | return len; 149 | } 150 | 151 | static ssize_t mycxadc_audsel_store(struct device *dev, 152 | struct device_attribute *attr, const char *buf, size_t count) 153 | { 154 | int ret; 155 | struct cxadc *mycxadc = dev_get_drvdata(dev); 156 | 157 | ret = kstrtoint(buf, 10, &mycxadc->audsel); 158 | return count; 159 | } 160 | 161 | /* 162 | * show/store for level 163 | */ 164 | 165 | static ssize_t mycxadc_level_show(struct device *dev, 166 | struct device_attribute *attr, char *buf) 167 | { 168 | struct cxadc *mycxadc = dev_get_drvdata(dev); 169 | int len; 170 | 171 | len = sprintf(buf, "%d\n", mycxadc->level); 172 | if (len <= 0) 173 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 174 | return len; 175 | } 176 | 177 | static ssize_t mycxadc_level_store(struct device *dev, 178 | struct device_attribute *attr, const char *buf, size_t count) 179 | { 180 | int ret; 181 | struct cxadc *mycxadc = dev_get_drvdata(dev); 182 | 183 | ret = kstrtoint(buf, 10, &mycxadc->level); 184 | return count; 185 | } 186 | 187 | /* 188 | * show/store for vmux 189 | */ 190 | 191 | static ssize_t mycxadc_vmux_show(struct device *dev, 192 | struct device_attribute *attr, char *buf) 193 | { 194 | struct cxadc *mycxadc = dev_get_drvdata(dev); 195 | int len; 196 | 197 | len = sprintf(buf, "%d\n", mycxadc->vmux); 198 | if (len <= 0) 199 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 200 | return len; 201 | } 202 | 203 | static ssize_t mycxadc_vmux_store(struct device *dev, 204 | struct device_attribute *attr, const char *buf, size_t count) 205 | { 206 | int ret; 207 | struct cxadc *mycxadc = dev_get_drvdata(dev); 208 | 209 | ret = kstrtoint(buf, 10, &mycxadc->vmux); 210 | return count; 211 | } 212 | 213 | /* 214 | * show/store for tenbit 215 | */ 216 | 217 | static ssize_t mycxadc_tenbit_show(struct device *dev, 218 | struct device_attribute *attr, char *buf) 219 | { 220 | struct cxadc *mycxadc = dev_get_drvdata(dev); 221 | int len; 222 | 223 | len = sprintf(buf, "%d\n", mycxadc->tenbit); 224 | if (len <= 0) 225 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 226 | return len; 227 | } 228 | 229 | static ssize_t mycxadc_tenbit_store(struct device *dev, 230 | struct device_attribute *attr, const char *buf, size_t count) 231 | { 232 | int ret; 233 | struct cxadc *mycxadc = dev_get_drvdata(dev); 234 | 235 | ret = kstrtoint(buf, 10, &mycxadc->tenbit); 236 | return count; 237 | } 238 | 239 | /* 240 | * show/store for tenfsc 241 | */ 242 | 243 | static ssize_t mycxadc_tenxfsc_show(struct device *dev, 244 | struct device_attribute *attr, char *buf) 245 | { 246 | struct cxadc *mycxadc = dev_get_drvdata(dev); 247 | int len; 248 | 249 | len = sprintf(buf, "%d\n", mycxadc->tenxfsc); 250 | if (len <= 0) 251 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 252 | return len; 253 | } 254 | 255 | static ssize_t mycxadc_tenxfsc_store(struct device *dev, 256 | struct device_attribute *attr, const char *buf, size_t count) 257 | { 258 | int ret; 259 | struct cxadc *mycxadc = dev_get_drvdata(dev); 260 | 261 | ret = kstrtoint(buf, 10, &mycxadc->tenxfsc); 262 | return count; 263 | } 264 | 265 | /* 266 | * show/store for sixdb 267 | */ 268 | 269 | static ssize_t mycxadc_sixdb_show(struct device *dev, 270 | struct device_attribute *attr, char *buf) 271 | { 272 | struct cxadc *mycxadc = dev_get_drvdata(dev); 273 | int len; 274 | 275 | len = sprintf(buf, "%d\n", mycxadc->sixdb); 276 | if (len <= 0) 277 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 278 | return len; 279 | } 280 | 281 | static ssize_t mycxadc_sixdb_store(struct device *dev, 282 | struct device_attribute *attr, const char *buf, size_t count) 283 | { 284 | int ret; 285 | struct cxadc *mycxadc = dev_get_drvdata(dev); 286 | 287 | ret = kstrtoint(buf, 10, &mycxadc->sixdb); 288 | return count; 289 | } 290 | 291 | /* 292 | * show/store for crystal 293 | */ 294 | 295 | static ssize_t mycxadc_crystal_show(struct device *dev, 296 | struct device_attribute *attr, char *buf) 297 | { 298 | struct cxadc *mycxadc = dev_get_drvdata(dev); 299 | int len; 300 | 301 | len = sprintf(buf, "%d\n", mycxadc->crystal); 302 | if (len <= 0) 303 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 304 | return len; 305 | } 306 | 307 | static ssize_t mycxadc_crystal_store(struct device *dev, 308 | struct device_attribute *attr, const char *buf, size_t count) 309 | { 310 | int ret; 311 | struct cxadc *mycxadc = dev_get_drvdata(dev); 312 | 313 | ret = kstrtoint(buf, 10, &mycxadc->crystal); 314 | return count; 315 | } 316 | 317 | /* 318 | * show/store for center_offset 319 | */ 320 | 321 | static ssize_t mycxadc_center_offset_show(struct device *dev, 322 | struct device_attribute *attr, char *buf) 323 | { 324 | struct cxadc *mycxadc = dev_get_drvdata(dev); 325 | int len; 326 | 327 | len = sprintf(buf, "%d\n", mycxadc->center_offset); 328 | if (len <= 0) 329 | dev_err(dev, "cxadc: Invalid sprintf len: %d\n", len); 330 | return len; 331 | } 332 | 333 | static ssize_t mycxadc_center_offset_store(struct device *dev, 334 | struct device_attribute *attr, const char *buf, size_t count) 335 | { 336 | int ret; 337 | struct cxadc *mycxadc = dev_get_drvdata(dev); 338 | 339 | ret = kstrtoint(buf, 10, &mycxadc->center_offset); 340 | return count; 341 | } 342 | 343 | static struct device_attribute dev_attr_latency = { 344 | .attr = { 345 | .name = "latency", 346 | .mode = 0664, 347 | }, 348 | .show = mycxadc_latency_show, 349 | .store = mycxadc_latency_store, 350 | }; 351 | 352 | static struct device_attribute dev_attr_audsel = { 353 | .attr = { 354 | .name = "audsel", 355 | .mode = 0664, 356 | }, 357 | .show = mycxadc_audsel_show, 358 | .store = mycxadc_audsel_store, 359 | }; 360 | 361 | static struct device_attribute dev_attr_vmux = { 362 | .attr = { 363 | .name = "vmux", 364 | .mode = 0664, 365 | }, 366 | .show = mycxadc_vmux_show, 367 | .store = mycxadc_vmux_store, 368 | }; 369 | 370 | static struct device_attribute dev_attr_level = { 371 | .attr = { 372 | .name = "level", 373 | .mode = 0664, 374 | }, 375 | .show = mycxadc_level_show, 376 | .store = mycxadc_level_store, 377 | }; 378 | 379 | static struct device_attribute dev_attr_tenbit = { 380 | .attr = { 381 | .name = "tenbit", 382 | .mode = 0664, 383 | }, 384 | .show = mycxadc_tenbit_show, 385 | .store = mycxadc_tenbit_store, 386 | }; 387 | 388 | static struct device_attribute dev_attr_tenxfsc = { 389 | .attr = { 390 | .name = "tenxfsc", 391 | .mode = 0664, 392 | }, 393 | .show = mycxadc_tenxfsc_show, 394 | .store = mycxadc_tenxfsc_store, 395 | }; 396 | 397 | static struct device_attribute dev_attr_sixdb = { 398 | .attr = { 399 | .name = "sixdb", 400 | .mode = 0664, 401 | }, 402 | .show = mycxadc_sixdb_show, 403 | .store = mycxadc_sixdb_store, 404 | }; 405 | 406 | static struct device_attribute dev_attr_crystal = { 407 | .attr = { 408 | .name = "crystal", 409 | .mode = 0664, 410 | }, 411 | .show = mycxadc_crystal_show, 412 | .store = mycxadc_crystal_store, 413 | }; 414 | 415 | static struct device_attribute dev_attr_center_offset = { 416 | .attr = { 417 | .name = "center_offset", 418 | .mode = 0664, 419 | }, 420 | .show = mycxadc_center_offset_show, 421 | .store = mycxadc_center_offset_store, 422 | }; 423 | 424 | static struct attribute *mycxadc_attrs[] = { 425 | &dev_attr_latency.attr, 426 | &dev_attr_audsel.attr, 427 | &dev_attr_vmux.attr, 428 | &dev_attr_level.attr, 429 | &dev_attr_tenbit.attr, 430 | &dev_attr_tenxfsc.attr, 431 | &dev_attr_sixdb.attr, 432 | &dev_attr_crystal.attr, 433 | &dev_attr_center_offset.attr, 434 | NULL 435 | }; 436 | 437 | static struct attribute_group mycxadc_group = { 438 | .name = "parameters", 439 | .attrs = mycxadc_attrs, 440 | }; 441 | 442 | /* 443 | * end boiler plate 444 | */ 445 | 446 | static struct cxadc *cxadcs; 447 | static unsigned int cxcount; 448 | /* 449 | * linux supports 32 devices per bus, 8 functions per device 450 | */ 451 | #define CXCOUNT_MAX 256 452 | 453 | static struct class *cxadc_class; 454 | static int cxadc_major; 455 | 456 | #define NUMBER_OF_CLUSTER_BUFFER 8 457 | #define CX_SRAM_BASE 0x180000 458 | 459 | #define CDT_BASE (CX_SRAM_BASE+0x1000) 460 | #define CLUSTER_BUFFER_BASE (CX_SRAM_BASE+0x4000) 461 | #define RISC_BUFFER_BASE (CX_SRAM_BASE+0x2000) 462 | #define RISC_INST_QUEUE (CX_SRAM_BASE+0x800) 463 | #define CHN24_CMDS_BASE 0x180100 464 | #define DMA_BUFFER_SIZE (256*1024) 465 | 466 | #define INTERRUPT_MASK 0x18888 467 | 468 | static struct pci_device_id cxadc_pci_tbl[] = { 469 | { 470 | .vendor = 0x14f1, 471 | .device = 0x8800, 472 | .subvendor = PCI_ANY_ID, 473 | .subdevice = PCI_ANY_ID, 474 | }, { 475 | /* --- end of list --- */ 476 | } 477 | }; 478 | 479 | /* turn off all DMA / IRQs */ 480 | static void disable_card(struct cxadc *ctd) 481 | { 482 | /* turn off pci interrupt */ 483 | cx_write(MO_PCI_INTMSK, 0); 484 | /* turn off interrupt */ 485 | cx_write(MO_VID_INTMSK, 0); 486 | cx_write(MO_VID_INTSTAT, ~(u32)0); 487 | /* disable fifo and risc */ 488 | cx_write(MO_VID_DMACNTRL, 0); 489 | /* disable risc */ 490 | cx_write(MO_DEV_CNTRL2, 0); 491 | } 492 | 493 | /* 494 | * numbuf - number of buffer 495 | * buffsize - buffer size in bytes 496 | * buffptr - CX sram start addr for buffer 497 | * e.g. 0x182000 as in example pg 2-62 of CX23880/1/2/3 datasheet 498 | * cdtptr - CX sram start addr for CDT 499 | * e.g. 0x181000 as in example pg 2-62 of CX23880/1/2/3 datasheet 500 | */ 501 | static void create_cdt_table(struct cxadc *ctd, 502 | unsigned int numbuf, unsigned int buffsize, 503 | unsigned int buffptr, unsigned int cdtptr) 504 | { 505 | int i; 506 | unsigned int pp, qq; 507 | 508 | pp = buffptr; 509 | qq = cdtptr; 510 | 511 | for (i = 0; i < numbuf; i++) { 512 | writel(pp, ctd->mmio+(qq>>2)); 513 | qq += 4; 514 | 515 | writel(0, ctd->mmio+(qq>>2)); /*not needed but we do it anyway*/ 516 | qq += 4; 517 | 518 | writel(0, ctd->mmio+(qq>>2)); /*not needed but we do it anyway*/ 519 | qq += 4; 520 | 521 | writel(0, ctd->mmio+(qq>>2)); /*not needed but we do it anyway*/ 522 | qq += 4; 523 | 524 | pp += buffsize; 525 | } 526 | 527 | } 528 | 529 | static void free_dma_buffer(struct cxadc *ctd) 530 | { 531 | int i; 532 | 533 | for (i = 0; i < MAX_DMA_PAGE; i++) { 534 | if (ctd->pgvec_virt[i]) 535 | dma_free_coherent(&ctd->pci->dev, PAGE_SIZE, ctd->pgvec_virt[i], ctd->pgvec_phy[i]); 536 | } 537 | } 538 | 539 | static int alloc_risc_inst_buffer(struct cxadc *ctd) 540 | { 541 | /* add 1 page for sync instruct and jump */ 542 | ctd->risc_inst_buff_size = (VBI_DMA_BUFF_SIZE/CLUSTER_BUFFER_SIZE)*8+PAGE_SIZE; 543 | ctd->risc_inst_virt = dma_alloc_coherent(&ctd->pci->dev, ctd->risc_inst_buff_size, &ctd->risc_inst_phy, GFP_KERNEL); 544 | if (ctd->risc_inst_virt == NULL) 545 | return -ENOMEM; 546 | memset(ctd->risc_inst_virt, 0, ctd->risc_inst_buff_size); 547 | 548 | cx_info("risc inst buff allocated at virt 0x%p phy 0x%lx size %u kbytes\n", 549 | ctd->risc_inst_virt, (unsigned long)ctd->risc_inst_phy, ctd->risc_inst_buff_size / 1024); 550 | 551 | return 0; 552 | } 553 | 554 | static void free_risc_inst_buffer(struct cxadc *ctd) 555 | { 556 | if (ctd->risc_inst_virt != NULL) 557 | dma_free_coherent(&ctd->pci->dev, ctd->risc_inst_buff_size, ctd->risc_inst_virt, ctd->risc_inst_phy); 558 | } 559 | 560 | static int make_risc_instructions(struct cxadc *ctd) 561 | { 562 | int page, wr; 563 | unsigned int dma_addr; 564 | unsigned int *pp = (unsigned int *)ctd->risc_inst_virt; 565 | 566 | /* The RISC program is just a long sequence of WRITEs that fill each DMA page in 567 | sequence. It begins with a SYNC and ends with a JUMP back to the first WRITE. */ 568 | 569 | *pp++ = RISC_SYNC|RISC_CNT_RESET; 570 | 571 | for (page = 0; page < MAX_DMA_PAGE; page++) { 572 | dma_addr = ctd->pgvec_phy[page]; 573 | 574 | /* Each WRITE is CLUSTER_BUFFER_SIZE bytes so each DMA page requires 575 | n = (PAGE_SIZE / CLUSTER_BUFFER_SIZE) WRITEs to fill it. */ 576 | 577 | /* Generate n - 1 WRITEs. */ 578 | for (wr = 0; wr < (PAGE_SIZE / CLUSTER_BUFFER_SIZE) - 1; wr++) { 579 | *pp++ = RISC_WRITE|CLUSTER_BUFFER_SIZE|RISC_SOL|RISC_EOL|RISC_CNT_NONE; 580 | *pp++ = dma_addr; 581 | dma_addr += CLUSTER_BUFFER_SIZE; 582 | } 583 | 584 | /* Generate the final write which may trigger side effects. */ 585 | *pp++ = RISC_WRITE|CLUSTER_BUFFER_SIZE|RISC_SOL|RISC_EOL| 586 | /* If this is the last DMA page, reset counter, otherwise increment it. */ 587 | (page == (MAX_DMA_PAGE - 1) ? RISC_CNT_RESET : RISC_CNT_INC)| 588 | /* If we've filled enough pages, trigger IRQ1. */ 589 | ((((page + 1) % IRQ_PERIOD_IN_PAGES) == 0) ? RISC_IRQ1 : 0); 590 | *pp++ = dma_addr; 591 | } 592 | 593 | *pp++ = RISC_JUMP; /* Jump back to first WRITE (+4 skips the SYNC command.) */ 594 | *pp++ = ctd->risc_inst_phy + 4; 595 | 596 | cx_info("end of risc inst 0x%p total size %lu kbyte\n", 597 | pp, (unsigned long)((char *)pp - (char *)ctd->risc_inst_virt) / 1024); 598 | return 0; 599 | } 600 | 601 | static int cxadc_char_open(struct inode *inode, struct file *file) 602 | { 603 | int minor = iminor(inode); 604 | struct cxadc *ctd = container_of(inode->i_cdev, struct cxadc, cdev); 605 | unsigned long longtenxfsc, longPLLboth, longPLLint; 606 | int PLLint, PLLfrac, PLLfin, SConv, rv; 607 | 608 | for (ctd = cxadcs; ctd != NULL; ctd = ctd->next) 609 | if (MINOR(ctd->cdev.dev) == minor) 610 | break; 611 | if (ctd == NULL) 612 | return -ENODEV; 613 | 614 | mutex_lock(&ctd->lock); 615 | if (ctd->in_use) { 616 | mutex_unlock(&ctd->lock); 617 | return -EBUSY; 618 | } 619 | 620 | kref_get(&ctd->refcnt); 621 | file->private_data = ctd; 622 | 623 | ctd->in_use = true; 624 | mutex_unlock(&ctd->lock); 625 | 626 | /* source select (see datasheet on how to change adc source) */ 627 | ctd->vmux &= 3;/* default vmux=1 */ 628 | /* pal-B */ 629 | cx_write(MO_INPUT_FORMAT, (ctd->vmux<<14)|(1<<13)|0x01|0x10|0x10000); 630 | 631 | /* capture 16 bit or 8 bit raw samples */ 632 | if (ctd->tenbit) 633 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(1<<5))); 634 | else 635 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(0<<5))); 636 | 637 | /* re-set the level, clock speed, and bit size */ 638 | 639 | if (ctd->level < 0) 640 | ctd->level = 0; 641 | if (ctd->level > 31) 642 | ctd->level = 31; 643 | /* control gain also bit 16 */ 644 | cx_write(MO_AGC_GAIN_ADJ4, (ctd->sixdb<<23)|(0<<22)|(0<<21)|(ctd->level<<16)|(0xff<<8)|(0x0<<0)); 645 | cx_write(MO_AGC_SYNC_TIP3, (0x1e48<<16)|(0xff<<8)|(ctd->center_offset)); 646 | 647 | if (ctd->tenxfsc < 10) { 648 | //old code for old parameter compatibility 649 | switch (ctd->tenxfsc) { 650 | case 0: 651 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 652 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 653 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 654 | break; 655 | case 1: 656 | /* clock speed equal to 1.25 x crystal speed, unmodified card = 35.8 mhz */ 657 | cx_write(MO_SCONV_REG, 131072*4/5); /* set SRC to 1.25x/10fsc */ 658 | cx_write(MO_PLL_REG, 0x01400000); /* set PLL to 1.25x/10fsc */ 659 | break; 660 | case 2: 661 | /* clock speed equal to ~1.4 x crystal speed, unmodified card = 40 mhz */ 662 | cx_write(MO_SCONV_REG, 131072*0.715909072483); 663 | cx_write(MO_PLL_REG, 0x0165965A); /* 40000000.1406459 */ 664 | break; 665 | default: 666 | /* if someone sets value out of range, default to crystal speed */ 667 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 668 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 669 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 670 | } 671 | } else { 672 | if (ctd->tenxfsc < 100) 673 | ctd->tenxfsc = ctd->tenxfsc * 1000000; //if number 11-99, conver to 11,000,000 to 99,000,000 674 | PLLint = ctd->tenxfsc/(ctd->crystal/40); //always use PLL_PRE of 5 (=64) 675 | longtenxfsc = (long)ctd->tenxfsc * 1000000; 676 | longPLLboth = (long)(longtenxfsc/(long)(ctd->crystal/40)); 677 | longPLLint = (long)PLLint * 1000000; 678 | PLLfrac = ((longPLLboth-longPLLint)*1048576)/1000000; 679 | PLLfin = ((PLLint+64)*1048576)+PLLfrac; 680 | if (PLLfin < 81788928) 681 | PLLfin = 81788928; // 81788928 lowest possible value 682 | if (PLLfin > 119537664) 683 | PLLfin = 119537664 ; //133169152 is highest possible value with PLL_PRE = 5 but above 119537664 may crash 684 | cx_write(MO_PLL_REG, PLLfin); 685 | //cx_write(MO_SCONV_REG, 131072 * (crystal / tenxfsc)); 686 | SConv = (long)(131072 * (long)ctd->crystal) / (long)ctd->tenxfsc; 687 | cx_write(MO_SCONV_REG, SConv); 688 | } 689 | 690 | 691 | /* capture 16 bit or 8 bit raw samples */ 692 | if (ctd->tenbit) 693 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(1<<5))); 694 | else 695 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(0<<5))); 696 | 697 | file->private_data = ctd; 698 | 699 | atomic_set(&ctd->lgpcnt, -1); 700 | cx_write(MO_PCI_INTMSK, 1); /* enable interrupt */ 701 | 702 | rv = wait_event_interruptible(ctd->readQ, atomic_read(&ctd->lgpcnt) != -1); 703 | if (rv) { 704 | cx_write(MO_PCI_INTMSK, 0); 705 | 706 | mutex_lock(&ctd->lock); 707 | ctd->in_use = false; 708 | mutex_unlock(&ctd->lock); 709 | 710 | return rv; 711 | } 712 | 713 | ctd->initial_page = atomic_read(&ctd->lgpcnt); 714 | 715 | return 0; 716 | } 717 | 718 | static int cxadc_char_release(struct inode *inode, struct file *file) 719 | { 720 | struct cxadc *ctd = file->private_data; 721 | 722 | cx_write(MO_PCI_INTMSK, 0); 723 | 724 | mutex_lock(&ctd->lock); 725 | ctd->in_use = false; 726 | mutex_unlock(&ctd->lock); 727 | return 0; 728 | } 729 | 730 | static ssize_t cxadc_char_read(struct file *file, char __user *tgt, 731 | size_t count, loff_t *offset) 732 | { 733 | struct cxadc *ctd = file->private_data; 734 | unsigned int rv = 0; 735 | unsigned int pnum; 736 | int gp_cnt; 737 | 738 | pnum = (*offset % VBI_DMA_BUFF_SIZE) / PAGE_SIZE; 739 | pnum += ctd->initial_page; 740 | pnum %= MAX_DMA_PAGE; 741 | 742 | gp_cnt = atomic_read(&ctd->lgpcnt); 743 | 744 | if ((pnum == gp_cnt) && (file->f_flags & O_NONBLOCK)) 745 | return rv; 746 | 747 | while (count) { 748 | while ((count > 0) && (pnum != gp_cnt)) { 749 | unsigned int len; 750 | 751 | /* handle partial pages for either reason */ 752 | len = (*offset % PAGE_SIZE) ? (PAGE_SIZE - (*offset % PAGE_SIZE)) : PAGE_SIZE; 753 | if (len > count) 754 | len = count; 755 | 756 | if (copy_to_user(tgt, ctd->pgvec_virt[pnum] + (*offset % PAGE_SIZE), len)) 757 | return -EFAULT; 758 | memset(ctd->pgvec_virt[pnum] + (*offset % PAGE_SIZE), 0, len); 759 | 760 | count -= len; 761 | tgt += len; 762 | *offset += len; 763 | rv += len; 764 | 765 | pnum = (*offset % VBI_DMA_BUFF_SIZE) / PAGE_SIZE; 766 | pnum += ctd->initial_page; 767 | pnum %= MAX_DMA_PAGE; 768 | } 769 | /* 770 | * adding code to allow level change during read, have tested, works with CAV capture 771 | * script i have been working on 772 | */ 773 | if (ctd->level < 0) 774 | ctd->level = 0; 775 | if (ctd->level > 31) 776 | ctd->level = 31; 777 | cx_write(MO_AGC_GAIN_ADJ4, (ctd->sixdb<<23)|(0<<22)|(0<<21)|(ctd->level<<16)|(0xff<<8)|(0x0<<0)); 778 | cx_write(MO_AGC_SYNC_TIP3, (0x1e48<<16)|(0xff<<8)|(ctd->center_offset)); 779 | 780 | if (count) { 781 | int rv2; 782 | 783 | if (file->f_flags & O_NONBLOCK) 784 | return rv; 785 | 786 | rv2 = wait_event_interruptible(ctd->readQ, atomic_read(&ctd->lgpcnt) != gp_cnt); 787 | if (rv2) { 788 | return rv ? rv : rv2; 789 | } 790 | 791 | gp_cnt = atomic_read(&ctd->lgpcnt); 792 | } 793 | }; 794 | 795 | return rv; 796 | } 797 | 798 | static long cxadc_char_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 799 | { 800 | struct cxadc *ctd = file->private_data; 801 | int ret = 0; 802 | 803 | if (cmd == 0x12345670) { 804 | int gain = arg; 805 | 806 | if (gain < 0) 807 | gain = 0; 808 | if (gain > 31) 809 | gain = 31; 810 | 811 | /* control gain also bit 16 */ 812 | cx_write(MO_AGC_GAIN_ADJ4, (ctd->sixdb<<23)|(0<<22)|(0<<21)|(gain<<16)|(0xff<<8)|(0x0<<0)); 813 | } 814 | 815 | return ret; 816 | } 817 | 818 | static const struct file_operations cxadc_char_fops = { 819 | .owner = THIS_MODULE, 820 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) 821 | .llseek = no_llseek, 822 | #endif 823 | .unlocked_ioctl = cxadc_char_ioctl, 824 | .open = cxadc_char_open, 825 | .release = cxadc_char_release, 826 | .read = cxadc_char_read, 827 | }; 828 | 829 | static irqreturn_t cxadc_irq(int irq, void *dev_id) 830 | { 831 | struct cxadc *ctd = dev_id; 832 | u32 allstat = cx_read(MO_VID_INTSTAT); 833 | u32 stat = cx_read(MO_VID_INTMSK); 834 | u32 astat = stat & allstat; 835 | u32 ostat = astat; 836 | 837 | if (ostat != 8 && allstat != 0 && ostat != 0) 838 | cx_info("interrupt stat 0x%x masked 0x%x\n", allstat, ostat); 839 | 840 | if (!astat) 841 | return IRQ_RETVAL(0); /* if no interrupt bit set we return */ 842 | 843 | if (astat & 0x8) { 844 | int gp_cnt = cx_read(MO_VBI_GPCNT); 845 | /* NB: MO_VBI_GPCNT is not guaranteed to be in-sync with resident pages. 846 | i.e. we can get gpcnt == 1 but the first page may not yet have been transferred 847 | to main memory. on the other hand, if an interrupt has occurred, we are guaranteed to have the page 848 | in main memory. so we only retrieve MO_VBI_GPCNT after an interrupt has occurred and then round 849 | it down to the last page that we know should have triggered an interrupt. */ 850 | gp_cnt &= ~(IRQ_PERIOD_IN_PAGES - 1); 851 | atomic_set(&ctd->lgpcnt, gp_cnt); 852 | wake_up_interruptible(&ctd->readQ); 853 | } 854 | cx_write(MO_VID_INTSTAT, ostat); 855 | 856 | return IRQ_RETVAL(1); 857 | } 858 | 859 | static int cxadc_probe(struct pci_dev *pci_dev, 860 | const struct pci_device_id *pci_id) 861 | { 862 | u32 i, intstat; 863 | struct cxadc *ctd; 864 | unsigned char revision, lat; 865 | int rc; 866 | unsigned int total_size; 867 | unsigned long longtenxfsc, longPLLboth, longPLLint; 868 | int PLLint, PLLfrac, PLLfin, SConv; 869 | 870 | if (pci_enable_device(pci_dev)) { 871 | dev_err(&pci_dev->dev, "cxadc: enable device failed\n"); 872 | return -EIO; 873 | } 874 | 875 | if (!request_mem_region(pci_resource_start(pci_dev, 0), 876 | pci_resource_len(pci_dev, 0), 877 | "cxadc")) { 878 | dev_err(&pci_dev->dev, "cxadc: request memory region failed\n"); 879 | return -EBUSY; 880 | } 881 | 882 | ctd = kmalloc(sizeof(*ctd), GFP_KERNEL); 883 | if (!ctd) { 884 | rc = -ENOMEM; 885 | dev_err(&pci_dev->dev, "cxadc: kmalloc failed\n"); 886 | goto fail0; 887 | } 888 | memset(ctd, 0, sizeof(*ctd)); 889 | 890 | if (cxcount >= CXCOUNT_MAX) { 891 | dev_err(&pci_dev->dev, "cxadc: only 256 cards are supported\n"); 892 | return -EBUSY; 893 | } 894 | 895 | ctd->pci = pci_dev; 896 | ctd->irq = pci_dev->irq; 897 | 898 | /* set default device attributes */ 899 | ctd->latency = default_latency; 900 | ctd->audsel = default_audsel; 901 | ctd->vmux = default_vmux; 902 | ctd->level = default_level; 903 | ctd->tenbit = default_tenbit; 904 | ctd->tenxfsc = default_tenxfsc; 905 | ctd->sixdb = default_sixdb; 906 | ctd->crystal = default_crystal; 907 | ctd->center_offset = default_center_offset; 908 | 909 | /* 910 | * creates our device attributs in 911 | * /sys/class/cxadc/cxadc[0-7]/device/parameters 912 | */ 913 | 914 | if (sysfs_create_group(&pci_dev->dev.kobj, &mycxadc_group)) { 915 | cx_err("cannot create sysfs attributes\n"); 916 | /* something is very wrong if we can't create sysfs files */ 917 | rc = -ENOMEM; 918 | goto fail1; 919 | } 920 | 921 | /* We can use cx_err/cx_info from here, now ctd has been set up. */ 922 | 923 | if (alloc_risc_inst_buffer(ctd)) { 924 | cx_err("cannot alloc risc buffer\n"); 925 | rc = -ENOMEM; 926 | goto fail1s; 927 | } 928 | 929 | for (i = 0; i < (MAX_DMA_PAGE+1); i++) { 930 | ctd->pgvec_virt[i] = 0; 931 | ctd->pgvec_phy[i] = 0; 932 | } 933 | 934 | total_size = 0; 935 | 936 | for (i = 0; i < MAX_DMA_PAGE; i++) { 937 | dma_addr_t dma_handle; 938 | 939 | ctd->pgvec_virt[i] = dma_zalloc_coherent(&ctd->pci->dev, PAGE_SIZE, 940 | &dma_handle, GFP_KERNEL); 941 | 942 | if (ctd->pgvec_virt[i] != 0) { 943 | ctd->pgvec_phy[i] = dma_handle; 944 | total_size += PAGE_SIZE; 945 | } else { 946 | cx_err("alloc dma buffer failed. index = %u\n", i); 947 | 948 | rc = -ENOMEM; 949 | goto fail1x; 950 | } 951 | 952 | } 953 | 954 | cx_info("total DMA size allocated = %u kb\n", total_size / 1024); 955 | 956 | make_risc_instructions(ctd); 957 | 958 | ctd->mem = pci_resource_start(pci_dev, 0); 959 | 960 | ctd->mmio = ioremap(pci_resource_start(pci_dev, 0), 961 | pci_resource_len(pci_dev, 0)); 962 | 963 | cx_info("MEM :%x MMIO :%p\n", ctd->mem, ctd->mmio); 964 | 965 | ctd->in_use = false; 966 | mutex_init(&ctd->lock); 967 | kref_init(&ctd->refcnt); 968 | 969 | init_waitqueue_head(&ctd->readQ); 970 | 971 | if (ctd->latency != -1) { 972 | cx_info("setting pci latency timer to %d\n", ctd->latency); 973 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, ctd->latency); 974 | } else { 975 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 255); 976 | } 977 | 978 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); 979 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat); 980 | 981 | cx_info("dev 0x%X (rev %d) at %02x:%02x.%x, ", 982 | pci_dev->device, revision, pci_dev->bus->number, 983 | PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); 984 | 985 | cx_info("irq: %d, latency: %d, mmio: 0x%x\n", 986 | ctd->irq, lat, ctd->mem); 987 | 988 | /* init hw */ 989 | pci_set_master(pci_dev); 990 | disable_card(ctd); 991 | 992 | /* we use 16kbytes of FIFO buffer */ 993 | create_cdt_table(ctd, NUMBER_OF_CLUSTER_BUFFER, CLUSTER_BUFFER_SIZE, 994 | CLUSTER_BUFFER_BASE, CDT_BASE); 995 | 996 | /* size of one buffer in qword -1 */ 997 | cx_write(MO_DMA24_CNT1, (CLUSTER_BUFFER_SIZE/8-1)); 998 | 999 | /* ptr to cdt */ 1000 | cx_write(MO_DMA24_PTR2, CDT_BASE); 1001 | /* size of cdt in qword */ 1002 | cx_write(MO_DMA24_CNT2, 2*NUMBER_OF_CLUSTER_BUFFER); 1003 | 1004 | /* clear interrupt */ 1005 | intstat = cx_read(MO_VID_INTSTAT); 1006 | cx_write(MO_VID_INTSTAT, intstat); 1007 | 1008 | cx_write(CHN24_CMDS_BASE, ctd->risc_inst_phy); /* working */ 1009 | cx_write(CHN24_CMDS_BASE+4, CDT_BASE); 1010 | cx_write(CHN24_CMDS_BASE+8, 2*NUMBER_OF_CLUSTER_BUFFER); 1011 | cx_write(CHN24_CMDS_BASE+12, RISC_INST_QUEUE); 1012 | 1013 | cx_write(CHN24_CMDS_BASE+16, 0x40); 1014 | 1015 | /* source select (see datasheet on how to change adc source) */ 1016 | ctd->vmux &= 3;/* default vmux=1 */ 1017 | /* pal-B */ 1018 | cx_write(MO_INPUT_FORMAT, (ctd->vmux<<14)|(1<<13)|0x01|0x10|0x10000); 1019 | cx_write(MO_OUTPUT_FORMAT, 0x0f); /* allow full range */ 1020 | 1021 | cx_write(MO_CONTR_BRIGHT, 0xff00); 1022 | 1023 | /* vbi lenght CLUSTER_BUFFER_SIZE/2 work */ 1024 | 1025 | /* 1026 | * no of byte transferred from peripehral to fifo 1027 | * if fifo buffer < this, it will still transfer this no of byte 1028 | * must be multiple of 8, if not go haywire? 1029 | */ 1030 | cx_write(MO_VBI_PACKET, (((CLUSTER_BUFFER_SIZE)<<17)|(2<<11))); 1031 | 1032 | /* raw mode & byte swap <<8 (3<<8=swap) */ 1033 | cx_write(MO_COLOR_CTRL, ((0xe)|(0xe<<4)|(0<<8))); 1034 | 1035 | /* capture 16 bit or 8 bit raw samples */ 1036 | if (ctd->tenbit) 1037 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(1<<5))); 1038 | else 1039 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(0<<5))); 1040 | 1041 | /* power down audio and chroma DAC+ADC */ 1042 | cx_write(MO_AFECFG_IO, 0x12); 1043 | 1044 | /* run risc */ 1045 | cx_write(MO_DEV_CNTRL2, 1<<5); 1046 | /* enable fifo and risc */ 1047 | cx_write(MO_VID_DMACNTRL, ((1<<7)|(1<<3))); 1048 | 1049 | rc = request_irq(ctd->irq, cxadc_irq, IRQF_SHARED, "cxadc", ctd); 1050 | if (rc < 0) { 1051 | cx_err("can't request irq (rc=%d)\n", rc); 1052 | goto fail1x; 1053 | } 1054 | 1055 | /* register devices */ 1056 | cdev_init(&ctd->cdev, &cxadc_char_fops); 1057 | if (cdev_add(&ctd->cdev, MKDEV(cxadc_major, cxcount), 1)) { 1058 | cx_err("failed to register device\n"); 1059 | rc = -EIO; 1060 | goto fail2; 1061 | } 1062 | 1063 | if (IS_ERR(device_create(cxadc_class, &pci_dev->dev, 1064 | MKDEV(cxadc_major, cxcount), NULL, 1065 | "cxadc%u", cxcount))) 1066 | dev_err(&pci_dev->dev, "can't create device\n"); 1067 | 1068 | cx_info("char dev register ok\n"); 1069 | 1070 | if (ctd->tenxfsc < 10) { 1071 | //old code for old parameter compatibility 1072 | switch (ctd->tenxfsc) { 1073 | case 0: 1074 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 1075 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 1076 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 1077 | break; 1078 | case 1: 1079 | /* clock speed equal to 1.25 x crystal speed, unmodified card = 35.8 mhz */ 1080 | cx_write(MO_SCONV_REG, 131072*4/5); /* set SRC to 1.25x/10fsc */ 1081 | cx_write(MO_PLL_REG, 0x01400000); /* set PLL to 1.25x/10fsc */ 1082 | break; 1083 | case 2: 1084 | /* clock speed equal to ~1.4 x crystal speed, unmodified card = 40 mhz */ 1085 | cx_write(MO_SCONV_REG, 131072*0.715909072483); 1086 | cx_write(MO_PLL_REG, 0x0165965A); /* 40000000.1406459 */ 1087 | break; 1088 | default: 1089 | /* if someone sets value out of range, default to crystal speed */ 1090 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 1091 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 1092 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 1093 | } 1094 | } else { 1095 | if (ctd->tenxfsc < 100) 1096 | ctd->tenxfsc = ctd->tenxfsc * 1000000; //if number 11-99, conver to 11,000,000 to 99,000,000 1097 | PLLint = ctd->tenxfsc/(ctd->crystal/40); //always use PLL_PRE of 5 (=64) 1098 | longtenxfsc = (long)ctd->tenxfsc * 1000000; 1099 | longPLLboth = (long)(longtenxfsc/(long)(ctd->crystal/40)); 1100 | longPLLint = (long)PLLint * 1000000; 1101 | PLLfrac = ((longPLLboth-longPLLint)*1048576)/1000000; 1102 | PLLfin = ((PLLint+64)*1048576)+PLLfrac; 1103 | if (PLLfin < 81788928) 1104 | PLLfin = 81788928; // 81788928 lowest possible value 1105 | if (PLLfin > 119537664) 1106 | PLLfin = 119537664 ; //133169152 is highest possible value with PLL_PRE = 5 but above 119537664 may crash 1107 | cx_write(MO_PLL_REG, PLLfin); 1108 | SConv = (long)(131072 * (long)ctd->crystal) / (long)ctd->tenxfsc; 1109 | cx_write(MO_SCONV_REG, SConv); 1110 | } 1111 | 1112 | 1113 | 1114 | /* set vbi agc */ 1115 | cx_write(MO_AGC_SYNC_SLICER, 0x0); 1116 | 1117 | if (ctd->level < 0) 1118 | ctd->level = 0; 1119 | if (ctd->level > 31) 1120 | ctd->level = 31; 1121 | 1122 | cx_write(MO_AGC_BACK_VBI, (0<<27)|(0<<26)|(1<<25)|(0x100<<16)|(0xfff<<0)); 1123 | /* control gain also bit 16 */ 1124 | cx_write(MO_AGC_GAIN_ADJ4, (ctd->sixdb<<23)|(0<<22)|(0<<21)|(ctd->level<<16)|(0xff<<8)|(0x0<<0)); 1125 | /* for 'cooked' composite */ 1126 | cx_write(MO_AGC_SYNC_TIP1, (0x1c0<<17)|(0x0<<9)|(0<<7)|(0xf<<0)); 1127 | cx_write(MO_AGC_SYNC_TIP2, (0x20<<17)|(0x0<<9)|(0<<7)|(0xf<<0)); 1128 | cx_write(MO_AGC_SYNC_TIP3, (0x1e48<<16)|(0xff<<8)|(ctd->center_offset)); 1129 | cx_write(MO_AGC_GAIN_ADJ1, (0xe0<<17)|(0xe<<9)|(0x0<<7)|(0x7<<0)); 1130 | cx_write(MO_AGC_GAIN_ADJ2, (0x20<<17)|(2<<7)|0x0f); 1131 | /* set gain of agc but not offset */ 1132 | cx_write(MO_AGC_GAIN_ADJ3, (0x28<<16)|(0x28<<8)|(0x50<<0)); 1133 | 1134 | if (ctd->audsel != -1) { 1135 | /* 1136 | * Pixelview PlayTVPro Ultracard specific 1137 | * select which output is redirected to audio output jack 1138 | * GPIO bit 3 is to enable 4052 , bit 0-1 4052's AB 1139 | */ 1140 | cx_write(MO_GP3_IO, 1<<25); /* use as 24 bit GPIO/GPOE */ 1141 | cx_write(MO_GP1_IO, 0x0b); 1142 | cx_write(MO_GP0_IO, ctd->audsel&3); 1143 | cx_info("audsel = %d\n", ctd->audsel&3); 1144 | } 1145 | 1146 | /* i2c sda/scl set to high and use software control */ 1147 | cx_write(MO_I2C, 3); 1148 | 1149 | /* hook into linked list */ 1150 | ctd->next = cxadcs; 1151 | cxadcs = ctd; 1152 | cxcount++; 1153 | 1154 | pci_set_drvdata(pci_dev, ctd); 1155 | cx_write(MO_VID_INTMSK, INTERRUPT_MASK); 1156 | 1157 | return 0; 1158 | 1159 | fail2: 1160 | free_irq(ctd->irq, ctd); 1161 | fail1x: 1162 | free_dma_buffer(ctd); 1163 | free_risc_inst_buffer(ctd); 1164 | fail1s: 1165 | sysfs_remove_group(&pci_dev->dev.kobj, &mycxadc_group); 1166 | fail1: 1167 | kfree(ctd); 1168 | fail0: 1169 | release_mem_region(pci_resource_start(pci_dev, 0), 1170 | pci_resource_len(pci_dev, 0)); 1171 | return rc; 1172 | } 1173 | 1174 | static void agc_reset(struct cxadc *ctd) 1175 | { 1176 | /* 1177 | * Set AGC registers back to their default values, as per the CX23833 1178 | * datasheet. This is in case you want to load cx8800 after unloading 1179 | * cxadc; cx8800 doesn't know about all of these. 1180 | */ 1181 | cx_write(MO_AGC_BACK_VBI, 1182 | (0xe0<<16)|0x555); 1183 | cx_write(MO_AGC_SYNC_SLICER, 1184 | (1<<21)|(1<<20)|(1<<19)|(0x4<<16)|(0x60<<8)|0x1c); 1185 | cx_write(MO_AGC_SYNC_TIP1, 1186 | (0x1c0<<17)|0x0f); 1187 | cx_write(MO_AGC_SYNC_TIP2, 1188 | (0x20<<17)|(1<<7)|0x3f); 1189 | cx_write(MO_AGC_SYNC_TIP3, 1190 | (0x1e48<<16)|(0xe0<<8)|0x40); 1191 | cx_write(MO_AGC_GAIN_ADJ1, 1192 | (0xe0<<17)|(0x0e<<9)|0x07); 1193 | cx_write(MO_AGC_GAIN_ADJ2, 1194 | (0x20<<17)|(2<<7)|0x0f); 1195 | cx_write(MO_AGC_GAIN_ADJ3, 1196 | (0x28<<16)|(0x38<<8)|0xc0); 1197 | cx_write(MO_AGC_GAIN_ADJ4, 1198 | (1<<22)|(1<<21)|(0xa<<16)|(0x2c<<8)|0x34); 1199 | } 1200 | 1201 | static void cxadc_remove(struct pci_dev *pci_dev) 1202 | { 1203 | struct cxadc *ctd = pci_get_drvdata(pci_dev); 1204 | /* struct cxadc *walk; */ 1205 | 1206 | disable_card(ctd); 1207 | 1208 | /* removes our sysfs files */ 1209 | sysfs_remove_group(&pci_dev->dev.kobj, &mycxadc_group); 1210 | agc_reset(ctd); 1211 | device_destroy(cxadc_class, MKDEV(cxadc_major, ctd->cdev.dev)); 1212 | cdev_del(&ctd->cdev); 1213 | 1214 | /* free resources */ 1215 | free_risc_inst_buffer(ctd); 1216 | free_irq(ctd->irq, ctd); 1217 | free_dma_buffer(ctd); 1218 | iounmap(ctd->mmio); 1219 | release_mem_region(pci_resource_start(pci_dev, 0), 1220 | pci_resource_len(pci_dev, 0)); 1221 | 1222 | /* remove from linked list */ 1223 | /* CAUSES KERNEL PANIC 1224 | * if (ctd == cxadcs) { 1225 | * cxadcs = NULL; 1226 | * } else { 1227 | * for (walk = cxadcs; walk->next != ctd; walk = walk->next) 1228 | * ; 1229 | * walk->next = ctd->next; 1230 | * } 1231 | */ 1232 | 1233 | cxcount--; 1234 | 1235 | cx_info("reset drv data\n"); 1236 | pci_set_drvdata(pci_dev, NULL); 1237 | cx_info("reset drv ok\n"); 1238 | kfree(ctd); 1239 | pci_disable_device(pci_dev); 1240 | } 1241 | 1242 | static int cxadc_suspend(struct pci_dev *pci_dev, pm_message_t state) 1243 | { 1244 | struct cxadc *ctd = pci_get_drvdata(pci_dev); 1245 | 1246 | disable_card(ctd); 1247 | agc_reset(ctd); 1248 | pci_save_state(pci_dev); 1249 | pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); 1250 | pci_disable_device(pci_dev); 1251 | return 0; 1252 | } 1253 | 1254 | static int cxadc_resume(struct pci_dev *pci_dev) 1255 | { 1256 | /* 1257 | * I have no idea what state this card is in after resume 1258 | * so re-init the hardware and re-sync our settings 1259 | */ 1260 | struct cxadc *ctd = pci_get_drvdata(pci_dev); 1261 | unsigned long longtenxfsc, longPLLboth, longPLLint; 1262 | int PLLint, PLLfrac, PLLfin, SConv, intstat, ret; 1263 | 1264 | ret = pci_enable_device(pci_dev); 1265 | pci_set_power_state(pci_dev, PCI_D0); 1266 | pci_restore_state(pci_dev); 1267 | /* init hw */ 1268 | pci_set_master(pci_dev); 1269 | disable_card(ctd); 1270 | 1271 | /* we use 16kbytes of FIFO buffer */ 1272 | create_cdt_table(ctd, NUMBER_OF_CLUSTER_BUFFER, CLUSTER_BUFFER_SIZE, 1273 | CLUSTER_BUFFER_BASE, CDT_BASE); 1274 | /* size of one buffer in qword -1 */ 1275 | cx_write(MO_DMA24_CNT1, (CLUSTER_BUFFER_SIZE/8-1)); 1276 | 1277 | /* ptr to cdt */ 1278 | cx_write(MO_DMA24_PTR2, CDT_BASE); 1279 | /* size of cdt in qword */ 1280 | cx_write(MO_DMA24_CNT2, 2*NUMBER_OF_CLUSTER_BUFFER); 1281 | 1282 | /* clear interrupt */ 1283 | intstat = cx_read(MO_VID_INTSTAT); 1284 | cx_write(MO_VID_INTSTAT, intstat); 1285 | 1286 | cx_write(CHN24_CMDS_BASE, ctd->risc_inst_phy); /* working */ 1287 | cx_write(CHN24_CMDS_BASE+4, CDT_BASE); 1288 | cx_write(CHN24_CMDS_BASE+8, 2*NUMBER_OF_CLUSTER_BUFFER); 1289 | cx_write(CHN24_CMDS_BASE+12, RISC_INST_QUEUE); 1290 | 1291 | cx_write(CHN24_CMDS_BASE+16, 0x40); 1292 | 1293 | /* source select (see datasheet on how to change adc source) */ 1294 | ctd->vmux &= 3;/* default vmux=1 */ 1295 | /* pal-B */ 1296 | cx_write(MO_INPUT_FORMAT, (ctd->vmux<<14)|(1<<13)|0x01|0x10|0x10000); 1297 | cx_write(MO_OUTPUT_FORMAT, 0x0f); /* allow full range */ 1298 | 1299 | cx_write(MO_CONTR_BRIGHT, 0xff00); 1300 | 1301 | /* vbi lenght CLUSTER_BUFFER_SIZE/2 work */ 1302 | 1303 | /* 1304 | * no of byte transferred from peripehral to fifo 1305 | * if fifo buffer < this, it will still transfer this no of byte 1306 | * must be multiple of 8, if not go haywire? 1307 | */ 1308 | cx_write(MO_VBI_PACKET, (((CLUSTER_BUFFER_SIZE)<<17)|(2<<11))); 1309 | 1310 | /* raw mode & byte swap <<8 (3<<8=swap) */ 1311 | cx_write(MO_COLOR_CTRL, ((0xe)|(0xe<<4)|(0<<8))); 1312 | 1313 | /* capture 16 bit or 8 bit raw samples */ 1314 | if (ctd->tenbit) 1315 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(1<<5))); 1316 | else 1317 | cx_write(MO_CAPTURE_CTRL, ((1<<6)|(3<<1)|(0<<5))); 1318 | 1319 | /* power down audio and chroma DAC+ADC */ 1320 | cx_write(MO_AFECFG_IO, 0x12); 1321 | 1322 | /* run risc */ 1323 | cx_write(MO_DEV_CNTRL2, 1<<5); 1324 | /* enable fifo and risc */ 1325 | cx_write(MO_VID_DMACNTRL, ((1<<7)|(1<<3))); 1326 | if (ctd->tenxfsc < 10) { 1327 | //old code for old parameter compatibility 1328 | switch (ctd->tenxfsc) { 1329 | case 0: 1330 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 1331 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 1332 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 1333 | break; 1334 | case 1: 1335 | /* clock speed equal to 1.25 x crystal speed, unmodified card = 35.8 mhz */ 1336 | cx_write(MO_SCONV_REG, 131072*4/5); /* set SRC to 1.25x/10fsc */ 1337 | cx_write(MO_PLL_REG, 0x01400000); /* set PLL to 1.25x/10fsc */ 1338 | break; 1339 | case 2: 1340 | /* clock speed equal to ~1.4 x crystal speed, unmodified card = 40 mhz */ 1341 | cx_write(MO_SCONV_REG, 131072*0.715909072483); 1342 | cx_write(MO_PLL_REG, 0x0165965A); /* 40000000.1406459 */ 1343 | break; 1344 | default: 1345 | /* if someone sets value out of range, default to crystal speed */ 1346 | /* clock speed equal to crystal speed, unmodified card = 28.6 mhz */ 1347 | cx_write(MO_SCONV_REG, 131072); /* set SRC to 8xfsc */ 1348 | cx_write(MO_PLL_REG, 0x11000000); /* set PLL to 1:1 */ 1349 | } 1350 | } else { 1351 | if (ctd->tenxfsc < 100) 1352 | ctd->tenxfsc = ctd->tenxfsc * 1000000; //if number 11-99, conver to 11,000,000 to 99,000,000 1353 | PLLint = ctd->tenxfsc/(ctd->crystal/40); //always use PLL_PRE of 5 (=64) 1354 | longtenxfsc = (long)ctd->tenxfsc * 1000000; 1355 | longPLLboth = (long)(longtenxfsc/(long)(ctd->crystal/40)); 1356 | longPLLint = (long)PLLint * 1000000; 1357 | PLLfrac = ((longPLLboth-longPLLint)*1048576)/1000000; 1358 | PLLfin = ((PLLint+64)*1048576)+PLLfrac; 1359 | if (PLLfin < 81788928) 1360 | PLLfin = 81788928; // 81788928 lowest possible value 1361 | if (PLLfin > 119537664) 1362 | PLLfin = 119537664 ; //133169152 is highest possible value with PLL_PRE = 5 but above 119537664 may crash 1363 | cx_write(MO_PLL_REG, PLLfin); 1364 | SConv = (long)(131072 * (long)ctd->crystal) / (long)ctd->tenxfsc; 1365 | cx_write(MO_SCONV_REG, SConv); 1366 | } 1367 | 1368 | /* set vbi agc */ 1369 | cx_write(MO_AGC_SYNC_SLICER, 0x0); 1370 | 1371 | if (ctd->level < 0) 1372 | ctd->level = 0; 1373 | if (ctd->level > 31) 1374 | ctd->level = 31; 1375 | 1376 | cx_write(MO_AGC_BACK_VBI, (0<<27)|(0<<26)|(1<<25)|(0x100<<16)|(0xfff<<0)); 1377 | /* control gain also bit 16 */ 1378 | cx_write(MO_AGC_GAIN_ADJ4, (ctd->sixdb<<23)|(0<<22)|(0<<21)|(ctd->level<<16)|(0xff<<8)|(0x0<<0)); 1379 | /* for 'cooked' composite */ 1380 | cx_write(MO_AGC_SYNC_TIP1, (0x1c0<<17)|(0x0<<9)|(0<<7)|(0xf<<0)); 1381 | cx_write(MO_AGC_SYNC_TIP2, (0x20<<17)|(0x0<<9)|(0<<7)|(0xf<<0)); 1382 | cx_write(MO_AGC_SYNC_TIP3, (0x1e48<<16)|(0xff<<8)|(ctd->center_offset)); 1383 | cx_write(MO_AGC_GAIN_ADJ1, (0xe0<<17)|(0xe<<9)|(0x0<<7)|(0x7<<0)); 1384 | cx_write(MO_AGC_GAIN_ADJ2, (0x20<<17)|(2<<7)|0x0f); 1385 | /* set gain of agc but not offset */ 1386 | cx_write(MO_AGC_GAIN_ADJ3, (0x28<<16)|(0x28<<8)|(0x50<<0)); 1387 | 1388 | if (ctd->audsel != -1) { 1389 | /* 1390 | * Pixelview PlayTVPro Ultracard specific 1391 | * select which output is redirected to audio output jack 1392 | * GPIO bit 3 is to enable 4052 , bit 0-1 4052's AB 1393 | */ 1394 | cx_write(MO_GP3_IO, 1<<25); /* use as 24 bit GPIO/GPOE */ 1395 | cx_write(MO_GP1_IO, 0x0b); 1396 | cx_write(MO_GP0_IO, ctd->audsel&3); 1397 | } 1398 | 1399 | /* i2c sda/scl set to high and use software control */ 1400 | cx_write(MO_I2C, 3); 1401 | 1402 | ret = request_irq(ctd->irq, cxadc_irq, IRQF_SHARED, "cxadc", ctd); 1403 | cx_write(MO_VID_INTMSK, INTERRUPT_MASK); 1404 | return 0; 1405 | } 1406 | 1407 | MODULE_DEVICE_TABLE(pci, cxadc_pci_tbl); 1408 | 1409 | static struct pci_driver cxadc_pci_driver = { 1410 | .name = "cxadc", 1411 | .id_table = cxadc_pci_tbl, 1412 | .probe = cxadc_probe, 1413 | .remove = cxadc_remove, 1414 | .shutdown = cxadc_remove, 1415 | .suspend = cxadc_suspend, 1416 | .resume = cxadc_resume, 1417 | }; 1418 | 1419 | static int __init cxadc_init_module(void) 1420 | { 1421 | int retval; 1422 | dev_t dev; 1423 | 1424 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) 1425 | cxadc_class = class_create("cxadc"); 1426 | #else 1427 | cxadc_class = class_create(THIS_MODULE, "cxadc"); 1428 | #endif 1429 | if (IS_ERR(cxadc_class)) { 1430 | retval = PTR_ERR(cxadc_class); 1431 | printk(KERN_ERR "cxadc: can't register cxadc class\n"); 1432 | goto err; 1433 | } 1434 | 1435 | retval = alloc_chrdev_region(&dev, 0, CXCOUNT_MAX, "cxadc"); 1436 | if (retval) { 1437 | printk(KERN_ERR "cxadc: can't register character device\n"); 1438 | goto err_class; 1439 | } 1440 | cxadc_major = MAJOR(dev); 1441 | 1442 | retval = pci_register_driver(&cxadc_pci_driver); 1443 | if (retval) { 1444 | printk(KERN_ERR "cxadc: can't register pci driver\n"); 1445 | goto err_unchr; 1446 | } 1447 | 1448 | printk(KERN_INFO "cxadc driver loaded\n"); 1449 | 1450 | return 0; 1451 | 1452 | err_unchr: 1453 | unregister_chrdev_region(dev, CXCOUNT_MAX); 1454 | err_class: 1455 | class_destroy(cxadc_class); 1456 | err: 1457 | return retval; 1458 | } 1459 | 1460 | static void __exit cxadc_cleanup_module(void) 1461 | { 1462 | pci_unregister_driver(&cxadc_pci_driver); 1463 | 1464 | unregister_chrdev_region(MKDEV(cxadc_major, 0), CXCOUNT_MAX); 1465 | 1466 | class_destroy(cxadc_class); 1467 | } 1468 | 1469 | module_init(cxadc_init_module); 1470 | module_exit(cxadc_cleanup_module); 1471 | 1472 | MODULE_DESCRIPTION("cx2388xx adc driver"); 1473 | MODULE_AUTHOR("Hew How Chee"); 1474 | MODULE_LICENSE("GPL"); 1475 | 1476 | -------------------------------------------------------------------------------- /cxadc.conf: -------------------------------------------------------------------------------- 1 | # blacklist cx88 modules 2 | blacklist cx88_alsa 3 | blacklist cx8800 4 | blacklist cx88xx 5 | blacklist cx8802 6 | blacklist cx88_blackbird 7 | blacklist cx2341x 8 | -------------------------------------------------------------------------------- /cxadc.rules: -------------------------------------------------------------------------------- 1 | KERNEL=="cxadc*", GROUP="video" 2 | 3 | # Rule for just cxadc0 to select vmux 0 4 | KERNEL=="cxadc0", SUBSYSTEM=="cxadc", ATTR{device/parameters/vmux}="1" 5 | -------------------------------------------------------------------------------- /cxadcnc.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=CXADC over netcat 3 | 4 | [Service] 5 | ExecStart=/bin/sh -c 'cat /dev/cxadc0 | netcat -l -k 4444' 6 | Restart=always 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="cxadc" 2 | PACKAGE_VERSION="0.1" 3 | BUILT_MODULE_NAME="cxadc" 4 | DEST_MODULE_LOCATION="/updates/dkms" 5 | AUTOINSTALL="YES" 6 | REMAKE_INITRD="NO" 7 | -------------------------------------------------------------------------------- /leveladj.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // this needs to be one over the ring buffer size to work 10 | #define bufsize (1024*1024*65) 11 | unsigned char buf[bufsize]; 12 | 13 | int readlen = 2048 * 1024; 14 | 15 | void set(char *name, char *device, int level) 16 | { 17 | char str[512]; 18 | 19 | sprintf(str, "/sys/class/cxadc/%s/device/parameters/%s", device, name); 20 | 21 | int fd = open(str, O_WRONLY); 22 | 23 | sprintf(str, "%d", level); 24 | write(fd, str, strlen(str) + 1); 25 | 26 | close(fd); 27 | } 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | 32 | FILE *syssfys; 33 | int fd; 34 | int level = 20; 35 | int go_on = 1; // 2 after going over 36 | char *device; 37 | char *device_path; 38 | char str[512]; 39 | 40 | int tenbit = 0; 41 | int tenxfsc = 0; 42 | 43 | int c; 44 | 45 | opterr = 0; 46 | device = (char *)malloc(64); 47 | device_path = (char *)malloc(128); 48 | sprintf(device, "cxadc0"); 49 | sprintf(device_path, "/dev/cxadc0"); 50 | 51 | while ((c = getopt(argc, argv, "d:bx")) != -1) { 52 | switch (c) { 53 | case 'b': 54 | tenbit = 1; 55 | break; 56 | case 'x': 57 | tenxfsc = 1; 58 | break; 59 | case 'd': 60 | if (strlen(optarg) <= 30) { 61 | sprintf(device_path, "/dev/%s", optarg); 62 | sprintf(device, "%s", optarg); 63 | } 64 | break; 65 | }; 66 | } 67 | 68 | fd = open(device_path, O_RDWR); 69 | if (fd <= 0) { 70 | fprintf(stderr, "%s not found\n", device_path); 71 | if (device_path) 72 | free(device_path); 73 | if (device) 74 | free(device); 75 | return -1; 76 | } 77 | close(fd); 78 | 79 | sprintf(str, "/sys/class/cxadc/%s/device/parameters/tenbit", device); 80 | syssfys = fopen(str, "r"); 81 | 82 | if (syssfys == NULL) { 83 | fprintf(stderr, "no sysfs paramerters\n"); 84 | if (device_path) 85 | free(device_path); 86 | if (device) 87 | free(device); 88 | return -1; 89 | } 90 | 91 | fscanf(syssfys, "%d", &tenbit); 92 | fclose(syssfys); 93 | 94 | sprintf(str, "/sys/class/cxadc/%s/device/parameters/tenxfsc", device); 95 | syssfys = fopen(str, "r"); 96 | 97 | if (syssfys == NULL) { 98 | fprintf(stderr, "no sysfs paramerters\n"); 99 | if (device_path) 100 | free(device_path); 101 | if (device) 102 | free(device); 103 | return -1; 104 | } 105 | 106 | fscanf(syssfys, "%d", &tenxfsc); 107 | fclose(syssfys); 108 | 109 | 110 | set("tenbit", device, tenbit); 111 | set("tenxfsc", device, tenxfsc); 112 | 113 | if (argc > optind) { 114 | level = atoi(argv[optind]); 115 | 116 | set("level", device, level); 117 | if (device_path) 118 | free(device_path); 119 | if (device) 120 | free(device); 121 | return 0; 122 | } 123 | 124 | while (go_on) { 125 | int over = 0; 126 | unsigned int low = tenbit ? 65535 : 255, high = 0; 127 | 128 | set("level", device, level); 129 | 130 | fd = open(device_path, O_RDWR); 131 | 132 | printf("testing level %d\n", level); 133 | 134 | // read a bit 135 | read(fd, buf, readlen); 136 | 137 | if (tenbit) { 138 | unsigned short *wbuf = (void *)buf; 139 | 140 | for (int i = 0; i < (readlen / 2) && (over < (readlen / 200000)); i++) { 141 | if (wbuf[i] < low) 142 | low = wbuf[i]; 143 | if (wbuf[i] > high) 144 | high = wbuf[i]; 145 | 146 | if ((wbuf[i] < 0x0800) || (wbuf[i] > 0xf800)) 147 | over++; 148 | 149 | // auto fail on 0 and 65535 150 | if ((wbuf[i] == 0) || (wbuf[i] == 0xffff)) 151 | over += (readlen / 50000); 152 | } 153 | } else { 154 | for (int i = 0; i < readlen && (over < (readlen / 100000)); i++) { 155 | if (buf[i] < low) 156 | low = buf[i]; 157 | if (buf[i] > high) 158 | high = buf[i]; 159 | 160 | if ((buf[i] < 0x08) || (buf[i] > 0xf8)) 161 | over++; 162 | 163 | // auto fail on 0 and 255 164 | if ((buf[i] == 0) || (buf[i] == 0xff)) 165 | over += (readlen / 50000); 166 | } 167 | } 168 | 169 | printf("low %d high %d clipped %d nsamp %d\n", (int)low, (int)high, over, readlen); 170 | 171 | if (over >= 20) { 172 | go_on = 2; 173 | } else { 174 | if (go_on == 2) 175 | go_on = 0; 176 | } 177 | 178 | if (go_on == 1) 179 | level++; 180 | else if (go_on == 2) 181 | level--; 182 | 183 | if ((level < 0) || (level > 31)) 184 | go_on = 0; 185 | close(fd); 186 | } 187 | if (device_path) 188 | free(device_path); 189 | if (device) 190 | free(device); 191 | return 0; 192 | } 193 | 194 | -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | Tony Anderson 2022 2 | tandersn@uw.edu 3 | 4 | Convenient scripts to manipulate cx card parameters. 5 | 6 | # To install: (Requires sudo to install) 7 | 8 | sudo ./inst_scripts 9 | 10 | inst_scripts = create simlinks to these scripts in /usr/bin. 11 | 12 | ## IMPORTANT: About capturing a CAV laserdisc 13 | 14 | CAV laserdiscs increase in gain as they play, in order to get a good quality capture, you have to adjust the CX card gain *down* as the disc plays (unless using the RMS amp). This means the physical amp must be set as such, that at the end of the disc, the CX card gain is about 1 or 2. If you were, to say, run level adjust at the beginning of the disc and adjust the amp until it landed at 1 or 2, after about 5 minutes the entire capture would be clipping. ⚡ 🔥 🤕 The **cxlvlcavdd** script is designed to capture the data and turn down the CX card gain as the capture progresses. 15 | 16 | The user which you are capturing with must have read-write access to the sysfs parameters. 17 | 18 | There's a few steps to using cxlvlcavdd: 19 | 20 | 1. Go to near the end of the disk, use leveladj and the gain POT of the amp to get leveladj to land at 1 or 2. 21 | 2. Go to the beginning of the disc and run leveladj again. 22 | 3. Finally, start the capture with `cxlvlcavdd CaptureFileName.r8`. 23 | 24 | 25 | ## Command Arguments 26 | 27 | Most commands now take a numerical argument corresponding to the card you want to apply the change to. Commands that previously had an argument, that argument is now the second argument. cxlvlcavdd assumes card 0 and does not take a numerical argument for the card. 28 | 29 | cx8fsc = set 8fsc sample rate mode on card 0. 1x crystal speed. 30 | 31 | cx10fsc = set 10fsc sample rate mode on card 1. 1.25x crystal speed (only recommended when also using 16bit mode). 32 | 33 | cx16bit = set cxadc to return unsigned 16 bit samples. 34 | 35 | cx6off = set sixdb to off. This is a 6db gain setting for the AFE. Kind of like a "loud" button on your stereo. 36 | 37 | cx6on = set sixdb to on. (see above). 38 | 39 | cx8bit = set cxadc to return unsigned 8 bit samples. 40 | 41 | cxvx0 = set cxadc to work off vmux0 42 | 43 | cxvx1 = set cxadc to work off vmux1 44 | 45 | cxvx2 = set cxadc to work off vmux2 46 | 47 | cxfreq = set cx card desired frequency, (same as echo 'somenumber' > tenxfsc. See main wiki for tenxfsc parameter). 48 | 49 | cxlevel = set cx card level 0-31. 50 | 51 | cxlvlcavdd = A capture script to use that adjusts the gain automatically. 52 | 53 | cxvalues = display current values of cx card module parameters. 54 | 55 | 56 | ## Example of CX Values with 4 Cards 57 | 58 | 59 | harry@Decode-Station:~$ cxvalues 60 | /sys/class/cxadc/cxadc0/device/parameters/sixdb 1 61 | /sys/class/cxadc/cxadc0/device/parameters/tenbit 0 62 | /sys/class/cxadc/cxadc0/device/parameters/audsel -1 63 | /sys/class/cxadc/cxadc0/device/parameters/center_offset 8 64 | /sys/class/cxadc/cxadc0/device/parameters/latency -1 65 | /sys/class/cxadc/cxadc0/device/parameters/crystal 28636363 66 | /sys/class/cxadc/cxadc0/device/parameters/vmux 2 67 | /sys/class/cxadc/cxadc0/device/parameters/tenxfsc 0 68 | /sys/class/cxadc/cxadc0/device/parameters/level 16 69 | /sys/class/cxadc/cxadc1/device/parameters/sixdb 1 70 | /sys/class/cxadc/cxadc1/device/parameters/tenbit 0 71 | /sys/class/cxadc/cxadc1/device/parameters/audsel -1 72 | /sys/class/cxadc/cxadc1/device/parameters/center_offset 8 73 | /sys/class/cxadc/cxadc1/device/parameters/latency -1 74 | /sys/class/cxadc/cxadc1/device/parameters/crystal 28636363 75 | /sys/class/cxadc/cxadc1/device/parameters/vmux 2 76 | /sys/class/cxadc/cxadc1/device/parameters/tenxfsc 0 77 | /sys/class/cxadc/cxadc1/device/parameters/level 16 78 | /sys/class/cxadc/cxadc2/device/parameters/sixdb 1 79 | /sys/class/cxadc/cxadc2/device/parameters/tenbit 0 80 | /sys/class/cxadc/cxadc2/device/parameters/audsel -1 81 | /sys/class/cxadc/cxadc2/device/parameters/center_offset 8 82 | /sys/class/cxadc/cxadc2/device/parameters/latency -1 83 | /sys/class/cxadc/cxadc2/device/parameters/crystal 28636363 84 | /sys/class/cxadc/cxadc2/device/parameters/vmux 2 85 | /sys/class/cxadc/cxadc2/device/parameters/tenxfsc 0 86 | /sys/class/cxadc/cxadc2/device/parameters/level 16 87 | /sys/class/cxadc/cxadc3/device/parameters/sixdb 1 88 | /sys/class/cxadc/cxadc3/device/parameters/tenbit 0 89 | /sys/class/cxadc/cxadc3/device/parameters/audsel -1 90 | /sys/class/cxadc/cxadc3/device/parameters/center_offset 8 91 | /sys/class/cxadc/cxadc3/device/parameters/latency -1 92 | /sys/class/cxadc/cxadc3/device/parameters/crystal 28636363 93 | /sys/class/cxadc/cxadc3/device/parameters/vmux 2 94 | /sys/class/cxadc/cxadc3/device/parameters/tenxfsc 0 95 | /sys/class/cxadc/cxadc3/device/parameters/level 16 96 | -------------------------------------------------------------------------------- /utils/cx10fsc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 1 > /sys/class/cxadc/cxadc$1/device/parameters/tenxfsc 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cx16bit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 1 > /sys/class/cxadc/cxadc$1/device/parameters/tenbit 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cx6off: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 0 > /sys/class/cxadc/cxadc$1/device/parameters/sixdb 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cx6on: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 1 > /sys/class/cxadc/cxadc$1/device/parameters/sixdb 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cx8bit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 0 > /sys/class/cxadc/cxadc$1/device/parameters/tenbit 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cx8fsc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 0 > /sys/class/cxadc/cxadc$1/device/parameters/tenxfsc 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cxfreq: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo $2 > /sys/class/cxadc/cxadc$1/device/parameters/tenxfsc 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cxlevel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo $2 > /sys/class/cxadc/cxadc$1/device/parameters/level 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cxlvlcavdd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ###################################### 3 | # 2021 tony anderson tandersn@uw.edu # 4 | ###################################### 5 | # Contrary to what the name implies, 6 | # this script does not use 'dd' but 7 | # simply reads and writes chunks of 8 | # binary data. Every 'CheckInterval' 9 | # forks itself and runs a leveladj 10 | # type block and adjusts the gain. 11 | # the actual time interval will be 12 | # sample rate / BUFSIZE * CheckInterval 13 | # this version of the script uses the 14 | # cx card 'level' paramter to adjust gain 15 | # the cx card has a lot of inherent noise 16 | # so cx gain levels above 10 can cause 17 | # interference with the captured signal 18 | 19 | import time 20 | import os 21 | import sys 22 | import datetime 23 | import numpy as np 24 | def read_in_chunks(file_object): 25 | global BUFSIZE 26 | while True: 27 | data = file_object.read(BUFSIZE) 28 | if not data: 29 | break 30 | yield data 31 | 32 | def child16(data): 33 | #syssyfsfile = open(r"/sys/module/cxadc/parameters/level","r") 34 | syssyfsfile = open(r"/sys/class/cxadc/cxadc0/device/parameters/level","r") 35 | GainLevel = int(syssyfsfile.read()) 36 | syssyfsfile.close() 37 | OldGainLevel = GainLevel 38 | data = bytes(data) # convert from list of ints into a byte array 39 | mv = memoryview(data) # convert to a memory view... 40 | mv = mv.cast('H') # treat every 2-bytes as a 16-bit value 41 | NumSampOver = 0 42 | NumSampGood = 0 43 | HighestSamp = 0 44 | LowestSamp = 45555 45 | GainAction = "Maintaining Gain: " 46 | for i in range(0, len(mv), 16): 47 | OneOfBuff = mv[i] 48 | if OneOfBuff > HighestSamp: 49 | HighestSamp = OneOfBuff 50 | if OneOfBuff < LowestSamp: 51 | LowestSamp = OneOfBuff 52 | if NumSampOver < BUFSIZE / 50000: 53 | if OneOfBuff < 514 or OneOfBuff > 64900: 54 | NumSampOver += 1 55 | else: 56 | NumSampOver = 999 57 | break 58 | if OneOfBuff > 62000 or OneOfBuff < 4000: 59 | NumSampGood += 1 60 | if NumSampOver >= 20: 61 | GainLevel -= 1 62 | if GainLevel < 0 : 63 | GainLevel = 0 64 | GainAction = "!!!Warning!!! Signal high, gain can't go low enough:" + str(GainLevel) + " " 65 | else: 66 | GainAction = "Lowering Gain: " + str(GainLevel) + " " 67 | elif NumSampGood < 0: #disabling this, not tested enough 68 | GainLevel += 1 69 | if GainLevel > 31 : 70 | GainLevel = 31 71 | GainAction = "!!!Warning!!! Signal quite low, gain maxed:" + str(GainLevel) + " " 72 | else: 73 | GainAction = "Raising Gain: " + str(GainLevel) + " " 74 | if OldGainLevel != GainLevel: 75 | #syssyfsfile = open(r"/sys/module/cxadc/parameters/level","w") 76 | syssyfsfile = open(r"/sys/class/cxadc/cxadc0/device/parameters/level","w") 77 | syssyfsfile.write(str(GainLevel)) 78 | syssyfsfile.close() 79 | 80 | now = datetime.datetime.now() 81 | print (now,":",GainAction,"Low:",LowestSamp," High:",HighestSamp," Over Threshold:",NumSampOver," ") 82 | os._exit(0) 83 | 84 | def child(data): 85 | #syssyfsfile = open(r"/sys/module/cxadc/parameters/level","r") 86 | syssyfsfile = open(r"/sys/class/cxadc/cxadc0/device/parameters/level","r") 87 | GainLevel = int(syssyfsfile.read()) 88 | syssyfsfile.close() 89 | OldGainLevel = GainLevel 90 | NumSampOver = 0 91 | NumSampGood = 0 92 | OneOfBuff = 0 93 | HighestSamp = 0 94 | LowestSamp = 215 95 | GainAction = "Maintaining Gain: " 96 | for OneOfBuff in data: 97 | if OneOfBuff > HighestSamp: 98 | HighestSamp = OneOfBuff 99 | if OneOfBuff < LowestSamp: 100 | LowestSamp = OneOfBuff 101 | if NumSampOver < BUFSIZE / 50000: 102 | if OneOfBuff < 8 or OneOfBuff >248: 103 | NumSampOver += 1 104 | else: 105 | NumSampOver = 999 106 | break 107 | if OneOfBuff > 225 or OneOfBuff < 15: 108 | NumSampGood += 1 109 | if NumSampOver >= 20: 110 | GainLevel -= 1 111 | if GainLevel < 0 : 112 | GainLevel = 0 113 | GainAction = "!!!Warning!!! Signal high, gain can't go low enough:" + str(GainLevel) + " " 114 | else: 115 | GainAction = "Lowering Gain: " + str(GainLevel) + " " 116 | elif NumSampGood < 0: #disabling this, not enough testing done 117 | GainLevel += 1 118 | if GainLevel > 31 : 119 | GainLevel = 31 120 | GainAction = "!!!Warning!!! Signal quite low, gain maxed:" + str(GainLevel) + " " 121 | else: 122 | GainAction = "Raising Gain: " + str(GainLevel) + " " 123 | if GainLevel != OldGainLevel: 124 | #syssyfsfile = open(r"/sys/module/cxadc/parameters/level","w") 125 | syssyfsfile = open(r"/sys/class/cxadc/cxadc0/device/parameters/level","w") 126 | syssyfsfile.write(str(GainLevel)) 127 | syssyfsfile.close() 128 | 129 | now = datetime.datetime.now() 130 | print (now,":",GainAction,"Low:",LowestSamp," High:",HighestSamp," Over Threshold:",NumSampOver," ") 131 | os._exit(0) 132 | 133 | ########################################################################################################## 134 | 135 | name_in = "/dev/cxadc0" 136 | name_out = sys.argv[1] 137 | CheckInterval = 150 #checking interval 125 = ~7sec@40msps 138 | CountVar = -150 139 | BUFSIZE = 2097152 140 | #syssyfsfile = open(r"/sys/module/cxadc/parameters/tenbit","r") 141 | syssyfsfile = open(r"/sys/class/cxadc/cxadc0/device/parameters/tenbit","r") 142 | tenbit = int(syssyfsfile.read()) 143 | syssyfsfile.close() 144 | val_compare = (2 ** ((tenbit+1)*8)) -1 145 | print ("using: /dev/cxadc0") 146 | print (val_compare,tenbit) 147 | in_fh = open(name_in, "rb") 148 | out_fh = open(name_out, "wb") 149 | for piece in read_in_chunks(in_fh): 150 | out_fh.write(piece) 151 | CountVar +=1 152 | if CountVar > CheckInterval: 153 | CountVar = 0 154 | newpid = os.fork() 155 | if newpid == 0: 156 | if tenbit == 1: 157 | child16(piece) 158 | if tenbit == 0: 159 | child(piece) 160 | 161 | in_fh.close() 162 | out_fh.close() 163 | print ("Fin") 164 | os._exit(0) 165 | -------------------------------------------------------------------------------- /utils/cxvalues: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ls /dev |grep cxadc |sed -e's/dev//g'|xargs -I % bash -c 'find /sys/class/cxadc/%/device/parameters|grep -v parameters$'|xargs -I % bash -c 'echo -n "% " && cat %' 3 | -------------------------------------------------------------------------------- /utils/cxvx0: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 0 > /sys/class/cxadc/cxadc$1/device/parameters/vmux 3 | cxvalues 4 | 5 | -------------------------------------------------------------------------------- /utils/cxvx1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 1 > /sys/class/cxadc/cxadc$1/device/parameters/vmux 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/cxvx2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 2 > /sys/class/cxadc/cxadc$1/device/parameters/vmux 3 | cxvalues 4 | -------------------------------------------------------------------------------- /utils/inst_scripts: -------------------------------------------------------------------------------- 1 | ls|grep cx |xargs -I % bash -c 'ln -s `pwd`/% /usr/bin/%' 2 | --------------------------------------------------------------------------------