Adding Peripheral Chip support
OverviewVideo capture card do capture video image, but also controls sound volume, sound mixing, tuning frequency, radio demodulation and so on. Extra electrical devices on card do these controls; we call these "peripheral chips". Peripheral chips are connected to Bt8x8 by two paths. One is I2C bus, and another is GPIO. In this page we describe how to add a support for peripheral chips.
I2C is small-scale bus designed for on-board chips connection. There is only one master node, and some (up to 126?) slave devices. Slave devices are identified by its I2C address. All data transaction is initiated by master node, sending "command" from master to slave, and receives "response" from slave to master. Slave nodes will not send any data spontaneously. Transfer rate is about 100kbps.
GPIO is synonym of "General Purpose Input/Output" and stand for electronical signals of Bt8x8 pins. These pins become output and input, according to GPIO_OUT_EN register. Usually, they are used for audio signal selection, muting control, multi-lingual sound selection, stereo/mono switching, and so on. Bt8x8 has 4-to-1 video signal multiplexer inside it, so GPIO is not used for video input switching for most cards.
Attaching I2C device to bt848x driverbt848x core driver probes I2C devices, set up I2C bus , and calls btx_init_card2() function in drv/bt848-cards.c at startup. At this point, following information is set:
|btv||bt848x device itself.|
|btv->nr||Instance number of bt848x device.|
|btv->cardid||PCI subsystem ID.|
|btv->card_type||Any of BTTV_* in bttv.h.
||Card intrinsic. All values are set from bt848x.conf.
See struct tvcard for members.
||Tuner status, including tuner type. See struct tuner in
In btx_init_card2(), peripheral chip support implementer should verify card type by using these info (Implementer can modify these info as he wants).
After card type verification, implementer call i2c_attach_device() function to register I2C device. This i2c_attach_device() requires I2C bus object (supplied by core driver) and I2C device profile (supplied by implementer). struct i2c_device_profile represents I2C device profile:
|char name||Name of the chip|
|uint8_t addr_l, addr_h||Range of possible I2C address.|
|int (*attach)(struct i2c_device *dev)||Pointer to callback function. It will be called when I2C device is attached.|
|int (*detach)(struct i2c_device *dev)||Pointer to callback function. It will be called when I2C device is detached.|
|int (*command)(struct i2c_device *dev, unsigned cmd, void *arg)||Pointer to callback function. It will be called when core driver wants to communicate with peripheral chip.|
|int idata||In bt848x driver, this value is device class of the chip. Class code is bit-OR of I2C_CLASS_* in bttv.h.|
|void *pdata||Free use for chip support routine.|
If i2c_attach_device() finds some I2C device that matches to supplied profile, "attach" callback function of profile is called.
"attach" callback function receives pointer to struct i2c_device, it represents chip instance. Callback function should allocate resources for the instance, and record it onto i2c_device structure:
|int id||Free use for chip support routine|
|void *data||Free use for chip support routine|
|struct i2c_bus *bus||Represents I2C bus object. In bt848x driver, bus->data points bt848x objects that bus belongs to.|
|uint8_t addr||I2C address of the chip (implementer should not modify this)|
|int (*attach)(struct i2c_device *dev)||Pointer to callback function. This is copy of i2c_device_profile, not used in fact.|
|int (*detach)(struct i2c_device *dev)||Pointer to callback function. It will be called when I2C device is detached. This is copied from i2c_device_profile, but implementer can rewrite it.|
|int (*command)(struct i2c_device *dev, unsigned cmd, void *arg)||Pointer to callback function. It will be called when core driver wants to communicate with peripheral chip. This is copied from i2c_device_profile, but implementer can rewrite it.|
Note: tuner_attach() function in drv/tuner.c is typical example of "attach" callback function
Communication with I2C device
After "attach" callback function returns, instance of peripheral chip is activated. Core driver calls "command" callback function in some situation. In such situation, I2C devices are selected by its class, and receives command. For example, tuner class device is sent command when user changes TV channel, but mixer class device is not sent.
|situation||device class that is called||possible command|
|Sound source is being switched.||Multiplexer class and fader class are selected.||AUDC_SET_INPUT|
|User request getting or setting sound attribute. That is, VIDIOCGAUDIO or VIDIOCSAUDIO ioctl is being processed.||Tuner class, IF demodulator class, multiplexer class and fader class are selected.||VIDIOCGAUDIO, VIDIOCSAUDIO|
|User request getting or setting tuner attribute, or setting tuning frequency. That is, VIDIOCGTUNER or VIDIOCSTUNER, VIDIOCSFREQ ioctl is being processed.||Tuner class is selected.||VIDIOCGTUNER, VIDIOCSTUNER, TUNER_SET_TV_FREQ, TUNER_SET_RADIO_FREQ|
"command" callback function takes three arguments. First is pointer to struct i2c_device, device info of the I2C device itself. Second is command code listed above table. Last is general-purpose data argument, it may be pointer to some data or merely integer, depending on command type. ioctl-derived command passes pointer. If argument is pointer, pointed data is in kernel space.
GPIO is simple I/O, not so difficult to use, but has many aspect.
Signal direction of each GPIO is configured by "gpio-mask" configuration parameter. If a bit is set to '1', associated GPIO pin is configured as output pin. If else, it is configured as input pin, and driver can read its value from GPIO_DATA register.
"audio-mux" configuration parameter determines sound source and GPIO output value. Whenever core driver set sound source, it set GPIO output value. So, if card is designed not to use GPIO for sound switching, "audio-mux" is meaningless. And this implicitly means "audio-mux" & "gpio-mask" should be "audio-mux".
Other pins other than "audio-mux" treats can be freely used by driver. Role of these pins varies among cards and even among models in a card. To get pin assignment information, try following method:
- Checking config/card-def.in
- Checking disabled part of drv/bt848-cards.c
- Reading source of recent version of BTTV or WDMDRV or other driver.
- Ask Google
- Ask Vendor
If pin assignment given, and right value is set to "gpio-mask" parameter according to signal direction, then do write by "btwrite(btv, value, BT848_GPIO_DATA" and read by "btread(btv, BT848_GPIO_DATA)" in code.
Adding GPIO manipulating routineTo add GPIO manipulating routine, implementer should do:
- Write your function in drv/bt848-cards.c
- Add "muxsel_hook" or "audio_hook" parameter in config/card-def.in
- Specify adequate "card-type" parameter.
Communicating with GPIO-wired device
Core driver calls hook function in some situation. Hook function should be statically linked to bt848x driver, and registered in card definition file as described above.
"muxsel_hook" is called when video channel is being changed by VIDIOCSCHAN ioctl. This function takes two arguments. First argument is pointer to struct bttv, driver object itself. Second argument is selection of video channel, ranges from 0 to 3.
"audio_hook" is called when audio setting is being altered by VIDIOCSAUDIO ioctl, or audio setting is queried by VIDIOCGAUDIO ioctl. This function takes three arguments. First argument is pointer to struct bttv, driver object itself. Second is pointer to struct video_audio object. Pointed object is in kernel space. Third argument is data direction. If this is 0, driver is responsible to store audio setting to object that second argument points. If this is 1, driver interprets audio setting from second argument and configure audio hardware.