/* initialize variables depending on type and decompressor */ void pwc_construct(struct pwc_device *pdev) { if (DEVICE_USE_CODEC1(pdev->type)) { pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; pdev->vcinterface = 2; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } else if (DEVICE_USE_CODEC3(pdev->type)) { pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; pdev->vcinterface = 3; pdev->vendpoint = 5; pdev->frame_header_size = TOUCAM_HEADER_SIZE; pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; } else { /* if (DEVICE_USE_CODEC2(pdev->type)) */ pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; pdev->vcinterface = 3; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } }
int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, 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, 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, pixfmt, frames, compression, send_to_cam); } else if (DEVICE_USE_CODEC3(pdev->type)) { ret = set_video_mode_Kiara(pdev, size, pixfmt, frames, compression, send_to_cam); } else { 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); return ret; } pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); return 0; }
static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) { memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); f->fmt.pix.width = pdev->view.x; f->fmt.pix.height = pdev->view.y; f->fmt.pix.field = V4L2_FIELD_NONE; if (pdev->vpalette == VIDEO_PALETTE_YUV420P) { f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; } else { /* vbandlength contains 4 lines ... */ f->fmt.pix.bytesperline = pdev->vbandlength/4; f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame); if (DEVICE_USE_CODEC1(pdev->type)) f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1; else f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2; } PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage, (f->fmt.pix.pixelformat)&255, (f->fmt.pix.pixelformat>>8)&255, (f->fmt.pix.pixelformat>>16)&255, (f->fmt.pix.pixelformat>>24)&255); }
/* initialize variables depending on type and decompressor*/ void pwc_construct(struct pwc_device *pdev) { if (DEVICE_USE_CODEC1(pdev->type)) { pdev->view_min.x = 128; pdev->view_min.y = 96; pdev->view_max.x = 352; pdev->view_max.y = 288; pdev->abs_max.x = 352; pdev->abs_max.y = 288; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; pdev->vcinterface = 2; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } else if (DEVICE_USE_CODEC3(pdev->type)) { pdev->view_min.x = 160; pdev->view_min.y = 120; pdev->view_max.x = 640; pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; pdev->abs_max.x = 640; pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 5; pdev->frame_header_size = TOUCAM_HEADER_SIZE; pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { pdev->view_min.x = 128; pdev->view_min.y = 96; /* Anthill bug #38: PWC always reports max size, even without PWCX */ pdev->view_max.x = 640; pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; pdev->abs_max.x = 640; pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; /* length of image, in YUV format; always allocate enough memory. */ pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); }
unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) { unsigned int ret; if (DEVICE_USE_CODEC1(pdev->type)) { ret = pwc_get_fps_Nala(pdev, index, size); } else if (DEVICE_USE_CODEC3(pdev->type)) { ret = pwc_get_fps_Kiara(pdev, index, size); } else { ret = pwc_get_fps_Timon(pdev, index, size); } return ret; }
/* ioctl(VIDIOC_TRY_FMT) */ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); return -EINVAL; } switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: break; case V4L2_PIX_FMT_PWC1: if (DEVICE_USE_CODEC23(pdev->type)) { PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n"); return -EINVAL; } break; case V4L2_PIX_FMT_PWC2: if (DEVICE_USE_CODEC1(pdev->type)) { PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n"); return -EINVAL; } break; default: PWC_DEBUG_IOCTL("Unsupported pixel format\n"); return -EINVAL; } if (f->fmt.pix.width > pdev->view_max.x) f->fmt.pix.width = pdev->view_max.x; else if (f->fmt.pix.width < pdev->view_min.x) f->fmt.pix.width = pdev->view_min.x; if (f->fmt.pix.height > pdev->view_max.y) f->fmt.pix.height = pdev->view_max.y; else if (f->fmt.pix.height < pdev->view_min.y) f->fmt.pix.height = pdev->view_min.y; return 0; }
/* ioctl(VIDIOC_TRY_FMT) */ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) { int size; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); return -EINVAL; } switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: break; case V4L2_PIX_FMT_PWC1: if (DEVICE_USE_CODEC23(pdev->type)) { PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n"); return -EINVAL; } break; case V4L2_PIX_FMT_PWC2: if (DEVICE_USE_CODEC1(pdev->type)) { PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n"); return -EINVAL; } break; default: PWC_DEBUG_IOCTL("Unsupported pixel format\n"); return -EINVAL; } size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height); pwc_vidioc_fill_fmt(f, pwc_image_sizes[size][0], pwc_image_sizes[size][1], f->fmt.pix.pixelformat); return 0; }
int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) { int n, line, col; void *yuv, *image; u16 *src; u16 *dsty, *dstu, *dstv; image = vb2_plane_vaddr(&fbuf->vb, 0); yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ /* Raw format; that's easy... */ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) { struct pwc_raw_frame *raw_frame = image; raw_frame->type = cpu_to_le16(pdev->type); raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength); /* cmd_buf is always 4 bytes, but sometimes, only the * first 3 bytes is filled (Nala case). We can * determine this using the type of the webcam */ memcpy(raw_frame->cmd, pdev->cmd_buf, 4); memcpy(raw_frame+1, yuv, pdev->frame_size); vb2_set_plane_payload(&fbuf->vb, 0, pdev->frame_size + sizeof(struct pwc_raw_frame)); return 0; } vb2_set_plane_payload(&fbuf->vb, 0, pdev->width * pdev->height * 3 / 2); if (pdev->vbandlength == 0) { /* Uncompressed mode. * * We do some byte shuffling here to go from the * native format to YUV420P. */ src = (u16 *)yuv; n = pdev->width * pdev->height; dsty = (u16 *)(image); dstu = (u16 *)(image + n); dstv = (u16 *)(image + n + n / 4); for (line = 0; line < pdev->height; line++) { for (col = 0; col < pdev->width; col += 4) { *dsty++ = *src++; *dsty++ = *src++; if (line & 1) *dstv++ = *src++; else *dstu++ = *src++; } } return 0; } /* * Compressed; * the decompressor routines will write the data in planar format * immediately. */ if (DEVICE_USE_CODEC1(pdev->type)) { /* TODO & FIXME */ PWC_ERROR("This chipset is not supported for now\n"); return -ENXIO; /* No such device or address: missing decompressor */ } else { pwc_dec23_decompress(pdev, yuv, image); } return 0; }