V4L/DVB (12226): gspca - spca508: Extend the write_vector routine.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 2ed2669..9696c4c 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1304,19 +1304,70 @@
 	return gspca_dev->usb_buf[0];
 }
 
+/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */
+static int ssi_w(struct gspca_dev *gspca_dev,
+		u16 reg, u16 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, retry;
+
+	ret = reg_write(dev, 0x8802, reg >> 8);
+	if (ret < 0)
+		goto out;
+	ret = reg_write(dev, 0x8801, reg & 0x00ff);
+	if (ret < 0)
+		goto out;
+	if ((reg & 0xff00) == 0x1000) {		/* if 2 bytes */
+		ret = reg_write(dev, 0x8805, val & 0x00ff);
+		if (ret < 0)
+			goto out;
+		val >>= 8;
+	}
+	ret = reg_write(dev, 0x8800, val);
+	if (ret < 0)
+		goto out;
+
+	/* poll until not busy */
+	retry = 10;
+	for (;;) {
+		ret = reg_read(gspca_dev, 0x8803);
+		if (ret < 0)
+			break;
+		if (gspca_dev->usb_buf[0] == 0)
+			break;
+		if (--retry <= 0) {
+			PDEBUG(D_ERR, "ssi_w busy %02x",
+					gspca_dev->usb_buf[0]);
+			ret = -1;
+			break;
+		}
+		msleep(8);
+	}
+
+out:
+	return ret;
+}
+
 static int write_vector(struct gspca_dev *gspca_dev,
 			const u16 (*data)[2])
 {
 	struct usb_device *dev = gspca_dev->dev;
-	int ret;
+	int ret = 0;
 
 	while ((*data)[1] != 0) {
-		ret = reg_write(dev, (*data)[1], (*data)[0]);
+		if ((*data)[1] & 0x8000) {
+			if ((*data)[1] == 0xdd00)	/* delay */
+				msleep((*data)[0]);
+			else
+				ret = reg_write(dev, (*data)[1], (*data)[0]);
+		} else {
+			ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]);
+		}
 		if (ret < 0)
-			return ret;
+			break;
 		data++;
 	}
-	return 0;
+	return ret;
 }
 
 /* this function is called at probe time */