diff options
Diffstat (limited to 'drivers/media/video/pwc')
-rw-r--r-- | drivers/media/video/pwc/pwc-ctrl.c | 239 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec1.c | 16 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec1.h | 6 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec23.c | 41 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec23.h | 9 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 175 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-misc.c | 1 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 90 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc.h | 14 |
9 files changed, 230 insertions, 361 deletions
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 905d41d90c6a..1f506fde97d0 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -104,47 +104,16 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = /****************************************************************************/ -static int _send_control_msg(struct pwc_device *pdev, - u8 request, u16 value, int index, void *buf, int buflen) -{ - int rc; - void *kbuf = NULL; - - if (buflen) { - kbuf = kmemdup(buf, buflen, GFP_KERNEL); /* not allowed on stack */ - if (kbuf == NULL) - return -ENOMEM; - } - - rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - kbuf, buflen, USB_CTRL_SET_TIMEOUT); - - kfree(kbuf); - return rc; -} - static int recv_control_msg(struct pwc_device *pdev, - u8 request, u16 value, void *buf, int buflen) + u8 request, u16 value, int recv_count) { int rc; - void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ - - if (kbuf == NULL) - return -ENOMEM; rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), request, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - pdev->vcinterface, - kbuf, buflen, USB_CTRL_GET_TIMEOUT); - memcpy(buf, kbuf, buflen); - kfree(kbuf); - + value, pdev->vcinterface, + pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT); if (rc < 0) PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", rc, request, value); @@ -152,27 +121,39 @@ static int recv_control_msg(struct pwc_device *pdev, } static inline int send_video_command(struct pwc_device *pdev, - int index, void *buf, int buflen) + int index, const unsigned char *buf, int buflen) { - return _send_control_msg(pdev, - SET_EP_STREAM_CTL, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen); + int rc; + + memcpy(pdev->ctrl_buf, buf, buflen); + + rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, index, + pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT); + if (rc >= 0) + memcpy(pdev->cmd_buf, buf, buflen); + else + PWC_ERROR("send_video_command error %d\n", rc); + + return rc; } int send_control_msg(struct pwc_device *pdev, u8 request, u16 value, void *buf, int buflen) { - return _send_control_msg(pdev, - request, value, pdev->vcinterface, buf, buflen); + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, pdev->vcinterface, + buf, buflen, USB_CTRL_SET_TIMEOUT); } -static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames, - int *compression) +static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { - unsigned char buf[3]; - int ret, fps; + int fps, ret = 0; struct Nala_table_entry *pEntry; int frames2frames[31] = { /* closest match of framerate */ @@ -194,30 +175,29 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames, 7 /* 30 */ }; - if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) + if (size < 0 || size > PSZ_CIF) return -EINVAL; + if (frames < 4) + frames = 4; + else if (frames > 25) + frames = 25; frames = frames2frames[frames]; fps = frames2table[frames]; pEntry = &Nala_table[size][fps]; if (pEntry->alternate == 0) return -EINVAL; - memcpy(buf, pEntry->mode, 3); - ret = send_video_command(pdev, pdev->vendpoint, buf, 3); - if (ret < 0) { - PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); + if (send_to_cam) + ret = send_video_command(pdev, pdev->vendpoint, + pEntry->mode, 3); + if (ret < 0) return ret; - } - if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf); - if (ret < 0) - return ret; - } - pdev->cmd_len = 3; - memcpy(pdev->cmd_buf, buf, 3); + if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec1_init(pdev, pEntry->mode); /* Set various parameters */ + pdev->pixfmt = pixfmt; pdev->vframes = frames; pdev->valternate = pEntry->alternate; pdev->width = pwc_image_sizes[size][0]; @@ -243,18 +223,20 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames, } -static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, - int *compression) +static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { - unsigned char buf[13]; const struct Timon_table_entry *pChoose; - int ret, fps; + int fps, ret = 0; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || - *compression < 0 || *compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) + if (size >= PSZ_MAX || *compression < 0 || *compression > 3) return -EINVAL; + if (frames < 5) + frames = 5; + else if (size == PSZ_VGA && frames > 15) + frames = 15; + else if (frames > 30) + frames = 30; fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ @@ -268,22 +250,18 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ - memcpy(buf, pChoose->mode, 13); - ret = send_video_command(pdev, pdev->vendpoint, buf, 13); + if (send_to_cam) + ret = send_video_command(pdev, pdev->vendpoint, + pChoose->mode, 13); if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec23_init(pdev, pdev->type, buf); - if (ret < 0) - return ret; - } - - pdev->cmd_len = 13; - memcpy(pdev->cmd_buf, buf, 13); + if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec23_init(pdev, pChoose->mode); /* Set various parameters */ - pdev->vframes = frames; + pdev->pixfmt = pixfmt; + pdev->vframes = (fps + 1) * 5; pdev->valternate = pChoose->alternate; pdev->width = pwc_image_sizes[size][0]; pdev->height = pwc_image_sizes[size][1]; @@ -296,18 +274,20 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, } -static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, - int *compression) +static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { const struct Kiara_table_entry *pChoose = NULL; - int fps, ret; - unsigned char buf[12]; + int fps, ret = 0; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || - *compression < 0 || *compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) + if (size >= PSZ_MAX || *compression < 0 || *compression > 3) return -EINVAL; + if (frames < 5) + frames = 5; + else if (size == PSZ_VGA && frames > 15) + frames = 15; + else if (frames > 30) + frames = 30; fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ @@ -320,26 +300,18 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ - PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate); - - /* usb_control_msg won't take staticly allocated arrays as argument?? */ - memcpy(buf, pChoose->mode, 12); - /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ - ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); + if (send_to_cam) + ret = send_video_command(pdev, 4, pChoose->mode, 12); if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec23_init(pdev, pdev->type, buf); - if (ret < 0) - return ret; - } + if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec23_init(pdev, pChoose->mode); - pdev->cmd_len = 12; - memcpy(pdev->cmd_buf, buf, 12); /* All set and go */ - pdev->vframes = frames; + pdev->pixfmt = pixfmt; + pdev->vframes = (fps + 1) * 5; pdev->valternate = pChoose->alternate; pdev->width = pwc_image_sizes[size][0]; pdev->height = pwc_image_sizes[size][1]; @@ -354,22 +326,24 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, } int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, - int frames, int *compression) + int pixfmt, int frames, int *compression, int send_to_cam) { int ret, size; - PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); + PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", + width, height, frames, pixfmt); size = pwc_get_size(pdev, width, height); PWC_TRACE("decode_size = %d.\n", size); if (DEVICE_USE_CODEC1(pdev->type)) { - ret = set_video_mode_Nala(pdev, size, frames, compression); - + ret = set_video_mode_Nala(pdev, size, pixfmt, frames, + compression, send_to_cam); } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = set_video_mode_Kiara(pdev, size, frames, compression); - + ret = set_video_mode_Kiara(pdev, size, pixfmt, frames, + compression, send_to_cam); } else { - ret = set_video_mode_Timon(pdev, size, frames, compression); + ret = set_video_mode_Timon(pdev, size, pixfmt, frames, + compression, send_to_cam); } if (ret < 0) { PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); @@ -436,13 +410,12 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - u8 buf; - ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 1); if (ret < 0) return ret; - *data = buf; + *data = pdev->ctrl_buf[0]; return 0; } @@ -450,7 +423,8 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) { int ret; - ret = send_control_msg(pdev, request, value, &data, sizeof(data)); + pdev->ctrl_buf[0] = data; + ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); if (ret < 0) return ret; @@ -460,37 +434,34 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - s8 buf; - ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 1); if (ret < 0) return ret; - *data = buf; + *data = ((s8 *)pdev->ctrl_buf)[0]; return 0; } int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - u8 buf[2]; - ret = recv_control_msg(pdev, request, value, buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 2); if (ret < 0) return ret; - *data = (buf[1] << 8) | buf[0]; + *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; return 0; } int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) { int ret; - u8 buf[2]; - buf[0] = data & 0xff; - buf[1] = data >> 8; - ret = send_control_msg(pdev, request, value, buf, sizeof(buf)); + pdev->ctrl_buf[0] = data & 0xff; + pdev->ctrl_buf[1] = data >> 8; + ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2); if (ret < 0) return ret; @@ -511,7 +482,6 @@ int pwc_button_ctrl(struct pwc_device *pdev, u16 value) /* POWER */ void pwc_camera_power(struct pwc_device *pdev, int power) { - char buf; int r; if (!pdev->power_save) @@ -521,13 +491,11 @@ void pwc_camera_power(struct pwc_device *pdev, int power) return; /* Not supported by Nala or Timon < release 6 */ if (power) - buf = 0x00; /* active */ + pdev->ctrl_buf[0] = 0x00; /* active */ else - buf = 0xFF; /* power save */ - r = send_control_msg(pdev, - SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, - &buf, sizeof(buf)); - + pdev->ctrl_buf[0] = 0xFF; /* power save */ + r = send_control_msg(pdev, SET_STATUS_CTL, + SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1); if (r < 0) PWC_ERROR("Failed to power %s camera (%d)\n", power ? "on" : "off", r); @@ -535,7 +503,6 @@ void pwc_camera_power(struct pwc_device *pdev, int power) int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) { - unsigned char buf[2]; int r; if (pdev->type < 730) @@ -551,11 +518,11 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) if (off_value > 0xff) off_value = 0xff; - buf[0] = on_value; - buf[1] = off_value; + pdev->ctrl_buf[0] = on_value; + pdev->ctrl_buf[1] = off_value; r = send_control_msg(pdev, - SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); + SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); if (r < 0) PWC_ERROR("Failed to set LED on/off time (%d)\n", r); @@ -565,7 +532,6 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) #ifdef CONFIG_USB_PWC_DEBUG int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) { - unsigned char buf; int ret = -1, request; if (pdev->type < 675) @@ -575,14 +541,13 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) else request = SENSOR_TYPE_FORMATTER2; - ret = recv_control_msg(pdev, - GET_STATUS_CTL, request, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); if (ret < 0) return ret; if (pdev->type < 675) - *sensor = buf | 0x100; + *sensor = pdev->ctrl_buf[0] | 0x100; else - *sensor = buf; + *sensor = pdev->ctrl_buf[0]; return 0; } #endif diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c index be0e02cb487f..e899036aadf4 100644 --- a/drivers/media/video/pwc/pwc-dec1.c +++ b/drivers/media/video/pwc/pwc-dec1.c @@ -22,19 +22,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "pwc-dec1.h" +#include "pwc.h" -int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer) +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd) { - struct pwc_dec1_private *pdec; + struct pwc_dec1_private *pdec = &pdev->dec1; - if (pwc->decompress_data == NULL) { - pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL); - if (pdec == NULL) - return -ENOMEM; - pwc->decompress_data = pdec; - } - pdec = pwc->decompress_data; - - return 0; + pdec->version = pdev->release; } diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h index a57d8601080b..c565ef8f52fb 100644 --- a/drivers/media/video/pwc/pwc-dec1.h +++ b/drivers/media/video/pwc/pwc-dec1.h @@ -25,13 +25,15 @@ #ifndef PWC_DEC1_H #define PWC_DEC1_H -#include "pwc.h" +#include <linux/mutex.h> + +struct pwc_device; struct pwc_dec1_private { int version; }; -int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer); +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd); #endif diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c index 2c6709112b2f..3792fedff951 100644 --- a/drivers/media/video/pwc/pwc-dec23.c +++ b/drivers/media/video/pwc/pwc-dec23.c @@ -294,22 +294,17 @@ static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; /* If the type or the command change, we rebuild the lookup table */ -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd) { int flags, version, shift, i; - struct pwc_dec23_private *pdec; - - if (pwc->decompress_data == NULL) { - pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - if (pdec == NULL) - return -ENOMEM; - pwc->decompress_data = pdec; - } - pdec = pwc->decompress_data; + struct pwc_dec23_private *pdec = &pdev->dec23; mutex_init(&pdec->lock); - if (DEVICE_USE_CODEC3(type)) { + if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2]) + return; + + if (DEVICE_USE_CODEC3(pdev->type)) { flags = cmd[2] & 0x18; if (flags == 8) pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */ @@ -356,7 +351,8 @@ int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255; #endif - return 0; + pdec->last_cmd = cmd[2]; + pdec->last_cmd_valid = 1; } /* @@ -659,12 +655,12 @@ static void DecompressBand23(struct pwc_dec23_private *pdec, * src: raw data * dst: image output */ -void pwc_dec23_decompress(const struct pwc_device *pwc, +void pwc_dec23_decompress(struct pwc_device *pdev, const void *src, void *dst) { int bandlines_left, bytes_per_block; - struct pwc_dec23_private *pdec = pwc->decompress_data; + struct pwc_dec23_private *pdec = &pdev->dec23; /* YUV420P image format */ unsigned char *pout_planar_y; @@ -674,23 +670,22 @@ void pwc_dec23_decompress(const struct pwc_device *pwc, mutex_lock(&pdec->lock); - bandlines_left = pwc->height / 4; - bytes_per_block = pwc->width * 4; - plane_size = pwc->height * pwc->width; + bandlines_left = pdev->height / 4; + bytes_per_block = pdev->width * 4; + plane_size = pdev->height * pdev->width; pout_planar_y = dst; pout_planar_u = dst + plane_size; pout_planar_v = dst + plane_size + plane_size / 4; while (bandlines_left--) { - DecompressBand23(pwc->decompress_data, - src, + DecompressBand23(pdec, src, pout_planar_y, pout_planar_u, pout_planar_v, - pwc->width, pwc->width); - src += pwc->vbandlength; + pdev->width, pdev->width); + src += pdev->vbandlength; pout_planar_y += bytes_per_block; - pout_planar_u += pwc->width; - pout_planar_v += pwc->width; + pout_planar_u += pdev->width; + pout_planar_v += pdev->width; } mutex_unlock(&pdec->lock); } diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h index d64a3c281af6..c655b1c1e6a9 100644 --- a/drivers/media/video/pwc/pwc-dec23.h +++ b/drivers/media/video/pwc/pwc-dec23.h @@ -25,17 +25,20 @@ #ifndef PWC_DEC23_H #define PWC_DEC23_H -#include "pwc.h" +struct pwc_device; struct pwc_dec23_private { struct mutex lock; + unsigned char last_cmd, last_cmd_valid; + unsigned int scalebits; unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */ unsigned int reservoir; unsigned int nbits_in_reservoir; + const unsigned char *stream; int temp_colors[16]; @@ -51,8 +54,8 @@ struct pwc_dec23_private }; -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); -void pwc_dec23_decompress(const struct pwc_device *pwc, +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd); +void pwc_dec23_decompress(struct pwc_device *pdev, const void *src, void *dst); #endif diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 943d37ad0d33..122fbd0081eb 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -128,18 +128,11 @@ static struct usb_driver pwc_driver = { #define MAX_DEV_HINTS 20 #define MAX_ISOC_ERRORS 20 -static int default_fps = 10; #ifdef CONFIG_USB_PWC_DEBUG int pwc_trace = PWC_DEBUG_LEVEL; #endif static int power_save = -1; -static int led_on = 100, led_off; /* defaults to LED that is on while in use */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; +static int leds[2] = { 100, 0 }; /***/ @@ -386,8 +379,8 @@ static int pwc_isoc_init(struct pwc_device *pdev) retry: /* We first try with low compression and then retry with a higher compression setting if there is not enough bandwidth. */ - ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, - pdev->vframes, &compression); + ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, + pdev->vframes, &compression, 1); /* Get the current alternate interface, adjust packet size */ intf = usb_ifnum_to_if(udev, 0); @@ -597,23 +590,9 @@ leave: static void pwc_video_release(struct v4l2_device *v) { struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); - int hint; - - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - - /* Free intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", - pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } v4l2_ctrl_handler_free(&pdev->ctrl_handler); - + kfree(pdev->ctrl_buf); kfree(pdev); } @@ -758,7 +737,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* Turn on camera and set LEDS on */ pwc_camera_power(pdev, 1); - pwc_set_leds(pdev, led_on, led_off); + pwc_set_leds(pdev, leds[0], leds[1]); r = pwc_isoc_init(pdev); if (r) { @@ -813,10 +792,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int hint, rc; + int rc; int features = 0; int compression = 0; - int video_nr = -1; /* default: use next available device */ int my_power_save = power_save; char serial_number[30], *name; @@ -1076,7 +1054,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return -ENOMEM; } pdev->type = type_id; - pdev->vframes = default_fps; pdev->features = features; pwc_construct(pdev); /* set min/max sizes correct */ @@ -1107,24 +1084,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } + /* Allocate USB command buffers */ + pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL); + if (!pdev->ctrl_buf) { + PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); + rc = -ENOMEM; + goto err_free_mem; } - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - #ifdef CONFIG_USB_PWC_DEBUG /* Query sensor type */ if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { @@ -1138,8 +1105,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); /* Setup intial videomode */ - rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, pdev->vframes, - &compression); + rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, + V4L2_PIX_FMT_YUV420, 30, &compression, 1); if (rc) goto err_free_mem; @@ -1164,7 +1131,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; pdev->vdev.v4l2_dev = &pdev->v4l2_dev; - rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); + rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); if (rc < 0) { PWC_ERROR("Failed to register as video device (%d).\n", rc); goto err_unregister_v4l2_dev; @@ -1207,8 +1174,7 @@ err_unregister_v4l2_dev: err_free_controls: v4l2_ctrl_handler_free(&pdev->ctrl_handler); err_free_mem: - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = NULL; + kfree(pdev->ctrl_buf); kfree(pdev); return rc; } @@ -1243,27 +1209,19 @@ static void usb_pwc_disconnect(struct usb_interface *intf) * Initialization code & module stuff */ -static int fps; -static int leds[2] = { -1, -1 }; static unsigned int leds_nargs; -static char *dev_hint[MAX_DEV_HINTS]; -static unsigned int dev_hint_nargs; -module_param(fps, int, 0444); #ifdef CONFIG_USB_PWC_DEBUG module_param_named(trace, pwc_trace, int, 0644); #endif module_param(power_save, int, 0644); module_param_array(leds, int, &leds_nargs, 0444); -module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); -MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); #ifdef CONFIG_USB_PWC_DEBUG MODULE_PARM_DESC(trace, "For debugging purposes"); #endif MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); @@ -1273,114 +1231,13 @@ MODULE_VERSION( PWC_VERSION ); static int __init usb_pwc_init(void) { - int i; - -#ifdef CONFIG_USB_PWC_DEBUG - PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); - PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); - - if (pwc_trace >= 0) { - PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); - } -#endif - - if (fps) { - if (fps < 4 || fps > 30) { - PWC_ERROR("Framerate out of bounds (4-30).\n"); - return -EINVAL; - } - default_fps = fps; - PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); - } - - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; - - /* Big device node whoopla. Basically, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type - & serial number. The format is [type[.serialnumber]:]node. - - Any camera that isn't matched by these rules gets the next - available free device node. - */ - for (i = 0; i < MAX_DEV_HINTS; i++) { - char *s, *colon, *dot; - - /* This loop also initializes the array */ - device_hint[i].pdev = NULL; - s = dev_hint[i]; - if (s != NULL && *s != '\0') { - device_hint[i].type = -1; /* wildcard */ - strcpy(device_hint[i].serial_number, "*"); - - /* parse string: chop at ':' & '/' */ - colon = dot = s; - while (*colon != '\0' && *colon != ':') - colon++; - while (*dot != '\0' && *dot != '.') - dot++; - /* Few sanity checks */ - if (*dot != '\0' && dot > colon) { - PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n"); - return -EINVAL; - } - - if (*colon == '\0') { - /* No colon */ - if (*dot != '\0') { - PWC_ERROR("Malformed camera hint: no colon + device node given.\n"); - return -EINVAL; - } - else { - /* No type or serial number specified, just a number. */ - device_hint[i].device_node = - simple_strtol(s, NULL, 10); - } - } - else { - /* There's a colon, so we have at least a type and a device node */ - device_hint[i].type = - simple_strtol(s, NULL, 10); - device_hint[i].device_node = - simple_strtol(colon + 1, NULL, 10); - if (*dot != '\0') { - /* There's a serial number as well */ - int k; - - dot++; - k = 0; - while (*dot != ':' && k < 29) { - device_hint[i].serial_number[k++] = *dot; - dot++; - } - device_hint[i].serial_number[k] = '\0'; - } - } - PWC_TRACE("device_hint[%d]:\n", i); - PWC_TRACE(" type : %d\n", device_hint[i].type); - PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number); - PWC_TRACE(" node : %d\n", device_hint[i].device_node); - } - else - device_hint[i].type = 0; /* not filled */ - } /* ..for MAX_DEV_HINTS */ - - PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver); return usb_register(&pwc_driver); } static void __exit usb_pwc_exit(void) { - PWC_DEBUG_MODULE("Deregistering driver.\n"); usb_deregister(&pwc_driver); - PWC_INFO("Philips webcam module removed.\n"); } module_init(usb_pwc_init); module_exit(usb_pwc_exit); - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c index 23a55b5814fc..9be5adffa874 100644 --- a/drivers/media/video/pwc/pwc-misc.c +++ b/drivers/media/video/pwc/pwc-misc.c @@ -90,5 +90,4 @@ void pwc_construct(struct pwc_device *pdev) pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } - pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ } diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 80e25842e84a..f495eeb5403a 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -493,16 +493,11 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) (pixelformat>>24)&255); ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height, - pdev->vframes, &compression); + pixelformat, 30, &compression, 0); PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); - if (ret == 0) { - pdev->pixfmt = pixelformat; - pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, - pdev->pixfmt); - } - + pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); leave: mutex_unlock(&pdev->udevlock); return ret; @@ -777,33 +772,33 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev) static int pwc_set_motor(struct pwc_device *pdev) { int ret; - u8 buf[4]; - buf[0] = 0; + pdev->ctrl_buf[0] = 0; if (pdev->motor_pan_reset->is_new) - buf[0] |= 0x01; + pdev->ctrl_buf[0] |= 0x01; if (pdev->motor_tilt_reset->is_new) - buf[0] |= 0x02; + pdev->ctrl_buf[0] |= 0x02; if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) { ret = send_control_msg(pdev, SET_MPT_CTL, - PT_RESET_CONTROL_FORMATTER, buf, 1); + PT_RESET_CONTROL_FORMATTER, + pdev->ctrl_buf, 1); if (ret < 0) return ret; } - memset(buf, 0, sizeof(buf)); + memset(pdev->ctrl_buf, 0, 4); if (pdev->motor_pan->is_new) { - buf[0] = pdev->motor_pan->val & 0xFF; - buf[1] = (pdev->motor_pan->val >> 8); + pdev->ctrl_buf[0] = pdev->motor_pan->val & 0xFF; + pdev->ctrl_buf[1] = (pdev->motor_pan->val >> 8); } if (pdev->motor_tilt->is_new) { - buf[2] = pdev->motor_tilt->val & 0xFF; - buf[3] = (pdev->motor_tilt->val >> 8); + pdev->ctrl_buf[2] = pdev->motor_tilt->val & 0xFF; + pdev->ctrl_buf[3] = (pdev->motor_tilt->val >> 8); } if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) { ret = send_control_msg(pdev, SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, - buf, sizeof(buf)); + pdev->ctrl_buf, 4); if (ret < 0) return ret; } @@ -1094,6 +1089,63 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, return 0; } +static int pwc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct pwc_device *pdev = video_drvdata(file); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(parm, 0, sizeof(*parm)); + + parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parm->parm.capture.readbuffers = MIN_FRAMES; + parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.denominator = pdev->vframes; + parm->parm.capture.timeperframe.numerator = 1; + + return 0; +} + +static int pwc_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct pwc_device *pdev = video_drvdata(file); + int compression = 0; + int ret, fps; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + parm->parm.capture.timeperframe.numerator == 0) + return -EINVAL; + + if (pwc_test_n_set_capt_file(pdev, file)) + return -EBUSY; + + fps = parm->parm.capture.timeperframe.denominator / + parm->parm.capture.timeperframe.numerator; + + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + ret = -ENODEV; + goto leave; + } + + if (pdev->iso_init) { + ret = -EBUSY; + goto leave; + } + + ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, + fps, &compression, 0); + + pwc_g_parm(file, fh, parm); + +leave: + mutex_unlock(&pdev->udevlock); + return ret; +} + static int pwc_log_status(struct file *file, void *priv) { struct pwc_device *pdev = video_drvdata(file); @@ -1120,4 +1172,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_log_status = pwc_log_status, .vidioc_enum_framesizes = pwc_enum_framesizes, .vidioc_enum_frameintervals = pwc_enum_frameintervals, + .vidioc_g_parm = pwc_g_parm, + .vidioc_s_parm = pwc_s_parm, }; diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 47c518fef179..e4d4d711dd1f 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -44,6 +44,8 @@ #ifdef CONFIG_USB_PWC_INPUT_EVDEV #include <linux/input.h> #endif +#include "pwc-dec1.h" +#include "pwc-dec23.h" /* Version block */ #define PWC_VERSION "10.0.15" @@ -132,9 +134,6 @@ #define DEVICE_USE_CODEC3(x) ((x)>=700) #define DEVICE_USE_CODEC23(x) ((x)>=675) -/* from pwc-dec.h */ -#define PWCX_FLAG_PLANAR 0x0001 - /* Request types: video */ #define SET_LUM_CTL 0x01 #define GET_LUM_CTL 0x02 @@ -248,8 +247,8 @@ struct pwc_device char vmirror; /* for ToUCaM series */ char power_save; /* Do powersaving for this cam */ - int cmd_len; unsigned char cmd_buf[13]; + unsigned char *ctrl_buf; struct urb *urbs[MAX_ISO_BUFS]; char iso_init; @@ -272,7 +271,10 @@ struct pwc_device int frame_total_size; /* including header & trailer */ int drop_frames; - void *decompress_data; /* private data for decompression engine */ + union { /* private data for decompression engine */ + struct pwc_dec1_private dec1; + struct pwc_dec23_private dec23; + }; /* * We have an 'image' and a 'view', where 'image' is the fixed-size img @@ -364,7 +366,7 @@ void pwc_construct(struct pwc_device *pdev); /** Functions in pwc-ctrl.c */ /* Request a certain video mode. Returns < 0 if not possible */ extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, - int frames, int *compression); + int pixfmt, int frames, int *compression, int send_to_cam); extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); |