Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (4647): Added module for DiB0700 based devices

Added module for DiB0700 based USB devices. This module is preliminary and
untested (because of a lack of test devices) but should work.
Further commits will be necessary to make it work properly.

Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

authored by

Patrick Boettcher and committed by
Mauro Carvalho Chehab
b7f54910 136cafbf

+526
+47
drivers/media/dvb/dvb-usb/dib0700.h
··· 1 + /* Linux driver for devices based on the DiBcom DiB0700 USB bridge 2 + * 3 + * This program is free software; you can redistribute it and/or modify it 4 + * under the terms of the GNU General Public License as published by the Free 5 + * Software Foundation, version 2. 6 + * 7 + * Copyright (C) 2005-6 DiBcom, SA 8 + */ 9 + #ifndef _DIB0700_H_ 10 + #define _DIB0700_H_ 11 + 12 + #define DVB_USB_LOG_PREFIX "dib0700" 13 + #include "dvb-usb.h" 14 + 15 + #include "dib07x0.h" 16 + 17 + extern int dvb_usb_dib0700_debug; 18 + #define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) 19 + #define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) 20 + #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) 21 + #define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) 22 + 23 + #define REQUEST_I2C_READ 0x2 24 + #define REQUEST_I2C_WRITE 0x3 25 + #define REQUEST_POLL_RC 0x4 26 + #define REQUEST_JUMPRAM 0x8 27 + #define REQUEST_SET_GPIO 0xC 28 + #define REQUEST_ENABLE_VIDEO 0xF 29 + // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) 30 + // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) 31 + // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) 32 + 33 + struct dib0700_state { 34 + u8 channel_state; 35 + u8 mt2060_if1[2]; 36 + }; 37 + 38 + extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); 39 + extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); 40 + extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); 41 + extern struct i2c_algorithm dib0700_i2c_algo; 42 + 43 + extern int dib0700_device_count; 44 + extern struct dvb_usb_device_properties dib0700_devices[]; 45 + extern struct usb_device_id dib0700_usb_id_table[]; 46 + 47 + #endif
+264
drivers/media/dvb/dvb-usb/dib0700_core.c
··· 1 + /* Linux driver for devices based on the DiBcom DiB0700 USB bridge 2 + * 3 + * This program is free software; you can redistribute it and/or modify it 4 + * under the terms of the GNU General Public License as published by the Free 5 + * Software Foundation, version 2. 6 + * 7 + * Copyright (C) 2005-6 DiBcom, SA 8 + */ 9 + #include "dib0700.h" 10 + 11 + /* debug */ 12 + int dvb_usb_dib0700_debug; 13 + module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); 14 + MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); 15 + 16 + /* expecting rx buffer: request data[0] data[1] ... data[2] */ 17 + static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) 18 + { 19 + int status; 20 + 21 + deb_data(">>> "); 22 + debug_dump(tx,txlen,deb_data); 23 + 24 + status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), 25 + tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, 26 + USB_CTRL_GET_TIMEOUT); 27 + 28 + if (status != txlen) 29 + err("ep 0 write error (status = %d, len: %d)",status,txlen); 30 + 31 + return status < 0 ? status : 0; 32 + } 33 + 34 + /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ 35 + static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) 36 + { 37 + u16 index, value; 38 + int status; 39 + 40 + if (txlen < 2) { 41 + err("tx buffer length is smaller than 2. Makes no sense."); 42 + return -EINVAL; 43 + } 44 + if (txlen > 4) { 45 + err("tx buffer length is larger than 4. Not supported."); 46 + return -EINVAL; 47 + } 48 + 49 + deb_data(">>> "); 50 + debug_dump(tx,txlen,deb_data); 51 + 52 + value = ((txlen - 2) << 8) | tx[1]; 53 + index = 0; 54 + if (txlen > 2) 55 + index |= (tx[2] << 8); 56 + if (txlen > 3) 57 + index |= tx[3]; 58 + 59 + /* think about swapping here */ 60 + value = le16_to_cpu(value); 61 + index = le16_to_cpu(index); 62 + 63 + status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], 64 + USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, 65 + USB_CTRL_GET_TIMEOUT); 66 + 67 + if (status < 0) 68 + err("ep 0 read error (status = %d)",status); 69 + 70 + deb_data("<<< "); 71 + debug_dump(rx,rxlen,deb_data); 72 + 73 + return status; /* length in case of success */ 74 + } 75 + 76 + int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) 77 + { 78 + u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) }; 79 + return dib0700_ctrl_wr(d,buf,3); 80 + } 81 + 82 + /* 83 + * I2C master xfer function 84 + */ 85 + static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) 86 + { 87 + struct dvb_usb_device *d = i2c_get_adapdata(adap); 88 + int i,len; 89 + u8 buf[255]; 90 + 91 + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 92 + return -EAGAIN; 93 + 94 + for (i = 0; i < num; i++) { 95 + /* fill in the address */ 96 + buf[1] = (msg[i].addr << 1); 97 + /* fill the buffer */ 98 + memcpy(&buf[2], msg[i].buf, msg[i].len); 99 + 100 + /* write/read request */ 101 + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { 102 + buf[0] = REQUEST_I2C_READ; 103 + buf[1] |= 1; 104 + 105 + /* special thing in the current firmware: when length is zero the read-failed */ 106 + if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) 107 + break; 108 + 109 + msg[i+1].len = len; 110 + 111 + i++; 112 + } else { 113 + buf[0] = REQUEST_I2C_WRITE; 114 + if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0) 115 + break; 116 + } 117 + } 118 + 119 + mutex_unlock(&d->i2c_mutex); 120 + return i; 121 + } 122 + 123 + static u32 dib0700_i2c_func(struct i2c_adapter *adapter) 124 + { 125 + return I2C_FUNC_I2C; 126 + } 127 + 128 + struct i2c_algorithm dib0700_i2c_algo = { 129 + .master_xfer = dib0700_i2c_xfer, 130 + .functionality = dib0700_i2c_func, 131 + }; 132 + 133 + static int dib0700_jumpram(struct usb_device *udev, u32 address) 134 + { 135 + int ret, actlen; 136 + u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0, 137 + (address >> 24) & 0xff, 138 + (address >> 16) & 0xff, 139 + (address >> 8) & 0xff, 140 + address & 0xff }; 141 + 142 + if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { 143 + deb_fw("jumpram to 0x%x failed\n",address); 144 + return ret; 145 + } 146 + if (actlen != 8) { 147 + deb_fw("jumpram to 0x%x failed\n",address); 148 + return -EIO; 149 + } 150 + return 0; 151 + } 152 + 153 + int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) 154 + { 155 + struct hexline hx; 156 + int pos = 0, ret, act_len; 157 + 158 + u8 buf[260]; 159 + 160 + while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { 161 + deb_fwdata("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk); 162 + 163 + buf[0] = hx.len; 164 + buf[1] = hx.addr >> 8; 165 + buf[2] = hx.addr & 0xff; 166 + buf[3] = hx.type; 167 + memcpy(&buf[4],hx.data,hx.len); 168 + buf[4+hx.len] = hx.chk; 169 + 170 + ret = usb_bulk_msg(udev, 171 + usb_sndbulkpipe(udev, 0x01), 172 + buf, 173 + hx.len + 5, 174 + &act_len, 175 + 1000); 176 + 177 + if (ret < 0) { 178 + err("firmware download failed at %d with %d",pos,ret); 179 + return ret; 180 + } 181 + } 182 + 183 + if (ret == 0) { 184 + /* start the firmware */ 185 + if ((ret = dib0700_jumpram(udev,0x70000000)) == 0) 186 + info("firmware started successfully."); 187 + } else 188 + ret = -EIO; 189 + 190 + return ret; 191 + } 192 + 193 + int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) 194 + { 195 + struct dib0700_state *st = adap->dev->priv; 196 + u8 b[4]; 197 + 198 + b[0] = REQUEST_ENABLE_VIDEO; 199 + b[1] = 0x00; 200 + b[2] = (0x01 << 4); /* Master mode */ 201 + b[3] = 0x00; 202 + 203 + deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); 204 + 205 + if (onoff) 206 + st->channel_state |= 1 << adap->id; 207 + else 208 + st->channel_state &= ~(1 << adap->id); 209 + 210 + b[2] |= st->channel_state; 211 + 212 + if (st->channel_state) /* if at least one channel is active */ 213 + b[1] = (0x01 << 4) | 0x00; 214 + 215 + deb_info("data for streaming: %x %x\n",b[1],b[2]); 216 + 217 + return dib0700_ctrl_wr(adap->dev, b, 4); 218 + } 219 + 220 + static int dib0700_probe(struct usb_interface *intf, 221 + const struct usb_device_id *id) 222 + { 223 + int i; 224 + 225 + for (i = 0; i < dib0700_device_count; i++) 226 + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) 227 + return 0; 228 + 229 + return -ENODEV; 230 + } 231 + 232 + static struct usb_driver dib0700_driver = { 233 + .name = "dvb_usb_dib0700", 234 + .probe = dib0700_probe, 235 + .disconnect = dvb_usb_device_exit, 236 + .id_table = dib0700_usb_id_table, 237 + }; 238 + 239 + /* module stuff */ 240 + static int __init dib0700_module_init(void) 241 + { 242 + int result; 243 + info("loaded with support for %d different device-types", dib0700_device_count); 244 + if ((result = usb_register(&dib0700_driver))) { 245 + err("usb_register failed. Error number %d",result); 246 + return result; 247 + } 248 + 249 + return 0; 250 + } 251 + 252 + static void __exit dib0700_module_exit(void) 253 + { 254 + /* deregister this driver from the USB subsystem */ 255 + usb_deregister(&dib0700_driver); 256 + } 257 + 258 + module_init (dib0700_module_init); 259 + module_exit (dib0700_module_exit); 260 + 261 + MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); 262 + MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); 263 + MODULE_VERSION("1.0"); 264 + MODULE_LICENSE("GPL");
+194
drivers/media/dvb/dvb-usb/dib0700_devices.c
··· 1 + /* Linux driver for devices based on the DiBcom DiB0700 USB bridge 2 + * 3 + * This program is free software; you can redistribute it and/or modify it 4 + * under the terms of the GNU General Public License as published by the Free 5 + * Software Foundation, version 2. 6 + * 7 + * Copyright (C) 2005-6 DiBcom, SA 8 + */ 9 + #include "dib0700.h" 10 + 11 + #include "dib3000mc.h" 12 + #include "dib7000m.h" 13 + #include "mt2060.h" 14 + 15 + /* Hauppauge Nova-T 500 16 + * has a LNA on GPIO0 which is enabled by setting 1 */ 17 + static struct mt2060_config bristol_mt2060_config[2] = { 18 + { 19 + .i2c_address = 0x60, 20 + .clock_out = 1, 21 + }, { 22 + .i2c_address = 0x61, 23 + } 24 + }; 25 + 26 + static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { 27 + .band_caps = BAND_VHF | BAND_UHF, 28 + .setup = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0), 29 + 30 + .agc1_max = 48497, 31 + .agc1_min = 23593, 32 + .agc2_max = 46531, 33 + .agc2_min = 24904, 34 + 35 + .agc1_pt1 = 0x65, 36 + .agc1_pt2 = 0x69, 37 + 38 + .agc1_slope1 = 0x51, 39 + .agc1_slope2 = 0x27, 40 + 41 + .agc2_pt1 = 0, 42 + .agc2_pt2 = 0x33, 43 + 44 + .agc2_slope1 = 0x35, 45 + .agc2_slope2 = 0x37, 46 + }; 47 + 48 + static struct dib3000mc_config bristol_dib3000mc_config[2] = { 49 + { .agc = &bristol_dib3000p_mt2060_agc_config, 50 + .max_time = 0x196, 51 + .ln_adc_level = 0x1cc7, 52 + .output_mpeg2_in_188_bytes = 1, 53 + }, 54 + { .agc = &bristol_dib3000p_mt2060_agc_config, 55 + .max_time = 0x196, 56 + .ln_adc_level = 0x1cc7, 57 + .output_mpeg2_in_188_bytes = 1, 58 + } 59 + }; 60 + 61 + static int bristol_frontend_attach(struct dvb_usb_adapter *adap) 62 + { 63 + if (adap->id == 0) { 64 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); 65 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); 66 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); 67 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); 68 + 69 + if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { 70 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); 71 + return -ENODEV; 72 + } 73 + } 74 + return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, 10 + adap->id, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; 75 + } 76 + 77 + static int bristol_tuner_attach(struct dvb_usb_adapter *adap) 78 + { 79 + struct dib0700_state *st = adap->dev->priv; 80 + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); 81 + return mt2060_attach(adap->fe, tun_i2c, &bristol_mt2060_config[adap->id], st->mt2060_if1[adap->id]); 82 + } 83 + 84 + /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ 85 + static struct mt2060_config stk7000p_mt2060_config = { 86 + 0x60 87 + }; 88 + 89 + static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) 90 + { 91 + /* unless there is no real power management in DVB - we leave the device on GPIO6 */ 92 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); 93 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); 94 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); 95 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); 96 + 97 + // adap->fe = dib7000m_attach(&adap->dev->i2c_adap, &stk7700p_dib7000m_config, 18); 98 + return 0; 99 + } 100 + 101 + static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) 102 + { 103 + // tun_i2c = dib7000m_get_tuner_i2c_master(adap->fe, 1); 104 + // return mt2060_attach(adap->fe, tun_i2c, &stk3000p_mt2060_config, if1); 105 + return 0; 106 + } 107 + 108 + struct usb_device_id dib0700_usb_id_table[] = { 109 + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, 110 + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, 111 + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, 112 + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, 113 + { } /* Terminating entry */ 114 + }; 115 + MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); 116 + 117 + #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ 118 + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ 119 + .usb_ctrl = DEVICE_SPECIFIC, \ 120 + .firmware = "dvb-usb-dib0700-01.fw", \ 121 + .download_firmware = dib0700_download_firmware, \ 122 + .size_of_priv = sizeof(struct dib0700_state), \ 123 + .i2c_algo = &dib0700_i2c_algo 124 + 125 + #define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ 126 + .streaming_ctrl = dib0700_streaming_ctrl, \ 127 + .stream = { \ 128 + .type = USB_BULK, \ 129 + .count = 4, \ 130 + .endpoint = ep, \ 131 + .u = { \ 132 + .bulk = { \ 133 + .buffersize = 39480, \ 134 + } \ 135 + } \ 136 + } 137 + 138 + struct dvb_usb_device_properties dib0700_devices[] = { 139 + { 140 + DIB0700_DEFAULT_DEVICE_PROPERTIES, 141 + 142 + .num_adapters = 1, 143 + .adapter = { 144 + { 145 + .frontend_attach = stk7700p_frontend_attach, 146 + .tuner_attach = stk7700p_tuner_attach, 147 + 148 + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), 149 + }, 150 + }, 151 + 152 + .num_device_descs = 3, 153 + .devices = { 154 + { "DiBcom STK7700P reference design", 155 + { &dib0700_usb_id_table[0], NULL }, 156 + { NULL }, 157 + }, 158 + { "Hauppauge Nova-T Stick", 159 + { &dib0700_usb_id_table[2], NULL }, 160 + { NULL }, 161 + }, 162 + { "AVerMedia AVerTV DVB-T Volar", 163 + { &dib0700_usb_id_table[3], NULL }, 164 + { NULL }, 165 + }, 166 + } 167 + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, 168 + 169 + .num_adapters = 2, 170 + .adapter = { 171 + { 172 + .frontend_attach = bristol_frontend_attach, 173 + .tuner_attach = bristol_tuner_attach, 174 + 175 + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), 176 + }, { 177 + .frontend_attach = bristol_frontend_attach, 178 + .tuner_attach = bristol_tuner_attach, 179 + 180 + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), 181 + } 182 + }, 183 + 184 + .num_device_descs = 1, 185 + .devices = { 186 + { "Hauppauge Nova-T 500 Dual DVB-T", 187 + { &dib0700_usb_id_table[1], NULL }, 188 + { NULL }, 189 + }, 190 + } 191 + } 192 + }; 193 + 194 + int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
+21
drivers/media/dvb/dvb-usb/dib07x0.h
··· 1 + #ifndef _DIB07X0_H_ 2 + #define _DIB07X0_H_ 3 + 4 + enum dib07x0_gpios { 5 + GPIO0 = 0, 6 + GPIO1 = 2, 7 + GPIO2 = 3, 8 + GPIO3 = 4, 9 + GPIO4 = 5, 10 + GPIO5 = 6, 11 + GPIO6 = 8, 12 + GPIO7 = 10, 13 + GPIO8 = 11, 14 + GPIO9 = 14, 15 + GPIO10 = 15, 16 + }; 17 + 18 + #define GPIO_IN 0 19 + #define GPIO_OUT 1 20 + 21 + #endif