Commit 41b44e04 authored by Pierrick Hascoet's avatar Pierrick Hascoet Committed by Mauro Carvalho Chehab

[media] staging: as102: Initial import from Abilis

Changes by Devin Heitmueller:

Import the original Abilis Systems as102 driver.  The source is unmodified,
with the only changes I've made so far were that I created a Kconfig and
Makefile so that the code builds in a standard v4l-dvb tree.

This driver requires firmware (which Abilis has provided with redistribution
terms which will allow it to be bundled in the Linux distributions).   The
firmware can be downloaded from here:

Thanks to Rainer Miethling from PCTV Systems for working to get the driver
released (for use with the PCTV 74e) and Pierrick Hascoet from Abilis for
authoring the driver.

Changes by Piotr Chmura:
 - moved the driver from media/dvb to staging/media
 - removed Makefile/Kconfig - compilation fails in current tree

[snjw23@gmail.com: edited changelog]
Signed-off-by: default avatarPierrick Hascoet <pierrick.hascoet@abilis.com>
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarPiotr Chmura <chmooreck@poczta.onet.pl>
Signed-off-by: default avatarSylwester Nawrocki <snjw23@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 539b4695
config DVB_AS102
tristate "Abilis AS102 DVB receiver"
depends on DVB_CORE && USB && I2C && INPUT
help
Choose Y or M here if you have a device containing an AS102
To compile this driver as a module, choose M here
dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o
obj-$(CONFIG_DVB_AS102) += dvb-as102.o
EXTRA_CFLAGS += -DLINUX -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
/* header file for Usb device driver*/
#include "as102_drv.h"
#include "as102_fw.h"
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
#include "dvbdev.h"
#else
#warning >>> DVB_CORE not defined !!! <<<
#endif
int debug = 0;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)");
int dual_tuner = 0;
module_param_named(dual_tuner, dual_tuner, int, 0644);
MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner configuration (default: off)");
static int fw_upload = 1;
module_param_named(fw_upload, fw_upload, int, 0644);
MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
static int pid_filtering = 0;
module_param_named(pid_filtering, pid_filtering, int, 0644);
MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
static int ts_auto_disable = 0;
module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
int elna_enable = 1;
module_param_named(elna_enable, elna_enable, int, 0644);
MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#endif
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
static void as102_stop_stream(struct as102_dev_t *dev) {
struct as102_bus_adapter_t *bus_adap;
if (dev != NULL)
bus_adap = &dev->bus_adap;
else
return;
if (bus_adap->ops->stop_stream != NULL)
bus_adap->ops->stop_stream(dev);
if (ts_auto_disable) {
if (mutex_lock_interruptible(&dev->bus_adap.lock))
return;
if (as10x_cmd_stop_streaming(bus_adap) < 0) {
dprintk(debug, "as10x_cmd_stop_streaming failed\n");
}
mutex_unlock(&dev->bus_adap.lock);
}
}
static int as102_start_stream(struct as102_dev_t *dev) {
struct as102_bus_adapter_t *bus_adap;
int ret = -EFAULT;
if (dev != NULL)
bus_adap = &dev->bus_adap;
else
return ret;
if (bus_adap->ops->start_stream != NULL) {
ret = bus_adap->ops->start_stream(dev);
}
if (ts_auto_disable) {
if (mutex_lock_interruptible(&dev->bus_adap.lock))
return -EFAULT;
ret = as10x_cmd_start_streaming(bus_adap);
mutex_unlock(&dev->bus_adap.lock);
}
return ret;
}
static int as10x_pid_filter(struct as102_dev_t *dev,
int index, u16 pid, int onoff) {
struct as102_bus_adapter_t *bus_adap = &dev->bus_adap;
int ret = -EFAULT;
ENTER();
if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
dprintk(debug, "mutex_lock_interruptible(lock) failed !\n");
return -EBUSY;
}
switch(onoff) {
case 0:
ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
index, pid, ret);
break;
case 1:
{
struct as10x_ts_filter filter;
filter.type = TS_PID_TYPE_TS;
filter.idx = 0xFF;
filter.pid = pid;
ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
index, filter.idx, filter.pid, ret);
break;
}
}
mutex_unlock(&dev->bus_adap.lock);
LEAVE();
return ret;
}
static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) {
int ret = 0;
struct dvb_demux *demux = dvbdmxfeed->demux;
struct as102_dev_t *as102_dev = demux->priv;
ENTER();
if (mutex_lock_interruptible(&as102_dev->sem))
return -ERESTARTSYS;
if (pid_filtering) {
as10x_pid_filter(as102_dev,
dvbdmxfeed->index, dvbdmxfeed->pid, 1);
}
if (as102_dev->streaming++ == 0) {
ret = as102_start_stream(as102_dev);
}
mutex_unlock(&as102_dev->sem);
LEAVE();
return ret;
}
static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) {
struct dvb_demux *demux = dvbdmxfeed->demux;
struct as102_dev_t *as102_dev = demux->priv;
ENTER();
if (mutex_lock_interruptible(&as102_dev->sem))
return -ERESTARTSYS;
if (--as102_dev->streaming == 0) {
as102_stop_stream(as102_dev);
}
if (pid_filtering) {
as10x_pid_filter(as102_dev,
dvbdmxfeed->index, dvbdmxfeed->pid, 0);
}
mutex_unlock(&as102_dev->sem);
LEAVE();
return 0;
}
#endif
int as102_dvb_register(struct as102_dev_t *as102_dev) {
int ret = 0;
ENTER();
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
ret = dvb_register_adapter(&as102_dev->dvb_adap,
DEVICE_FULL_NAME,
THIS_MODULE,
#if defined(CONFIG_AS102_USB)
&as102_dev->bus_adap.usb_dev->dev
#elif defined(CONFIG_AS102_SPI)
&as102_dev->bus_adap.spi_dev->dev
#else
#error >>> dvb_register_adapter <<<
#endif
#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
, adapter_nr
#endif
);
if (ret < 0) {
err("%s: dvb_register_adapter() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}
as102_dev->dvb_dmx.priv = as102_dev;
as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
as102_dev->dvb_dmx.feednum = 256;
as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
DMX_SECTION_FILTERING;
as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
as102_dev->dvb_dmxdev.capabilities = 0;
if ((ret = dvb_dmx_init(&as102_dev->dvb_dmx)) < 0) {
err("%s: dvb_dmx_init() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}
ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
if (ret < 0) {
err("%s: dvb_dmxdev_init() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}
ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe);
if (ret < 0) {
err("%s: as102_dvb_register_frontend() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}
#endif
/* init bus mutex for token locking */
mutex_init(&as102_dev->bus_adap.lock);
/* init start / stop stream mutex */
mutex_init(&as102_dev->sem);
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
/*
* try to load as102 firmware. If firmware upload failed, we'll be
* able to upload it later.
*/
if (fw_upload)
try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
"firmware_class");
#endif
failed:
LEAVE();
/* FIXME: free dvb_XXX */
return ret;
}
void as102_dvb_unregister(struct as102_dev_t *as102_dev) {
ENTER();
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
/* unregister as102 frontend */
as102_dvb_unregister_fe(&as102_dev->dvb_fe);
/* unregister demux device */
dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
dvb_dmx_release(&as102_dev->dvb_dmx);
/* unregister dvb adapter */
dvb_unregister_adapter(&as102_dev->dvb_adap);
#endif
LEAVE();
}
static int __init as102_driver_init(void) {
int ret = 0;
ENTER();
/* register this driver with the low level subsystem */
#if defined(CONFIG_AS102_USB)
ret = usb_register(&as102_usb_driver);
if (ret)
err("usb_register failed (ret = %d)", ret);
#endif
#if defined(CONFIG_AS102_SPI)
ret = spi_register_driver(&as102_spi_driver);
if (ret)
printk(KERN_ERR "spi_register failed (ret = %d)", ret);
#endif
LEAVE();
return ret;
}
/*
* Mandatory function : Adds a special section to the module indicating
* where initialisation function is defined
*/
module_init(as102_driver_init);
/**
* \brief as102 driver exit point. This function is called when device has
* to be removed.
*/
static void __exit as102_driver_exit(void) {
ENTER();
/* deregister this driver with the low level bus subsystem */
#if defined(CONFIG_AS102_USB)
usb_deregister(&as102_usb_driver);
#endif
#if defined(CONFIG_AS102_SPI)
spi_unregister_driver(&as102_spi_driver);
#endif
LEAVE();
}
/*
* required function for unload: Adds a special section to the module
* indicating where unload function is defined
*/
module_exit(as102_driver_exit);
/* modinfo details */
MODULE_DESCRIPTION(DRIVER_FULL_NAME);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(CONFIG_AS102_USB)
#include <linux/usb.h>
extern struct usb_driver as102_usb_driver;
#endif
#if defined(CONFIG_AS102_SPI)
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/cdev.h>
extern struct spi_driver as102_spi_driver;
#endif
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dmxdev.h"
#endif
#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
#define DRIVER_NAME "as10x_usb"
extern int debug;
#define dprintk(debug, args...) \
do { if (debug) { \
printk(KERN_DEBUG "%s: ",__FUNCTION__); \
printk(args); \
} } while (0)
#ifdef TRACE
#define ENTER() printk(">> enter %s\n", __FUNCTION__)
#define LEAVE() printk("<< leave %s\n", __FUNCTION__)
#else
#define ENTER()
#define LEAVE()
#endif
#define AS102_DEVICE_MAJOR 192
#define AS102_USB_BUF_SIZE 512
#define MAX_STREAM_URB 32
#include "as10x_cmd.h"
#if defined(CONFIG_AS102_USB)
#include "as102_usb_drv.h"
#endif
#if defined(CONFIG_AS102_SPI)
#include "as10x_spi_drv.h"
#endif
struct as102_bus_adapter_t {
#if defined(CONFIG_AS102_USB)
struct usb_device *usb_dev;
#elif defined(CONFIG_AS102_SPI)
struct spi_device *spi_dev;
struct cdev cdev; /* spidev raw device */
struct timer_list timer;
struct completion xfer_done;
#endif
/* bus token lock */
struct mutex lock;
/* low level interface for bus adapter */
union as10x_bus_token_t {
#if defined(CONFIG_AS102_USB)
/* usb token */
struct as10x_usb_token_cmd_t usb;
#endif
#if defined(CONFIG_AS102_SPI)
/* spi token */
struct as10x_spi_token_cmd_t spi;
#endif
} token;
/* token cmd xfer id */
uint16_t cmd_xid;
/* as10x command and response for dvb interface*/
struct as10x_cmd_t *cmd, *rsp;
/* bus adapter private ops callback */
struct as102_priv_ops_t *ops;
};
struct as102_dev_t {
struct as102_bus_adapter_t bus_adap;
struct list_head device_entry;
struct kref kref;
unsigned long minor;
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
struct dvb_adapter dvb_adap;
struct dvb_frontend dvb_fe;
struct dvb_demux dvb_dmx;
struct dmxdev dvb_dmxdev;
#endif
/* demodulator stats */
struct as10x_demod_stats demod_stats;
/* signal strength */
uint16_t signal_strength;
/* bit error rate */
uint32_t ber;
/* timer handle to trig ts stream download */
struct timer_list timer_handle;
struct mutex sem;
dma_addr_t dma_addr;
void *stream;
int streaming;
struct urb *stream_urb[MAX_STREAM_URB];
};
int as102_dvb_register(struct as102_dev_t *dev);
void as102_dvb_unregister(struct as102_dev_t *dev);
#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe);
int as102_dvb_unregister_fe(struct dvb_frontend *dev);
#endif
/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
This diff is collapsed.
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include "as102_drv.h"
#include "as102_fw.h"
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
char as102_st_fw1[] = "as102_data1_st.hex";
char as102_st_fw2[] = "as102_data2_st.hex";
char as102_dt_fw1[] = "as102_data1_dt.hex";
char as102_dt_fw2[] = "as102_data2_dt.hex";
static unsigned char atohx(unsigned char *dst, char *src) {
unsigned char value = 0;
char msb = tolower(*src) - '0';
char lsb = tolower(*(src +1)) - '0';
if (msb > 9 )
msb -= 7;
if (lsb > 9 )
lsb -= 7;
*dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
return value;
}
/*
* Parse INTEL HEX firmware file to extract address and data.
*/
static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
unsigned char *data, int *dataLength,
unsigned char *addr_has_changed) {
int count = 0;
unsigned char *src, dst;
if (*fw_data++ != ':') {
printk(KERN_ERR "invalid firmware file\n");
return -EFAULT;
}
/* locate end of line */
for (src=fw_data; *src != '\n'; src += 2) {
atohx(&dst, src);
/* parse line to split addr / data */
switch (count) {
case 0:
*dataLength = dst;
break;
case 1:
addr[2] = dst;
break;
case 2:
addr[3] = dst;
break;
case 3:
/* check if data is an address */
if (dst == 0x04)
*addr_has_changed = 1;
else
*addr_has_changed = 0;
break;
case 4:
case 5:
if (*addr_has_changed) {
addr[(count - 4)] = dst;
} else {
data[(count - 4)] = dst;
}
break;
default:
data[(count - 4)] = dst;
break;
}
count++;
}
/* return read value + ':' + '\n' */
return ((count * 2) + 2);
}
static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
unsigned char *cmd,
const struct firmware *firmware) {
struct as10x_fw_pkt_t fw_pkt;
int total_read_bytes = 0, errno = 0;
unsigned char addr_has_changed = 0;
ENTER();
for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
int read_bytes = 0, data_len = 0;
/* parse intel hex line */
read_bytes = parse_hex_line(
(u8 *) (firmware->data + total_read_bytes),
fw_pkt.raw.address,
fw_pkt.raw.data,
&data_len,
&addr_has_changed);
if (read_bytes <= 0) {
goto error;
}
/* detect the end of file */
if ((total_read_bytes += read_bytes) == firmware->size) {
fw_pkt.u.request[0] = 0x00;
fw_pkt.u.request[1] = 0x03;
/* send EOF command */
if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap,(uint8_t *) &fw_pkt, 2, 0)) < 0)
goto error;
} else {
if (!addr_has_changed) {
/* prepare command to send */
fw_pkt.u.request[0] = 0x00;
fw_pkt.u.request[1] = 0x01;
data_len += sizeof(fw_pkt.u.request);
data_len += sizeof(fw_pkt.raw.address);
/* send cmd to device */
if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) &fw_pkt, data_len, 0)) < 0)
goto error;
}
}
}
error:
LEAVE();
return (errno == 0) ? total_read_bytes : errno;
}
int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) {
int errno = -EFAULT;
const struct firmware *firmware;
unsigned char *cmd_buf = NULL;
char *fw1, *fw2;
#if defined(CONFIG_AS102_USB)
struct usb_device *dev = bus_adap->usb_dev;
#endif
#if defined(CONFIG_AS102_SPI)
struct spi_device *dev = bus_adap->spi_dev;
#endif
ENTER();
/* select fw file to upload */
if (dual_tuner) {
fw1 = as102_dt_fw1;
fw2 = as102_dt_fw2;
} else {
fw1 = as102_st_fw1;
fw2 = as102_st_fw2;
}
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
/* allocate buffer to store firmware upload command and data */
if ((cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL)) == NULL) {
errno = -ENOMEM;
goto error;
}
/* request kernel to locate firmware file: part1 */
if ((errno = request_firmware(&firmware, fw1, &dev->dev)) < 0) {
printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
DRIVER_NAME, fw1);
goto error;
}
/* initiate firmware upload */
if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) {
printk(KERN_ERR "%s: error during firmware upload part1\n",
DRIVER_NAME);
goto error;
}
printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
DRIVER_NAME, fw1);
release_firmware(firmware);
/* wait for boot to complete */
mdelay(100);
/* request kernel to locate firmware file: part2 */
if ((errno = request_firmware(&firmware, fw2, &dev->dev)) < 0) {
printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
DRIVER_NAME, fw2);
goto error;
}
/* initiate firmware upload */
if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) {
printk(KERN_ERR "%s: error during firmware upload part2\n",
DRIVER_NAME);
goto error;
}
printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
DRIVER_NAME, fw2);
error:
/* free data buffer */
kfree(cmd_buf);
/* release firmware if needed */
if (firmware != NULL)
release_firmware(firmware);
#endif
LEAVE();
return errno;
}
#endif
/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define MAX_FW_PKT_SIZE 64
extern int dual_tuner;
#pragma pack(1)
struct as10x_raw_fw_pkt {
unsigned char address[4];
unsigned char data[MAX_FW_PKT_SIZE - 6];
};
struct as10x_fw_pkt_t {
union {
unsigned char request[2];
unsigned char length[2];
} u;
struct as10x_raw_fw_pkt raw;
};
#pragma pack()
#ifdef __KERNEL__
int as102_fw_upload(struct as102_bus_adapter_t *bus_adap);
#endif
/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
This diff is collapsed.
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/version.h>
#ifndef _AS102_USB_DRV_H_
#define _AS102_USB_DRV_H_
#define AS102_USB_DEVICE_TX_CTRL_CMD 0xF1
#define AS102_USB_DEVICE_RX_CTRL_CMD 0xF2
/* define these values to match the supported devices */
/* Abilis system: "TITAN" */
#define AS102_USB_DEVICE_VENDOR_ID 0x1BA6
#define AS102_USB_DEVICE_PID_0001 0x0001
/* PCTV Systems: PCTV picoStick (74e) */
#define DEVICE_FULL_NAME "PCTV Systems : PCTV picoStick (74e)"
#define PCTV_74E_USB_VID 0x2013
#define PCTV_74E_USB_PID 0x0246
extern struct file_operations as102_dev_fops;
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18))
void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs);
#else
void as102_urb_stream_irq(struct urb *urb);
#endif
struct as10x_usb_token_cmd_t {
/* token cmd */
struct as10x_cmd_t c;
/* token response */
struct as10x_cmd_t r;
};
#endif
/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
This diff is collapsed.
This diff is collapsed.
/**
\file as10x_cmd_cfg.c
\version $Id$
\author: S. Martinelli
----------------------------------------------------------------------------\n
(c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n
www.abilis.com \n
----------------------------------------------------------------------------\n
\brief AS10x API, configuration services
AS10x cmd management: build command buffer, send command through
selected port and wait for the response when required.
*/
#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */
#include <linux/kernel.h>
#include "as102_drv.h"
#elif defined(WIN32)
#if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) /* win32 ddk implementation */
#include "wdm.h"
#include "Device.h"
#include "endian_mgmt.h" /* FIXME */
#else /* win32 sdk implementation */
#include <windows.h>
#include "types.h"
#include "util.h"
#include "as10x_handle.h"
#include "endian_mgmt.h"
#endif
#else /* all other cases */
#include <string.h>
#include "types.h"
#include "util.h"
#include "as10x_handle.h"
#include "endian_mgmt.h" /* FIXME */
#endif /* __KERNEL__ */
#include "as10x_types.h"
#include "as10x_cmd.h"
/***************************/
/* FUNCTION DEFINITION */
/***************************/
/**
\brief send get context command to AS10x
\param phandle: pointer to AS10x handle
\param tag: context tag
\param pvalue: pointer where to store context value read
\return 0 when no error, < 0 in case of error.
\callgraph
*/
int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag,
uint32_t *pvalue)
{
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.context.req));
/* fill command */
pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
pcmd->body.context.req.tag = cpu_to_le16(tag);
pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
/* send command */
if(phandle->ops->xfer_cmd) {
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.context.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.context.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response: context command do not follow the common response */
/* structure -> specific handling response parse required */
error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
if(error == 0) {
/* Response OK -> get response data */
*pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32);
/* value returned is always a 32-bit value */
}
out:
LEAVE();
return(error);
}
/**
\brief send set context command to AS10x
\param phandle: pointer to AS10x handle
\param tag: context tag
\param value: value to set in context
\return 0 when no error, < 0 in case of error.
\callgraph
*/
int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag,
uint32_t value)
{
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd,(++phandle->cmd_xid),sizeof(pcmd->body.context.req));
/* fill command */
pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
/* pcmd->body.context.req.reg_val.mode initialization is not required */
pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value);
pcmd->body.context.req.tag = cpu_to_le16(tag);
pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
/* send command */
if(phandle->ops->xfer_cmd){
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.context.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.context.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response: context command do not follow the common response */
/* structure -> specific handling response parse required */
error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
out:
LEAVE();
return(error);
}
/**
\brief send eLNA change mode command to AS10x
\param phandle: pointer to AS10x handle
\param tag: context tag
\param mode: mode selected:
- ON : 0x0 => eLNA always ON
- OFF : 0x1 => eLNA always OFF
- AUTO : 0x2 => eLNA follow hysteresis parameters to be
ON or OFF
\return 0 when no error, < 0 in case of error.
\callgraph
*/
int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode)
{
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.cfg_change_mode.req));
/* fill command */
pcmd->body.cfg_change_mode.req.proc_id =
cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
pcmd->body.cfg_change_mode.req.mode = mode;
/* send command */
if(phandle->ops->xfer_cmd){
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.cfg_change_mode.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.cfg_change_mode.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response */
error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
out:
LEAVE();
return(error);
}
/**
\brief Parse context command response. Since this command does not follow
the common response, a specific parse function is required.
\param prsp: pointer to AS10x command response buffer
\param proc_id: id of the command
\return 0 when no error, < 0 in case of error.
ABILIS_RC_NOK
\callgraph
*/
int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) {
int err;
err = prsp->body.context.rsp.error;
if((err == 0) &&
(le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
return 0;
}
return AS10X_CMD_ERROR;
}
/**
\file as10x_cmd_stream.c
\version $Id$
\author: S. Martinelli
----------------------------------------------------------------------------\n
(c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n
www.abilis.com \n
----------------------------------------------------------------------------\n
\brief AS10x CMD, stream services
AS10x CMD management: build command buffer, send command through
selected port and wait for the response when required.
*/
#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */
#include <linux/kernel.h>
#include "as102_drv.h"
#elif defined(WIN32)
#if defined(DDK) /* win32 ddk implementation */
#include "wdm.h"
#include "Device.h"
#include "endian_mgmt.h" /* FIXME */
#else /* win32 sdk implementation */
#include <windows.h>
#include "types.h"
#include "util.h"
#include "as10x_handle.h"
#include "endian_mgmt.h"
#endif
#else /* all other cases */
#include <string.h>
#include "types.h"
#include "util.h"
#include "as10x_handle.h"
#include "endian_mgmt.h" /* FIXME */
#endif /* __KERNEL__ */
#include "as10x_cmd.h"
/**
\brief send add filter command to AS10x
\param phandle: pointer to AS10x handle
\param filter: TSFilter filter for DVB-T
\param pfilter_handle: pointer where to store filter handle
\return 0 when no error, < 0 in case of error.
\callgraph
*/
int as10x_cmd_add_PID_filter(as10x_handle_t* phandle,
struct as10x_ts_filter *filter) {
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.add_pid_filter.req));
/* fill command */
pcmd->body.add_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_SETFILTER);
pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
pcmd->body.add_pid_filter.req.stream_type = filter->type;
if(filter->idx < 16)
pcmd->body.add_pid_filter.req.idx = filter->idx;
else
pcmd->body.add_pid_filter.req.idx = 0xFF;
/* send command */
if(phandle->ops->xfer_cmd) {
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.add_pid_filter.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.add_pid_filter.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response */
error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
if(error == 0) {
/* Response OK -> get response data */
filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
}
out:
LEAVE();
return(error);
}
/**
\brief Send delete filter command to AS10x
\param phandle: pointer to AS10x handle
\param filter_handle: filter handle
\return 0 when no error, < 0 in case of error.
\callgraph
*/
int as10x_cmd_del_PID_filter(as10x_handle_t* phandle,
uint16_t pid_value)
{
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.del_pid_filter.req));
/* fill command */
pcmd->body.del_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
/* send command */
if(phandle->ops->xfer_cmd){
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.del_pid_filter.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.del_pid_filter.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response */
error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
out:
LEAVE();
return(error);
}
/**
\brief Send start streaming command to AS10x
\param phandle: pointer to AS10x handle
\return 0 when no error, < 0 in case of error. 
\callgraph
*/
int as10x_cmd_start_streaming(as10x_handle_t* phandle)
{
int error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.start_streaming.req));
/* fill command */
pcmd->body.start_streaming.req.proc_id =
cpu_to_le16(CONTROL_PROC_START_STREAMING);
/* send command */
if(phandle->ops->xfer_cmd){
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.start_streaming.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.start_streaming.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response */
error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
out:
LEAVE();
return(error);
}
/**
\brief Send stop streaming command to AS10x
\param phandle: pointer to AS10x handle
\return 0 when no error, < 0 in case of error. 
\callgraph
*/
int as10x_cmd_stop_streaming(as10x_handle_t* phandle)
{
int8_t error;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
pcmd = phandle->cmd;
prsp = phandle->rsp;
/* prepare command */
as10x_cmd_build(pcmd, (++phandle->cmd_xid),
sizeof(pcmd->body.stop_streaming.req));
/* fill command */
pcmd->body.stop_streaming.req.proc_id =
cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
/* send command */
if(phandle->ops->xfer_cmd){
error = phandle->ops->xfer_cmd(phandle,
(uint8_t *) pcmd,
sizeof(pcmd->body.stop_streaming.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.stop_streaming.rsp) + HEADER_SIZE);
}
else{
error = AS10X_CMD_ERROR;
}
if(error < 0) {
goto out;
}
/* parse response */
error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
out:
LEAVE();
return(error);
}
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef __KERNEL__
struct as102_bus_adapter_t;
struct as102_dev_t;
#define as10x_handle_t struct as102_bus_adapter_t
#include "as10x_cmd.h"
/* values for "mode" field */
#define REGMODE8 8
#define REGMODE16 16
#define REGMODE32 32
struct as102_priv_ops_t {
int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap,
unsigned char *buf, int buflen, int swap32);
int (*send_cmd) (struct as102_bus_adapter_t *bus_adap,
unsigned char *buf, int buflen);
int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap,
unsigned char *send_buf, int send_buf_len,
unsigned char *recv_buf, int recv_buf_len);
/*
int (*pid_filter) (struct as102_bus_adapter_t *bus_adap,
int index, u16 pid, int onoff);
*/
int (*start_stream) (struct as102_dev_t *dev);
void (*stop_stream) (struct as102_dev_t *dev);
int (*reset_target) (struct as102_bus_adapter_t *bus_adap);
int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode,
uint32_t rd_addr, uint16_t rd_len,
uint32_t wr_addr, uint16_t wr_len);
int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap,
unsigned char *recv_buf,
int recv_buf_len);
};
#endif
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _AS10X_TYPES_H_
#define _AS10X_TYPES_H_
#include "as10x_handle.h"
/*********************************/
/* MACRO DEFINITIONS */
/*********************************/
/* bandwidth constant values */
#define BW_5_MHZ 0x00
#define BW_6_MHZ 0x01
#define BW_7_MHZ 0x02
#define BW_8_MHZ 0x03
/* hierarchy priority selection values */
#define HIER_NO_PRIORITY 0x00
#define HIER_LOW_PRIORITY 0x01
#define HIER_HIGH_PRIORITY 0x02
/* constellation available values */
#define CONST_QPSK 0x00
#define CONST_QAM16 0x01
#define CONST_QAM64 0x02
#define CONST_UNKNOWN 0xFF
/* hierarchy available values */
#define HIER_NONE 0x00
#define HIER_ALPHA_1 0x01
#define HIER_ALPHA_2 0x02
#define HIER_ALPHA_4 0x03
#define HIER_UNKNOWN 0xFF
/* interleaving available values */
#define INTLV_NATIVE 0x00
#define INTLV_IN_DEPTH 0x01
#define INTLV_UNKNOWN 0xFF
/* code rate available values */
#define CODE_RATE_1_2 0x00
#define CODE_RATE_2_3 0x01
#define CODE_RATE_3_4 0x02
#define CODE_RATE_5_6 0x03
#define CODE_RATE_7_8 0x04
#define CODE_RATE_UNKNOWN 0xFF
/* guard interval available values */
#define GUARD_INT_1_32 0x00
#define GUARD_INT_1_16 0x01
#define GUARD_INT_1_8 0x02
#define GUARD_INT_1_4 0x03
#define GUARD_UNKNOWN 0xFF
/* transmission mode available values */
#define TRANS_MODE_2K 0x00
#define TRANS_MODE_8K 0x01
#define TRANS_MODE_4K 0x02
#define TRANS_MODE_UNKNOWN 0xFF
/* DVBH signalling available values */
#define TIMESLICING_PRESENT 0x01
#define MPE_FEC_PRESENT 0x02
/* tune state available */
#define TUNE_STATUS_NOT_TUNED 0x00
#define TUNE_STATUS_IDLE 0x01
#define TUNE_STATUS_LOCKING 0x02
#define TUNE_STATUS_SIGNAL_DVB_OK 0x03
#define TUNE_STATUS_STREAM_DETECTED 0x04
#define TUNE_STATUS_STREAM_TUNED 0x05
#define TUNE_STATUS_ERROR 0xFF
/* available TS FID filter types */
#define TS_PID_TYPE_TS 0
#define TS_PID_TYPE_PSI_SI 1
#define TS_PID_TYPE_MPE 2
/* number of echos available */
#define MAX_ECHOS 15
/* Context types */
#define CONTEXT_LNA 1010
#define CONTEXT_ELNA_HYSTERESIS 4003
#define CONTEXT_ELNA_GAIN 4004
#define CONTEXT_MER_THRESHOLD 5005
#define CONTEXT_MER_OFFSET 5006
#define CONTEXT_IR_STATE 7000
#define CONTEXT_TSOUT_MSB_FIRST 7004
#define CONTEXT_TSOUT_FALLING_EDGE 7005
/* Configuration modes */
#define CFG_MODE_ON 0
#define CFG_MODE_OFF 1
#define CFG_MODE_AUTO 2
#pragma pack(1)
struct as10x_tps {
uint8_t constellation;
uint8_t hierarchy;
uint8_t interleaving_mode;
uint8_t code_rate_HP;
uint8_t code_rate_LP;
uint8_t guard_interval;
uint8_t transmission_mode;
uint8_t DVBH_mask_HP;
uint8_t DVBH_mask_LP;
uint16_t cell_ID;
};
struct as10x_tune_args {
/* frequency */
uint32_t freq;
/* bandwidth */
uint8_t bandwidth;
/* hierarchy selection */
uint8_t hier_select;
/* constellation */
uint8_t constellation;
/* hierarchy */
uint8_t hierarchy;
/* interleaving mode */
uint8_t interleaving_mode;
/* code rate */
uint8_t code_rate;
/* guard interval */
uint8_t guard_interval;
/* transmission mode */
uint8_t transmission_mode;
};
struct as10x_tune_status {
/* tune status */
uint8_t tune_state;
/* signal strength */
int16_t signal_strength;
/* packet error rate 10^-4 */
uint16_t PER;
/* bit error rate 10^-4 */
uint16_t BER;
};
struct as10x_demod_stats {
/* frame counter */
uint32_t frame_count;
/* Bad frame counter */
uint32_t bad_frame_count;
/* Number of wrong bytes fixed by Reed-Solomon */
uint32_t bytes_fixed_by_rs;
/* Averaged MER */
uint16_t mer;
/* statistics calculation state indicator (started or not) */
uint8_t has_started;
};
struct as10x_ts_filter {
uint16_t pid; /** valid PID value 0x00 : 0x2000 */
uint8_t type; /** Red TS_PID_TYPE_<N> values */
uint8_t idx; /** index in filtering table */
};
struct as10x_register_value {
uint8_t mode;
union {
uint8_t value8; /* 8 bit value */
uint16_t value16; /* 16 bit value */
uint32_t value32; /* 32 bit value */
}u;
};
#pragma pack()
struct as10x_register_addr {
/* register addr */
uint32_t addr;
/* register mode access */
uint8_t mode;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment