diff options
46 files changed, 2090 insertions, 644 deletions
diff --git a/linux/Documentation/video4linux/gspca.txt b/linux/Documentation/video4linux/gspca.txt index 76203a221..4686e84dd 100644 --- a/linux/Documentation/video4linux/gspca.txt +++ b/linux/Documentation/video4linux/gspca.txt @@ -183,6 +183,7 @@ ov534 06f8:3002 Hercules Blog Webcam ov534 06f8:3003 Hercules Dualpix HD Weblog sonixj 06f8:3004 Hercules Classic Silver sonixj 06f8:3008 Hercules Deluxe Optical Glass +pac7311 06f8:3009 Hercules Classic Link spca508 0733:0110 ViewQuest VQ110 spca508 0130:0130 Clone Digital Webcam 11043 spca501 0733:0401 Intel Create and Share diff --git a/linux/drivers/media/dvb/Kconfig b/linux/drivers/media/dvb/Kconfig index b01986918..1d0e4b1ef 100644 --- a/linux/drivers/media/dvb/Kconfig +++ b/linux/drivers/media/dvb/Kconfig @@ -2,6 +2,19 @@ # DVB device configuration # +config DVB_MAX_ADAPTERS + int "maximum number of DVB/ATSC adapters" + depends on DVB_CORE + default 8 + range 1 255 + help + Maximum number of DVB/ATSC adapters. Increasing this number + increases the memory consumption of the DVB subsystem even + if a much lower number of DVB/ATSC adapters is present. + Only values in the range 4-32 are tested. + + If you are unsure about this, use the default value 8 + config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index 41166d407..56a11d32a 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -77,6 +77,7 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open( #define FESTATE_ZIGZAG_FAST 32 #define FESTATE_ZIGZAG_SLOW 64 #define FESTATE_DISEQC 128 +#define FESTATE_ERROR 256 #define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC) #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST) #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) @@ -274,6 +275,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra { int autoinversion; int ready = 0; + int fe_set_err = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; int original_inversion = fepriv->parameters.inversion; u32 original_frequency = fepriv->parameters.frequency; @@ -350,7 +352,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra if (autoinversion) fepriv->parameters.inversion = fepriv->inversion; if (fe->ops.set_frontend) - fe->ops.set_frontend(fe, &fepriv->parameters); + fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters); + if (fe_set_err < 0) { + fepriv->state = FESTATE_ERROR; + return fe_set_err; + } fepriv->parameters.frequency = original_frequency; fepriv->parameters.inversion = original_inversion; @@ -362,6 +368,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra static void dvb_frontend_swzigzag(struct dvb_frontend *fe) { fe_status_t s = 0; + int retval = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; /* if we've got no parameters, just keep idling */ @@ -375,8 +382,12 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { if (fepriv->state & FESTATE_RETUNE) { if (fe->ops.set_frontend) - fe->ops.set_frontend(fe, &fepriv->parameters); - fepriv->state = FESTATE_TUNED; + retval = fe->ops.set_frontend(fe, + &fepriv->parameters); + if (retval < 0) + fepriv->state = FESTATE_ERROR; + else + fepriv->state = FESTATE_TUNED; } fepriv->delay = 3*HZ; fepriv->quality = 0; @@ -454,7 +465,11 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) fepriv->delay = fepriv->min_delay; /* peform a tune */ - if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) { + retval = dvb_frontend_swzigzag_autotune(fe, + fepriv->check_wrapped); + if (retval < 0) { + return; + } else if (retval) { /* OK, if we've run out of trials at the fast speed. * Drop back to slow for the _next_ attempt */ fepriv->state = FESTATE_SEARCHING_SLOW; @@ -834,6 +849,15 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, } } + /* check for supported modulation */ + if (fe->ops.info.type == FE_QAM && + (parms->u.qam.modulation > QAM_AUTO || + !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { + printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", + fe->dvb->num, fe->id, parms->u.qam.modulation); + return -EINVAL; + } + return 0; } @@ -1614,7 +1638,8 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, /* if retune was requested but hasn't occured yet, prevent * that user get signal state from previous tuning */ - if(fepriv->state == FESTATE_RETUNE) { + if (fepriv->state == FESTATE_RETUNE || + fepriv->state == FESTATE_ERROR) { err=0; *status = 0; break; diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h index 487919bea..895e2efca 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h @@ -30,7 +30,12 @@ #define DVB_MAJOR 212 +#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 +#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS +#else +#warning invalid CONFIG_DVB_MAX_ADAPTERS value #define DVB_MAX_ADAPTERS 8 +#endif #define DVB_UNSET (-1) diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 656604dc9..d12c8c890 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -2275,11 +2275,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) if (disable_ir) { ir->get_key = NULL; - return ; + return; } #else - struct i2c_board_info info; - struct IR_i2c_init_data init_data; const unsigned short addr_list[] = { 0x30, 0x47, I2C_CLIENT_END }; @@ -2287,9 +2285,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) if (disable_ir) return; - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + memset(&dev->info, 0, sizeof(&dev->info)); + memset(&dev->init_data, 0, sizeof(dev->init_data)); + strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE); #endif /* detect & configure */ @@ -2306,9 +2304,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) snprintf(ir->name, sizeof(ir->name), "i2c IR (EM28XX Terratec)"); #else - init_data.ir_codes = &ir_codes_em_terratec_table; - init_data.get_key = em28xx_get_key_terratec; - init_data.name = "i2c IR (EM28XX Terratec)"; + dev->init_data.ir_codes = &ir_codes_em_terratec_table; + dev->init_data.get_key = em28xx_get_key_terratec; + dev->init_data.name = "i2c IR (EM28XX Terratec)"; #endif break; case (EM2820_BOARD_PINNACLE_USB_2): @@ -2318,9 +2316,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) snprintf(ir->name, sizeof(ir->name), "i2c IR (EM28XX Pinnacle PCTV)"); #else - init_data.ir_codes = &ir_codes_pinnacle_grey_table; - init_data.get_key = em28xx_get_key_pinnacle_usb_grey; - init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; + dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table; + dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; + dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; #endif break; case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): @@ -2330,9 +2328,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) snprintf(ir->name, sizeof(ir->name), "i2c IR (EM2840 Hauppauge)"); #else - init_data.ir_codes = &ir_codes_hauppauge_new_table; - init_data.get_key = em28xx_get_key_em_haup; - init_data.name = "i2c IR (EM2840 Hauppauge)"; + dev->init_data.ir_codes = &ir_codes_hauppauge_new_table; + dev->init_data.get_key = em28xx_get_key_em_haup; + dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; #endif break; case (EM2820_BOARD_MSI_VOX_USB_2): @@ -2346,9 +2344,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) - if (init_data.name) - info.platform_data = &init_data; - i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); + if (dev->init_data.name) + dev->info.platform_data = &dev->init_data; + i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list); #endif } diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index a603d981b..e5d6b0695 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -606,6 +606,10 @@ struct em28xx { struct delayed_work sbutton_query_work; struct em28xx_dvb *dvb; + + /* I2C keyboard data */ + struct i2c_board_info info; + struct IR_i2c_init_data init_data; }; struct em28xx_ops { diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 301325134..140c8f320 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -3,6 +3,21 @@ * * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com> * + * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+ + * and for the routines for detecting and classifying these various cameras, + * + * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu> + * + * Acknowledgements: + * + * The MR97311A support in gspca/mars.c has been helpful in understanding some + * of the registers in these cameras. + * + * Hans de Goede <hdgoede@redhat.com> and + * Thomas Kaiser <thomas@kaiser-linux.li> + * have assisted with their experience. Each of them has also helped by + * testing a previously unsupported camera. + * * 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 @@ -22,18 +37,108 @@ #include "gspca.h" -MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>"); +#define CAM_TYPE_CIF 0 +#define CAM_TYPE_VGA 1 + +#define MR97310A_BRIGHTNESS_MIN -254 +#define MR97310A_BRIGHTNESS_MAX 255 +#define MR97310A_BRIGHTNESS_DEFAULT 0 + +#define MR97310A_EXPOSURE_MIN 300 +#define MR97310A_EXPOSURE_MAX 4095 +#define MR97310A_EXPOSURE_DEFAULT 1000 + +#define MR97310A_GAIN_MIN 0 +#define MR97310A_GAIN_MAX 31 +#define MR97310A_GAIN_DEFAULT 25 + +MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>," + "Theodore Kilgore <kilgota@auburn.edu>"); MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); MODULE_LICENSE("GPL"); +/* global parameters */ +int force_sensor_type = -1; +module_param(force_sensor_type, int, 0644); +MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ u8 sof_read; + u8 cam_type; /* 0 is CIF and 1 is VGA */ + u8 sensor_type; /* We use 0 and 1 here, too. */ + u8 do_lcd_stop; + + int brightness; + u16 exposure; + u8 gain; +}; + +struct sensor_w_data { + u8 reg; + u8 flags; + u8 data[16]; + int len; }; +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static void setbrightness(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); + /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { + { +#define BRIGHTNESS_IDX 0 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = MR97310A_BRIGHTNESS_MIN, + .maximum = MR97310A_BRIGHTNESS_MAX, + .step = 1, + .default_value = MR97310A_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { +#define EXPOSURE_IDX 1 + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = MR97310A_EXPOSURE_MIN, + .maximum = MR97310A_EXPOSURE_MAX, + .step = 1, + .default_value = MR97310A_EXPOSURE_DEFAULT, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { +#define GAIN_IDX 2 + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = MR97310A_GAIN_MIN, + .maximum = MR97310A_GAIN_MAX, + .step = 1, + .default_value = MR97310A_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, }; static const struct v4l2_pix_format vga_mode[] = { @@ -65,7 +170,7 @@ static const struct v4l2_pix_format vga_mode[] = { }; /* the bytes to write are in gspca_dev->usb_buf */ -static int reg_w(struct gspca_dev *gspca_dev, int len) +static int mr_write(struct gspca_dev *gspca_dev, int len) { int rc; @@ -78,15 +183,249 @@ static int reg_w(struct gspca_dev *gspca_dev, int len) return rc; } +/* the bytes are read into gspca_dev->usb_buf */ +static int mr_read(struct gspca_dev *gspca_dev, int len) +{ + int rc; + + rc = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, len, NULL, 500); + if (rc < 0) + PDEBUG(D_ERR, "reg read [%02x] error %d", + gspca_dev->usb_buf[0], rc); + return rc; +} + +static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags, + const u8 *data, int len) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = flags; + gspca_dev->usb_buf[2] = reg; + memcpy(gspca_dev->usb_buf + 3, data, len); + + return mr_write(gspca_dev, len + 3); +} + +static int sensor_write_regs(struct gspca_dev *gspca_dev, + const struct sensor_w_data *data, int len) +{ + int i, rc; + + for (i = 0; i < len; i++) { + rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags, + data[i].data, data[i].len); + if (rc < 0) + return rc; + } + + return 0; +} + +static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 buf, confirm_reg; + int rc; + + buf = data; + rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1); + if (rc < 0) + return rc; + + buf = 0x01; + confirm_reg = sd->sensor_type ? 0x13 : 0x11; + rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1); + if (rc < 0) + return rc; + + return 0; +} + +static int cam_get_response16(struct gspca_dev *gspca_dev) +{ + __u8 *data = gspca_dev->usb_buf; + int err_code; + + data[0] = 0x21; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + return err_code; +} + +static int zero_the_pointer(struct gspca_dev *gspca_dev) +{ + __u8 *data = gspca_dev->usb_buf; + int err_code; + u8 status = 0; + int tries = 0; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + err_code = mr_write(gspca_dev, 1); + data[0] = 0x19; + data[1] = 0x51; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0xba; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + while (status != 0x0a && tries < 256) { + err_code = cam_get_response16(gspca_dev); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + if (status != 0x0a) + PDEBUG(D_ERR, "status is %02x", status); + + tries = 0; + while (tries < 4) { + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + + data[0] = 0x19; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + return 0; +} + +static u8 get_sensor_id(struct gspca_dev *gspca_dev) +{ + int err_code; + + gspca_dev->usb_buf[0] = 0x1e; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]); + + return gspca_dev->usb_buf[0]; +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { + struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; + __u8 *data = gspca_dev->usb_buf; + int err_code; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + + if (id->idProduct == 0x010e) { + sd->cam_type = CAM_TYPE_CIF; + cam->nmodes--; + + data[0] = 0x01; + data[1] = 0x01; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + msleep(200); + data[0] = get_sensor_id(gspca_dev); + /* + * Known CIF cameras. If you have another to report, please do + * + * Name byte just read sd->sensor_type + * reported by + * Sakar Spy-shot 0x28 T. Kilgore 0 + * Innovage 0xf5 (unstable) T. Kilgore 0 + * Vivitar Mini 0x53 H. De Goede 0 + * Vivitar Mini 0x04 / 0x24 E. Rodriguez 0 + * Vivitar Mini 0x08 T. Kilgore 1 + * Elta-Media 8212dc 0x23 T. Kaiser 1 + * Philips dig. keych. 0x37 T. Kilgore 1 + */ + if ((data[0] & 0x78) == 8 || + ((data[0] & 0x2) == 0x2 && data[0] != 0x53)) + sd->sensor_type = 1; + else + sd->sensor_type = 0; + + PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", + sd->sensor_type); + + if (force_sensor_type != -1) { + sd->sensor_type = !! force_sensor_type; + PDEBUG(D_PROBE, "Forcing sensor type to: %d", + sd->sensor_type); + } + + if (sd->sensor_type == 0) + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); + } else { + sd->cam_type = CAM_TYPE_VGA; + PDEBUG(D_PROBE, "MR97310A VGA camera detected"); + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | + (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); + } + + sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; + sd->exposure = MR97310A_EXPOSURE_DEFAULT; + sd->gain = MR97310A_GAIN_DEFAULT; + return 0; } @@ -96,183 +435,462 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int sd_start(struct gspca_dev *gspca_dev) +static int start_cif_cam(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 *data = gspca_dev->usb_buf; int err_code; - - sd->sof_read = 0; - - /* Note: register descriptions guessed from MR97113A driver */ - + const __u8 startup_string[] = { + 0x00, + 0x0d, + 0x01, + 0x00, /* Hsize/8 for 352 or 320 */ + 0x00, /* Vsize/4 for 288 or 240 */ + 0x13, /* or 0xbb, depends on sensor */ + 0x00, /* Hstart, depends on res. */ + 0x00, /* reserved ? */ + 0x00, /* Vstart, depends on res. and sensor */ + 0x50, /* 0x54 to get 176 or 160 */ + 0xc0 + }; + + /* Note: Some of the above descriptions guessed from MR97113A driver */ data[0] = 0x01; data[1] = 0x01; - err_code = reg_w(gspca_dev, 2); + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x00; - data[1] = 0x0d; - data[2] = 0x01; - data[5] = 0x2b; - data[7] = 0x00; - data[9] = 0x50; /* reg 8, no scale down */ - data[10] = 0xc0; + memcpy(data, startup_string, 11); + if (sd->sensor_type) + data[5] = 0xbb; switch (gspca_dev->width) { case 160: - data[9] |= 0x0c; /* reg 8, 4:1 scale down */ + data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ /* fall thru */ case 320: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ - case 640: default: - data[3] = 0x50; /* reg 2, H size */ - data[4] = 0x78; /* reg 3, V size */ - data[6] = 0x04; /* reg 5, H start */ - data[8] = 0x03; /* reg 7, V start */ + data[3] = 0x28; /* reg 2, H size/8 */ + data[4] = 0x3c; /* reg 3, V size/4 */ + data[6] = 0x14; /* reg 5, H start */ + data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */ break; - case 176: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ + data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ /* fall thru */ case 352: - data[3] = 0x2c; /* reg 2, H size */ - data[4] = 0x48; /* reg 3, V size */ - data[6] = 0x94; /* reg 5, H start */ - data[8] = 0x63; /* reg 7, V start */ + data[3] = 0x2c; /* reg 2, H size/8 */ + data[4] = 0x48; /* reg 3, V size/4 */ + data[6] = 0x06; /* reg 5, H start */ + data[8] = 0x06 + sd->sensor_type; /* reg 7, V start */ break; } - - err_code = reg_w(gspca_dev, 11); + err_code = mr_write(gspca_dev, 11); if (err_code < 0) return err_code; - data[0] = 0x0a; - data[1] = 0x80; - err_code = reg_w(gspca_dev, 2); + if (!sd->sensor_type) { + const struct sensor_w_data cif_sensor0_init_data[] = { + {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01, + 0x0f, 0x14, 0x0f, 0x10}, 8}, + {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5}, + {0x12, 0x00, {0x07}, 1}, + {0x1f, 0x00, {0x06}, 1}, + {0x27, 0x00, {0x04}, 1}, + {0x29, 0x00, {0x0c}, 1}, + {0x40, 0x00, {0x40, 0x00, 0x04}, 3}, + {0x50, 0x00, {0x60}, 1}, + {0x60, 0x00, {0x06}, 1}, + {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6}, + {0x72, 0x00, {0x1e, 0x56}, 2}, + {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02, + 0x31, 0x80, 0x00}, 9}, + {0x11, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data, + ARRAY_SIZE(cif_sensor0_init_data)); + } else { /* sd->sensor_type = 1 */ + const struct sensor_w_data cif_sensor1_init_data[] = { + /* Reg 3,4, 7,8 get set by the controls */ + {0x02, 0x00, {0x10}, 1}, + {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */ + {0x06, 0x01, {0x00}, 1}, + {0x09, 0x02, {0x0e}, 1}, + {0x0a, 0x02, {0x05}, 1}, + {0x0b, 0x02, {0x05}, 1}, + {0x0c, 0x02, {0x0f}, 1}, + {0x0d, 0x02, {0x07}, 1}, + {0x0e, 0x02, {0x0c}, 1}, + {0x0f, 0x00, {0x00}, 1}, + {0x10, 0x00, {0x06}, 1}, + {0x11, 0x00, {0x07}, 1}, + {0x12, 0x00, {0x00}, 1}, + {0x13, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data, + ARRAY_SIZE(cif_sensor1_init_data)); + } if (err_code < 0) return err_code; - data[0] = 0x14; - data[1] = 0x0a; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + setbrightness(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); - data[0] = 0x1b; - data[1] = 0x00; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + msleep(200); - data[0] = 0x15; - data[1] = 0x16; - err_code = reg_w(gspca_dev, 2); + data[0] = 0x00; + data[1] = 0x4d; /* ISOC transfering enable... */ + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x16; - data[1] = 0x10; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + return 0; +} - data[0] = 0x17; - data[1] = 0x3a; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; +static int start_vga_cam(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *data = gspca_dev->usb_buf; + int err_code; + const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x50, 0xc0}; - data[0] = 0x18; - data[1] = 0x68; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + /* What some of these mean is explained in start_cif_cam(), above */ + sd->sof_read = 0; - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x02; - data[3] = 0x06; - data[4] = 0x59; - data[5] = 0x0c; - data[6] = 0x16; - data[7] = 0x00; - data[8] = 0x07; - data[9] = 0x00; - data[10] = 0x01; - err_code = reg_w(gspca_dev, 11); + /* + * We have to know which camera we have, because the register writes + * depend upon the camera. This test, run before we actually enter + * the initialization routine, distinguishes most of the cameras, If + * needed, another routine is done later, too. + */ + memset(data, 0, 16); + data[0] = 0x20; + err_code = mr_write(gspca_dev, 1); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); + err_code = mr_read(gspca_dev, 16); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x0a; - data[3] = 0x00; - data[4] = 0x01; - data[5] = 0x00; - data[6] = 0x00; - data[7] = 0x01; - data[8] = 0x00; - data[9] = 0x0a; - err_code = reg_w(gspca_dev, 10); - if (err_code < 0) - return err_code; + PDEBUG(D_PROBE, "Byte reported is %02x", data[0]); + + msleep(200); + /* + * Known VGA cameras. If you have another to report, please do + * + * Name byte just read sd->sensor_type + * sd->do_lcd_stop + * Aiptek Pencam VGA+ 0x31 0 1 + * ION digital 0x31 0 1 + * Argus DC-1620 0x30 1 0 + * Argus QuickClix 0x30 1 1 (not caught here) + */ + sd->sensor_type = data[0] & 1; + sd->do_lcd_stop = (~data[0]) & 1; + + - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); + /* Streaming setup begins here. */ + + + data[0] = 0x01; + data[1] = 0x01; + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x12; - data[3] = 0x00; - data[4] = 0x63; - data[5] = 0x00; - data[6] = 0x70; - data[7] = 0x00; - data[8] = 0x00; - err_code = reg_w(gspca_dev, 9); + /* + * A second test can now resolve any remaining ambiguity in the + * identification of the camera type, + */ + if (!sd->sensor_type) { + data[0] = get_sensor_id(gspca_dev); + if (data[0] == 0x7f) { + sd->sensor_type = 1; + PDEBUG(D_PROBE, "sensor_type corrected to 1"); + } + msleep(200); + } + + if (force_sensor_type != -1) { + sd->sensor_type = !! force_sensor_type; + PDEBUG(D_PROBE, "Forcing sensor type to: %d", + sd->sensor_type); + } + + /* + * Known VGA cameras. + * This test is only run if the previous test returned 0x30, but + * here is the information for all others, too, just for reference. + * + * Name byte just read sd->sensor_type + * + * Aiptek Pencam VGA+ 0xfb (this test not run) 1 + * ION digital 0xbd (this test not run) 1 + * Argus DC-1620 0xe5 (no change) 0 + * Argus QuickClix 0x7f (reclassified) 1 + */ + memcpy(data, startup_string, 11); + if (!sd->sensor_type) { + data[5] = 0x00; + data[10] = 0x91; + } + + switch (gspca_dev->width) { + case 160: + data[9] |= 0x0c; /* reg 8, 4:1 scale down */ + /* fall thru */ + case 320: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 640: + default: + data[3] = 0x50; /* reg 2, H size/8 */ + data[4] = 0x78; /* reg 3, V size/4 */ + data[6] = 0x04; /* reg 5, H start */ + data[8] = 0x03; /* reg 7, V start */ + if (sd->do_lcd_stop) + data[8] = 0x04; /* Bayer tile shifted */ + break; + + case 176: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 352: + data[3] = 0x2c; /* reg 2, H size */ + data[4] = 0x48; /* reg 3, V size */ + data[6] = 0x94; /* reg 5, H start */ + data[8] = 0x63; /* reg 7, V start */ + if (sd->do_lcd_stop) + data[8] = 0x64; /* Bayer tile shifted */ + break; + } + + err_code = mr_write(gspca_dev, 11); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); + if (!sd->sensor_type) { + /* The only known sensor_type 0 cam is the Argus DC-1620 */ + const struct sensor_w_data vga_sensor0_init_data[] = { + {0x01, 0x00, {0x0c, 0x00, 0x04}, 3}, + {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4}, + {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4}, + {0x25, 0x00, {0x03, 0xa9, 0x80}, 3}, + {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data, + ARRAY_SIZE(vga_sensor0_init_data)); + } else { /* sd->sensor_type = 1 */ + const struct sensor_w_data vga_sensor1_init_data[] = { + {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, + 0x07, 0x00, 0x01}, 8}, + {0x11, 0x04, {0x01}, 1}, + /*{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, */ + {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, + 0x00, 0x0a}, 7}, + {0x11, 0x04, {0x01}, 1}, + {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6}, + {0x11, 0x04, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data, + ARRAY_SIZE(vga_sensor1_init_data)); + } if (err_code < 0) return err_code; + msleep(200); data[0] = 0x00; data[1] = 0x4d; /* ISOC transfering enable... */ - err_code = reg_w(gspca_dev, 2); + err_code = mr_write(gspca_dev, 2); + + return err_code; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err_code; + struct cam *cam; + + cam = &gspca_dev->cam; + sd->sof_read = 0; + /* + * Some of the supported cameras require the memory pointer to be + * set to 0, or else they will not stream. + */ + zero_the_pointer(gspca_dev); + msleep(200); + if (sd->cam_type == CAM_TYPE_CIF) { + err_code = start_cif_cam(gspca_dev); + } else { + err_code = start_vga_cam(gspca_dev); + } return err_code; } static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; int result; gspca_dev->usb_buf[0] = 1; gspca_dev->usb_buf[1] = 0; - result = reg_w(gspca_dev, 2); + result = mr_write(gspca_dev, 2); if (result < 0) PDEBUG(D_ERR, "Camera Stop failed"); + + /* Not all the cams need this, but even if not, probably a good idea */ + zero_the_pointer(gspca_dev); + if (sd->do_lcd_stop) { + gspca_dev->usb_buf[0] = 0x19; + gspca_dev->usb_buf[1] = 0x54; + result = mr_write(gspca_dev, 2); + if (result < 0) + PDEBUG(D_ERR, "Camera Stop failed"); + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX)) + return; + + /* Note register 7 is also seen as 0x8x or 0xCx in dumps */ + if (sd->brightness > 0) { + sensor_write1(gspca_dev, 7, 0x00); + val = sd->brightness; + } else { + sensor_write1(gspca_dev, 7, 0x01); + val = 257 - sd->brightness; + } + sensor_write1(gspca_dev, 8, val); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) + return; + + if (sd->sensor_type) { + val = sd->exposure >> 4; + sensor_write1(gspca_dev, 3, val); + val = sd->exposure & 0xf; + sensor_write1(gspca_dev, 4, val); + } else { + u8 clockdiv; + int exposure; + + /* We have both a clock divider and an exposure register. + We first calculate the clock divider, as that determines + the maximum exposure and then we calculayte the exposure + register setting (which goes from 0 - 511). + + Note our 0 - 4095 exposure is mapped to 0 - 511 + milliseconds exposure time */ + clockdiv = (60 * sd->exposure + 7999) / 8000; + + /* Limit framerate to not exceed usb bandwidth */ + if (clockdiv < 3 && gspca_dev->width >= 320) + clockdiv = 3; + else if (clockdiv < 2) + clockdiv = 2; + + /* Frame exposure time in ms = 1000 * clockdiv / 60 -> + exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ + exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); + if (exposure > 511) + exposure = 511; + + /* exposure register value is reversed! */ + exposure = 511 - exposure; + + sensor_write1(gspca_dev, 0x02, clockdiv); + sensor_write1(gspca_dev, 0x0e, exposure & 0xff); + sensor_write1(gspca_dev, 0x0f, exposure >> 8); + } +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) + return; + + if (sd->sensor_type) { + sensor_write1(gspca_dev, 0x0e, sd->gain); + } else { + sensor_write1(gspca_dev, 0x10, sd->gain); + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; } /* Include pac common sof detection functions */ @@ -320,8 +938,9 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0111)}, - {USB_DEVICE(0x093a, 0x010f)}, + {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ + {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ + {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */ {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 95a97ab68..96659433d 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -35,25 +35,17 @@ MODULE_LICENSE("GPL"); #define PAC207_BRIGHTNESS_MIN 0 #define PAC207_BRIGHTNESS_MAX 255 -#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */ - -/* An exposure value of 4 also works (3 does not) but then we need to lower - the compression balance setting when in 352x288 mode, otherwise the usb - bandwidth is not enough and packets get dropped resulting in corrupt - frames. The problem with this is that when the compression balance gets - lowered below 0x80, the pac207 starts using a different compression - algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix - and currently we do not know how to decompress these lines, so for now - we use a minimum exposure value of 5 */ -#define PAC207_EXPOSURE_MIN 5 +#define PAC207_BRIGHTNESS_DEFAULT 46 + +#define PAC207_EXPOSURE_MIN 3 #define PAC207_EXPOSURE_MAX 26 -#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */ -#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */ +#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ +#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ #define PAC207_GAIN_MIN 0 #define PAC207_GAIN_MAX 31 #define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 20 +#define PAC207_GAIN_KNEE 31 #define PAC207_AUTOGAIN_DEADZONE 30 @@ -166,16 +158,12 @@ static const struct v4l2_pix_format sif_mode[] = { }; static const __u8 pac207_sensor_init[][8] = { - {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0}, - {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, + {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84}, + {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, - {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02}, {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00}, }; - /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ -static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; - static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, const u8 *buffer, u16 length) { @@ -274,7 +262,6 @@ static int sd_init(struct gspca_dev *gspca_dev) * Bit_1=LED, * Bit_2=Compression test mode enable */ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ - pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ return 0; } @@ -289,15 +276,13 @@ static int sd_start(struct gspca_dev *gspca_dev) pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); - pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8); - pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8); - pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4); + pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); /* Compression Balance */ if (gspca_dev->width == 176) pac207_write_reg(gspca_dev, 0x4a, 0xff); else - pac207_write_reg(gspca_dev, 0x4a, 0x88); + pac207_write_reg(gspca_dev, 0x4a, 0x30); pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ pac207_write_reg(gspca_dev, 0x08, sd->brightness); @@ -346,7 +331,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, + 100, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index ed10134c9..356111956 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -1071,6 +1071,7 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 6a668deb1..3746ddbbe 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -1177,7 +1177,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x17, 0x20); reg_w1(gspca_dev, 0x01, 0x62); reg_w1(gspca_dev, 0x01, 0x42); - mdelay(100); + msleep(100); reg_w1(gspca_dev, 0x02, 0x62); break; /* case SENSOR_HV7131R: */ @@ -2385,8 +2385,8 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)}, - {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)}, {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)}, #endif {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/ diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c index 33bac051d..32ff7cd32 100644 --- a/linux/drivers/media/video/gspca/sunplus.c +++ b/linux/drivers/media/video/gspca/sunplus.c @@ -32,22 +32,22 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - unsigned char autogain; + s8 brightness; + u8 contrast; + u8 colors; + u8 autogain; u8 quality; #define QUALITY_MIN 70 #define QUALITY_MAX 95 #define QUALITY_DEF 85 - char bridge; + u8 bridge; #define BRIDGE_SPCA504 0 #define BRIDGE_SPCA504B 1 #define BRIDGE_SPCA504C 2 #define BRIDGE_SPCA533 3 #define BRIDGE_SPCA536 4 - char subtype; + u8 subtype; #define AiptekMiniPenCam13 1 #define LogitechClickSmart420 2 #define LogitechClickSmart820 3 @@ -68,21 +68,20 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", - .minimum = 0, - .maximum = 0xff, + .minimum = -128, + .maximum = 127, .step = 1, - .default_value = 0, +#define BRIGHTNESS_DEF 0 + .default_value = BRIGHTNESS_DEF, }, .set = sd_setbrightness, .get = sd_getbrightness, }, -#define SD_CONTRAST 1 { { .id = V4L2_CID_CONTRAST, @@ -91,12 +90,12 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0x20, +#define CONTRAST_DEF 0x20 + .default_value = CONTRAST_DEF, }, .set = sd_setcontrast, .get = sd_getcontrast, }, -#define SD_COLOR 2 { { .id = V4L2_CID_SATURATION, @@ -105,12 +104,12 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0x1a, +#define COLOR_DEF 0x1a + .default_value = COLOR_DEF, }, .set = sd_setcolors, .get = sd_getcolors, }, -#define SD_AUTOGAIN 3 { { .id = V4L2_CID_AUTOGAIN, @@ -119,7 +118,8 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, }, .set = sd_setautogain, .get = sd_getautogain, @@ -181,14 +181,20 @@ static const struct v4l2_pix_format vga_mode2[] = { #define SPCA504_PCCAM600_OFFSET_MODE 5 #define SPCA504_PCCAM600_OFFSET_DATA 14 /* Frame packet header offsets for the spca533 */ -#define SPCA533_OFFSET_DATA 16 +#define SPCA533_OFFSET_DATA 16 #define SPCA533_OFFSET_FRAMSEQ 15 /* Frame packet header offsets for the spca536 */ -#define SPCA536_OFFSET_DATA 4 -#define SPCA536_OFFSET_FRAMSEQ 1 +#define SPCA536_OFFSET_DATA 4 +#define SPCA536_OFFSET_FRAMSEQ 1 + +struct cmd { + u8 req; + u16 val; + u16 idx; +}; /* Initialisation data for the Creative PC-CAM 600 */ -static const __u16 spca504_pccam600_init_data[][3] = { +static const struct cmd spca504_pccam600_init_data[] = { /* {0xa0, 0x0000, 0x0503}, * capture mode */ {0x00, 0x0000, 0x2000}, {0x00, 0x0013, 0x2301}, @@ -219,22 +225,20 @@ static const __u16 spca504_pccam600_init_data[][3] = { {0x00, 0x0003, 0x2000}, {0x00, 0x0013, 0x2301}, {0x00, 0x0003, 0x2000}, - {} }; /* Creative PC-CAM 600 specific open data, sent before using the * generic initialisation data from spca504_open_data. */ -static const __u16 spca504_pccam600_open_data[][3] = { +static const struct cmd spca504_pccam600_open_data[] = { {0x00, 0x0001, 0x2501}, {0x20, 0x0500, 0x0001}, /* snapshot mode */ {0x00, 0x0003, 0x2880}, {0x00, 0x0001, 0x2881}, - {} }; /* Initialisation data for the logitech clicksmart 420 */ -static const __u16 spca504A_clicksmart420_init_data[][3] = { +static const struct cmd spca504A_clicksmart420_init_data[] = { /* {0xa0, 0x0000, 0x0503}, * capture mode */ {0x00, 0x0000, 0x2000}, {0x00, 0x0013, 0x2301}, @@ -261,7 +265,7 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = { #endif #if 1 - {0x0a1, 0x0080, 0x0001}, + {0xa1, 0x0080, 0x0001}, {0x30, 0x0049, 0x0000}, {0x30, 0x0060, 0x0005}, {0x0c, 0x0004, 0x0000}, @@ -285,11 +289,10 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = { {0x00, 0x0013, 0x2301}, {0x00, 0x0003, 0x2000}, #endif - {} }; /* clicksmart 420 open data ? */ -static const __u16 spca504A_clicksmart420_open_data[][3] = { +static const struct cmd spca504A_clicksmart420_open_data[] = { {0x00, 0x0001, 0x2501}, {0x20, 0x0502, 0x0000}, {0x06, 0x0000, 0x0000}, @@ -433,10 +436,9 @@ static const __u16 spca504A_clicksmart420_open_data[][3] = { {0x00, 0x0028, 0x287f}, {0xa0, 0x0000, 0x0503}, - {} }; -static const __u8 qtable_creative_pccam[2][64] = { +static const u8 qtable_creative_pccam[2][64] = { { /* Q-table Y-components */ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, @@ -461,7 +463,7 @@ static const __u8 qtable_creative_pccam[2][64] = { * except for one byte. Possibly a typo? * NWG: 18/05/2003. */ -static const __u8 qtable_spca504_default[2][64] = { +static const u8 qtable_spca504_default[2][64] = { { /* Q-table Y-components */ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, @@ -485,9 +487,9 @@ static const __u8 qtable_spca504_default[2][64] = { /* read <len> bytes to gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, - __u16 req, - __u16 index, - __u16 len) + u8 req, + u16 index, + u16 len) { #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { @@ -505,31 +507,26 @@ static void reg_r(struct gspca_dev *gspca_dev, 500); } -/* write <len> bytes from gspca_dev->usb_buf */ -static void reg_w(struct gspca_dev *gspca_dev, - __u16 req, - __u16 value, - __u16 index, - __u16 len) +/* write one byte */ +static void reg_w_1(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index, + u16 byte) { -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); - return; - } -#endif + gspca_dev->usb_buf[0] = byte; usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, - len ? gspca_dev->usb_buf : NULL, len, + gspca_dev->usb_buf, 1, 500); } /* write req / index / value */ static int reg_w_riv(struct usb_device *dev, - __u16 req, __u16 index, __u16 value) + u8 req, u16 index, u16 value) { int ret; @@ -547,7 +544,7 @@ static int reg_w_riv(struct usb_device *dev, /* read 1 byte */ static int reg_r_1(struct gspca_dev *gspca_dev, - __u16 value) /* wValue */ + u16 value) /* wValue */ { int ret; @@ -568,9 +565,9 @@ static int reg_r_1(struct gspca_dev *gspca_dev, /* read 1 or 2 bytes - returns < 0 if error */ static int reg_r_12(struct gspca_dev *gspca_dev, - __u16 req, /* bRequest */ - __u16 index, /* wIndex */ - __u16 length) /* wLength (1 or 2 only) */ + u8 req, /* bRequest */ + u16 index, /* wIndex */ + u16 length) /* wLength (1 or 2 only) */ { int ret; @@ -591,43 +588,40 @@ static int reg_r_12(struct gspca_dev *gspca_dev, } static int write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][3]) + const struct cmd *data, int ncmds) { struct usb_device *dev = gspca_dev->dev; - int ret, i = 0; + int ret; - while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { - ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]); + while (--ncmds >= 0) { + ret = reg_w_riv(dev, data->req, data->idx, data->val); if (ret < 0) { PDEBUG(D_ERR, - "Register write failed for 0x%x,0x%x,0x%x", - data[i][0], data[i][1], data[i][2]); + "Register write failed for 0x%02x, 0x%04x, 0x%04x", + data->req, data->val, data->idx); return ret; } - i++; + data++; } return 0; } static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, - unsigned int request, - unsigned int ybase, - unsigned int cbase, - const __u8 qtable[2][64]) + const u8 qtable[2][64]) { struct usb_device *dev = gspca_dev->dev; int i, err; /* loop over y components */ for (i = 0; i < 64; i++) { - err = reg_w_riv(dev, request, ybase + i, qtable[0][i]); + err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]); if (err < 0) return err; } /* loop over c components */ for (i = 0; i < 64; i++) { - err = reg_w_riv(dev, request, cbase + i, qtable[1][i]); + err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]); if (err < 0) return err; } @@ -635,34 +629,34 @@ static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, } static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, - __u16 req, __u16 idx, __u16 val) + u8 req, u16 idx, u16 val) { struct usb_device *dev = gspca_dev->dev; - __u8 notdone; + int notdone; reg_w_riv(dev, req, idx, val); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); reg_w_riv(dev, req, idx, val); - PDEBUG(D_FRAM, "before wait 0x%x", notdone); + PDEBUG(D_FRAM, "before wait 0x%04x", notdone); msleep(200); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - PDEBUG(D_FRAM, "after wait 0x%x", notdone); + PDEBUG(D_FRAM, "after wait 0x%04x", notdone); } static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, - __u16 req, - __u16 idx, __u16 val, __u8 stat, __u8 count) + u8 req, + u16 idx, u16 val, u8 stat, u8 count) { struct usb_device *dev = gspca_dev->dev; - __u8 status; - __u8 endcode; + int status; + u8 endcode; reg_w_riv(dev, req, idx, val); status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); endcode = stat; - PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat); + PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat); if (!count) return; count = 200; @@ -672,7 +666,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, /* reg_w_riv(dev, req, idx, val); */ status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); if (status == endcode) { - PDEBUG(D_FRAM, "status 0x%x after wait 0x%x", + PDEBUG(D_FRAM, "status 0x%04x after wait %d", status, 200 - count); break; } @@ -699,8 +693,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) while (--count > 0) { reg_r(gspca_dev, 0x21, 1, 1); if (gspca_dev->usb_buf[0] != 0) { - gspca_dev->usb_buf[0] = 0; - reg_w(gspca_dev, 0x21, 0, 1, 1); + reg_w_1(gspca_dev, 0x21, 0, 1, 0); reg_r(gspca_dev, 0x21, 1, 1); spca504B_PollingDataReady(gspca_dev); break; @@ -711,7 +704,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) { - __u8 *data; + u8 *data; data = gspca_dev->usb_buf; reg_r(gspca_dev, 0x20, 0, 5); @@ -725,41 +718,34 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; - __u8 Size; - __u8 Type; + u8 Size; int rc; - Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - Type = 0; + Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; switch (sd->bridge) { case BRIDGE_SPCA533: - reg_w(gspca_dev, 0x31, 0, 0, 0); + reg_w_riv(dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); - gspca_dev->usb_buf[0] = 2; /* type */ - reg_w(gspca_dev, 0x24, 0, 8, 1); + reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ reg_r(gspca_dev, 0x24, 8, 1); - gspca_dev->usb_buf[0] = Size; - reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_w_1(gspca_dev, 0x25, 0, 4, Size); reg_r(gspca_dev, 0x25, 4, 1); /* size */ rc = spca504B_PollingDataReady(gspca_dev); /* Init the cam width height with some values get on init ? */ - reg_w(gspca_dev, 0x31, 0, 4, 0); + reg_w_riv(dev, 0x31, 0, 0x04); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); break; default: /* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA536: */ - gspca_dev->usb_buf[0] = Size; - reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_w_1(gspca_dev, 0x25, 0, 4, Size); reg_r(gspca_dev, 0x25, 4, 1); /* size */ - Type = 6; - gspca_dev->usb_buf[0] = Type; - reg_w(gspca_dev, 0x27, 0, 0, 1); + reg_w_1(gspca_dev, 0x27, 0, 0, 6); reg_r(gspca_dev, 0x27, 0, 1); /* type */ rc = spca504B_PollingDataReady(gspca_dev); break; @@ -799,17 +785,51 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev) static void spca504B_setQtable(struct gspca_dev *gspca_dev) { - gspca_dev->usb_buf[0] = 3; - reg_w(gspca_dev, 0x26, 0, 0, 1); + reg_w_1(gspca_dev, 0x26, 0, 0, 3); reg_r(gspca_dev, 0x26, 0, 1); spca504B_PollingDataReady(gspca_dev); } -static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; + reg_w_riv(dev, 0x00, reg, sd->brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; + reg_w_riv(dev, 0x00, reg, sd->contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; + reg_w_riv(dev, 0x00, reg, sd->colors); +} + +static void init_ctl_reg(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; int pollreg = 1; + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); + switch (sd->bridge) { case BRIDGE_SPCA504: case BRIDGE_SPCA504C: @@ -818,20 +838,14 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA504B: */ - reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */ - reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */ - reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */ - reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */ - reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */ - reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */ + reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */ + reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */ + reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */ break; case BRIDGE_SPCA536: - reg_w(gspca_dev, 0, 0, 0x20f0, 0); - reg_w(gspca_dev, 0, 0x21, 0x20f1, 0); - reg_w(gspca_dev, 0, 0x40, 0x20f5, 0); - reg_w(gspca_dev, 0, 1, 0x20f4, 0); - reg_w(gspca_dev, 0, 0x40, 0x20f6, 0); - reg_w(gspca_dev, 0, 0, 0x2089, 0); + reg_w_riv(dev, 0, 0x40, 0x20f5); + reg_w_riv(dev, 0, 0x01, 0x20f4); + reg_w_riv(dev, 0, 0x00, 0x2089); break; } if (pollreg) @@ -886,9 +900,10 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode2); break; } - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; sd->quality = QUALITY_DEF; return 0; } @@ -898,32 +913,29 @@ static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; - int rc; - __u8 i; - __u8 info[6]; - int err_code; + int i, err_code; + u8 info[6]; switch (sd->bridge) { case BRIDGE_SPCA504B: - reg_w(gspca_dev, 0x1d, 0, 0, 0); - reg_w(gspca_dev, 0, 1, 0x2306, 0); - reg_w(gspca_dev, 0, 0, 0x0d04, 0); - reg_w(gspca_dev, 0, 0, 0x2000, 0); - reg_w(gspca_dev, 0, 0x13, 0x2301, 0); - reg_w(gspca_dev, 0, 0, 0x2306, 0); + reg_w_riv(dev, 0x1d, 0x00, 0); + reg_w_riv(dev, 0, 0x01, 0x2306); + reg_w_riv(dev, 0, 0x00, 0x0d04); + reg_w_riv(dev, 0, 0x00, 0x2000); + reg_w_riv(dev, 0, 0x13, 0x2301); + reg_w_riv(dev, 0, 0x00, 0x2306); /* fall thru */ case BRIDGE_SPCA533: - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); break; case BRIDGE_SPCA536: spca50x_GetFirmware(gspca_dev); reg_r(gspca_dev, 0x00, 0x5002, 1); - gspca_dev->usb_buf[0] = 0; - reg_w(gspca_dev, 0x24, 0, 0, 1); + reg_w_1(gspca_dev, 0x24, 0, 0, 0); reg_r(gspca_dev, 0x24, 0, 1); - rc = spca504B_PollingDataReady(gspca_dev); - reg_w(gspca_dev, 0x34, 0, 0, 0); + spca504B_PollingDataReady(gspca_dev); + reg_w_riv(dev, 0x34, 0, 0); spca504B_WaitCmdStatus(gspca_dev); break; case BRIDGE_SPCA504C: /* pccam600 */ @@ -933,12 +945,13 @@ static int sd_init(struct gspca_dev *gspca_dev) spca504_wait_status(gspca_dev); if (sd->subtype == LogitechClickSmart420) write_vector(gspca_dev, - spca504A_clicksmart420_open_data); + spca504A_clicksmart420_open_data, + ARRAY_SIZE(spca504A_clicksmart420_open_data)); else - write_vector(gspca_dev, spca504_pccam600_open_data); + write_vector(gspca_dev, spca504_pccam600_open_data, + ARRAY_SIZE(spca504_pccam600_open_data)); err_code = spca50x_setup_qtable(gspca_dev, - 0x00, 0x2800, - 0x2840, qtable_creative_pccam); + qtable_creative_pccam); if (err_code < 0) { PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed"); return err_code; @@ -976,8 +989,8 @@ static int sd_init(struct gspca_dev *gspca_dev) 6, 0, 0x86, 1); */ /* spca504A_acknowledged_command (gspca_dev, 0x24, 0, 0, 0x9D, 1); */ - reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */ - reg_w_riv(dev, 0x0, 0x2310, 0x05); + reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ + reg_w_riv(dev, 0x00, 0x2310, 0x05); spca504A_acknowledged_command(gspca_dev, 0x01, 0x0f, 0, 0xff, 0); } @@ -985,8 +998,6 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w_riv(dev, 0, 0x2000, 0); reg_w_riv(dev, 0, 0x2883, 1); err_code = spca50x_setup_qtable(gspca_dev, - 0x00, 0x2800, - 0x2840, qtable_spca504_default); if (err_code < 0) { PDEBUG(D_ERR, "spca50x_setup_qtable failed"); @@ -1001,10 +1012,9 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; - int rc; int enable; - __u8 i; - __u8 info[6]; + int i; + u8 info[6]; /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); @@ -1022,17 +1032,20 @@ static int sd_start(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ - if (sd->subtype == MegapixV4 || - sd->subtype == LogitechClickSmart820 || - sd->subtype == MegaImageVI) { - reg_w(gspca_dev, 0xf0, 0, 0, 0); + switch (sd->subtype) { + case MegapixV4: + case LogitechClickSmart820: + case MegaImageVI: + reg_w_riv(dev, 0xf0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); reg_r(gspca_dev, 0xf0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); - } else { - reg_w(gspca_dev, 0x31, 0, 4, 0); + break; + default: + reg_w_riv(dev, 0x31, 0, 0x04); spca504B_WaitCmdStatus(gspca_dev); - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); + break; } break; case BRIDGE_SPCA504: @@ -1066,15 +1079,17 @@ static int sd_start(struct gspca_dev *gspca_dev) spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); } spca504B_SetSizeType(gspca_dev); - reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */ - reg_w_riv(dev, 0x0, 0x2310, 0x05); + reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ + reg_w_riv(dev, 0x00, 0x2310, 0x05); break; case BRIDGE_SPCA504C: if (sd->subtype == LogitechClickSmart420) { write_vector(gspca_dev, - spca504A_clicksmart420_init_data); + spca504A_clicksmart420_init_data, + ARRAY_SIZE(spca504A_clicksmart420_init_data)); } else { - write_vector(gspca_dev, spca504_pccam600_init_data); + write_vector(gspca_dev, spca504_pccam600_init_data, + ARRAY_SIZE(spca504_pccam600_init_data)); } enable = (sd->autogain ? 0x04 : 0x01); reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */ @@ -1086,7 +1101,7 @@ static int sd_start(struct gspca_dev *gspca_dev) spca504B_SetSizeType(gspca_dev); break; } - sp5xx_initContBrigHueRegisters(gspca_dev); + init_ctl_reg(gspca_dev); return 0; } @@ -1100,7 +1115,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ /* case BRIDGE_SPCA504B: */ - reg_w(gspca_dev, 0x31, 0, 0, 0); + reg_w_riv(dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); break; @@ -1118,7 +1133,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) 0x0f, 0x00, 0xff, 1); } else { spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); - reg_w_riv(dev, 0x01, 0x000f, 0x00); + reg_w_riv(dev, 0x01, 0x000f, 0x0000); } break; } @@ -1133,12 +1148,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev) static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ - __u8 *data, /* isoc packet */ + u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; int i, sof = 0; - static unsigned char ffd9[] = {0xff, 0xd9}; + static u8 ffd9[] = {0xff, 0xd9}; /* frames are jpeg 4.1.1 without 0xff escape */ switch (sd->bridge) { @@ -1226,63 +1241,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA504: */ -/* case BRIDGE_SPCA504C: */ - reg_w_riv(dev, 0x0, 0x21a7, sd->brightness); - break; - case BRIDGE_SPCA536: - reg_w_riv(dev, 0x0, 0x20f0, sd->brightness); - break; - } -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA504: */ -/* case BRIDGE_SPCA504C: */ - reg_w_riv(dev, 0x0, 0x21a8, sd->contrast); - break; - case BRIDGE_SPCA536: - reg_w_riv(dev, 0x0, 0x20f1, sd->contrast); - break; - } -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA504: */ -/* case BRIDGE_SPCA504C: */ - reg_w_riv(dev, 0x0, 0x21ae, sd->colors); - break; - case BRIDGE_SPCA536: - reg_w_riv(dev, 0x0, 0x20f6, sd->colors); - break; - } -} - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index 6f9aab89c..9464454f1 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -1940,109 +1940,200 @@ static const u8 po3130_initQVGA_data[][4] = { }; static const u8 hv7131r_gamma[17] = { -/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - * 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */ +#if 1 + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +#else 0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1, 0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff +#endif }; static const u8 hv7131r_matrix[9] = { 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 }; static const u8 hv7131r_initVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x20, 0xdd}, {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x01, 0x45, 0xcc}, {0xb3, 0x03, 0x0b, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0xb3, 0x03, 0x0b, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x02, 0xcc}, {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0x91, 0xcc}, {0xb3, 0x00, 0x27, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0x91, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x73, 0xcc}, - {0xb8, 0x00, 0x23, 0xcc}, {0x00, 0x01, 0x0c, 0xaa}, - {0x00, 0x14, 0x01, 0xaa}, {0x00, 0x15, 0xe6, 0xaa}, - {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x17, 0x86, 0xaa}, {0x00, 0x23, 0x00, 0xaa}, - {0x00, 0x25, 0x09, 0xaa}, {0x00, 0x26, 0x27, 0xaa}, - {0x00, 0x27, 0xc0, 0xaa}, - {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x00, 0x23, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc}, - {0xb8, 0x33, 0xf8, 0xcc}, {0xb8, 0x34, 0x65, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x58, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x01, 0x7d, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc}, - {0xb8, 0xff, 0x28, 0xcc}, {0xb9, 0x00, 0x28, 0xcc}, - {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, - {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0x00, 0x01, 0x0c, 0xaa}, + {0x00, 0x14, 0x01, 0xaa}, + {0x00, 0x15, 0xe6, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, + {0x00, 0x23, 0x00, 0xaa}, + {0x00, 0x25, 0x03, 0xaa}, + {0x00, 0x26, 0xa9, 0xaa}, + {0x00, 0x27, 0x80, 0xaa}, {0x00, 0x30, 0x18, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {} }; static const u8 hv7131r_initQVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x20, 0xdd}, {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x03, 0x0b, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0xb3, 0x03, 0x0b, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x02, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0x91, 0xcc}, - {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, - {0xb8, 0x00, 0x21, 0xcc}, - {0x00, 0x01, 0x0c, 0xaa}, {0x00, 0x14, 0x01, 0xaa}, - {0x00, 0x15, 0xe6, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x17, 0x86, 0xaa}, - {0x00, 0x23, 0x00, 0xaa}, {0x00, 0x25, 0x01, 0xaa}, - {0x00, 0x26, 0xd4, 0xaa}, {0x00, 0x27, 0xc0, 0xaa}, - {0xbc, 0x02, 0x08, 0xcc}, - {0xbc, 0x03, 0x70, 0xcc}, {0xbc, 0x04, 0x08, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x3c, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x04, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, - {0xb8, 0xfe, 0x02, 0xcc}, - {0xb8, 0xff, 0x07, 0xcc}, {0xb9, 0x00, 0x14, 0xcc}, - {0xb9, 0x01, 0x14, 0xcc}, {0xb9, 0x02, 0x14, 0xcc}, - {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x02, 0xcc}, {0xb9, 0x05, 0x05, 0xcc}, - {0xb9, 0x06, 0x0f, 0xcc}, {0xb9, 0x07, 0x0f, 0xcc}, - {0xb9, 0x08, 0x0f, 0xcc}, - {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0x91, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, + {0xbc, 0x00, 0xd3, 0xcc}, + {0xb8, 0x00, 0x23, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x65, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x34, 0x58, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc}, - {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, - {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc}, - {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x01, 0x7d, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, {0x00, 0x30, 0x18, 0xaa}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0x00, 0x01, 0x0c, 0xaa}, + {0x00, 0x14, 0x01, 0xaa}, + {0x00, 0x15, 0xe6, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, + {0x00, 0x23, 0x00, 0xaa}, + {0x00, 0x25, 0x03, 0xaa}, + {0x00, 0x26, 0xa9, 0xaa}, + {0x00, 0x27, 0x80, 0xaa}, + {0x00, 0x30, 0x18, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, + {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, + {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, + {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {} }; @@ -3319,21 +3410,22 @@ static int sd_start(struct gspca_dev *gspca_dev) put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c); /* set the led on 0x0892 0x0896 */ - if (sd->sensor == SENSOR_PO1200) { - setsharpness(gspca_dev); - sethvflip(gspca_dev); + switch (sd->sensor) { + case SENSOR_PO1200: + case SENSOR_HV7131R: reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415); - } else if (sd->sensor == SENSOR_MI1310_SOC) { + break; + case SENSOR_MI1310_SOC: reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000); - msleep(100); - sethvflip(gspca_dev); - setlightfreq(gspca_dev); - } else { + break; + default: reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); - msleep(100); - sethvflip(gspca_dev); - setlightfreq(gspca_dev); + break; } + msleep(100); + setsharpness(gspca_dev); + sethvflip(gspca_dev); + setlightfreq(gspca_dev); } return 0; } diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index 38a716020..36ee43a9e 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -123,8 +123,8 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, #if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, +#endif { } }; diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c index 8383e6f80..5a8dd5e19 100644 --- a/linux/drivers/media/video/vino.c +++ b/linux/drivers/media/video/vino.c @@ -50,6 +50,7 @@ #include <asm/sgi/ip22.h> #include <asm/sgi/mc.h> +#include "compat.h" #include "vino.h" #include "saa7191.h" #include "indycam.h" diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h index 6fc44b733..9d61bae27 100644 --- a/linux/include/linux/videodev2.h +++ b/linux/include/linux/videodev2.h @@ -375,6 +375,7 @@ struct v4l2_fmtdesc { }; #define V4L2_FMT_FLAG_COMPRESSED 0x0001 +#define V4L2_FMT_FLAG_EMULATED 0x0002 #if 1 /*KEEP*/ /* Experimental Frame Size and frame rate enumeration */ diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index e69a8c8f4..e2e7ac36f 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,21 @@ +libv4l-0.6.2 +------------ +* Add more laptop models to the upside down devices table + +libv4l-0.6.1 +------------ +* Add more laptop models to the upside down devices table +* Makefile changes to make life easier for the Debian package (Gregor Jasny) +* Bugfix: fixup 320x240 output for pac7302 cameras +* README improvements / clarifications (Bifferos) +* Bugfix: fix reqbuf Device or Resource busy error when using v4l2_read() +* Some applications want to use jpg format if possible, so do not hide + it from the apps (do not assume it always needs conversion) +* Change controls shm segment name to include the username, as it is only + writable by the user (this means libv4l controls are per user) (Gregor Jasny) +* Add support for decompressing sn9c2028 compressed bayer (Theodore Kilgore) +* Report V4L2_FMT_FLAG_EMULATED in v4l2_fmtdesc flags for emulated formats + libv4l-0.6.0 ------------ * Recognize disabled controls and replace with fake equivalents where @@ -6,8 +24,12 @@ libv4l-0.6.0 an external helper as I've failed to contact Mark W. McClelland to get permission to relicense the code. If you know a working email address for Mark W. McClelland, please let me know. -* Fix a bug in the always report widths which are a multiple of 8 code added - in 0.5.97 +* Add tons of laptop models to the upside down devices table +* Support for rgb565 source format by Mauro Carvalho Chehab +* Many bug fixes (see the mercurial tree for details) +* Improved pac207 decompression code to also support higher compression + modes of the pac207, which enables us to use higher framerates. + Many many thanks to Bertrik Sikken for figuring the decompression out! libv4l-0.5.99 ------------- diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index acec5c540..1afca883c 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.99 +V4L2_LIB_VERSION=$(LIB_RELEASE).6.2-test all install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/README b/v4l2-apps/libv4l/README index 481d5b92e..20eee5858 100644 --- a/v4l2-apps/libv4l/README +++ b/v4l2-apps/libv4l/README @@ -25,13 +25,13 @@ libv4lconvert/libv4lconvert.c for the full list. For more details on the v4lconvert_ functions see libv4lconvert.h. Later on libv4lconvert was expanded to also be able to do various video -processing functions improve webcam video quality on a software basis. So +processing functions to improve webcam video quality on a software basis. So the name no longer 100% covers the functionality. The video processing is split in to 2 parts, libv4lconvert/control and libv4lconvert/processing. The control part is used to offer video controls which can be used to control the video processing functions made available by libv4lconvert/processing. -These controls are stored application wide (untill reboot) by using a +These controls are stored application wide (until reboot) by using a persistent shared memory object. libv4lconvert/processing offers the actual video processing functionality. @@ -80,6 +80,12 @@ $ export LD_PRELOAD=/usr/local/lib/libv4l/v4l1compat.so $ camorama +Prerequisites +------------- + +libv4l requires shmem file system support in the kernel (CONFIG_SHMEM). + + Installation Instructions ------------------------- @@ -88,9 +94,15 @@ Simple type the following commands from the libv4l-x.y.z directory make make install PREFIX=/usr/local -Note: make install also supports the DESTDIR=... paramter for installation +Note: make install also supports the DESTDIR=... parameter for installation into chroots. +If you require static libraries to also be built, these can be compiled +along with the dynamic equivalents by defining LINKTYPE to 'static', e.g.: + +make LINKTYPE=static +make install LINKTYPE=static + FAQ --- @@ -117,10 +129,13 @@ So clearly this belongs in a library, and in a library with a license which allows this code to be used from as many different applications as possible. Hence libv4l was born. + Q: Under which license may I use and distribute libv4l? -A: All libv4l components are licensed under the GNU Library General Publishing +A: The libv4l libraries are licensed under the GNU Library General Publishing License version 2 or (at your option) any later version. See the included -COPYING.LIB file. +COPYING.LIB file. The decompression helpers are licensed under the GNU +Library Publishing License version 2 (as they are derived from kernel code) + Q: Okay so I get the use of having a libv4lconvert, but why libv4l1 ? A: Many v4l2 drivers do not offer full v4l1 compatibility. They often do not @@ -138,9 +153,8 @@ applications. Q: Why should I use libv4l2 in my app instead of direct device access -combined with libv4lconvert? - -libv4l2 is mainly meant for quickly and easily adding support for more + combined with libv4lconvert? +A: libv4l2 is mainly meant for quickly and easily adding support for more pixelformats to existing v4l2 applications. So if you feel better directly accessing the device in combination with libv4lconvert thats fine too. @@ -151,3 +165,11 @@ zero-copy access to the captured frame, and then it can write the converted data directly to the buffer the application provided to v4l2_read(). Thus another reason to use liv4l2 is to get the no memcpy advantage of the mmap capture method combined with the simplicity of making a simple read() call. + + +Q: Where to send bugreports / questions? +A: Please send libv4l questions / bugreports to the: + Linux Media Mailing List <linux-media@vger.kernel.org> + Subscription is not necessary to send mail to this list. If you're not + subscribed please put yourself in the CC of your original mail so you + will receive replies. diff --git a/v4l2-apps/libv4l/include/libv4l1.h b/v4l2-apps/libv4l/include/libv4l1.h index 4ddf8efdb..a2f8bd8d4 100644 --- a/v4l2-apps/libv4l/include/libv4l1.h +++ b/v4l2-apps/libv4l/include/libv4l1.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h index 7ecbb2cee..dfae21471 100644 --- a/v4l2-apps/libv4l/include/libv4l2.h +++ b/v4l2-apps/libv4l/include/libv4l2.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -51,6 +51,13 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file; Note the device name passed to v4l2_open must be of a video4linux2 device, if it is anything else (including a video4linux1 device), v4l2_open will fail. + + Note that the argument to v4l2_ioctl after the request must be a valid + memory address of structure of the appropriate type for the request (for + v4l2 requests which expect a structure address). Passing in NULL or an + invalid memory address will not lead to failure with errno being EFAULT, + as it would with a real ioctl, but will cause libv4l2 to break, and you + get to keep both pieces. */ LIBV4L_PUBLIC int v4l2_open (const char *file, int oflag, ...); diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h index b274c938b..09ce17cae 100644 --- a/v4l2-apps/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/libv4l/include/libv4lconvert.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index e6d306055..3403f3710 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -33,6 +33,10 @@ ifeq ($(LIBDIR),) LIBDIR = $(PREFIX)/lib endif +ifeq ($(LIBSUBDIR),) +LIBSUBDIR = libv4l +endif + all: $(TARGETS) -include $(V4L1_OBJS:.o=.d) @@ -60,12 +64,12 @@ ifeq ($(LINKTYPE),static) mkdir -p $(DESTDIR)$(LIBDIR) install -m 644 $(V4L1_LIB) $(DESTDIR)$(LIBDIR) else - mkdir -p $(DESTDIR)$(LIBDIR)/libv4l + mkdir -p $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR) install -m 755 $(V4L1_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR) cd $(DESTDIR)$(LIBDIR) && \ ln -f -s $(V4L1_LIB).$(LIB_RELEASE) $(V4L1_LIB) install -m 755 $(V4L1COMPAT).$(LIB_RELEASE) \ - $(DESTDIR)$(LIBDIR)/libv4l/$(V4L1COMPAT) + $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR)/$(V4L1COMPAT) endif mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h index 370686b3a..33abcdcb0 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h +++ b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index 9b23926be..29df658b1 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -1,7 +1,7 @@ /* # libv4l1 userspace v4l1 api emulation for v4l2 devices -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4l1/log.c b/v4l2-apps/libv4l/libv4l1/log.c index fd095817f..68060e65a 100644 --- a/v4l2-apps/libv4l/libv4l1/log.c +++ b/v4l2-apps/libv4l/libv4l1/log.c @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/libv4l/libv4l1/v4l1compat.c index 704ec22dd..50fc2bab1 100644 --- a/v4l2-apps/libv4l/libv4l1/v4l1compat.c +++ b/v4l2-apps/libv4l/libv4l1/v4l1compat.c @@ -2,7 +2,7 @@ # open/close/ioctl/mmap/munmap library call wrapper doing v4l1 api emulation # for v4l2 devices -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 06c010f3c..c13d7315d 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -33,6 +33,10 @@ ifeq ($(LIBDIR),) LIBDIR = $(PREFIX)/lib endif +ifeq ($(LIBSUBDIR),) +LIBSUBDIR = libv4l +endif + all: $(TARGETS) -include $(V4L2_OBJS:.o=.d) @@ -60,12 +64,12 @@ ifeq ($(LINKTYPE),static) mkdir -p $(DESTDIR)$(LIBDIR) install -m 644 $(V4L2_LIB) $(DESTDIR)$(LIBDIR) else - mkdir -p $(DESTDIR)$(LIBDIR)/libv4l + mkdir -p $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR) install -m 755 $(V4L2_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR) cd $(DESTDIR)$(LIBDIR) && \ ln -f -s $(V4L2_LIB).$(LIB_RELEASE) $(V4L2_LIB) install -m 755 $(V4L2CONVERT).$(LIB_RELEASE) \ - $(DESTDIR)$(LIBDIR)/libv4l/$(V4L2CONVERT) + $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR)/$(V4L2CONVERT) endif mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h index 0bfd53e2a..8256cfdb6 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h +++ b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -80,6 +80,9 @@ struct v4l2_dev_info { int frame_queued; /* 1 status bit per frame */ /* mapping tracking of our fake (converting mmap) frame buffers */ unsigned char frame_map_count[V4L2_MAX_NO_FRAMES]; + /* buffer when doing conversion and using read() for read() */ + int readbuf_size; + unsigned char *readbuf; }; /* From log.c */ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index b71c9b4c6..3366538a7 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -77,6 +77,7 @@ #define V4L2_SUPPORTS_READ 0x0800 #define V4L2_IS_UVC 0x1000 #define V4L2_STREAM_TOUCHED 0x2000 +#define V4L2_USE_READ_FOR_READ 0x4000 #define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u @@ -101,7 +102,7 @@ static int v4l2_request_read_buffers(int index) req.memory = V4L2_MEMORY_MMAP; if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){ int saved_err = errno; - V4L2_LOG_ERR("requesting %u buffers: %s\n", req.count, strerror(errno)); + V4L2_LOG("warning reqbuf (%u) failed: %s\n", req.count, strerror(errno)); errno = saved_err; return result; } @@ -305,6 +306,62 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, return result; } +static int v4l2_read_and_convert(int index, unsigned char *dest, int dest_size) +{ + const int max_tries = 10; + int result, buf_size, tries = max_tries; + + buf_size = devices[index].dest_fmt.fmt.pix.sizeimage; + + if (devices[index].readbuf_size < buf_size) { + unsigned char *new_buf; + + new_buf = realloc(devices[index].readbuf, buf_size); + if (!new_buf) + return -1; + + devices[index].readbuf = new_buf; + devices[index].readbuf_size = buf_size; + } + + do { + result = SYS_READ(devices[index].fd, devices[index].readbuf, buf_size); + if (result <= 0) { + if (result && errno != EAGAIN) { + int saved_err = errno; + V4L2_LOG_ERR("reading: %s\n", strerror(errno)); + errno = saved_err; + } + return result; + } + + result = v4lconvert_convert(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt, + devices[index].readbuf, result, dest, dest_size); + + if (result < 0) { + int saved_err = errno; + + if(errno == EAGAIN) + V4L2_LOG("warning error while converting frame data: %s\n", + v4lconvert_get_error_message(devices[index].convert)); + else + V4L2_LOG_ERR("converting / decoding frame data: %s\n", + v4lconvert_get_error_message(devices[index].convert)); + + errno = saved_err; + } + tries--; + } while (result < 0 && errno == EAGAIN && tries); + + if (result < 0 && errno == EAGAIN) { + V4L2_LOG_ERR("got %d consecutive frame decode errors, last error: %s\n", + max_tries, v4lconvert_get_error_message(devices[index].convert)); + } + + return result; +} + static int v4l2_queue_read_buffers(int index) { unsigned int i; @@ -332,6 +389,11 @@ static int v4l2_activate_read_stream(int index) { int result; + if ((devices[index].flags & V4L2_STREAMON) || devices[index].frame_queued) { + errno = EBUSY; + return -1; + } + if ((result = v4l2_request_read_buffers(index))) return result; @@ -463,10 +525,9 @@ int v4l2_fd_open(int fd, int v4l2_flags) return -1; } - /* we only add functionality for video capture devices, and we do not - handle devices which don't do mmap */ + /* we only add functionality for video capture devices */ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || - !(cap.capabilities & V4L2_CAP_STREAMING)) + !(cap.capabilities & (V4L2_CAP_STREAMING|V4L2_CAP_READWRITE))) return fd; /* Get current cam format */ @@ -501,6 +562,8 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].flags = v4l2_flags; if (cap.capabilities & V4L2_CAP_READWRITE) devices[index].flags |= V4L2_SUPPORTS_READ; + if (!(cap.capabilities & V4L2_CAP_STREAMING)) + devices[index].flags |= V4L2_USE_READ_FOR_READ; if (!strcmp((char *)cap.driver, "uvcvideo")) devices[index].flags |= V4L2_IS_UVC; devices[index].open_count = 1; @@ -508,7 +571,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].dest_fmt = fmt; /* When a user does a try_fmt with the current dest_fmt and the dest_fmt - is a supported one we will align the resulution (see try_fmt for why). + is a supported one we will align the resolution (see try_fmt for why). Do the same here now, so that a try_fmt on the result of a get_fmt done immediately after open leaves the fmt unchanged. */ if (v4lconvert_supported_dst_format( @@ -528,6 +591,8 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].frame_map_count[i] = 0; } devices[index].frame_queued = 0; + devices[index].readbuf = NULL; + devices[index].readbuf_size = 0; if (index >= devices_used) devices_used = index + 1; @@ -585,6 +650,9 @@ int v4l2_close(int fd) devices[index].convert_mmap_buf = MAP_FAILED; } v4lconvert_destroy(devices[index].convert); + free(devices[index].readbuf); + devices[index].readbuf = NULL; + devices[index].readbuf_size = 0; /* Remove the fd from our list of managed fds before closing it, because as soon as we've done the actual close the fd maybe returned by an open in @@ -1070,7 +1138,6 @@ ssize_t v4l2_read (int fd, void* dest, size_t n) { ssize_t result; int index; - struct v4l2_buffer buf; if ((index = v4l2_get_index(fd)) == -1) return SYS_READ(fd, dest, n); @@ -1085,23 +1152,33 @@ ssize_t v4l2_read (int fd, void* dest, size_t n) goto leave; } - if (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)) { - if ((devices[index].flags & V4L2_STREAMON) || - devices[index].frame_queued) { - errno = EBUSY; - result = -1; - goto leave; - } + /* Since we need to do conversion try to use mmap (streaming) mode under + the hood as that safes a memcpy for each frame read. + + Note sometimes this will fail as some drivers (atleast gspca) do not allow + switching from read mode to mmap mode and they assume read() mode if a + select or poll() is done before any buffers are requested. So using mmap + mode under the hood will fail if a select() or poll() is done before the + first emulated read() call. */ + if (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) && + !(devices[index].flags & V4L2_USE_READ_FOR_READ)) { if ((result = v4l2_activate_read_stream(index))) - goto leave; + /* Activating mmap mode failed, use read() instead */ + devices[index].flags |= V4L2_USE_READ_FOR_READ; } - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - result = v4l2_dequeue_and_convert(index, &buf, dest, n); + if (devices[index].flags & V4L2_USE_READ_FOR_READ) { + result = v4l2_read_and_convert(index, dest, n); + } else { + struct v4l2_buffer buf; - if (result >= 0) - v4l2_queue_read_buffer(index, buf.index); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + result = v4l2_dequeue_and_convert(index, &buf, dest, n); + + if (result >= 0) + v4l2_queue_read_buffer(index, buf.index); + } leave: pthread_mutex_unlock(&devices[index].stream_lock); @@ -1226,9 +1303,15 @@ int v4l2_set_control(int fd, int cid, int value) { struct v4l2_queryctrl qctrl = { .id = cid }; struct v4l2_control ctrl = { .id = cid }; - int result; + int index, result; + + if ((index = v4l2_get_index(fd)) == -1) { + V4L2_LOG_ERR("v4l2_set_control called with invalid fd: %d\n", fd); + errno = EBADF; + return -1; + } - if ((result = SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl))) + if ((result = v4lconvert_vidioc_queryctrl(devices[index].convert, &qctrl))) return result; if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED) && @@ -1239,7 +1322,7 @@ int v4l2_set_control(int fd, int cid, int value) ctrl.value = (value * (qctrl.maximum - qctrl.minimum) + 32767) / 65535 + qctrl.minimum; - result = SYS_IOCTL(fd, VIDIOC_S_CTRL, &ctrl); + result = v4lconvert_vidioc_s_ctrl(devices[index].convert, &ctrl); } return result; @@ -1249,14 +1332,21 @@ int v4l2_get_control(int fd, int cid) { struct v4l2_queryctrl qctrl = { .id = cid }; struct v4l2_control ctrl = { .id = cid }; + int index; + + if ((index = v4l2_get_index(fd)) == -1) { + V4L2_LOG_ERR("v4l2_set_control called with invalid fd: %d\n", fd); + errno = EBADF; + return -1; + } - if (SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl)) + if (v4lconvert_vidioc_queryctrl(devices[index].convert, &qctrl)) return 0; if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) return 0; - if (SYS_IOCTL(fd, VIDIOC_G_CTRL, &ctrl)) + if (v4lconvert_vidioc_g_ctrl(devices[index].convert, &ctrl)) return 0; return ((ctrl.value - qctrl.minimum) * 65535 + diff --git a/v4l2-apps/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c index 4b75a5ebf..e402f78d8 100644 --- a/v4l2-apps/libv4l/libv4l2/v4l2convert.c +++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c @@ -3,7 +3,7 @@ # for v4l2 applications which want to be able to simply capture bgr24 / yuv420 # from v4l2 devices with more exotic frame formats. -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 036649e86..cc3941b87 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -14,10 +14,10 @@ endif CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \ mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \ - rgbyuv.o spca501.o sq905c.o bayer.o hm12.o helper.o \ + rgbyuv.o sn9c2028-decomp.o spca501.o sq905c.o bayer.o hm12.o \ control/libv4lcontrol.o processing/libv4lprocessing.o \ processing/whitebalance.o processing/autogain.o \ - processing/gamma.o + processing/gamma.o helper.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov511-decomp ov518-decomp INCLUDES = ../include/libv4lconvert.h @@ -33,7 +33,11 @@ ifeq ($(LIBDIR),) LIBDIR = $(PREFIX)/lib endif -override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\" +ifeq ($(LIBSUBDIR),) +LIBSUBDIR = libv4l +endif + +override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\" -DLIBSUBDIR=\"$(LIBSUBDIR)\" all: $(TARGETS) @@ -55,7 +59,7 @@ libv4lconvert.pc: install: all mkdir -p $(DESTDIR)$(PREFIX)/include install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include - mkdir -p $(DESTDIR)$(LIBDIR)/libv4l + mkdir -p $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR) ifeq ($(LINKTYPE),static) install -m 644 $(CONVERT_LIB) $(DESTDIR)$(LIBDIR) else @@ -63,7 +67,7 @@ else cd $(DESTDIR)$(LIBDIR) && \ ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB) endif - install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/libv4l + install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR) mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig diff --git a/v4l2-apps/libv4l/libv4lconvert/bayer.c b/v4l2-apps/libv4l/libv4lconvert/bayer.c index 033ee2724..d299629a6 100644 --- a/v4l2-apps/libv4l/libv4lconvert/bayer.c +++ b/v4l2-apps/libv4l/libv4lconvert/bayer.c @@ -1,6 +1,6 @@ /* * lib4lconvert, video4linux2 format conversion lib - * (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + * (C) 2008 Hans de Goede <hdegoede@redhat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 6211ee22a..632e9338a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -25,6 +25,7 @@ #define V4LCONTROL_SHM_SIZE 4096 #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 +#define V4LCONTROL_MEMORY_IS_MALLOCED 0x02 struct v4lcontrol_flags_info; @@ -49,6 +50,15 @@ struct v4lcontrol_flags_info { const char *product; */ int flags; int default_gamma; +/* Some seldom used dmi strings (for notebooks with bogus info in the board + entries, but usefull info elsewhere). We keep this at the end as to not + polute the initalizers for the normal case. */ + /* System (product) vendor / name */ + const char *dmi_system_vendor; + const char *dmi_system_name; + /* Board and System versions */ + const char *dmi_board_version; + const char *dmi_system_version; }; #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 4e600351b..243f35dae 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -3,6 +3,7 @@ # (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com> # (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com> # (C) 2008-2009 Hans de Goede <hdegoede@redhat.com> +# (C) 2009 Paul Sladen <ubuntu@paul.sladen.org> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -28,6 +29,7 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <pwd.h> #include "libv4lcontrol.h" #include "libv4lcontrol-priv.h" #include "../libv4lsyscall-priv.h" @@ -57,9 +59,111 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* Genius E-M 112 (also want whitebalance by default) */ { 0x093a, 0x2476, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB, 1500 }, - /* Asus N50Vn laptop */ + /* Laptops */ + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7L ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7Sg ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7SR ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "G50VT ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7S ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SR ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SV ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + /* note different white space: http://launchpad.net/bugs/413752 */ + { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X71SL ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + /* These 3 PACKARD BELL's seem to be Asus notebook in disguise */ + { 0x04f2, 0xb012, 0, "Packard Bell BV", "T32A ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG45", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG46", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6S ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6V ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K40IJ ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IJ ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IN ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70AB ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70IO ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N10J ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N20A ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + /* Note no whitespace padding for these 2 models, this is not a typo */ + { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "K50AB", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "N5051Tp", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vc ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ", V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vf ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vg ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vn ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x04f2, 0xb16b, 0, "ASUSTeK Computer Inc. ", "U80A ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + /* Note no whitespace padding for board vendor, this is not a typo */ + { 0x064e, 0xa111, 0, "ASUSTeK Computer Inc.", "F5RL ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + /* Another Asus laptop in disguise */ + { 0x064e, 0xa111, 0, "PEGATRON CORPORATION ", "F5SR ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jb ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jc ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N20A ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "X58LE ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x090c, 0xe370, 0, "ASUSTeK Computer Inc. ", "U6S ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Ke ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Q ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sa ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sg ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sr ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5N ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5SL ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1S ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1Sn ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G2S ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x174f, 0xa311, 0, "ASUSTeK Computer Inc. ", "A3F ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, + { 0x5986, 0x0200, 0, "LENOVO", "SPEEDY ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL, + "Lenovo IdeaPad Y510" }, + { 0x5986, 0x0205, 0, "LENOVO", "Base Board Product Name", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL, + "Lenovo IdeaPad U330" }, + /* Second: devices which should use some software processing by default */ /* Pac207 based devices */ { 0x041e, 0x4028, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 }, @@ -69,6 +173,8 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* Pac7302 based devices */ { 0x093a, 0x2620, 0x0f, NULL, NULL, V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB }, + { 0x06f8, 0x3009, 0, NULL, NULL, + V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB }, /* Pac7311 based devices */ { 0x093a, 0x2600, 0x0f, NULL, NULL, V4LCONTROL_WANTS_WB }, /* sq905 devices */ @@ -87,6 +193,33 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { static const struct v4l2_queryctrl fake_controls[]; +static void v4lcontrol_get_dmi_string(const char *string, char *buf, int size) +{ + FILE *f; + char *s, sysfs_name[512]; + + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/dmi/id/%s", string); + f = fopen(sysfs_name, "r"); + if (!f) { + /* Try again with a different sysfs path, not sure if this is needed + but we used to look under /sys/devices/virtual/dmi/id in older + libv4l versions, but this did not work with some kernels */ + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/devices/virtual/dmi/id/%s", string); + f = fopen(sysfs_name, "r"); + if (!f) { + buf[0] = 0; + return; + } + } + + s = fgets(buf, size, f); + if (s) + s[strlen(s) - 1] = 0; + fclose(f); +} + static void v4lcontrol_init_flags(struct v4lcontrol_data *data) { struct stat st; @@ -94,8 +227,8 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) char sysfs_name[512]; unsigned short vendor_id = 0; unsigned short product_id = 0; - char dmi_board_vendor[512] = ""; - char dmi_board_name[512]= ""; + char dmi_system_vendor[512], dmi_system_name[512], dmi_system_version[512]; + char dmi_board_vendor[512], dmi_board_name[512], dmi_board_version[512]; int i, minor; char c, *s, buf[32]; struct v4l2_input input; @@ -174,31 +307,39 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) return; /* Should never happen */ } - /* Get DMI board vendor and name */ - f = fopen("/sys/devices/virtual/dmi/id/board_vendor", "r"); - if (f) { - s = fgets(dmi_board_vendor, sizeof(dmi_board_vendor), f); - if (s) - s[strlen(s) - 1] = 0; - fclose(f); - } - - f = fopen("/sys/devices/virtual/dmi/id/board_name", "r"); - if (f) { - s = fgets(dmi_board_name, sizeof(dmi_board_name), f); - if (s) - s[strlen(s) - 1] = 0; - fclose(f); - } + /* Get DMI board and system strings */ + v4lcontrol_get_dmi_string("sys_vendor", dmi_system_vendor, + sizeof(dmi_system_vendor)); + v4lcontrol_get_dmi_string("product_name", dmi_system_name, + sizeof(dmi_system_name)); + v4lcontrol_get_dmi_string("product_version", dmi_system_version, + sizeof(dmi_system_version)); + + v4lcontrol_get_dmi_string("board_vendor", dmi_board_vendor, + sizeof(dmi_board_vendor)); + v4lcontrol_get_dmi_string("board_name", dmi_board_name, + sizeof(dmi_board_name)); + v4lcontrol_get_dmi_string("board_version", dmi_board_version, + sizeof(dmi_board_version)); for (i = 0; i < ARRAY_SIZE(v4lcontrol_flags); i++) if (v4lcontrol_flags[i].vendor_id == vendor_id && v4lcontrol_flags[i].product_id == (product_id & ~v4lcontrol_flags[i].product_mask) && + + (v4lcontrol_flags[i].dmi_system_vendor == NULL || + !strcmp(v4lcontrol_flags[i].dmi_system_vendor, dmi_system_vendor)) && + (v4lcontrol_flags[i].dmi_system_name == NULL || + !strcmp(v4lcontrol_flags[i].dmi_system_name, dmi_system_name)) && + (v4lcontrol_flags[i].dmi_system_version == NULL || + !strcmp(v4lcontrol_flags[i].dmi_system_version, dmi_system_version)) && + (v4lcontrol_flags[i].dmi_board_vendor == NULL || !strcmp(v4lcontrol_flags[i].dmi_board_vendor, dmi_board_vendor)) && (v4lcontrol_flags[i].dmi_board_name == NULL || - !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) { + !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name)) && + (v4lcontrol_flags[i].dmi_board_version == NULL || + !strcmp(v4lcontrol_flags[i].dmi_board_version, dmi_board_version))) { data->flags |= v4lcontrol_flags[i].flags; data->flags_info = &v4lcontrol_flags[i]; break; @@ -209,14 +350,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) { int shm_fd; int i, rc, init = 0; - char *s, shm_name[256]; + char *s, shm_name[256], pwd_buf[1024]; struct v4l2_capability cap; struct v4l2_queryctrl ctrl; + struct passwd pwd, *pwd_p; struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data)); - if (!data) + if (!data) { + fprintf(stderr, "libv4lcontrol: error: out of memory!\n"); return NULL; + } data->fd = fd; @@ -252,8 +396,19 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (data->controls == 0) return data; /* No need to create a shared memory segment */ - SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap); - snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card); + if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) { + perror("libv4lcontrol: error querying device capabilities"); + goto error; + } + + if (getpwuid_r(geteuid(), &pwd, pwd_buf, sizeof(pwd_buf), &pwd_p) == 0) { + snprintf(shm_name, 256, "/libv4l-%s:%s:%s", pwd.pw_name, + cap.bus_info, cap.card); + } else { + perror("libv4lcontrol: error getting username using uid instead"); + snprintf(shm_name, 256, "/libv4l-%lu:%s:%s", (unsigned long)geteuid(), + cap.bus_info, cap.card); + } /* / is not allowed inside shm names */ for (i = 1; shm_name[i]; i++) @@ -264,23 +419,41 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if ((shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR), (S_IREAD | S_IWRITE))) >= 0) init = 1; - else if ((shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE))) < 0) - goto error; + else + shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE)); - /* Set the shared memory size */ - ftruncate(shm_fd, V4LCONTROL_SHM_SIZE); + if (shm_fd >= 0) { + /* Set the shared memory size */ + ftruncate(shm_fd, V4LCONTROL_SHM_SIZE); - /* Retreive a pointer to the shm object */ - data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE), - MAP_SHARED, shm_fd, 0); - close(shm_fd); + /* Retreive a pointer to the shm object */ + data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE), + MAP_SHARED, shm_fd, 0); + close(shm_fd); - if (data->shm_values == MAP_FAILED) - goto error; + if (data->shm_values == MAP_FAILED) { + perror("libv4lcontrol: error shm mmap failed"); + data->shm_values = NULL; + } + } else + perror("libv4lcontrol: error creating shm segment failed"); + + /* Fall back to malloc */ + if (data->shm_values == NULL) { + fprintf(stderr, + "libv4lcontrol: falling back to malloc-ed memory for controls\n"); + data->shm_values = malloc(V4LCONTROL_SHM_SIZE); + if (!data->shm_values) { + fprintf(stderr, "libv4lcontrol: error: out of memory!\n"); + goto error; + } + init = 1; + data->priv_flags |= V4LCONTROL_MEMORY_IS_MALLOCED; + } if (init) { /* Initialize the new shm object we created */ - memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE)); + memset(data->shm_values, 0, V4LCONTROL_SHM_SIZE); for (i = 0; i < V4LCONTROL_COUNT; i++) data->shm_values[i] = fake_controls[i].default_value; @@ -301,12 +474,15 @@ error: void v4lcontrol_destroy(struct v4lcontrol_data *data) { - if (data->controls) - munmap(data->shm_values, V4LCONTROL_SHM_SIZE); + if (data->controls) { + if (data->priv_flags & V4LCONTROL_MEMORY_IS_MALLOCED) + free(data->shm_values); + else + munmap(data->shm_values, V4LCONTROL_SHM_SIZE); + } free(data); } -/* FIXME get better CID's for normalize */ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { { .id = V4L2_CID_AUTO_WHITE_BALANCE, diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c index 46c87f0ce..b2d878963 100644 --- a/v4l2-apps/libv4l/libv4lconvert/crop.c +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -2,7 +2,7 @@ # RGB and YUV crop routines -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index 8c4d8233c..dc9b858c9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -2,7 +2,7 @@ # RGB / YUV flip/rotate routines -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -219,6 +219,7 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, fmt->fmt.pix.height); break; } + v4lconvert_fixup_fmt(fmt); } void v4lconvert_flip(unsigned char *src, unsigned char *dest, diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 2cf8f6ba4..f16d05d02 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -52,6 +52,10 @@ #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M','3','1','0') #endif +#ifndef V4L2_PIX_FMT_SN9C2028 +#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') +#endif + #ifndef V4L2_PIX_FMT_SQ905C #define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') #endif @@ -92,6 +96,10 @@ #define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ #endif +#ifndef V4L2_FMT_FLAG_EMULATED +#define V4L2_FMT_FLAG_EMULATED 0x0002 +#endif + #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) #define V4LCONVERT_ERROR_MSG_SIZE 256 @@ -108,6 +116,7 @@ /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 /* Compressed format */ #define V4LCONVERT_NEEDS_CONVERSION 0x02 /* Apps likely wont know this */ +#define V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION 0x03 struct v4lconvert_data { int fd; @@ -184,6 +193,15 @@ void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst, void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dst, const struct v4l2_format *src_fmt); +void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest, + int width, int height); + +void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest, + int width, int height); + +void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, int yvu); + void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); @@ -202,12 +220,16 @@ void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst, void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst, int width, int height); -void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst, +int v4lconvert_decode_pac207(struct v4lconvert_data *data, + const unsigned char *inp, int src_size, unsigned char *outp, int width, int height); void v4lconvert_decode_mr97310a(const unsigned char *src, unsigned char *dst, int width, int height); +void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst, + int width, int height); + void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst, int width, int height); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 1389c58bc..32b9a51bb 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -46,6 +46,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_YUYV, 0 }, { V4L2_PIX_FMT_YVYU, 0 }, { V4L2_PIX_FMT_UYVY, 0 }, + { V4L2_PIX_FMT_RGB565, 0 }, { V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION }, { V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION }, { V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION }, @@ -57,14 +58,15 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION }, { V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SN9C2028, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION }, }; static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { @@ -94,8 +96,10 @@ struct v4lconvert_data *v4lconvert_create(int fd) processing controls without a performance impact. */ int always_needs_conversion = 1; - if (!data) + if (!data) { + fprintf(stderr, "libv4lconvert: error: out of memory!\n"); return NULL; + } data->fd = fd; data->decompress_pid = -1; @@ -113,7 +117,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) if (fmt.pixelformat == supported_src_pixfmts[j].fmt) { data->supported_src_formats |= 1 << j; v4lconvert_get_framesizes(data, fmt.pixelformat, j); - if (!supported_src_pixfmts[j].flags) + if (!(supported_src_pixfmts[j].flags & V4LCONVERT_NEEDS_CONVERSION)) always_needs_conversion = 0; break; } @@ -215,7 +219,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) return -1; } - fmt->flags = 0; + fmt->flags = V4L2_FMT_FLAG_EMULATED; fmt->pixelformat = faked_fmts[i]; fmt->description[0] = faked_fmts[i] & 0xff; fmt->description[1] = (faked_fmts[i] >> 8) & 0xff; @@ -490,6 +494,7 @@ static int v4lconvert_processing_needs_double_conversion( case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: case V4L2_PIX_FMT_MR97310A: + case V4L2_PIX_FMT_SN9C2028: case V4L2_PIX_FMT_SQ905C: case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: @@ -671,7 +676,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); break; case V4L2_PIX_FMT_OV511: - if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov511-decomp", + if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov511-decomp", src, src_size, d, d_size, width, height, yvu)) { /* Corrupt frame, better get another one */ errno = EAGAIN; @@ -679,7 +684,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; case V4L2_PIX_FMT_OV518: - if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp", + if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov518-decomp", src, src_size, d, d_size, width, height, yvu)) { /* Corrupt frame, better get another one */ errno = EAGAIN; @@ -724,6 +729,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: case V4L2_PIX_FMT_MR97310A: + case V4L2_PIX_FMT_SN9C2028: case V4L2_PIX_FMT_SQ905C: { unsigned char *tmpbuf; @@ -744,13 +750,22 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_PAC207: - v4lconvert_decode_pac207(src, tmpbuf, width, height); + if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf, + width, height)) { + /* Corrupt frame, better get another one */ + errno = EAGAIN; + return -1; + } tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_MR97310A: v4lconvert_decode_mr97310a(src, tmpbuf, width, height); tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; + case V4L2_PIX_FMT_SN9C2028: + v4lconvert_decode_sn9c2028(src, tmpbuf, width, height); + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; + break; case V4L2_PIX_FMT_SQ905C: v4lconvert_decode_sq905c(src, tmpbuf, width, height); tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8; @@ -787,6 +802,23 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; + case V4L2_PIX_FMT_RGB565: + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + v4lconvert_rgb565_to_rgb24(src, dest, width, height); + break; + case V4L2_PIX_FMT_BGR24: + v4lconvert_rgb565_to_bgr24(src, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1); + break; + } + break; + case V4L2_PIX_FMT_RGB24: switch (dest_pix_fmt) { case V4L2_PIX_FMT_BGR24: diff --git a/v4l2-apps/libv4l/libv4lconvert/pac207.c b/v4l2-apps/libv4l/libv4lconvert/pac207.c index 97ef4ebc0..a81d5d511 100644 --- a/v4l2-apps/libv4l/libv4lconvert/pac207.c +++ b/v4l2-apps/libv4l/libv4lconvert/pac207.c @@ -52,35 +52,35 @@ static void init_pixart_decoder(void) len = 2; } else if ((i & 0xC0) == 0x40) { /* code 01 */ - val = -5; + val = -1; len = 2; } else if ((i & 0xC0) == 0x80) { /* code 10 */ - val = +5; + val = +1; len = 2; } else if ((i & 0xF0) == 0xC0) { /* code 1100 */ - val = -10; + val = -2; len = 4; } else if ((i & 0xF0) == 0xD0) { /* code 1101 */ - val = +10; + val = +2; len = 4; } else if ((i & 0xF8) == 0xE0) { /* code 11100 */ - val = -15; + val = -3; len = 5; } else if ((i & 0xF8) == 0xE8) { /* code 11101 */ - val = +15; + val = +3; len = 5; } else if ((i & 0xFC) == 0xF0) { /* code 111100 */ - val = -20; + val = -4; len = 6; } else if ((i & 0xFC) == 0xF4) { /* code 111101 */ - val = +20; + val = +4; len = 6; } else if ((i & 0xF8) == 0xF8) { /* code 11111xxxxxx */ @@ -109,7 +109,8 @@ static inline unsigned short getShort(const unsigned char *pt) } static int -pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width) +pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width, + int step_size, int abs_bits) { int col; int val; @@ -135,11 +136,11 @@ pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width) if (table[code].is_abs) { /* absolute value: get 6 more bits */ code = getByte(inp, bitpos); - bitpos += 6; - *outp++ = code & 0xFC; + bitpos += abs_bits; + *outp++ = code & ~(0xff >> abs_bits); } else { /* relative to left pixel */ - val = outp[-2] + table[code].val; + val = outp[-2] + table[code].val * step_size; *outp++ = CLIP(val); } } @@ -148,18 +149,24 @@ pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width) return 2 * ((bitpos + 15) / 16); } -void v4lconvert_decode_pac207(const unsigned char *inp, unsigned char *outp, +int v4lconvert_decode_pac207(struct v4lconvert_data *data, + const unsigned char *inp, int src_size, unsigned char *outp, int width, int height) { /* we should received a whole frame with header and EOL marker in myframe->data and return a GBRG pattern in frame->tmpbuffer remove the header then copy line by line EOL is set with 0x0f 0xf0 marker or 0x1e 0xe1 for compressed line*/ + const unsigned char *end = inp + src_size; unsigned short word; int row; /* iterate over all rows */ for (row = 0; row < height; row++) { + if ((inp + 2) > end) { + V4LCONVERT_ERR("incomplete pac207 frame\n"); + return -1; + } word = getShort(inp); switch (word) { case 0x0FF0: @@ -167,21 +174,31 @@ or 0x1e 0xe1 for compressed line*/ inp += (2 + width); break; case 0x1EE1: - inp += pac_decompress_row(inp, outp, width); + inp += pac_decompress_row(inp, outp, width, 5, 6); + break; + + case 0x2DD2: + inp += pac_decompress_row(inp, outp, width, 9, 5); break; - case 0x2DD2: /* prefix for "stronger" compressed lines, currently the - kernel driver programs the cam so that we should not - get any of these */ + case 0x3CC3: + inp += pac_decompress_row(inp, outp, width, 17, 4); + break; + + case 0x4BB4: + /* skip or copy line? */ + memcpy(outp, outp - 2 * width, width); + inp += 2; + break; default: /* corrupt frame */ - /* FIXME add error reporting */ - return; + V4LCONVERT_ERR("unknown pac207 row header: 0x%04x\n", (int)word); + return -1; } outp += width; } - return; + return 0; } diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h index b73c73b53..c314231cd 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -30,6 +30,7 @@ struct v4lprocessing_data { struct v4lcontrol_data *control; int fd; int do_process; + int controls_changed; /* True if any of the lookup tables does not contain linear 0-255 */ int lookup_table_active; @@ -41,6 +42,11 @@ struct v4lprocessing_data { unsigned char green[256]; unsigned char comp2[256]; /* Filter private data for filters which need it */ + /* whitebalance.c data */ + int green_avg; + int comp1_avg; + int comp2_avg; + /* gamma.c data */ int last_gamma; unsigned char gamma_table[256]; }; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index cbbcca73c..424173ec5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -38,8 +38,10 @@ struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* struct v4lprocessing_data *data = calloc(1, sizeof(struct v4lprocessing_data)); - if (!data) + if (!data) { + fprintf(stderr, "libv4lprocessing: error: out of memory!\n"); return NULL; + } data->fd = fd; data->control = control; @@ -62,6 +64,8 @@ int v4lprocessing_pre_processing(struct v4lprocessing_data *data) data->do_process = 1; } + data->controls_changed |= v4lcontrol_controls_changed(data->control); + return data->do_process; } @@ -167,9 +171,10 @@ void v4lprocessing_processing(struct v4lprocessing_data *data, return; /* Non supported pix format */ } - if (v4lcontrol_controls_changed(data->control) || + if (data->controls_changed || data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) { v4lprocessing_update_lookup_tables(data, buf, fmt); + data->controls_changed = 0; data->lookup_table_update_counter = 0; } else data->lookup_table_update_counter++; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c index 64d20b3ff..5ee0cfaa8 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c @@ -27,10 +27,82 @@ #include "libv4lprocessing-priv.h" #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define CLIP256(color) (((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define CLIP(color, min, max) (((color)>(max))?(max):(((color)<(min))?(min):(color))) static int whitebalance_active(struct v4lprocessing_data *data) { - return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); + int wb; + + wb = v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); + if (!wb) { + /* Reset cached color averages */ + data->green_avg = 0; + } + + return wb; +} + +static int whitebalance_calculate_lookup_tables_generic( + struct v4lprocessing_data *data, int green_avg, int comp1_avg, int comp2_avg) +{ + int i, avg_avg; + const int max_step = 64; + + /* Clip averages (restricts maximum white balance correction) */ + green_avg = CLIP(green_avg, 512, 3072); + comp1_avg = CLIP(comp1_avg, 512, 3072); + comp2_avg = CLIP(comp2_avg, 512, 3072); + + /* First frame ? */ + if (data->green_avg == 0) { + data->green_avg = green_avg; + data->comp1_avg = comp1_avg; + data->comp2_avg = comp2_avg; + } else { + /* Slowly adjust the averages used for the correction, so that we + do not get a sudden change in colors */ + if (abs(data->green_avg - green_avg) > max_step) { + if (data->green_avg < green_avg) + data->green_avg += max_step; + else + data->green_avg -= max_step; + } + else + data->green_avg = green_avg; + + if (abs(data->comp1_avg - comp1_avg) > max_step) { + if (data->comp1_avg < comp1_avg) + data->comp1_avg += max_step; + else + data->comp1_avg -= max_step; + } + else + data->comp1_avg = comp1_avg; + + if (abs(data->comp2_avg - comp2_avg) > max_step) { + if (data->comp2_avg < comp2_avg) + data->comp2_avg += max_step; + else + data->comp2_avg -= max_step; + } + else + data->comp2_avg = comp2_avg; + } + + if (abs(data->green_avg - data->comp1_avg) < max_step && + abs(data->green_avg - data->comp2_avg) < max_step && + abs(data->comp1_avg - data->comp2_avg) < max_step) + return 0; + + avg_avg = (data->green_avg + data->comp1_avg + data->comp2_avg) / 3; + + for (i = 0; i < 256; i++) { + data->comp1[i] = CLIP256(data->comp1[i] * avg_avg / data->comp1_avg); + data->green[i] = CLIP256(data->green[i] * avg_avg / data->green_avg); + data->comp2[i] = CLIP256(data->comp2[i] * avg_avg / data->comp2_avg); + } + + return 1; } static int whitebalance_calculate_lookup_tables_bayer( @@ -38,7 +110,7 @@ static int whitebalance_calculate_lookup_tables_bayer( const struct v4l2_format *fmt, int starts_with_green) { int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0; - int green_avg, comp1_avg, comp2_avg, avg_avg; + int green_avg, comp1_avg, comp2_avg; for (y = 0; y < fmt->fmt.pix.height; y += 2) { for (x = 0; x < fmt->fmt.pix.width; x += 2) { @@ -54,37 +126,29 @@ static int whitebalance_calculate_lookup_tables_bayer( } if (starts_with_green) { - green_avg = (a1 + b2) / 512; - comp1_avg = a2 / 256; - comp2_avg = b1 / 256; + green_avg = a1 / 2 + b2 / 2; + comp1_avg = a2; + comp2_avg = b1; } else { - green_avg = (a2 + b1) / 512; - comp1_avg = a1 / 256; - comp2_avg = b2 / 256; + green_avg = a2 / 2 + b1 / 2; + comp1_avg = a1; + comp2_avg = b2; } - x = fmt->fmt.pix.width * fmt->fmt.pix.height / 64; - if (abs(green_avg - comp1_avg) < x && - abs(green_avg - comp2_avg) < x && - abs(comp1_avg - comp2_avg) < x) - return 0; - - avg_avg = (green_avg + comp1_avg + comp2_avg) / 3; - - for (x = 0; x < 256; x++) { - data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg); - data->green[x] = CLIP(data->green[x] * avg_avg / green_avg); - data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg); - } + /* Norm avg to ~ 0 - 4095 */ + green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; + comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; + comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; - return 1; + return whitebalance_calculate_lookup_tables_generic(data, green_avg, + comp1_avg, comp2_avg); } static int whitebalance_calculate_lookup_tables_rgb( struct v4lprocessing_data *data, unsigned char *buf, const struct v4l2_format *fmt) { - int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0, avg_avg; + int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0; for (y = 0; y < fmt->fmt.pix.height; y++) { for (x = 0; x < fmt->fmt.pix.width; x++) { @@ -95,25 +159,13 @@ static int whitebalance_calculate_lookup_tables_rgb( buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3; } - x = fmt->fmt.pix.width * fmt->fmt.pix.height * 4; - if (abs(green_avg - comp1_avg) < x && - abs(green_avg - comp2_avg) < x && - abs(comp1_avg - comp2_avg) < x) - return 0; - - /* scale to avoid integer overflows */ - green_avg /= 256; - comp1_avg /= 256; - comp2_avg /= 256; - avg_avg = (green_avg + comp1_avg + comp2_avg) / 3; + /* Norm avg to ~ 0 - 4095 */ + green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; + comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; + comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; - for (x = 0; x < 256; x++) { - data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg); - data->green[x] = CLIP(data->green[x] * avg_avg / green_avg); - data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg); - } - - return 1; + return whitebalance_calculate_lookup_tables_generic(data, green_avg, + comp1_avg, comp2_avg); } diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index 31cbc3c68..5c43ce07f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -1,8 +1,10 @@ /* # RGB <-> YUV conversion routines +# (C) 2008 Hans de Goede <hdegoede@redhat.com> -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# RGB565 conversion routines +# (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -472,3 +474,103 @@ void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dest, src += src_fmt->fmt.pix.bytesperline / 2; } } + +void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + int j; + while (--height >= 0) { + for (j = 0; j < width; j++) { + unsigned short tmp = *(unsigned short *)src; + + /* Original format: rrrrrggg gggbbbbb */ + *dest++ = 0xf8 & (tmp >> 8); + *dest++ = 0xfc & (tmp >> 3); + *dest++ = 0xf8 & (tmp << 3); + + src += 2; + } + } +} + +void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + int j; + while (--height >= 0) { + for (j = 0; j < width; j++) { + unsigned short tmp = *(unsigned short *)src; + + /* Original format: rrrrrggg gggbbbbb */ + *dest++ = 0xf8 & (tmp << 3); + *dest++ = 0xfc & (tmp >> 3); + *dest++ = 0xf8 & (tmp >> 8); + + src += 2; + } + } +} + +void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, int yvu) +{ + int x, y; + unsigned short tmp; + unsigned char *udest, *vdest; + unsigned r[4], g[4], b[4]; + int avg_src[3]; + + /* Y */ + for (y = 0; y < src_fmt->fmt.pix.height; y++) { + for (x = 0; x < src_fmt->fmt.pix.width; x++) { + tmp = *(unsigned short *)src; + r[0] = 0xf8 & (tmp << 3); + g[0] = 0xfc & (tmp >> 3); + b[0] = 0xf8 & (tmp >> 8); + RGB2Y(r[0], g[0], b[0], *dest++); + src += 2; + } + src += src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width; + } + src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline; + + /* U + V */ + if (yvu) { + vdest = dest; + udest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4; + } else { + udest = dest; + vdest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4; + } + + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < src_fmt->fmt.pix.width / 2; x++) { + tmp = *(unsigned short *)src; + r[0] = 0xf8 & (tmp << 3); + g[0] = 0xfc & (tmp >> 3); + b[0] = 0xf8 & (tmp >> 8); + + tmp = *(((unsigned short *)src) + 1); + r[1] = 0xf8 & (tmp << 3); + g[1] = 0xfc & (tmp >> 3); + b[1] = 0xf8 & (tmp >> 8); + + tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline); + r[2] = 0xf8 & (tmp << 3); + g[2] = 0xfc & (tmp >> 3); + b[2] = 0xf8 & (tmp >> 8); + + tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline + 1); + r[3] = 0xf8 & (tmp << 3); + g[3] = 0xfc & (tmp >> 3); + b[3] = 0xf8 & (tmp >> 8); + + avg_src[0] = (r[0] + r[1] + r[2] + r[3]) /4; + avg_src[1] = (g[0] + g[1] + g[2] + g[3]) /4; + avg_src[2] = (b[0] + b[1] + b[2] + b[3]) /4; + RGB2UV(avg_src[0], avg_src[1], avg_src[2], *udest++, *vdest++); + src += 4; + } + src += 2 * src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width; + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c b/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c new file mode 100644 index 000000000..c21696752 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c @@ -0,0 +1,157 @@ +/* + * sn9c2028-decomp.c + * + * Decompression function for the Sonix SN9C2028 dual-mode cameras. + * + * Code adapted from libgphoto2/camlibs/sonix, original version of which was + * Copyright (c) 2005 Theodore Kilgore <kilgota@auburn.edu> + * + * History: + * + * This decoding algorithm originates from the work of Bertrik Sikken for the + * SN9C102 cameras. This version is an adaptation of work done by Mattias + * Krauss for the webcam-osx (macam) project. There, it was further adapted + * for use with the Vivitar Vivicam 3350B (an SN9C2028 camera) by + * Harald Ruda <hrx@users.sourceforge.net>. Harald brought to my attention the + * work done in the macam project and suggested that I use it. One improvement + * of my own was to notice that the even and odd columns of the image have been + * reversed by the decompression algorithm, and this needs to be corrected + * during the decompression. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + */ + +#include "libv4lconvert-priv.h" + +/* Four defines for bitstream operations, used in the decode function */ + +#define PEEK_BITS(num,to) {\ + if (bitBufCount < num) {\ + do {\ + bitBuf = (bitBuf << 8)|(*(src++));\ + bitBufCount += 8; \ + } \ + while\ + (bitBufCount < 24);\ + } \ + to = bitBuf >> (bitBufCount-num);\ +} + +/* + * PEEK_BITS puts the next <num> bits into the low bits of <to>. + * when the buffer is empty, it is completely refilled. + * This strategy tries to reduce memory access. Note that the high bits + * are NOT set to zero! + */ + +#define EAT_BITS(num) { bitBufCount -= num; bits_eaten += num; } + +/* + * EAT_BITS consumes <num> bits (PEEK_BITS does not consume anything, + * it just peeks) + */ + +#define PARSE_PIXEL(val) {\ + PEEK_BITS(10, bits);\ + if ((bits&0x200) == 0) {\ + EAT_BITS(1);\ + } \ + else if ((bits&0x380) == 0x280) {\ + EAT_BITS(3);\ + val += 3;\ + if (val > 255)\ + val = 255;\ + } \ + else if ((bits&0x380) == 0x300) {\ + EAT_BITS(3);\ + val -= 3;\ + if (val < 0)\ + val = 0;\ + } \ + else if ((bits&0x3c0) == 0x200) {\ + EAT_BITS(4);\ + val += 8;\ + if (val > 255)\ + val = 255;\ + } \ + else if ((bits&0x3c0) == 0x240) {\ + EAT_BITS(4);\ + val -= 8;\ + if (val < 0)\ + val = 0;\ + } \ + else if ((bits&0x3c0) == 0x3c0) {\ + EAT_BITS(4);\ + val -= 20;\ + if (val < 0)\ + val = 0;\ + } \ + else if ((bits&0x3e0) == 0x380) {\ + EAT_BITS(5);\ + val += 20;\ + if (val > 255)\ + val = 255;\ + } \ + else {\ + EAT_BITS(10);\ + val = 8*(bits&0x1f)+0;\ + } \ +} + + +#define PUT_PIXEL_PAIR {\ + long pp;\ + pp = (c1val<<8)+c2val;\ + *((unsigned short *) (dst+dst_index)) = pp;\ + dst_index += 2;\ +} + +/* Now the decode function itself */ + +void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst, + int width, int height) +{ + long dst_index = 0; + int starting_row = 0; + unsigned short bits; + short c1val, c2val; + int x, y; + unsigned long bitBuf = 0; + unsigned long bitBufCount = 0; + unsigned long bits_eaten = 0; + + src += 12; /* Remove the header */ + + for (y = starting_row; y < height; y++) { + PEEK_BITS(8, bits); + EAT_BITS(8); + c2val = (bits & 0xff); + PEEK_BITS(8, bits); + EAT_BITS(8); + c1val = (bits & 0xff); + + PUT_PIXEL_PAIR; + + for (x = 2; x < width ; x += 2) { + /* The compression reversed the even and odd columns.*/ + PARSE_PIXEL(c2val); + PARSE_PIXEL(c1val); + PUT_PIXEL_PAIR; + } + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/spca501.c b/v4l2-apps/libv4l/libv4lconvert/spca501.c index f491512e3..f4fbc594a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/spca501.c +++ b/v4l2-apps/libv4l/libv4lconvert/spca501.c @@ -1,5 +1,5 @@ /* -# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> +# (C) 2008 Hans de Goede <hdegoede@redhat.com> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/v4l2-spec/vidioc-enum-fmt.sgml b/v4l2-spec/vidioc-enum-fmt.sgml index 7a31c2349..960d44615 100644 --- a/v4l2-spec/vidioc-enum-fmt.sgml +++ b/v4l2-spec/vidioc-enum-fmt.sgml @@ -127,6 +127,13 @@ the array to zero.</entry> <entry>0x0001</entry> <entry>This is a compressed format.</entry> </row> + <row> + <entry><constant>V4L2_FMT_FLAG_EMULATED</constant></entry> + <entry>0x0002</entry> + <entry>This format is not native to the device but emulated +through software (usually libv4l2), where possible try to use a native format +instead for better performance.</entry> + </row> </tbody> </tgroup> </table> |