├── .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 |
--------------------------------------------------------------------------------