Re: [PATCH] to add support for certain Jeilin dual-mode cameras.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello, Theodore

On Sun, Aug 2, 2009 at 1:56 AM, Theodore
Kilgore<kilgota@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> Several cameras are supported here, which all share the same USB
> Vendor:Product number when started up in streaming mode. All of these
> cameras use bulk transport for streaming, and all of them produce frames in
> JPEG format.
>
> Patch follows.
>
> Signed-off-by Theodore Kilgore <kilgota@xxxxxxxxxx>
>
> ------
> diff -r d189fb4be712 linux/Documentation/video4linux/gspca.txt
> --- a/linux/Documentation/video4linux/gspca.txt Wed Jul 29 10:01:54 2009
> +0200
> +++ b/linux/Documentation/video4linux/gspca.txt Sat Aug 01 15:42:02 2009
> -0500
> @@ -239,6 +239,9 @@
>  pac7311                093a:2629       Genious iSlim 300
>  pac7311                093a:262a       Webcam 300k
>  pac7311                093a:262c       Philips SPC 230 NC
> +jeilinj                0979:0280       Cobra DMC 300
> +jeilinj                0979:0280       FlyCamOne
> +jeilinj                0979:0280       Sakar 57379
>  zc3xx          0ac8:0302       Z-star Vimicro zc0302
>  vc032x         0ac8:0321       Vimicro generic vc0321
>  vc032x         0ac8:0323       Vimicro Vc0323
> diff -r d189fb4be712 linux/drivers/media/video/gspca/Kconfig
> --- a/linux/drivers/media/video/gspca/Kconfig   Wed Jul 29 10:01:54 2009
> +0200
> +++ b/linux/drivers/media/video/gspca/Kconfig   Sat Aug 01 15:42:02 2009
> -0500
> @@ -47,6 +47,15 @@
>          To compile this driver as a module, choose M here: the
>          module will be called gspca_finepix.
>
> +config USB_GSPCA_JEILINJ
> +       tristate "Jeilin JPEG USB V4L2 driver"
> +       depends on VIDEO_V4L2 && USB_GSPCA
> +       help
> +         Say Y here if you want support for cameras based on this Jeilin
> chip.
> +
> +         To compile this driver as a module, choose M here: the
> +         module will be called gspca_jeilinj.
> +
>  config USB_GSPCA_MARS
>        tristate "Mars USB Camera Driver"
>        depends on VIDEO_V4L2 && USB_GSPCA
> diff -r d189fb4be712 linux/drivers/media/video/gspca/Makefile
> --- a/linux/drivers/media/video/gspca/Makefile  Wed Jul 29 10:01:54 2009
> +0200
> +++ b/linux/drivers/media/video/gspca/Makefile  Sat Aug 01 15:42:02 2009
> -0500
> @@ -2,6 +2,7 @@
>  obj-$(CONFIG_USB_GSPCA_CONEX)    += gspca_conex.o
>  obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
>  obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
> +obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
>  obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
>  obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
>  obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
> @@ -30,6 +31,7 @@
>  gspca_conex-objs    := conex.o
>  gspca_etoms-objs    := etoms.o
>  gspca_finepix-objs  := finepix.o
> +gspca_jeilinj-objs  := jeilinj.o
>  gspca_mars-objs     := mars.o
>  gspca_mr97310a-objs := mr97310a.o
>  gspca_ov519-objs    := ov519.o
> diff -r d189fb4be712 linux/drivers/media/video/gspca/jeilinj.c
> --- /dev/null   Thu Jan 01 00:00:00 1970 +0000
> +++ b/linux/drivers/media/video/gspca/jeilinj.c Sat Aug 01 15:42:02 2009
> -0500
> @@ -0,0 +1,387 @@
> +/*
> + * Jeilinj subdriver
> + *
> + * Supports some Jeilin dual-mode cameras which use bulk transport and
> + * download raw JPEG data.
> + *
> + * Copyright (C) 2009 Theodore Kilgore
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#define MODULE_NAME "jeilinj"
> +
> +#include <linux/workqueue.h>
> +#include "gspca.h"
> +#include "jpeg.h"
> +
> +MODULE_AUTHOR("Theodore Kilgore <kilgota@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
> +MODULE_LICENSE("GPL");
> +
> +/* Default timeouts, in ms */
> +#define JEILINJ_CMD_TIMEOUT 500
> +#define JEILINJ_DATA_TIMEOUT 1000
> +
> +/* Maximum transfer size to use. */
> +#define JEILINJ_MAX_TRANSFER 0x200
> +
> +#define FRAME_HEADER_LEN 0x10
> +
> +/* Structure to hold all of our device specific stuff */
> +struct sd {
> +       struct gspca_dev gspca_dev;     /* !! must be the first item */
> +       const struct v4l2_pix_format *cap_mode;
> +       /* Driver stuff */
> +       struct work_struct work_struct;
> +       struct workqueue_struct *work_thread;
> +       u8 quality;                              /* image quality */
> +       u8 jpegqual;                            /* webcam quality */
> +       u8 *jpeg_hdr;
> +};
> +
> +       struct jlj_command {
> +               unsigned char instruction[2];
> +               unsigned char ack_wanted;
> +       };
> +
> +/* AFAICT these cameras will only do 320x240. */
> +static struct v4l2_pix_format jlj_mode[] = {
> +       { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
> +               .bytesperline = 320,
> +               .sizeimage = 320 * 240,
> +               .colorspace = V4L2_COLORSPACE_JPEG,
> +               .priv = 0}
> +};
> +
> +/*
> + * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
> + * and 0x82 for bulk transfer.
> + */
> +
> +/* All commands are two bytes only */
> +static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
> +{
> +       int retval;
> +
> +       memcpy(gspca_dev->usb_buf, command, 2);
> +       retval = usb_bulk_msg(gspca_dev->dev,
> +                       usb_sndbulkpipe(gspca_dev->dev, 3),
> +                       gspca_dev->usb_buf, 2, NULL, 500);
> +       if (retval < 0)
> +               PDEBUG(D_ERR, "command write [%02x] error %d",
> +                               gspca_dev->usb_buf[0], retval);
> +       return retval;
> +}
> +
> +/* Responses are one byte only */
> +static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
> +{
> +       int retval;
> +
> +       retval = usb_bulk_msg(gspca_dev->dev,
> +       usb_rcvbulkpipe(gspca_dev->dev, 0x84),
> +                               gspca_dev->usb_buf, 1, NULL, 500);
> +       response = gspca_dev->usb_buf[0];
> +       if (retval < 0)
> +               PDEBUG(D_ERR, "read command [%02x] error %d",
> +                               gspca_dev->usb_buf[0], retval);
> +       return retval;
> +}
> +
> +static int jlj_start(struct gspca_dev *gspca_dev)
> +{
> +       int i;
> +       int retval = -1;
> +       u8 response = 0xff;
> +       struct jlj_command start_commands[] = {
> +               {{0x71, 0x81}, 0},
> +               {{0x70, 0x05}, 0},
> +               {{0x95, 0x70}, 1},
> +               {{0x71, 0x81}, 0},
> +               {{0x70, 0x04}, 0},
> +               {{0x95, 0x70}, 1},
> +               {{0x71, 0x00}, 0},
> +               {{0x70, 0x08}, 0},
> +               {{0x95, 0x70}, 1},
> +               {{0x94, 0x02}, 0},
> +               {{0xde, 0x24}, 0},
> +               {{0x94, 0x02}, 0},
> +               {{0xdd, 0xf0}, 0},
> +               {{0x94, 0x02}, 0},
> +               {{0xe3, 0x2c}, 0},
> +               {{0x94, 0x02}, 0},
> +               {{0xe4, 0x00}, 0},
> +               {{0x94, 0x02}, 0},
> +               {{0xe5, 0x00}, 0},
> +               {{0x94, 0x02}, 0},
> +               {{0xe6, 0x2c}, 0},
> +               {{0x94, 0x03}, 0},
> +               {{0xaa, 0x00}, 0},
> +               {{0x71, 0x1e}, 0},
> +               {{0x70, 0x06}, 0},
> +               {{0x71, 0x80}, 0},
> +               {{0x70, 0x07}, 0}
> +       };
> +       for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
> +               retval = jlj_write2(gspca_dev,
> start_commands[i].instruction);
> +               if (retval < 0)
> +                       return retval;
> +               if (start_commands[i].ack_wanted)
> +                       retval = jlj_read1(gspca_dev, response);
> +               if (retval < 0)
> +                       return retval;
> +       }
> +       PDEBUG(D_ERR, "jlj_start retval is %d", retval);
> +       return retval;
> +}
> +
> +static int jlj_stop(struct gspca_dev *gspca_dev)
> +{
> +       int i;
> +       int retval;
> +       struct jlj_command stop_commands[] = {
> +               {{0x71, 0x00}, 0},
> +               {{0x70, 0x09}, 0},
> +               {{0x71, 0x80}, 0},
> +               {{0x70, 0x05}, 0}
> +       };
> +       for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
> +               retval = jlj_write2(gspca_dev,
> stop_commands[i].instruction);
> +               if (retval < 0)
> +                       return retval;
> +       }
> +       return retval;
> +}
> +
> +/* This function is called as a workqueue function and runs whenever the
> camera
> + * is streaming data. Because it is a workqueue function it is allowed to
> sleep
> + * so we can use synchronous USB calls. To avoid possible collisions with
> other
> + * threads attempting to use the camera's USB interface the gspca usb_lock
> is
> + * used when performing the one USB control operation inside the workqueue,
> + * which tells the camera to close the stream. In practice the only thing
> + * which needs to be protected against is the usb_set_interface call that
> + * gspca makes during stream_off. Otherwise the camera doesn't provide any
> + * controls that the user could try to change.
> + */
> +
> +static void jlj_dostream(struct work_struct *work)
> +{
> +       struct sd *dev = container_of(work, struct sd, work_struct);
> +       struct gspca_dev *gspca_dev = &dev->gspca_dev;
> +       struct gspca_frame *frame;
> +       int blocks_left; /* 0x200-sized blocks remaining in current frame.
> */
> +       int size_in_blocks;
> +       int act_len;
> +       int discarding = 0; /* true if we failed to get space for frame. */
> +       int packet_type;
> +       int ret;
> +       u8 *buffer;
> +
> +       buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
> +       if (!buffer) {
> +               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
> +               goto quit_stream;
> +       }

This clean up on error path looks bad. On quit_stream you have:

> +quit_stream:
> +       mutex_lock(&gspca_dev->usb_lock);
> +       if (gspca_dev->present)
> +               jlj_stop(gspca_dev);
> +       mutex_unlock(&gspca_dev->usb_lock);
> +       kfree(buffer);

kfree() tries to free null buffer after kmalloc for buffer failed.
Please, check if i'm not wrong.


-- 
Best regards, Klimov Alexey
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux