-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Patrick Boettcher
authored and
Mauro Carvalho Chehab
committed
Oct 3, 2006
1 parent
879be74
commit efef99c
Showing
5 changed files
with
527 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 136cafbf4a024b52ba0a10627217f03cea9ff9f8 | ||
refs/heads/master: b7f54910ce018f93a74211136be46c09cefd80e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge | ||
* | ||
* 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, version 2. | ||
* | ||
* Copyright (C) 2005-6 DiBcom, SA | ||
*/ | ||
#ifndef _DIB0700_H_ | ||
#define _DIB0700_H_ | ||
|
||
#define DVB_USB_LOG_PREFIX "dib0700" | ||
#include "dvb-usb.h" | ||
|
||
#include "dib07x0.h" | ||
|
||
extern int dvb_usb_dib0700_debug; | ||
#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) | ||
#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) | ||
#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) | ||
#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) | ||
|
||
#define REQUEST_I2C_READ 0x2 | ||
#define REQUEST_I2C_WRITE 0x3 | ||
#define REQUEST_POLL_RC 0x4 | ||
#define REQUEST_JUMPRAM 0x8 | ||
#define REQUEST_SET_GPIO 0xC | ||
#define REQUEST_ENABLE_VIDEO 0xF | ||
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) | ||
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) | ||
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) | ||
|
||
struct dib0700_state { | ||
u8 channel_state; | ||
u8 mt2060_if1[2]; | ||
}; | ||
|
||
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); | ||
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); | ||
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); | ||
extern struct i2c_algorithm dib0700_i2c_algo; | ||
|
||
extern int dib0700_device_count; | ||
extern struct dvb_usb_device_properties dib0700_devices[]; | ||
extern struct usb_device_id dib0700_usb_id_table[]; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge | ||
* | ||
* 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, version 2. | ||
* | ||
* Copyright (C) 2005-6 DiBcom, SA | ||
*/ | ||
#include "dib0700.h" | ||
|
||
/* debug */ | ||
int dvb_usb_dib0700_debug; | ||
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); | ||
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); | ||
|
||
/* expecting rx buffer: request data[0] data[1] ... data[2] */ | ||
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) | ||
{ | ||
int status; | ||
|
||
deb_data(">>> "); | ||
debug_dump(tx,txlen,deb_data); | ||
|
||
status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), | ||
tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, | ||
USB_CTRL_GET_TIMEOUT); | ||
|
||
if (status != txlen) | ||
err("ep 0 write error (status = %d, len: %d)",status,txlen); | ||
|
||
return status < 0 ? status : 0; | ||
} | ||
|
||
/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ | ||
static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) | ||
{ | ||
u16 index, value; | ||
int status; | ||
|
||
if (txlen < 2) { | ||
err("tx buffer length is smaller than 2. Makes no sense."); | ||
return -EINVAL; | ||
} | ||
if (txlen > 4) { | ||
err("tx buffer length is larger than 4. Not supported."); | ||
return -EINVAL; | ||
} | ||
|
||
deb_data(">>> "); | ||
debug_dump(tx,txlen,deb_data); | ||
|
||
value = ((txlen - 2) << 8) | tx[1]; | ||
index = 0; | ||
if (txlen > 2) | ||
index |= (tx[2] << 8); | ||
if (txlen > 3) | ||
index |= tx[3]; | ||
|
||
/* think about swapping here */ | ||
value = le16_to_cpu(value); | ||
index = le16_to_cpu(index); | ||
|
||
status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], | ||
USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, | ||
USB_CTRL_GET_TIMEOUT); | ||
|
||
if (status < 0) | ||
err("ep 0 read error (status = %d)",status); | ||
|
||
deb_data("<<< "); | ||
debug_dump(rx,rxlen,deb_data); | ||
|
||
return status; /* length in case of success */ | ||
} | ||
|
||
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) | ||
{ | ||
u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) }; | ||
return dib0700_ctrl_wr(d,buf,3); | ||
} | ||
|
||
/* | ||
* I2C master xfer function | ||
*/ | ||
static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) | ||
{ | ||
struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
int i,len; | ||
u8 buf[255]; | ||
|
||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
return -EAGAIN; | ||
|
||
for (i = 0; i < num; i++) { | ||
/* fill in the address */ | ||
buf[1] = (msg[i].addr << 1); | ||
/* fill the buffer */ | ||
memcpy(&buf[2], msg[i].buf, msg[i].len); | ||
|
||
/* write/read request */ | ||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { | ||
buf[0] = REQUEST_I2C_READ; | ||
buf[1] |= 1; | ||
|
||
/* special thing in the current firmware: when length is zero the read-failed */ | ||
if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) | ||
break; | ||
|
||
msg[i+1].len = len; | ||
|
||
i++; | ||
} else { | ||
buf[0] = REQUEST_I2C_WRITE; | ||
if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0) | ||
break; | ||
} | ||
} | ||
|
||
mutex_unlock(&d->i2c_mutex); | ||
return i; | ||
} | ||
|
||
static u32 dib0700_i2c_func(struct i2c_adapter *adapter) | ||
{ | ||
return I2C_FUNC_I2C; | ||
} | ||
|
||
struct i2c_algorithm dib0700_i2c_algo = { | ||
.master_xfer = dib0700_i2c_xfer, | ||
.functionality = dib0700_i2c_func, | ||
}; | ||
|
||
static int dib0700_jumpram(struct usb_device *udev, u32 address) | ||
{ | ||
int ret, actlen; | ||
u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0, | ||
(address >> 24) & 0xff, | ||
(address >> 16) & 0xff, | ||
(address >> 8) & 0xff, | ||
address & 0xff }; | ||
|
||
if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { | ||
deb_fw("jumpram to 0x%x failed\n",address); | ||
return ret; | ||
} | ||
if (actlen != 8) { | ||
deb_fw("jumpram to 0x%x failed\n",address); | ||
return -EIO; | ||
} | ||
return 0; | ||
} | ||
|
||
int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) | ||
{ | ||
struct hexline hx; | ||
int pos = 0, ret, act_len; | ||
|
||
u8 buf[260]; | ||
|
||
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { | ||
deb_fwdata("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk); | ||
|
||
buf[0] = hx.len; | ||
buf[1] = hx.addr >> 8; | ||
buf[2] = hx.addr & 0xff; | ||
buf[3] = hx.type; | ||
memcpy(&buf[4],hx.data,hx.len); | ||
buf[4+hx.len] = hx.chk; | ||
|
||
ret = usb_bulk_msg(udev, | ||
usb_sndbulkpipe(udev, 0x01), | ||
buf, | ||
hx.len + 5, | ||
&act_len, | ||
1000); | ||
|
||
if (ret < 0) { | ||
err("firmware download failed at %d with %d",pos,ret); | ||
return ret; | ||
} | ||
} | ||
|
||
if (ret == 0) { | ||
/* start the firmware */ | ||
if ((ret = dib0700_jumpram(udev,0x70000000)) == 0) | ||
info("firmware started successfully."); | ||
} else | ||
ret = -EIO; | ||
|
||
return ret; | ||
} | ||
|
||
int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
{ | ||
struct dib0700_state *st = adap->dev->priv; | ||
u8 b[4]; | ||
|
||
b[0] = REQUEST_ENABLE_VIDEO; | ||
b[1] = 0x00; | ||
b[2] = (0x01 << 4); /* Master mode */ | ||
b[3] = 0x00; | ||
|
||
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); | ||
|
||
if (onoff) | ||
st->channel_state |= 1 << adap->id; | ||
else | ||
st->channel_state &= ~(1 << adap->id); | ||
|
||
b[2] |= st->channel_state; | ||
|
||
if (st->channel_state) /* if at least one channel is active */ | ||
b[1] = (0x01 << 4) | 0x00; | ||
|
||
deb_info("data for streaming: %x %x\n",b[1],b[2]); | ||
|
||
return dib0700_ctrl_wr(adap->dev, b, 4); | ||
} | ||
|
||
static int dib0700_probe(struct usb_interface *intf, | ||
const struct usb_device_id *id) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < dib0700_device_count; i++) | ||
if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) | ||
return 0; | ||
|
||
return -ENODEV; | ||
} | ||
|
||
static struct usb_driver dib0700_driver = { | ||
.name = "dvb_usb_dib0700", | ||
.probe = dib0700_probe, | ||
.disconnect = dvb_usb_device_exit, | ||
.id_table = dib0700_usb_id_table, | ||
}; | ||
|
||
/* module stuff */ | ||
static int __init dib0700_module_init(void) | ||
{ | ||
int result; | ||
info("loaded with support for %d different device-types", dib0700_device_count); | ||
if ((result = usb_register(&dib0700_driver))) { | ||
err("usb_register failed. Error number %d",result); | ||
return result; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static void __exit dib0700_module_exit(void) | ||
{ | ||
/* deregister this driver from the USB subsystem */ | ||
usb_deregister(&dib0700_driver); | ||
} | ||
|
||
module_init (dib0700_module_init); | ||
module_exit (dib0700_module_exit); | ||
|
||
MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | ||
MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); | ||
MODULE_VERSION("1.0"); | ||
MODULE_LICENSE("GPL"); |
Oops, something went wrong.