* Supports Xirlink C-It Video Camera, IBM PC Camera,
* IBM NetCamera and Veo Stingray.
*
- * Copyright (C) 2010 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
*
* This driver is based on earlier work of:
*
#include "gspca.h"
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Xirlink C-IT");
MODULE_LICENSE("GPL");
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
value, index, NULL, 0, 1000);
if (err < 0)
- PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+ err("Failed to write a register (index 0x%04X,"
" value 0x%02X, error %d)", index, value, err);
return 0;
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
0x00, index, buf, 8, 1000);
if (res < 0) {
- PDEBUG(D_ERR,
- "Failed to read a register (index 0x%04X, error %d)",
+ err("Failed to read a register (index 0x%04X, error %d)",
index, res);
return res;
}
intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
alt = usb_altnum_to_altsetting(intf, gspca_dev->alt);
if (!alt) {
- PDEBUG(D_ERR, "Couldn't get altsetting");
+ err("Couldn't get altsetting");
return -EIO;
}
return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
}
-static int cit_start_model0(struct gspca_dev *gspca_dev)
+/* Calculate the clockdiv giving us max fps given the available bandwidth */
+static int cit_get_clock_div(struct gspca_dev *gspca_dev)
{
- const unsigned short compression = 0; /* 0=none, 7=best frame rate */
int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */
int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 };
int packet_size;
fps[clock_div - 1] * 3 / 2)
clock_div--;
+ PDEBUG(D_PROBE,
+ "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)",
+ packet_size, gspca_dev->width, gspca_dev->height, clock_div,
+ fps[clock_div]);
+
+ return clock_div;
+}
+
+static int cit_start_model0(struct gspca_dev *gspca_dev)
+{
+ const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+ int clock_div;
+
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
+
cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */
cit_write_reg(gspca_dev, 0x0003, 0x0438);
cit_write_reg(gspca_dev, 0x001e, 0x042b);
cit_write_reg(gspca_dev, compression, 0x0109);
cit_write_reg(gspca_dev, clock_div, 0x0111);
- PDEBUG(D_PROBE, "Using clockdiv: %d", clock_div);
return 0;
}
static int cit_start_model1(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */
- int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 };
- int i, packet_size;
+ int i, clock_div;
- packet_size = cit_get_packet_size(gspca_dev);
- if (packet_size < 0)
- return packet_size;
-
- while (clock_div > 3 &&
- 1000 * packet_size >
- gspca_dev->width * gspca_dev->height *
- fps[clock_div - 1] * 3 / 2)
- clock_div--;
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
cit_read_reg(gspca_dev, 0x0128);
cit_read_reg(gspca_dev, 0x0100);
cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
cit_write_reg(gspca_dev, clock_div, 0x0111);
- PDEBUG(D_PROBE, "Using clockdiv: %d", clock_div);
return 0;
}
cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */
cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+ /* FIXME we should probably use cit_get_clock_div() here (in
+ combination with isoc negotiation using the programmable isoc size)
+ like with the IBM netcam pro). */
cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
switch (gspca_dev->width) {
static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
{
const unsigned short compression = 0; /* 0=none, 7=best frame rate */
- int i, clock_div = 0;
+ int i, clock_div;
+
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
cit_write_reg(gspca_dev, 0x0003, 0x0133);
cit_write_reg(gspca_dev, 0x0000, 0x0117);
cit_write_reg(gspca_dev, 0x008b, 0x011c);
cit_write_reg(gspca_dev, 0x0008, 0x0118);
cit_write_reg(gspca_dev, 0x0000, 0x0132);
- clock_div = 3;
break;
case 320: /* 320x240 */
cit_write_reg(gspca_dev, 0x0028, 0x010b);
cit_write_reg(gspca_dev, 0x003f, 0x011c);
cit_write_reg(gspca_dev, 0x000c, 0x0118);
cit_write_reg(gspca_dev, 0x0000, 0x0132);
- clock_div = 5;
break;
}
return 0;
}
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ int max_packet_size;
+
+ switch (gspca_dev->width) {
+ case 160:
+ max_packet_size = 450;
+ break;
+ case 176:
+ max_packet_size = 600;
+ break;
+ default:
+ max_packet_size = 1022;
+ break;
+ }
+
+ /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
+
+ return 0;
+}
+
+static int sd_isoc_nego(struct gspca_dev *gspca_dev)
+{
+ int ret, packet_size, min_packet_size;
+ struct usb_host_interface *alt;
+
+ switch (gspca_dev->width) {
+ case 160:
+ min_packet_size = 200;
+ break;
+ case 176:
+ min_packet_size = 266;
+ break;
+ default:
+ min_packet_size = 400;
+ break;
+ }
+
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ if (packet_size <= min_packet_size)
+ return -EIO;
+
+ packet_size -= 100;
+ if (packet_size < min_packet_size)
+ packet_size = min_packet_size;
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ if (ret < 0)
+ err("set alt 1 err %d", ret);
+
+ return ret;
+}
+
static void sd_stopN(struct gspca_dev *gspca_dev)
{
cit_write_reg(gspca_dev, 0x0000, 0x010c);
.pkt_scan = sd_pkt_scan,
};
+static const struct sd_desc sd_desc_isoc_nego = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .isoc_init = sd_isoc_init,
+ .isoc_nego = sd_isoc_nego,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+};
+
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
{ USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 },
static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ const struct sd_desc *desc = &sd_desc;
+
switch (id->driver_info) {
case CIT_MODEL0:
case CIT_MODEL1:
return -ENODEV;
break;
case CIT_MODEL2:
- case CIT_MODEL3:
case CIT_MODEL4:
- case CIT_IBM_NETCAM_PRO:
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
break;
+ case CIT_MODEL3:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+ /* FIXME this likely applies to all model3 cams and probably
+ to other models too. */
+ if (ibm_netcam_pro)
+ desc = &sd_desc_isoc_nego;
+ break;
}
- return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd),
- THIS_MODULE);
+ return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE);
}
static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);