/* * This command sequence emulates the behaviour of the Windows driver. * The structure of these commands was determined by sniffing the * usb traffic of the device during startup. * Most likely, these commands make some queries to the device. * Commands are sent to enquire parameters like the bus mode, * component revision, boot mode, the device serial number etc. * * These commands are necessary to be sent in this order during startup. * The device fails to powerup if these commands are not sent. * * The complete list of startup commands is given in the start_seq table below.
*/ staticint si4713_send_startup_command(struct si4713_usb_device *radio)
{ unsignedlong until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
u8 *buffer = radio->buffer; int retval;
for (;;) { /* receive the response */
retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
0x01, 0xa1, 0x033f, 0, radio->buffer,
BUFFER_LENGTH, USB_TIMEOUT); if (retval < 0) return retval; if (!radio->buffer[1]) { /* USB traffic sniffing showed that some commands require
* additional checks. */ switch (buffer[1]) { case 0x32: if (radio->buffer[2] == 0) return 0; break; case 0x14: case 0x12: if (radio->buffer[2] & SI4713_CTS) return 0; break; case 0x06: if ((radio->buffer[2] & SI4713_CTS) && radio->buffer[9] == 0x08) return 0; break; default: return 0;
}
} if (time_is_before_jiffies(until_jiffies)) return -EIO;
msleep(3);
}
return retval;
}
struct si4713_start_seq_table { int len;
u8 payload[8];
};
/* * Some of the startup commands that could be recognized are : * (0x03): Get serial number of the board (Response : CB000-00-00) * (0x06, 0x03, 0x03, 0x08, 0x01, 0x0f) : Get Component revision
*/ staticconststruct si4713_start_seq_table start_seq[] = {
staticint si4713_i2c_read(struct si4713_usb_device *radio, char *data, int len)
{ unsignedlong until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1; int retval;
/* receive the response */ for (;;) {
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
0x01, 0xa1, 0x033f, 0, radio->buffer,
BUFFER_LENGTH, USB_TIMEOUT); if (retval < 0) return retval;
/* * Check that we get a valid reply back (buffer[1] == 0) and * that CTS is set before returning, otherwise we wait and try * again. The i2c driver also does the CTS check, but the timeouts * used there are much too small for this USB driver, so we wait * for it here.
*/ if (radio->buffer[1] == 0 && (radio->buffer[2] & SI4713_CTS)) {
memcpy(data, radio->buffer + 2, len); return 0;
} if (time_is_before_jiffies(until_jiffies)) { /* Zero the status value, ensuring CTS isn't set */
data[0] = 0; return 0;
}
msleep(3);
}
}
staticint si4713_i2c_write(struct si4713_usb_device *radio, char *data, int len)
{ int retval = -EINVAL; int i;
if (len > BUFFER_LENGTH - 5) return -EINVAL;
for (i = 0; i < ARRAY_SIZE(command_table); i++) { if (data[0] == command_table[i].command_id)
retval = send_command(radio, command_table[i].payload,
data, len);
}
return retval < 0 ? retval : 0;
}
staticint si4713_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, int num)
{ struct si4713_usb_device *radio = i2c_get_adapdata(i2c_adapter); int retval = -EINVAL; int i;
for (i = 0; i < num; i++) { if (msgs[i].flags & I2C_M_RD)
retval = si4713_i2c_read(radio, msgs[i].buf, msgs[i].len); else
retval = si4713_i2c_write(radio, msgs[i].buf, msgs[i].len); if (retval) break;
}
/* This name value shows up in the sysfs filename associated
with this I2C adapter */ staticconststruct i2c_adapter si4713_i2c_adapter_template = {
.name = "si4713-i2c",
.owner = THIS_MODULE,
.algo = &si4713_algo,
};
staticint si4713_register_i2c_adapter(struct si4713_usb_device *radio)
{
radio->i2c_adapter = si4713_i2c_adapter_template; /* set up sysfs linkage to our parent device */
radio->i2c_adapter.dev.parent = &radio->usbdev->dev;
i2c_set_adapdata(&radio->i2c_adapter, radio);
return i2c_add_adapter(&radio->i2c_adapter);
}
/* check if the device is present and register with v4l and usb if it is */ staticint usb_si4713_probe(struct usb_interface *intf, conststruct usb_device_id *id)
{ struct si4713_usb_device *radio; struct i2c_adapter *adapter; struct v4l2_subdev *sd; int retval;
dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
id->idVendor, id->idProduct);
/* Initialize local device structure */
radio = kzalloc(sizeof(struct si4713_usb_device), GFP_KERNEL); if (radio)
radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
if (!radio || !radio->buffer) {
dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
kfree(radio); return -ENOMEM;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.