Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Driver for Philips webcam
0003    Functions that send various control messages to the webcam, including
0004    video modes.
0005    (C) 1999-2003 Nemosoft Unv.
0006    (C) 2004-2006 Luc Saillard (luc@saillard.org)
0007    (C) 2011 Hans de Goede <hdegoede@redhat.com>
0008 
0009    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
0010    driver and thus may have bugs that are not present in the original version.
0011    Please send bug reports and support requests to <luc@saillard.org>.
0012 
0013    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
0014    driver and thus may have bugs that are not present in the original version.
0015    Please send bug reports and support requests to <luc@saillard.org>.
0016    The decompression routines have been implemented by reverse-engineering the
0017    Nemosoft binary pwcx module. Caveat emptor.
0018 
0019 */
0020 
0021 /*
0022    Changes
0023    2001/08/03  Alvarado   Added methods for changing white balance and
0024               red/green gains
0025  */
0026 
0027 /* Control functions for the cam; brightness, contrast, video mode, etc. */
0028 
0029 #ifdef __KERNEL__
0030 #include <linux/uaccess.h>
0031 #endif
0032 #include <asm/errno.h>
0033 
0034 #include "pwc.h"
0035 #include "pwc-kiara.h"
0036 #include "pwc-timon.h"
0037 #include "pwc-dec1.h"
0038 #include "pwc-dec23.h"
0039 
0040 /* Selectors for status controls used only in this file */
0041 #define GET_STATUS_B00              0x0B00
0042 #define SENSOR_TYPE_FORMATTER1          0x0C00
0043 #define GET_STATUS_3000             0x3000
0044 #define READ_RAW_Y_MEAN_FORMATTER       0x3100
0045 #define SET_POWER_SAVE_MODE_FORMATTER       0x3200
0046 #define MIRROR_IMAGE_FORMATTER          0x3300
0047 #define LED_FORMATTER               0x3400
0048 #define LOWLIGHT                0x3500
0049 #define GET_STATUS_3600             0x3600
0050 #define SENSOR_TYPE_FORMATTER2          0x3700
0051 #define GET_STATUS_3800             0x3800
0052 #define GET_STATUS_4000             0x4000
0053 #define GET_STATUS_4100             0x4100  /* Get */
0054 #define CTL_STATUS_4200             0x4200  /* [GS] 1 */
0055 
0056 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
0057 #define VIDEO_OUTPUT_CONTROL_FORMATTER      0x0100
0058 
0059 static const char *size2name[PSZ_MAX] =
0060 {
0061     "subQCIF",
0062     "QSIF",
0063     "QCIF",
0064     "SIF",
0065     "CIF",
0066     "VGA",
0067 };
0068 
0069 /********/
0070 
0071 /* Entries for the Nala (645/646) camera; the Nala doesn't have compression
0072    preferences, so you either get compressed or non-compressed streams.
0073 
0074    An alternate value of 0 means this mode is not available at all.
0075  */
0076 
0077 #define PWC_FPS_MAX_NALA 8
0078 
0079 struct Nala_table_entry {
0080     char alternate;         /* USB alternate setting */
0081     int compressed;         /* Compressed yes/no */
0082 
0083     unsigned char mode[3];      /* precomputed mode table */
0084 };
0085 
0086 static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 };
0087 
0088 static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
0089 {
0090 #include "pwc-nala.h"
0091 };
0092 
0093 /****************************************************************************/
0094 
0095 static int recv_control_msg(struct pwc_device *pdev,
0096     u8 request, u16 value, int recv_count)
0097 {
0098     int rc;
0099 
0100     rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
0101         request,
0102         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0103         value, pdev->vcinterface,
0104         pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT);
0105     if (rc < 0)
0106         PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
0107               rc, request, value);
0108     return rc;
0109 }
0110 
0111 static inline int send_video_command(struct pwc_device *pdev,
0112     int index, const unsigned char *buf, int buflen)
0113 {
0114     int rc;
0115 
0116     memcpy(pdev->ctrl_buf, buf, buflen);
0117 
0118     rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
0119             SET_EP_STREAM_CTL,
0120             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0121             VIDEO_OUTPUT_CONTROL_FORMATTER, index,
0122             pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT);
0123     if (rc >= 0)
0124         memcpy(pdev->cmd_buf, buf, buflen);
0125     else
0126         PWC_ERROR("send_video_command error %d\n", rc);
0127 
0128     return rc;
0129 }
0130 
0131 int send_control_msg(struct pwc_device *pdev,
0132     u8 request, u16 value, void *buf, int buflen)
0133 {
0134     return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
0135             request,
0136             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0137             value, pdev->vcinterface,
0138             buf, buflen, USB_CTRL_SET_TIMEOUT);
0139 }
0140 
0141 static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt,
0142                    int frames, int *compression, int send_to_cam)
0143 {
0144     int fps, ret = 0;
0145     struct Nala_table_entry *pEntry;
0146     int frames2frames[31] =
0147     { /* closest match of framerate */
0148        0,  0,  0,  0,  4,  /*  0-4  */
0149        5,  5,  7,  7, 10,  /*  5-9  */
0150       10, 10, 12, 12, 15,  /* 10-14 */
0151       15, 15, 15, 20, 20,  /* 15-19 */
0152       20, 20, 20, 24, 24,  /* 20-24 */
0153       24, 24, 24, 24, 24,  /* 25-29 */
0154       24                   /* 30    */
0155     };
0156     int frames2table[31] =
0157     { 0, 0, 0, 0, 0, /*  0-4  */
0158       1, 1, 1, 2, 2, /*  5-9  */
0159       3, 3, 4, 4, 4, /* 10-14 */
0160       5, 5, 5, 5, 5, /* 15-19 */
0161       6, 6, 6, 6, 7, /* 20-24 */
0162       7, 7, 7, 7, 7, /* 25-29 */
0163       7              /* 30    */
0164     };
0165 
0166     if (size < 0 || size > PSZ_CIF)
0167         return -EINVAL;
0168     if (frames < 4)
0169         frames = 4;
0170     else if (size > PSZ_QCIF && frames > 15)
0171         frames = 15;
0172     else if (frames > 25)
0173         frames = 25;
0174     frames = frames2frames[frames];
0175     fps = frames2table[frames];
0176     pEntry = &Nala_table[size][fps];
0177     if (pEntry->alternate == 0)
0178         return -EINVAL;
0179 
0180     if (send_to_cam)
0181         ret = send_video_command(pdev, pdev->vendpoint,
0182                      pEntry->mode, 3);
0183     if (ret < 0)
0184         return ret;
0185 
0186     if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420)
0187         pwc_dec1_init(pdev, pEntry->mode);
0188 
0189     /* Set various parameters */
0190     pdev->pixfmt = pixfmt;
0191     pdev->vframes = frames;
0192     pdev->valternate = pEntry->alternate;
0193     pdev->width  = pwc_image_sizes[size][0];
0194     pdev->height = pwc_image_sizes[size][1];
0195     pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
0196     if (pEntry->compressed) {
0197         if (pdev->release < 5) { /* 4 fold compression */
0198             pdev->vbandlength = 528;
0199             pdev->frame_size /= 4;
0200         }
0201         else {
0202             pdev->vbandlength = 704;
0203             pdev->frame_size /= 3;
0204         }
0205     }
0206     else
0207         pdev->vbandlength = 0;
0208 
0209     /* Let pwc-if.c:isoc_init know we don't support higher compression */
0210     *compression = 3;
0211 
0212     return 0;
0213 }
0214 
0215 
0216 static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt,
0217                 int frames, int *compression, int send_to_cam)
0218 {
0219     const struct Timon_table_entry *pChoose;
0220     int fps, ret = 0;
0221 
0222     if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
0223         return -EINVAL;
0224     if (frames < 5)
0225         frames = 5;
0226     else if (size == PSZ_VGA && frames > 15)
0227         frames = 15;
0228     else if (frames > 30)
0229         frames = 30;
0230     fps = (frames / 5) - 1;
0231 
0232     /* Find a supported framerate with progressively higher compression */
0233     do {
0234         pChoose = &Timon_table[size][fps][*compression];
0235         if (pChoose->alternate != 0)
0236             break;
0237         (*compression)++;
0238     } while (*compression <= 3);
0239 
0240     if (pChoose->alternate == 0)
0241         return -ENOENT; /* Not supported. */
0242 
0243     if (send_to_cam)
0244         ret = send_video_command(pdev, pdev->vendpoint,
0245                      pChoose->mode, 13);
0246     if (ret < 0)
0247         return ret;
0248 
0249     if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
0250         pwc_dec23_init(pdev, pChoose->mode);
0251 
0252     /* Set various parameters */
0253     pdev->pixfmt = pixfmt;
0254     pdev->vframes = (fps + 1) * 5;
0255     pdev->valternate = pChoose->alternate;
0256     pdev->width  = pwc_image_sizes[size][0];
0257     pdev->height = pwc_image_sizes[size][1];
0258     pdev->vbandlength = pChoose->bandlength;
0259     if (pChoose->bandlength > 0)
0260         pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
0261     else
0262         pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
0263     return 0;
0264 }
0265 
0266 
0267 static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt,
0268                 int frames, int *compression, int send_to_cam)
0269 {
0270     const struct Kiara_table_entry *pChoose;
0271     int fps, ret = 0;
0272 
0273     if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
0274         return -EINVAL;
0275     if (frames < 5)
0276         frames = 5;
0277     else if (size == PSZ_VGA && frames > 15)
0278         frames = 15;
0279     else if (frames > 30)
0280         frames = 30;
0281     fps = (frames / 5) - 1;
0282 
0283     /* Find a supported framerate with progressively higher compression */
0284     do {
0285         pChoose = &Kiara_table[size][fps][*compression];
0286         if (pChoose->alternate != 0)
0287             break;
0288         (*compression)++;
0289     } while (*compression <= 3);
0290 
0291     if (pChoose->alternate == 0)
0292         return -ENOENT; /* Not supported. */
0293 
0294     /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
0295     if (send_to_cam)
0296         ret = send_video_command(pdev, 4, pChoose->mode, 12);
0297     if (ret < 0)
0298         return ret;
0299 
0300     if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
0301         pwc_dec23_init(pdev, pChoose->mode);
0302 
0303     /* All set and go */
0304     pdev->pixfmt = pixfmt;
0305     pdev->vframes = (fps + 1) * 5;
0306     pdev->valternate = pChoose->alternate;
0307     pdev->width  = pwc_image_sizes[size][0];
0308     pdev->height = pwc_image_sizes[size][1];
0309     pdev->vbandlength = pChoose->bandlength;
0310     if (pdev->vbandlength > 0)
0311         pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
0312     else
0313         pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
0314     PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
0315         pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
0316     return 0;
0317 }
0318 
0319 int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
0320     int pixfmt, int frames, int *compression, int send_to_cam)
0321 {
0322     int ret, size;
0323 
0324     PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
0325                width, height, frames, pixfmt);
0326     size = pwc_get_size(pdev, width, height);
0327     PWC_TRACE("decode_size = %d.\n", size);
0328 
0329     if (DEVICE_USE_CODEC1(pdev->type)) {
0330         ret = set_video_mode_Nala(pdev, size, pixfmt, frames,
0331                       compression, send_to_cam);
0332     } else if (DEVICE_USE_CODEC3(pdev->type)) {
0333         ret = set_video_mode_Kiara(pdev, size, pixfmt, frames,
0334                        compression, send_to_cam);
0335     } else {
0336         ret = set_video_mode_Timon(pdev, size, pixfmt, frames,
0337                        compression, send_to_cam);
0338     }
0339     if (ret < 0) {
0340         PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
0341         return ret;
0342     }
0343     pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
0344     PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
0345     return 0;
0346 }
0347 
0348 static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size)
0349 {
0350     unsigned int i;
0351 
0352     for (i = 0; i < PWC_FPS_MAX_NALA; i++) {
0353         if (Nala_table[size][i].alternate) {
0354             if (index--==0) return Nala_fps_vector[i];
0355         }
0356     }
0357     return 0;
0358 }
0359 
0360 static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size)
0361 {
0362     unsigned int i;
0363 
0364     for (i = 0; i < PWC_FPS_MAX_KIARA; i++) {
0365         if (Kiara_table[size][i][3].alternate) {
0366             if (index--==0) return Kiara_fps_vector[i];
0367         }
0368     }
0369     return 0;
0370 }
0371 
0372 static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size)
0373 {
0374     unsigned int i;
0375 
0376     for (i=0; i < PWC_FPS_MAX_TIMON; i++) {
0377         if (Timon_table[size][i][3].alternate) {
0378             if (index--==0) return Timon_fps_vector[i];
0379         }
0380     }
0381     return 0;
0382 }
0383 
0384 unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size)
0385 {
0386     unsigned int ret;
0387 
0388     if (DEVICE_USE_CODEC1(pdev->type)) {
0389         ret = pwc_get_fps_Nala(pdev, index, size);
0390 
0391     } else if (DEVICE_USE_CODEC3(pdev->type)) {
0392         ret = pwc_get_fps_Kiara(pdev, index, size);
0393 
0394     } else {
0395         ret = pwc_get_fps_Timon(pdev, index, size);
0396     }
0397 
0398     return ret;
0399 }
0400 
0401 int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
0402 {
0403     int ret;
0404 
0405     ret = recv_control_msg(pdev, request, value, 1);
0406     if (ret < 0)
0407         return ret;
0408 
0409     *data = pdev->ctrl_buf[0];
0410     return 0;
0411 }
0412 
0413 int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
0414 {
0415     int ret;
0416 
0417     pdev->ctrl_buf[0] = data;
0418     ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1);
0419     if (ret < 0)
0420         return ret;
0421 
0422     return 0;
0423 }
0424 
0425 int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
0426 {
0427     int ret;
0428 
0429     ret = recv_control_msg(pdev, request, value, 1);
0430     if (ret < 0)
0431         return ret;
0432 
0433     *data = ((s8 *)pdev->ctrl_buf)[0];
0434     return 0;
0435 }
0436 
0437 int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
0438 {
0439     int ret;
0440 
0441     ret = recv_control_msg(pdev, request, value, 2);
0442     if (ret < 0)
0443         return ret;
0444 
0445     *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0];
0446     return 0;
0447 }
0448 
0449 int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
0450 {
0451     int ret;
0452 
0453     pdev->ctrl_buf[0] = data & 0xff;
0454     pdev->ctrl_buf[1] = data >> 8;
0455     ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2);
0456     if (ret < 0)
0457         return ret;
0458 
0459     return 0;
0460 }
0461 
0462 int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
0463 {
0464     int ret;
0465 
0466     ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
0467     if (ret < 0)
0468         return ret;
0469 
0470     return 0;
0471 }
0472 
0473 /* POWER */
0474 void pwc_camera_power(struct pwc_device *pdev, int power)
0475 {
0476     int r;
0477 
0478     if (!pdev->power_save)
0479         return;
0480 
0481     if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
0482         return; /* Not supported by Nala or Timon < release 6 */
0483 
0484     if (power)
0485         pdev->ctrl_buf[0] = 0x00; /* active */
0486     else
0487         pdev->ctrl_buf[0] = 0xFF; /* power save */
0488     r = send_control_msg(pdev, SET_STATUS_CTL,
0489         SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1);
0490     if (r < 0)
0491         PWC_ERROR("Failed to power %s camera (%d)\n",
0492               power ? "on" : "off", r);
0493 }
0494 
0495 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
0496 {
0497     int r;
0498 
0499     if (pdev->type < 730)
0500         return 0;
0501     on_value /= 100;
0502     off_value /= 100;
0503     if (on_value < 0)
0504         on_value = 0;
0505     if (on_value > 0xff)
0506         on_value = 0xff;
0507     if (off_value < 0)
0508         off_value = 0;
0509     if (off_value > 0xff)
0510         off_value = 0xff;
0511 
0512     pdev->ctrl_buf[0] = on_value;
0513     pdev->ctrl_buf[1] = off_value;
0514 
0515     r = send_control_msg(pdev,
0516         SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2);
0517     if (r < 0)
0518         PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
0519 
0520     return r;
0521 }
0522 
0523 #ifdef CONFIG_USB_PWC_DEBUG
0524 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
0525 {
0526     int ret, request;
0527 
0528     if (pdev->type < 675)
0529         request = SENSOR_TYPE_FORMATTER1;
0530     else if (pdev->type < 730)
0531         return -1; /* The Vesta series doesn't have this call */
0532     else
0533         request = SENSOR_TYPE_FORMATTER2;
0534 
0535     ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1);
0536     if (ret < 0)
0537         return ret;
0538     if (pdev->type < 675)
0539         *sensor = pdev->ctrl_buf[0] | 0x100;
0540     else
0541         *sensor = pdev->ctrl_buf[0];
0542     return 0;
0543 }
0544 #endif