diff options
Diffstat (limited to 'linux/drivers')
53 files changed, 2351 insertions, 818 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c index b58c8907f..6c0a80f45 100644 --- a/linux/drivers/media/common/ir-keymaps.c +++ b/linux/drivers/media/common/ir-keymaps.c @@ -2561,3 +2561,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys); + +/* ATI TV Wonder HD 600 USB + Devin Heitmueller <devin.heitmueller@gmail.com> + */ +IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = { + [0x00] = KEY_RECORD, /* Row 1 */ + [0x01] = KEY_PLAYPAUSE, + [0x02] = KEY_STOP, + [0x03] = KEY_POWER, + [0x04] = KEY_PREVIOUS, /* Row 2 */ + [0x05] = KEY_REWIND, + [0x06] = KEY_FORWARD, + [0x07] = KEY_NEXT, + [0x08] = KEY_EPG, /* Row 3 */ + [0x09] = KEY_HOME, + [0x0a] = KEY_MENU, + [0x0b] = KEY_CHANNELUP, + [0x0c] = KEY_BACK, /* Row 4 */ + [0x0d] = KEY_UP, + [0x0e] = KEY_INFO, + [0x0f] = KEY_CHANNELDOWN, + [0x10] = KEY_LEFT, /* Row 5 */ + [0x11] = KEY_SELECT, + [0x12] = KEY_RIGHT, + [0x13] = KEY_VOLUMEUP, + [0x14] = KEY_LAST, /* Row 6 */ + [0x15] = KEY_DOWN, + [0x16] = KEY_MUTE, + [0x17] = KEY_VOLUMEDOWN, +}; + +EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600); diff --git a/linux/drivers/media/common/tuners/mxl5005s.c b/linux/drivers/media/common/tuners/mxl5005s.c index 3ed0d45cd..58418277a 100644 --- a/linux/drivers/media/common/tuners/mxl5005s.c +++ b/linux/drivers/media/common/tuners/mxl5005s.c @@ -3600,7 +3600,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, 76, 77, 91, 134, 135, 137, 147, 156, 166, 167, 168, 25 }; - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); status += MXL_BlockInit(fe); @@ -3632,7 +3632,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, */ #endif - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); for (i = 0 ; i < *count; i++) { RegNum[i] = RegAddr[i]; @@ -3650,7 +3650,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, u8 RegAddr[] = {43, 136}; - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); for (i = 0; i < *count; i++) { RegNum[i] = RegAddr[i]; diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index 4d668e16d..e7adf9f47 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -656,6 +656,8 @@ restart: if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -1064,7 +1066,8 @@ void dtv_property_dump(struct dtv_property *tvp) int is_legacy_delivery_system(fe_delivery_system_t s) { if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS)) + (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || + (s == SYS_ATSC)) return 1; return 0; diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c index 6bc55614d..e6e534e04 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.c +++ b/linux/drivers/media/dvb/dvb-usb/af9015.c @@ -681,12 +681,6 @@ static int af9015_download_firmware(struct usb_device *udev, goto error; } - /* firmware is running, reconnect device in the usb bus */ - req.cmd = RECONNECT_USB; - ret = af9015_rw_udev(udev, &req); - if (ret) - err("reconnect failed: %d", ret); - error: return ret; } @@ -739,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev) af9015_config.ir_table_size = ARRAY_SIZE(af9015_ir_table_mygictv); break; + case AF9015_REMOTE_DIGITTRADE_DVB_T: + af9015_properties[i].rc_key_map = + af9015_rc_keys_digittrade; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_digittrade); + af9015_config.ir_table = + af9015_ir_table_digittrade; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_digittrade); + break; } } else { - switch (udev->descriptor.idVendor) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case USB_VID_LEADTEK: af9015_properties[i].rc_key_map = af9015_rc_keys_leadtek; @@ -754,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev) break; case USB_VID_VISIONPLUS: if (udev->descriptor.idProduct == - USB_PID_AZUREWAVE_AD_TU700) { + cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) { af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; af9015_properties[i].rc_key_map_size = @@ -1219,6 +1223,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .usb_ctrl = DEVICE_SPECIFIC, .download_firmware = af9015_download_firmware, .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, .size_of_priv = sizeof(struct af9015_state), \ @@ -1317,6 +1322,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .usb_ctrl = DEVICE_SPECIFIC, .download_firmware = af9015_download_firmware, .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, .size_of_priv = sizeof(struct af9015_state), \ diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.h b/linux/drivers/media/dvb/dvb-usb/af9015.h index 1ab86cc6c..21c7782f4 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.h +++ b/linux/drivers/media/dvb/dvb-usb/af9015.h @@ -123,6 +123,7 @@ enum af9015_remote { AF9015_REMOTE_A_LINK_DTU_M, AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, AF9015_REMOTE_MYGICTV_U718, + AF9015_REMOTE_DIGITTRADE_DVB_T, }; /* Leadtek WinFast DTV Dongle Gold */ @@ -596,4 +597,67 @@ static u8 af9015_ir_table_avermedia[] = { 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00, }; +/* Digittrade DVB-T USB Stick */ +static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = { + { 0x01, 0x0f, KEY_LAST }, /* RETURN */ + { 0x05, 0x17, KEY_TEXT }, /* TELETEXT */ + { 0x01, 0x08, KEY_EPG }, /* EPG */ + { 0x05, 0x13, KEY_POWER }, /* POWER */ + { 0x01, 0x09, KEY_ZOOM }, /* FULLSCREEN */ + { 0x00, 0x40, KEY_AUDIO }, /* DUAL SOUND */ + { 0x00, 0x2c, KEY_PRINT }, /* SNAPSHOT */ + { 0x05, 0x16, KEY_SUBTITLE }, /* SUBTITLE */ + { 0x00, 0x52, KEY_CHANNELUP }, /* CH Up */ + { 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */ + { 0x00, 0x57, KEY_VOLUMEUP }, /* Vol Up */ + { 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */ + { 0x01, 0x10, KEY_MUTE }, /* MUTE */ + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x01, 0x17, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x01, 0x15, KEY_RECORD }, /* RECORD */ + { 0x03, 0x13, KEY_PLAY }, /* PLAY */ + { 0x01, 0x16, KEY_STOP }, /* STOP */ + { 0x01, 0x13, KEY_PAUSE }, /* PAUSE */ +}; + +static u8 af9015_ir_table_digittrade[] = { + 0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00, + 0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00, + 0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00, + 0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00, + 0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00, + 0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00, + 0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00, + 0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00, + 0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00, + 0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00, + 0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00, + 0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00, + 0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00, + 0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00, + 0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00, + 0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00, + 0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00, + 0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00, + 0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00, + 0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00, + 0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00, + 0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00, + 0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00, + 0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00, + 0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00, + 0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00, + 0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00, +}; + #endif diff --git a/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 3ac9f74e9..80e37a0d0 100644 --- a/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -32,7 +32,6 @@ /* debug */ int dvb_usb_cinergyt2_debug; -int disable_remote; module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " @@ -45,7 +44,7 @@ struct cinergyt2_state { }; /* We are missing a release hook with usb_device data */ -struct dvb_usb_device *cinergyt2_usb_device; +static struct dvb_usb_device *cinergyt2_usb_device; static struct dvb_usb_device_properties cinergyt2_properties; diff --git a/linux/drivers/media/dvb/dvb-usb/cinergyT2.h b/linux/drivers/media/dvb/dvb-usb/cinergyT2.h index f008b41ad..4e3247d04 100644 --- a/linux/drivers/media/dvb/dvb-usb/cinergyT2.h +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2.h @@ -74,11 +74,11 @@ struct dvbt_get_status_msg { uint8_t bandwidth; uint16_t tps; uint8_t flags; - uint16_t gain; + __le16 gain; uint8_t snr; - uint32_t viterbi_error_rate; + __le32 viterbi_error_rate; uint32_t rs_error_rate; - uint32_t uncorrected_block_count; + __le32 uncorrected_block_count; uint8_t lock_bits; uint8_t prev_lock_bits; } __attribute__((packed)); @@ -86,9 +86,9 @@ struct dvbt_get_status_msg { struct dvbt_set_parameters_msg { uint8_t cmd; - uint32_t freq; + __le32 freq; uint8_t bandwidth; - uint16_t tps; + __le16 tps; uint8_t flags; } __attribute__((packed)); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700.h b/linux/drivers/media/dvb/dvb-usb/dib0700.h index 739193943..8b544fe79 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700.h +++ b/linux/drivers/media/dvb/dvb-usb/dib0700.h @@ -22,7 +22,7 @@ extern int dvb_usb_dib0700_debug; #define REQUEST_I2C_READ 0x2 #define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ #define REQUEST_JUMPRAM 0x8 #define REQUEST_SET_CLOCK 0xB #define REQUEST_SET_GPIO 0xC @@ -40,11 +40,14 @@ struct dib0700_state { u16 mt2060_if1[2]; u8 rc_toggle; u8 rc_counter; + u8 rc_func_version; u8 is_dib7000pc; u8 fw_use_new_i2c_api; u8 disable_streaming_master_mode; }; +extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype); extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c index 3c7bdef28..2fbb7049a 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -19,6 +19,22 @@ MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (defau DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype) +{ + u8 b[16]; + int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + b, sizeof(b), USB_CTRL_GET_TIMEOUT); + *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; + *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; + *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; + return ret; +} + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0cfccc24b..f28d3ae59 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -38,6 +38,7 @@ static struct mt2060_config bristol_mt2060_config[2] = { } }; + static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { .band_caps = BAND_VHF | BAND_UHF, .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), @@ -451,8 +452,13 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; /* Number of keypresses to ignore before start repeating */ #define RC_REPEAT_DELAY 2 +#define RC_REPEAT_DELAY_V1_20 5 -static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) + + +/* Used by firmware versions < 1.20 (deprecated) */ +static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event, + int *state) { u8 key[4]; int i; @@ -529,6 +535,137 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +/* This is the structure of the RC response packet starting in firmware 1.20 */ +struct dib0700_rc_response { + u8 report_id; + u8 data_state; + u8 system_msb; + u8 system_lsb; + u8 data; + u8 not_data; +}; + +/* This supports the new IR response format for firmware v1.20 */ +static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + struct dib0700_rc_response poll_reply; + u8 buf[6]; + int i; + int status; + int actlen; + int found = 0; + + /* Set initial results in case we exit the function early */ + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + /* Firmware v1.20 provides RC data via bulk endpoint 1 */ + status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf, + sizeof(buf), &actlen, 50); + if (status < 0) { + /* No data available (meaning no key press) */ + return 0; + } + + if (actlen != sizeof(buf)) { + /* We didn't get back the 6 byte message we expected */ + err("Unexpected RC response size [%d]", actlen); + return -1; + } + + poll_reply.report_id = buf[0]; + poll_reply.data_state = buf[1]; + poll_reply.system_msb = buf[2]; + poll_reply.system_lsb = buf[3]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; + + /* + info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n", + poll_reply.report_id, poll_reply.data_state, + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + */ + + if ((poll_reply.data + poll_reply.not_data) != 0xff) { + /* Key failed integrity check */ + err("key failed integrity check: %02x %02x %02x %02x", + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + return -1; + } + + /* Find the key in the map */ + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == poll_reply.system_lsb && + keymap[i].data == poll_reply.data) { + *event = keymap[i].event; + found = 1; + break; + } + } + + if (found == 0) { + err("Unknown remote controller key: %02x %02x %02x %02x", + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + d->last_event = 0; + return 0; + } + + if (poll_reply.data_state == 1) { + /* New key hit */ + st->rc_counter = 0; + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + d->last_event = keymap[i].event; + } else if (poll_reply.data_state == 2) { + /* Key repeated */ + st->rc_counter++; + + /* prevents unwanted double hits */ + if (st->rc_counter > RC_REPEAT_DELAY_V1_20) { + *event = d->last_event; + *state = REMOTE_KEY_PRESSED; + st->rc_counter = RC_REPEAT_DELAY_V1_20; + } + } else { + err("Unknown data state [%d]", poll_reply.data_state); + } + + return 0; +} + +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct dib0700_state *st = d->priv; + + /* Because some people may have improperly named firmware files, + let's figure out whether to use the new firmware call or the legacy + call based on the firmware version embedded in the file */ + if (st->rc_func_version == 0) { + u32 hwver, romver, ramver, fwtype; + int ret = dib0700_get_version(d, &hwver, &romver, &ramver, + &fwtype); + if (ret < 0) { + err("Could not determine version info"); + return -1; + } + if (ramver < 0x10200) + st->rc_func_version = 1; + else + st->rc_func_version = 2; + } + + if (st->rc_func_version == 2) + return dib0700_rc_query_v1_20(d, event, state); + else + return dib0700_rc_query_legacy(d, event, state); +} + static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, diff --git a/linux/drivers/media/dvb/frontends/s5h1411.c b/linux/drivers/media/dvb/frontends/s5h1411.c index 40644aacf..66e2dd6d6 100644 --- a/linux/drivers/media/dvb/frontends/s5h1411.c +++ b/linux/drivers/media/dvb/frontends/s5h1411.c @@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, /* Note: Leaving the I2C gate open here. */ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); + /* Put the device into low-power mode until first use */ + s5h1411_set_powerstate(&state->frontend, 1); + return &state->frontend; error: diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c index 208ade5b0..dbce57c26 100644 --- a/linux/drivers/media/radio/radio-mr800.c +++ b/linux/drivers/media/radio/radio-mr800.c @@ -142,6 +142,7 @@ struct amradio_device { unsigned char *buffer; struct mutex lock; /* buffer locking */ + struct mutex disconnect_lock; int curfreq; int stereo; int users; @@ -210,6 +211,10 @@ static int amradio_stop(struct amradio_device *radio) int retval; int size; + /* safety check */ + if (radio->removed) + return -EIO; + mutex_lock(&radio->lock); radio->buffer[0] = 0x00; @@ -243,6 +248,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) int size; unsigned short freq_send = 0x13 + (freq >> 3) / 25; + /* safety check */ + if (radio->removed) + return -EIO; + mutex_lock(&radio->lock); radio->buffer[0] = 0x00; @@ -296,18 +305,16 @@ static void usb_amradio_disconnect(struct usb_interface *intf) { struct amradio_device *radio = usb_get_intfdata(intf); + mutex_lock(&radio->disconnect_lock); + radio->removed = 1; usb_set_intfdata(intf, NULL); - if (radio) { + if (radio->users == 0) { video_unregister_device(radio->videodev); - radio->videodev = NULL; - if (radio->users) { - kfree(radio->buffer); - kfree(radio); - } else { - radio->removed = 1; - } + kfree(radio->buffer); + kfree(radio); } + mutex_unlock(&radio->disconnect_lock); } /* vidioc_querycap - query device capabilities */ @@ -328,6 +335,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + if (v->index > 0) return -EINVAL; @@ -354,6 +365,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + + /* safety check */ + if (radio->removed) + return -EIO; + if (v->index > 0) return -EINVAL; return 0; @@ -365,6 +382,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + radio->curfreq = f->frequency; if (amradio_setfreq(radio, radio->curfreq) < 0) amradio_dev_warn(&radio->videodev->dev, @@ -378,6 +399,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + f->type = V4L2_TUNER_RADIO; f->frequency = radio->curfreq; return 0; @@ -404,6 +429,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = radio->muted; @@ -418,6 +447,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + /* safety check */ + if (radio->removed) + return -EIO; + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) { @@ -503,14 +536,26 @@ static int usb_amradio_open(struct inode *inode, struct file *file) static int usb_amradio_close(struct inode *inode, struct file *file) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (!radio) return -ENODEV; + + mutex_lock(&radio->disconnect_lock); radio->users = 0; if (radio->removed) { + video_unregister_device(radio->videodev); kfree(radio->buffer); kfree(radio); + + } else { + retval = amradio_stop(radio); + if (retval < 0) + amradio_dev_warn(&radio->videodev->dev, + "amradio_stop failed\n"); } + + mutex_unlock(&radio->disconnect_lock); return 0; } @@ -610,6 +655,7 @@ static int usb_amradio_probe(struct usb_interface *intf, radio->usbdev = interface_to_usbdev(intf); radio->curfreq = 95.16 * FREQ_MUL; + mutex_init(&radio->disconnect_lock); mutex_init(&radio->lock); video_set_drvdata(radio->videodev, radio); diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index d67e127f1..a00228893 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -2240,9 +2240,9 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, - [BTTV_BOARD_VD009X1_MINIDIN] = { + [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { /* M.Klahr@phytec.de */ - .name = "PHYTEC VD-009-X1 MiniDIN (bt878)", + .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", .video_inputs = 4, .audio_inputs = 0, .tuner = UNSET, /* card has no tuner */ @@ -2250,14 +2250,14 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .muxsel = { 2, 3, 1, 0 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, + .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, - [BTTV_BOARD_VD009X1_COMBI] = { - .name = "PHYTEC VD-009-X1 Combi (bt878)", + [BTTV_BOARD_VD009X1_VD011_COMBI] = { + .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", .video_inputs = 4, .audio_inputs = 0, .tuner = UNSET, /* card has no tuner */ @@ -2265,7 +2265,7 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, + .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -3093,6 +3093,54 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .has_radio = 1, .has_remote = 1, + }, + [BTTV_BOARD_VD012] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = UNSET, /* card has no s-video */ + .gpiomask = 0x00, + .muxsel = { 0, 2, 3, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X1] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X1 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = { 2, 3, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X2] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X2 (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = UNSET, /* card has no tuner */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = { 3, 2, 1 }, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, } }; diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 09188617b..e398de6c1 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -163,14 +163,22 @@ MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* sysfs */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) +#else +static ssize_t show_card(struct class_device *cd, char *buf) +#endif { struct video_device *vfd = container_of(cd, struct video_device, dev); struct bttv *btv = dev_get_drvdata(vfd->parent); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +#else +static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +#endif /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ @@ -4089,7 +4097,7 @@ bttv_irq_switch_vbi(struct bttv *btv) spin_unlock(&btv->s_lock); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs) #else static irqreturn_t bttv_irq(int irq, void *dev_id) @@ -4271,8 +4279,13 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr, btv->video_dev->num); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) + if (class_device_create_file(&btv->video_dev->dev, + &class_device_attr_card)<0) { +#else if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { +#endif printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); goto err; diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h index 20f027ee4..ed0446a20 100644 --- a/linux/drivers/media/video/bt8xx/bttv.h +++ b/linux/drivers/media/video/bt8xx/bttv.h @@ -131,8 +131,8 @@ #define BTTV_BOARD_XGUARD 0x67 #define BTTV_BOARD_NEBULA_DIGITV 0x68 #define BTTV_BOARD_PV143 0x69 -#define BTTV_BOARD_VD009X1_MINIDIN 0x6a -#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b #define BTTV_BOARD_VD009_MINIDIN 0x6c #define BTTV_BOARD_VD009_COMBI 0x6d #define BTTV_BOARD_IVC100 0x6e @@ -178,6 +178,10 @@ #define BTTV_BOARD_GEOVISION_GV600 0x96 #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 #define BTTV_BOARD_ENLTV_FM_2 0x98 +#define BTTV_BOARD_VD012 0x99 +#define BTTV_BOARD_VD012_X1 0x9a +#define BTTV_BOARD_VD012_X2 0x9b + /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index d98e64545..dfe8ddbce 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -2,7 +2,7 @@ * * Support for a cx23417 mpeg encoder via cx23885 host port. * - * (c) 2004 Jelle Foks <jelle@foks.8m.com> + * (c) 2004 Jelle Foks <jelle@foks.us> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> * (c) 2008 Steven Toth <stoth@linuxtv.org> * - CX23885/7/8 support diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c index 3d2afe195..b090c6620 100644 --- a/linux/drivers/media/video/cx88/cx88-blackbird.c +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -3,7 +3,7 @@ * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. * - * (c) 2004 Jelle Foks <jelle@foks.8m.com> + * (c) 2004 Jelle Foks <jelle@foks.us> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> * * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> @@ -39,7 +39,7 @@ #include "cx88.h" MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); -MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); +MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); static unsigned int mpegbufs = 32; diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index dbad45a35..9d407ac26 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -3,7 +3,7 @@ * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. * - * (c) 2004 Jelle Foks <jelle@foks.8m.com> + * (c) 2004 Jelle Foks <jelle@foks.us> * (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> * @@ -34,7 +34,7 @@ /* ------------------------------------------------------------------ */ MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards"); -MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>"); +MODULE_AUTHOR("Jelle Foks <jelle@foks.us>"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 8d92cb05b..9177ea54b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -59,7 +59,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2800_BOARD_UNKNOWN] = { @@ -71,11 +71,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_UNKNOWN] = { @@ -91,7 +91,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { @@ -104,11 +104,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { @@ -120,15 +120,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_USB_2] = { @@ -140,15 +140,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { @@ -183,15 +183,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { @@ -204,15 +204,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { @@ -226,15 +226,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_GADMEI_UTV310] = { @@ -247,15 +247,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { @@ -268,15 +268,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = 2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = 9, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_DVC_100] = { @@ -287,11 +287,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { @@ -301,7 +301,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2821_BOARD_PROLINK_PLAYTV_USB2] = { @@ -315,15 +315,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2821_BOARD_SUPERCOMP_USB_2] = { @@ -339,15 +339,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2821_BOARD_USBGEAR_VD204] = { @@ -358,11 +358,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_NETGMBH_CAM] = { @@ -373,7 +373,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2860_BOARD_TYPHOON_DVD_MAKER] = { @@ -384,11 +384,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_GADMEI_UTV330] = { @@ -401,15 +401,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2860_BOARD_TERRATEC_HYBRID_XS] = { @@ -421,15 +421,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_KWORLD_PVRTV_300U] = { @@ -441,15 +441,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { @@ -460,15 +460,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2861_BOARD_PLEXTOR_PX_TV100U] = { @@ -481,15 +481,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2870_BOARD_TERRATEC_XS] = { @@ -531,15 +531,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { @@ -553,15 +553,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { @@ -574,7 +574,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, @@ -582,97 +582,96 @@ struct em28xx_board em28xx_boards[] = { }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_hauppauge_new, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { .name = "Pinnacle PCTV HD Pro Stick", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_pinnacle_pctv_hd, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { .name = "AMD ATI TV Wonder HD 600", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_ati_tv_wonder_hd_600, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .has_dvb = 1, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, /* maybe there's a reason behind it why Terratec sells the Hybrid XS @@ -681,21 +680,20 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_MSI_VOX_USB_2] = { @@ -711,15 +709,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE4, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_TERRATEC_CINERGY_200] = { @@ -732,15 +730,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_GRABBEEX_USB2800] = { @@ -751,11 +749,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { @@ -768,15 +766,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_KWORLD_USB2800] = { @@ -789,15 +787,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { @@ -808,11 +806,11 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2800_BOARD_VGEAR_POCKETTV] = { @@ -825,15 +823,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { @@ -845,7 +843,9 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, + .amux = EM28XX_AMUX_VIDEO, + .aout = EM28XX_AOUT_MONO | /* I2S */ + EM28XX_AOUT_MASTER, /* Line out pin */ }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, @@ -866,7 +866,7 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD] = { @@ -878,15 +878,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { @@ -898,15 +898,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_KWORLD_DVB_305U] = { @@ -918,15 +918,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2880_BOARD_KWORLD_DVB_310U] = { @@ -943,11 +943,11 @@ struct em28xx_board em28xx_boards[] = { }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_AC97_LINE_IN, + .amux = EM28XX_AMUX_LINE_IN, }, { /* S-video has not been tested yet */ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_AC97_LINE_IN, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2881_BOARD_DNT_DA2_HYBRID] = { @@ -959,15 +959,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { @@ -979,15 +979,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { @@ -1000,15 +1000,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_KWORLD_VS_DVBT] = { @@ -1020,15 +1020,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2882_BOARD_TERRATEC_HYBRID_XS] = { @@ -1040,15 +1040,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2883_BOARD_KWORLD_HYBRID_A316] = { @@ -1061,15 +1061,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { @@ -1093,6 +1093,7 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 0, .tuner_type = TUNER_ABSENT, .has_dvb = 1, + .ir_codes = ir_codes_pinnacle_pctv_hd, .decoder = EM28XX_NODECODER, #ifdef DJH_DEBUG .input = { { @@ -1334,6 +1335,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; dev->has_dvb = em28xx_boards[dev->model].has_dvb; dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; + dev->ir_codes = em28xx_boards[dev->model].ir_codes; dev->valid = em28xx_boards[dev->model].valid; } @@ -1355,6 +1357,15 @@ void em28xx_pre_card_setup(struct em28xx *dev) if (rc > 0) { dev->chip_id = rc; switch (rc) { + case CHIP_ID_EM2750: + em28xx_info("chip ID is em2750\n"); + break; + case CHIP_ID_EM2820: + em28xx_info("chip ID is em2820\n"); + break; + case CHIP_ID_EM2840: + em28xx_info("chip ID is em2840\n"); + break; case CHIP_ID_EM2860: em28xx_info("chip ID is em2860\n"); break; @@ -1391,7 +1402,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1403,7 +1416,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2882_BOARD_TERRATEC_HYBRID_XS: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* should be added ir_codes here */ @@ -1423,7 +1438,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_KWORLD_350U: case EM2881_BOARD_DNT_DA2_HYBRID: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital @@ -1440,7 +1457,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_MSI_DIGIVOX_AD: case EM2880_BOARD_MSI_DIGIVOX_AD_II: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1457,7 +1476,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_PLEXTOR_PX_TV100U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* FIXME guess */ /* Turn on analog audio output */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); @@ -1466,7 +1487,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(10); em28xx_write_regs(dev, 0x08, "\x6d", 1); msleep(10); @@ -1476,7 +1499,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_KWORLD_355U: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); msleep(50); /* Sets GPO/GPIO sequences for this device */ @@ -1485,7 +1510,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_COMPRO_VIDEOMATE: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* TODO: someone can do some cleanup here... not everything's needed */ em28xx_write_regs(dev, 0x04, "\x00", 1); @@ -1504,7 +1531,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2870_BOARD_TERRATEC_XS_MT2060: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* this device needs some gpio writes to get the DVB-T demod work */ em28xx_write_regs(dev, 0x08, "\xfe", 1); @@ -1516,7 +1545,10 @@ void em28xx_pre_card_setup(struct em28xx *dev) break; case EM2870_BOARD_PINNACLE_PCTV_DVB: - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); + /* this device needs some gpio writes to get the DVB-T demod work */ em28xx_write_regs(dev, 0x08, "\xfe", 1); @@ -1532,7 +1564,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2820_BOARD_GADMEI_UTV310: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* Turn on analog audio output */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; @@ -1540,20 +1574,27 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2860_BOARD_GADMEI_UTV330: /* Turn on IR */ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* should be added ir_codes here */ break; case EM2820_BOARD_MSI_VOX_USB_2: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ); /* enables audio for that device */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; case EM2874_BOARD_PINNACLE_PCTV_80E: - /* Set 400 KHz clock */ - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x45", 1); + /* Set 400 KHz clock and select secondary i2c bus */ + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, + EM28XX_I2C_CLK_WAIT_ENABLE | + EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_FREQ_400_KHZ); dev->digital_gpio = em2874_pinnacle_80e_digital; break; @@ -1765,6 +1806,8 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); dev->tuner_type = em28xx_boards[dev->model].tuner_type; + if (em28xx_boards[dev->model].tuner_addr) + dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; /* request some modules */ switch (dev->model) { diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 48c2caabe..eb8515895 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -69,19 +69,33 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, int ret, byte; if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); + return -ENODEV; + + if (len > URB_MAX_CTRL_SIZE) + return -EINVAL; em28xx_regdbg("req=%02x, reg=%02x ", req, reg); + mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, buf, len, HZ); + 0x0000, reg, dev->urb_buf, len, HZ); + if (ret < 0) { + if (reg_debug) + printk(" failed!\n"); + mutex_unlock(&dev->ctrl_urb_lock); + return ret; + } + + if (len) + memcpy(buf, dev->urb_buf, len); + + mutex_unlock(&dev->ctrl_urb_lock); if (reg_debug) { - printk(ret < 0 ? " failed!\n" : "%02x values: ", ret); + printk("%02x values: ", ret); for (byte = 0; byte < len; byte++) printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); } @@ -102,16 +116,20 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) em28xx_regdbg("req=%02x, reg=%02x:", req, reg); + mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, &val, 1, HZ); + 0x0000, reg, dev->urb_buf, 1, HZ); + val = dev->urb_buf[0]; + mutex_unlock(&dev->ctrl_urb_lock); - if (reg_debug) - printk(ret < 0 ? " failed!\n" : - "%02x\n", (unsigned char) val); - - if (ret < 0) + if (ret < 0) { + printk(" failed!\n"); return ret; + } + + if (reg_debug) + printk("%02x\n", (unsigned char) val); return val; } @@ -130,19 +148,13 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, { int ret; - /*usb_control_msg seems to expect a kmalloced buffer */ - unsigned char *bufs; - if (dev->state & DEV_DISCONNECTED) return -ENODEV; - if (len < 1) + if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) return -EINVAL; - bufs = kmalloc(len, GFP_KERNEL); - em28xx_regdbg("req=%02x reg=%02x:", req, reg); - if (reg_debug) { int i; for (i = 0; i < len; ++i) @@ -150,16 +162,16 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, printk("\n"); } - if (!bufs) - return -ENOMEM; - memcpy(bufs, buf, len); + mutex_lock(&dev->ctrl_urb_lock); + memcpy(dev->urb_buf, buf, len); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, bufs, len, HZ); + 0x0000, reg, dev->urb_buf, len, HZ); + mutex_unlock(&dev->ctrl_urb_lock); + if (dev->wait_after_write) msleep(dev->wait_after_write); - kfree(bufs); return ret; } @@ -184,6 +196,12 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) return rc; } +/* Write a single register */ +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) +{ + return em28xx_write_regs(dev, reg, &val, 1); +} + /* * em28xx_write_reg_bits() * sets only some bits (specified by bitmask) of a register, by first reading @@ -212,15 +230,70 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, } /* + * em28xx_is_ac97_ready() + * Checks if ac97 is ready + */ +static int em28xx_is_ac97_ready(struct em28xx *dev) +{ + int ret, i; + + /* Wait up to 50 ms for AC97 command to complete */ + for (i = 0; i < 10; i++, msleep(5)) { + ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); + if (ret < 0) + return ret; + + if (!(ret & 0x01)) + return 0; + } + + em28xx_warn("AC97 command still being executed: not handled properly!\n"); + return -EBUSY; +} + +/* + * em28xx_read_ac97() + * write a 16 bit value to the specified AC97 address (LSB first!) + */ +static int em28xx_read_ac97(struct em28xx *dev, u8 reg) +{ + int ret; + u8 addr = (reg & 0x7f) | 0x80; + u16 val; + + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); + if (ret < 0) + return ret; + + ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB, + (u8 *)&val, sizeof(val)); + + if (ret < 0) + return ret; + return le16_to_cpu(val); +} + +/* * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */ -static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) +static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) { - int ret, i; + int ret; u8 addr = reg & 0x7f; + __le16 value; + + value = cpu_to_le16(val); - ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2); + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2); if (ret < 0) return ret; @@ -228,33 +301,59 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) if (ret < 0) return ret; - /* Wait up to 50 ms for AC97 command to complete */ - for (i = 0; i < 10; i++) { - ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); - if (ret < 0) - return ret; + return 0; +} - if (!(ret & 0x01)) - return 0; - msleep(5); +struct em28xx_vol_table { + enum em28xx_amux mux; + u8 reg; +}; + +static struct em28xx_vol_table inputs[] = { + { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, + { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, + { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, + { EM28XX_AMUX_MIC, AC97_MIC_VOL }, + { EM28XX_AMUX_CD, AC97_CD_VOL }, + { EM28XX_AMUX_AUX, AC97_AUX_VOL }, + { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL }, +}; + +static int set_ac97_input(struct em28xx *dev) +{ + int ret, i; + enum em28xx_amux amux = dev->ctl_ainput; + + /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that + em28xx should point to LINE IN, while AC97 should use VIDEO + */ + if (amux == EM28XX_AMUX_VIDEO2) + amux = EM28XX_AMUX_VIDEO; + + /* Mute all entres but the one that were selected */ + for (i = 0; i < ARRAY_SIZE(inputs); i++) { + if (amux == inputs[i].mux) + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808); + else + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); + + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + inputs[i].reg); } - em28xx_warn("AC97 command still being executed: not handled properly!\n"); return 0; } static int em28xx_set_audio_source(struct em28xx *dev) { - static char *enable = "\x08\x08"; - static char *disable = "\x08\x88"; - char *video = enable, *line = disable; int ret; u8 input; if (dev->is_em2800) { - if (dev->ctl_ainput) - input = EM2800_AUDIO_SRC_LINE; - else + if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) input = EM2800_AUDIO_SRC_TUNER; + else + input = EM2800_AUDIO_SRC_LINE; ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); if (ret < 0) @@ -268,16 +367,8 @@ static int em28xx_set_audio_source(struct em28xx *dev) case EM28XX_AMUX_VIDEO: input = EM28XX_AUDIO_SRC_TUNER; break; - case EM28XX_AMUX_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_VIDEO: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_LINE_IN: + default: input = EM28XX_AUDIO_SRC_LINE; - video = disable; - line = enable; break; } } @@ -287,33 +378,44 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; msleep(5); - /* Sets AC97 mixer registers - This is seems to be needed, even for non-ac97 configs - */ - ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video); - if (ret < 0) - return ret; - - ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line); + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + break; + default: + ret = set_ac97_input(dev); + } return ret; } +struct em28xx_vol_table outputs[] = { + { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, + { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, + { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, + { EM28XX_AOUT_LFE, AC97_LFE_MASTER_VOL }, + { EM28XX_AOUT_SURR, AC97_SURR_MASTER_VOL }, +}; + int em28xx_audio_analog_set(struct em28xx *dev) { - int ret; - char s[2] = { 0x00, 0x00 }; + int ret, i; u8 xclk = 0x07; - s[0] |= 0x1f - dev->volume; - s[1] |= 0x1f - dev->volume; - - /* Mute */ - s[1] |= 0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); + if (!dev->audio_mode.has_audio) + return 0; - if (ret < 0) - return ret; + /* It is assumed that all devices use master volume for output. + It would be possible to use also line output. + */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + /* Mute all outputs */ + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i].reg); + } + } if (dev->has_12mhz_i2s) xclk |= 0x20; @@ -329,15 +431,129 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); - /* Unmute device */ - if (!dev->mute) - s[1] &= ~0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); + /* Sets volume */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + int vol; + + /* LSB: left channel - both channels with the same level */ + vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); + + /* Mute device, if needed */ + if (dev->mute) + vol |= 0x8000; + + /* Sets volume */ + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + if (dev->ctl_aoutput & outputs[i].mux) + ret = em28xx_write_ac97(dev, outputs[i].reg, + vol); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i].reg); + } + } return ret; } EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); +int em28xx_audio_setup(struct em28xx *dev) +{ + int vid1, vid2, feat, cfg; + u32 vid; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* Digital only device - don't load any alsa module */ + dev->audio_mode.has_audio = 0; + dev->has_audio_class = 0; + dev->has_alsa_audio = 0; + return 0; + } + + /* If device doesn't support Usb Audio Class, use vendor class */ + if (!dev->has_audio_class) + dev->has_alsa_audio = 1; + + dev->audio_mode.has_audio = 1; + + /* See how this device is configured */ + cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); + if (cfg < 0) + cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ + else + em28xx_info("Config register raw data: 0x%02x\n", cfg); + + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_3_SAMPRATES) { + em28xx_info("I2S Audio (3 sample rates)\n"); + dev->audio_mode.i2s_3rates = 1; + } + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_5_SAMPRATES) { + em28xx_info("I2S Audio (5 sample rates)\n"); + dev->audio_mode.i2s_5rates = 1; + } + + if (!(cfg & EM28XX_CHIPCFG_AC97)) { + dev->audio_mode.ac97 = EM28XX_NO_AC97; + goto init_audio; + } + + dev->audio_mode.ac97 = EM28XX_AC97_OTHER; + + vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1); + if (vid1 < 0) { + /* Device likely doesn't support AC97 */ + em28xx_warn("AC97 chip type couldn't be determined\n"); + goto init_audio; + } + + vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2); + if (vid2 < 0) + goto init_audio; + + vid = vid1 << 16 | vid2; + + dev->audio_mode.ac97_vendor_id = vid; + em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); + + feat = em28xx_read_ac97(dev, AC97_RESET); + if (feat < 0) + goto init_audio; + + dev->audio_mode.ac97_feat = feat; + em28xx_warn("AC97 features = 0x%04x\n", feat); + + /* Try to identify what audio processor we have */ + if ((vid == 0xffffffff) && (feat == 0x6a90)) + dev->audio_mode.ac97 = EM28XX_AC97_EM202; + else if ((vid >> 8) == 0x838476) + dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; + +init_audio: + /* Reports detected AC97 processor */ + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + em28xx_info("No AC97 audio processor\n"); + break; + case EM28XX_AC97_EM202: + em28xx_info("Empia 202 AC97 audio processor detected\n"); + break; + case EM28XX_AC97_SIGMATEL: + em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n", + dev->audio_mode.ac97_vendor_id & 0xff); + break; + case EM28XX_AC97_OTHER: + em28xx_warn("Unknown AC97 audio processor detected!\n"); + break; + default: + break; + } + + return em28xx_audio_analog_set(dev); +} +EXPORT_SYMBOL_GPL(em28xx_audio_setup); + int em28xx_colorlevels_set_default(struct em28xx *dev) { em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 51ecdcd34..ec3e3b157 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -348,9 +348,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client, &buf, 0); if (err < 0) { - em28xx_errdev("%s: i2c_master_recv failed! err [%d]\n", - __func__, err); - return err; + em28xx_errdev("board has no eeprom\n"); + memset(eedata, 0, len); + return -ENODEV; } buf = 0; @@ -620,14 +620,16 @@ int em28xx_i2c_register(struct em28xx *dev) dev->i2c_client.adapter = &dev->i2c_adap; retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); - if (retval < 0) { + if ((retval < 0) && (retval != -ENODEV)) { em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); + return retval; } if (i2c_scan) em28xx_do_i2c_scan(dev); + return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 92114875f..29900920d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -53,6 +53,13 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); Polling structure used by em28xx IR's **********************************************************/ +struct em28xx_ir_poll_result { + unsigned int toggle_bit:1; + unsigned int read_count:7; + u8 rc_address; + u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */ +}; + struct em28xx_IR { struct em28xx *dev; struct input_dev *input; @@ -64,13 +71,11 @@ struct em28xx_IR { int polling; struct work_struct work; struct timer_list timer; - u32 last_gpio; - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; - u32 mask_repeat; + unsigned int last_toggle:1; + unsigned int last_readcount; + unsigned int repeat_interval; - int (*get_key)(struct em28xx_IR *); + int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); }; /********************************************************** @@ -168,11 +173,13 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, Poll based get keycode functions **********************************************************/ -static int default_polling_getkey(struct em28xx_IR *ir) +/* This is for the em2860/em2880 */ +static int default_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) { struct em28xx *dev = ir->dev; int rc; - u8 msg[4] = { 0, 0, 0, 0 }; + u8 msg[3] = { 0, 0, 0 }; /* Read key toggle, brand, and key code on registers 0x45, 0x46 and 0x47 @@ -182,7 +189,51 @@ static int default_polling_getkey(struct em28xx_IR *ir) if (rc < 0) return rc; - return (int)(le32_to_cpu(*(u32 *)msg)); + /* Infrared toggle (Reg 0x45[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x45[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x46) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x47) */ + poll_result->rc_data[0] = msg[2]; + + return 0; +} + +static int em2874_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) +{ + struct em28xx *dev = ir->dev; + int rc; + u8 msg[5] = { 0, 0, 0, 0, 0 }; + + /* Read key toggle, brand, and key code + on registers 0x51-55 + */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, + msg, sizeof(msg)); + if (rc < 0) + return rc; + + /* Infrared toggle (Reg 0x51[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x51[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x52) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x53-55) */ + poll_result->rc_data[0] = msg[2]; + poll_result->rc_data[1] = msg[3]; + poll_result->rc_data[2] = msg[4]; + + return 0; } /********************************************************** @@ -191,52 +242,60 @@ static int default_polling_getkey(struct em28xx_IR *ir) static void em28xx_ir_handle_key(struct em28xx_IR *ir) { - int gpio; - u32 data; - - /* read gpio value */ - gpio = ir->get_key(ir); - if (gpio < 0) + int result; + int do_sendkey = 0; + struct em28xx_ir_poll_result poll_result; + + /* read the registers containing the IR status */ + result = ir->get_key(ir, &poll_result); + if (result < 0) { + dprintk("ir->get_key() failed %d\n", result); return; + } - if (gpio == ir->last_gpio) - return; + dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n", + poll_result.toggle_bit, poll_result.read_count, + ir->last_readcount, poll_result.rc_data[0]); + + if (ir->dev->chip_id == CHIP_ID_EM2874) { + /* The em2874 clears the readcount field every time the + register is read. The em2860/2880 datasheet says that it + is supposed to clear the readcount, but it doesn't. So with + the em2874, we are looking for a non-zero read count as + opposed to a readcount that is incrementing */ + ir->last_readcount = 0; + } - ir->last_gpio = gpio; - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk("irq gpio=0x%x code=%d | poll%s%s\n", - gpio, data, - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); - - /* Generate keyup/keydown events */ - if (ir->mask_keydown) { - /* bit set on keydown */ - if (gpio & ir->mask_keydown) - ir_input_keydown(ir->input, &ir->ir, data, data); - else - ir_input_nokey(ir->input, &ir->ir); - } else if (ir->mask_keyup) { - /* bit cleared on keydown */ - if (!(gpio & ir->mask_keyup)) - ir_input_keydown(ir->input, &ir->ir, data, data); - else - ir_input_nokey(ir->input, &ir->ir); - } else if (ir->mask_repeat) { - int count = ir->mask_repeat & gpio; - - /* Avoid keyboard bouncing */ - if ((count == 1) || (count >= 5)) { - ir_input_keydown(ir->input, &ir->ir, data, data); - ir_input_nokey(ir->input, &ir->ir); + if (poll_result.read_count == 0) { + /* The button has not been pressed since the last read */ + } else if (ir->last_toggle != poll_result.toggle_bit) { + /* A button has been pressed */ + dprintk("button has been pressed\n"); + ir->last_toggle = poll_result.toggle_bit; + ir->repeat_interval = 0; + do_sendkey = 1; + } else if (poll_result.toggle_bit == ir->last_toggle && + poll_result.read_count > 0 && + poll_result.read_count != ir->last_readcount) { + /* The button is still being held down */ + dprintk("button being held down\n"); + + /* Debouncer for first keypress */ + if (ir->repeat_interval++ > 9) { + /* Start repeating after 1 second */ + do_sendkey = 1; } - } else { - /* can't distinguish keydown/up :-/ */ - ir_input_keydown(ir->input, &ir->ir, data, data); + } + + if (do_sendkey) { + dprintk("sending keypress\n"); + ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0], + poll_result.rc_data[0]); ir_input_nokey(ir->input, &ir->ir); } + + ir->last_readcount = poll_result.read_count; + return; } static void ir_timer(unsigned long data) @@ -283,10 +342,14 @@ int em28xx_ir_init(struct em28xx *dev) { struct em28xx_IR *ir; struct input_dev *input_dev; - IR_KEYTAB_TYPE *ir_codes = NULL; - int ir_type = IR_TYPE_OTHER; + u8 ir_config; int err = -ENOMEM; + if (dev->ir_codes == NULL) { + /* No remote control support */ + return 0; + } + ir = kzalloc(sizeof(*ir), GFP_KERNEL); input_dev = input_allocate_device(); if (!ir || !input_dev) @@ -294,25 +357,26 @@ int em28xx_ir_init(struct em28xx *dev) ir->input = input_dev; - /* */ - ir->get_key = default_polling_getkey; - ir->polling = 50; /* ms */ - - /* detect & configure */ - switch (dev->model) { - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - ir_type = IR_TYPE_OTHER; - ir_codes = ir_codes_hauppauge_new; - ir->mask_keycode = 0x007f0000; - ir->mask_repeat = 0x0000007f; + /* Setup the proper handler based on the chip */ + switch (dev->chip_id) { + case CHIP_ID_EM2860: + case CHIP_ID_EM2883: + ir->get_key = default_polling_getkey; break; - } - - if (NULL == ir_codes) { - err = -ENODEV; + case CHIP_ID_EM2874: + ir->get_key = em2874_polling_getkey; + /* For now we only support RC5, so enable it */ + ir_config = EM2874_IR_RC5; + em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); + break; + default: + printk("Unrecognized em28xx chip id: IR not supported\n"); goto err_out_free; } + /* This is how often we ask the chip for IR information */ + ir->polling = 100; /* ms */ + /* init input device */ snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name); @@ -320,7 +384,7 @@ int em28xx_ir_init(struct em28xx *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->ir_codes); input_dev->name = ir->name; input_dev->phys = ir->phys; input_dev->id.bustype = BUS_USB; @@ -337,10 +401,6 @@ int em28xx_ir_init(struct em28xx *dev) ir->dev = dev; dev->ir = ir; - /* Get the current key status, to avoid adding an - unexistent key code */ - ir->last_gpio = ir->get_key(ir); - em28xx_ir_start(ir); /* all done */ diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index f67955a1b..98e95054e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -17,11 +17,34 @@ /* em28xx registers */ +#define EM28XX_R00_CHIPCFG 0x00 + +/* em28xx Chip Configuration 0x00 */ +#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 +#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 +#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x30 +#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x20 +#define EM28XX_CHIPCFG_AC97 0x10 +#define EM28XX_CHIPCFG_AUDIOMASK 0x30 + /* GPIO/GPO registers */ #define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ #define EM28XX_R06_I2C_CLK 0x06 + +/* em28xx I2C Clock Register (0x06) */ +#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80 +#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40 +#define EM28XX_I2C_EEPROM_ON_BOARD 0x08 +#define EM28XX_I2C_EEPROM_KEY_VALID 0x04 +#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */ +#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */ +#define EM28XX_I2C_FREQ_25_KHZ 0x02 +#define EM28XX_I2C_FREQ_400_KHZ 0x01 +#define EM28XX_I2C_FREQ_100_KHZ 0x00 + + #define EM28XX_R0A_CHIPID 0x0a #define EM28XX_R0C_USBSUSP 0x0c /* */ @@ -78,15 +101,18 @@ 0x47 IR data */ -/* em202 registers */ -#define EM28XX_R02_MASTER_AC97 0x02 -#define EM28XX_R10_LINE_IN_AC97 0x10 -#define EM28XX_R14_VIDEO_AC97 0x14 - /* em2874 registers */ +#define EM2874_R50_IR_CONFIG 0x50 +#define EM2874_R51_IR 0x51 #define EM2874_R5F_TS_ENABLE 0x5f #define EM2874_R80_GPIO 0x80 +/* em2874 IR config register (0x50) */ +#define EM2874_IR_NEC 0x00 +#define EM2874_IR_RC5 0x04 +#define EM2874_IR_RC5_MODE_0 0x08 +#define EM2874_IR_RC5_MODE_6A 0x0b + /* em2874 Transport Stream Enable Register (0x5f) */ #define EM2874_TS1_CAPTURE_ENABLE (1 << 0) #define EM2874_TS1_FILTER_ENABLE (1 << 1) @@ -103,7 +129,74 @@ /* FIXME: Need to be populated with the other chip ID's */ enum em28xx_chip_id { + CHIP_ID_EM2820 = 18, + CHIP_ID_EM2840 = 20, + CHIP_ID_EM2750 = 33, CHIP_ID_EM2860 = 34, CHIP_ID_EM2883 = 36, CHIP_ID_EM2874 = 65, }; + +/* + * Registers used by em202 and other AC97 chips + */ + +/* Standard AC97 registers */ +#define AC97_RESET 0x00 + + /* Output volumes */ +#define AC97_MASTER_VOL 0x02 +#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */ +#define AC97_MASTER_MONO_VOL 0x06 + + /* Input volumes */ +#define AC97_PC_BEEP_VOL 0x0a +#define AC97_PHONE_VOL 0x0c +#define AC97_MIC_VOL 0x0e +#define AC97_LINEIN_VOL 0x10 +#define AC97_CD_VOL 0x12 +#define AC97_VIDEO_VOL 0x14 +#define AC97_AUX_VOL 0x16 +#define AC97_PCM_OUT_VOL 0x18 + + /* capture registers */ +#define AC97_RECORD_SELECT 0x1a +#define AC97_RECORD_GAIN 0x1c + + /* control registers */ +#define AC97_GENERAL_PURPOSE 0x20 +#define AC97_3D_CTRL 0x22 +#define AC97_AUD_INT_AND_PAG 0x24 +#define AC97_POWER_DOWN_CTRL 0x26 +#define AC97_EXT_AUD_ID 0x28 +#define AC97_EXT_AUD_CTRL 0x2a + +/* Supported rate varies for each AC97 device + if write an unsupported value, it will return the closest one + */ +#define AC97_PCM_OUT_FRONT_SRATE 0x2c +#define AC97_PCM_OUT_SURR_SRATE 0x2e +#define AC97_PCM_OUT_LFE_SRATE 0x30 +#define AC97_PCM_IN_SRATE 0x32 + + /* For devices with more than 2 channels, extra output volumes */ +#define AC97_LFE_MASTER_VOL 0x36 +#define AC97_SURR_MASTER_VOL 0x38 + + /* Digital SPDIF output control */ +#define AC97_SPDIF_OUT_CTRL 0x3a + + /* Vendor ID identifier */ +#define AC97_VENDOR_ID1 0x7c +#define AC97_VENDOR_ID2 0x7e + +/* EMP202 vendor registers */ +#define EM202_EXT_MODEM_CTRL 0x3e +#define EM202_GPIO_CONF 0x4c +#define EM202_GPIO_POLARITY 0x4e +#define EM202_GPIO_STICKY 0x50 +#define EM202_GPIO_MASK 0x52 +#define EM202_GPIO_STATUS 0x54 +#define EM202_SPDIF_OUT_SEL 0x6a +#define EM202_ANTIPOP 0x72 +#define EM202_EAPD_GPIO_ACCESS 0x74 diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 09886d567..5da519bfa 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -73,6 +73,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static LIST_HEAD(em28xx_devlist); +static DEFINE_MUTEX(em28xx_devlist_mutex); static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; @@ -570,6 +571,10 @@ static void video_mux(struct em28xx *dev, int index) route.output = 0; dev->ctl_input = index; dev->ctl_ainput = INPUT(index)->amux; + dev->ctl_aoutput = INPUT(index)->aout; + + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); @@ -932,20 +937,38 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - unsigned int index = a->index; - - if (a->index > 1) - return -EINVAL; - index = dev->ctl_ainput; - - if (index == 0) + switch (a->index) { + case EM28XX_AMUX_VIDEO: strcpy(a->name, "Television"); - else + break; + case EM28XX_AMUX_LINE_IN: strcpy(a->name, "Line In"); + break; + case EM28XX_AMUX_VIDEO2: + strcpy(a->name, "Television alt"); + break; + case EM28XX_AMUX_PHONE: + strcpy(a->name, "Phone"); + break; + case EM28XX_AMUX_MIC: + strcpy(a->name, "Mic"); + break; + case EM28XX_AMUX_CD: + strcpy(a->name, "CD"); + break; + case EM28XX_AMUX_AUX: + strcpy(a->name, "Aux"); + break; + case EM28XX_AMUX_PCM_OUT: + strcpy(a->name, "PCM"); + break; + default: + return -EINVAL; + } + a->index = dev->ctl_ainput; a->capability = V4L2_AUDCAP_STEREO; - a->index = index; return 0; } @@ -955,9 +978,17 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; +#if 0 + /* Doesn't allow manual routing */ if (a->index != dev->ctl_ainput) return -EINVAL; +#else + dev->ctl_ainput = INPUT(a->index)->amux; + dev->ctl_aoutput = INPUT(a->index)->aout; + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; +#endif return 0; } @@ -1562,7 +1593,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) struct em28xx_fh *fh; enum v4l2_buf_type fh_type = 0; - lock_kernel(); + mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; @@ -1578,10 +1609,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev = h; } } - if (NULL == dev) { - unlock_kernel(); + mutex_unlock(&em28xx_devlist_mutex); + if (NULL == dev) return -ENODEV; - } + + mutex_lock(&dev->lock); em28xx_videodbg("open minor=%d type=%s users=%d\n", minor, v4l2_type_names[fh_type], dev->users); @@ -1590,6 +1622,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE); if (errCode < 0) { em28xx_errdev("Device locked on digital mode. Can't open analog\n"); + mutex_unlock(&dev->lock); return -EBUSY; } #endif @@ -1597,10 +1630,9 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - unlock_kernel(); + mutex_unlock(&dev->lock); return -ENOMEM; } - mutex_lock(&dev->lock); fh->dev = dev; fh->radio = radio; fh->type = fh_type; @@ -1641,7 +1673,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); - unlock_kernel(); return errCode; } @@ -1939,6 +1970,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) { struct em28xx *dev = NULL; + mutex_lock(&em28xx_devlist_mutex); mutex_lock(&em28xx_extension_devlist_lock); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { @@ -1947,6 +1979,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) } printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1955,6 +1988,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) { struct em28xx *dev = NULL; + mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { if (dev) ops->fini(dev); @@ -1964,6 +1998,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); } EXPORT_SYMBOL(em28xx_unregister_extension); @@ -1988,20 +2023,60 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } -int em28xx_supports_audio_extension(struct em28xx *dev) +static int register_analog_devices(struct em28xx *dev) { - /* The chip dictates whether we support the Empia analog audio - extension */ - switch (dev->chip_id) { - case CHIP_ID_EM2874: - /* Either a digital-only device or provides AC97 audio */ - return 0; - case CHIP_ID_EM2883: - default: - return 1; + int ret; + + /* allocate and fill video video_device struct */ + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); + if (!dev->vdev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + + /* register v4l2 video video_device */ + ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (ret) { + em28xx_errdev("unable to register video device (error=%i).\n", + ret); + return ret; + } + + /* Allocate and fill vbi video_device struct */ + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); + + /* register v4l2 vbi video_device */ + ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("unable to register vbi device\n"); + return ret; + } + + if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); + if (!dev->radio_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("can't register radio device\n"); + return ret; + } + em28xx_info("Registered radio device as /dev/radio%d\n", + dev->radio_dev->num); } + + em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", + dev->vdev->num, dev->vbi_dev->num); + + return 0; } + /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -2017,6 +2092,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->udev = udev; mutex_init(&dev->lock); + mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); init_waitqueue_head(&dev->open); init_waitqueue_head(&dev->wait_frame); @@ -2034,8 +2110,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, errCode = em28xx_config(dev); if (errCode) { em28xx_errdev("error configuring device\n"); - em28xx_devused &= ~(1<<dev->devno); - kfree(dev); return -ENOMEM; } @@ -2051,11 +2125,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_card_setup(dev); /* Configure audio */ - errCode = em28xx_audio_analog_set(dev); + errCode = em28xx_audio_setup(dev); if (errCode < 0) { - em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n", + em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", __func__, errCode); - return errCode; } /* configure the device */ @@ -2082,50 +2155,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return errCode; } - list_add_tail(&dev->devlist, &em28xx_devlist); - - /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (NULL == dev->vdev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - - /* register v4l2 video video_device */ - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (retval) { - em28xx_errdev("unable to register video device (error=%i).\n", - retval); - goto fail_unreg; - } - - /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); - /* register v4l2 vbi video_device */ - if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]) < 0) { - em28xx_errdev("unable to register vbi device\n"); - retval = -ENODEV; - goto fail_unreg; - } - - if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); - if (NULL == dev->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (retval < 0) { - em28xx_errdev("can't register radio device\n"); - goto fail_unreg; - } - em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->num); - } - /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.queued); @@ -2155,8 +2184,14 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, video_mux(dev, 0); - em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", - dev->vdev->num, dev->vbi_dev->num); + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&dev->devlist, &em28xx_devlist); + retval = register_analog_devices(dev); + if (retval < 0) { + em28xx_release_resources(dev); + mutex_unlock(&em28xx_devlist_mutex); + goto fail_reg_devices; + } mutex_lock(&em28xx_extension_devlist_lock); if (!list_empty(&em28xx_extension_devlist)) { @@ -2166,13 +2201,14 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } } mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); return 0; fail_unreg: em28xx_release_resources(dev); +fail_reg_devices: mutex_unlock(&dev->lock); - kfree(dev); return retval; } @@ -2244,12 +2280,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, return -ENODEV; } - em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - endpoint = &interface->cur_altsetting->endpoint[0].desc; /* check if the device has the iso in endpoint at the correct place */ @@ -2260,21 +2290,39 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* It's a newer em2874/em2875 device */ isoc_pipe = 0; } else { + int check_interface = 1; isoc_pipe = 1; endpoint = &interface->cur_altsetting->endpoint[1].desc; if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) { - em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); + USB_ENDPOINT_XFER_ISOC) + check_interface = 0; + + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) + check_interface = 0; + + if (!check_interface) { + em28xx_err(DRIVER_NAME " video device (%04x:%04x): " + "interface %i, class %i found.\n", + udev->descriptor.idVendor, + udev->descriptor.idProduct, + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + + em28xx_err(DRIVER_NAME " This is an anciliary " + "interface not used by the driver\n"); + em28xx_devused &= ~(1<<nr); return -ENODEV; } + } + em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", + udev->descriptor.idVendor, + udev->descriptor.idProduct, + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + if (nr >= EM28XX_MAXBOARDS) { printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", EM28XX_MAXBOARDS); @@ -2333,21 +2381,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate device struct */ retval = em28xx_init_dev(&dev, udev, nr); - if (retval) - return retval; - - em28xx_info("Found %s\n", em28xx_boards[dev->model].name); + if (retval) { + em28xx_devused &= ~(1<<dev->devno); + kfree(dev); - if (dev->has_audio_class == 0) { - /* We don't have a USB audio class, let's see if we support - ALSA Audio */ - dev->has_alsa_audio = em28xx_supports_audio_extension(dev); - if (dev->has_alsa_audio) - printk(KERN_INFO DRIVER_NAME " supports alsa audio\n"); - } else { - printk(KERN_INFO DRIVER_NAME " has usb audio class\n"); + return retval; } + em28xx_info("Found %s\n", em28xx_boards[dev->model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 1bccb9ee4..151668c60 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -104,6 +104,9 @@ #define EM28XX_MIN_BUF 4 #define EM28XX_DEF_BUF 8 +/*Limits the max URB message size */ +#define URB_MAX_CTRL_SIZE 80 + /* Params for validated field */ #define EM28XX_BOARD_NOT_VALIDATED 1 #define EM28XX_BOARD_VALIDATED 0 @@ -254,17 +257,59 @@ enum enum28xx_itype { EM28XX_RADIO, }; +enum em28xx_ac97_mode { + EM28XX_NO_AC97 = 0, + EM28XX_AC97_EM202, + EM28XX_AC97_SIGMATEL, + EM28XX_AC97_OTHER, +}; + +struct em28xx_audio_mode { + enum em28xx_ac97_mode ac97; + + u16 ac97_feat; + u32 ac97_vendor_id; + + unsigned int has_audio:1; + + unsigned int i2s_3rates:1; + unsigned int i2s_5rates:1; +}; + +/* em28xx has two audio inputs: tuner and line in. + However, on most devices, an auxiliary AC97 codec device is used. + The AC97 device may have several different inputs and outputs, + depending on their model. So, it is possible to use AC97 mixer to + address more than two different entries. + */ enum em28xx_amux { - EM28XX_AMUX_VIDEO, - EM28XX_AMUX_LINE_IN, - EM28XX_AMUX_AC97_VIDEO, - EM28XX_AMUX_AC97_LINE_IN, + /* This is the only entry for em28xx tuner input */ + EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ + + EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ + + /* Some less-common mixer setups */ + EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ + EM28XX_AMUX_PHONE, + EM28XX_AMUX_MIC, + EM28XX_AMUX_CD, + EM28XX_AMUX_AUX, + EM28XX_AMUX_PCM_OUT, +}; + +enum em28xx_aout { + EM28XX_AOUT_MASTER = 1 << 0, + EM28XX_AOUT_LINE = 1 << 1, + EM28XX_AOUT_MONO = 1 << 2, + EM28XX_AOUT_LFE = 1 << 3, + EM28XX_AOUT_SURR = 1 << 4, }; struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; enum em28xx_amux amux; + enum em28xx_aout aout; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -286,6 +331,7 @@ struct em28xx_board { char *name; int vchannels; int tuner_type; + int tuner_addr; /* i2c flags */ unsigned int tda9887_conf; @@ -303,6 +349,7 @@ struct em28xx_board { struct em28xx_input input[MAX_EM28XX_INPUT]; struct em28xx_input radio; + IR_KEYTAB_TYPE *ir_codes; }; struct em28xx_eeprom { @@ -407,6 +454,7 @@ struct em28xx { u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; + struct em28xx_audio_mode audio_mode; int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ @@ -421,6 +469,7 @@ struct em28xx { int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput;/* selected audio input */ + unsigned int ctl_aoutput;/* selected audio output */ int mute; int volume; /* frame properties */ @@ -445,6 +494,7 @@ struct em28xx { /* locks */ struct mutex lock; + struct mutex ctrl_urb_lock; /* protects urb_buf */ /* spinlock_t queue_lock; */ struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; @@ -466,6 +516,8 @@ struct em28xx { unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ + /* helper funcs that call usb_control_msg */ int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, char *buf, int len); @@ -484,6 +536,9 @@ struct em28xx { /* Caches GPO and GPIO registers */ unsigned char reg_gpo, reg_gpio; + /* Infrared remote control support */ + IR_KEYTAB_TYPE *ir_codes; + /* Snapshot button */ char snapshot_button_path[30]; /* path of the input dev */ struct input_dev *sbutton_input_dev; @@ -524,7 +579,10 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg); int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); + int em28xx_audio_analog_set(struct em28xx *dev); +int em28xx_audio_setup(struct em28xx *dev); int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig index 6b557c057..770fb699d 100644 --- a/linux/drivers/media/video/gspca/Kconfig +++ b/linux/drivers/media/video/gspca/Kconfig @@ -12,7 +12,7 @@ menuconfig USB_GSPCA "Video For Linux" to use this driver. To compile this driver as modules, choose M here: the - modules will be called gspca_main. + module will be called gspca_main. if USB_GSPCA && VIDEO_V4L2 @@ -64,6 +64,16 @@ config USB_GSPCA_OV519 To compile this driver as a module, choose M here: the module will be called gspca_ov519. +config USB_GSPCA_OV534 + tristate "OV534 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the OV534 chip. + (e.g. Sony Playstation EYE) + + To compile this driver as a module, choose M here: the + module will be called gspca_ov534. + config USB_GSPCA_PAC207 tristate "Pixart PAC207 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA @@ -83,10 +93,11 @@ config USB_GSPCA_PAC7311 module will be called gspca_pac7311. config USB_GSPCA_SONIXB - tristate "SN9C102 USB Camera Driver" + tristate "SONIX Bayer USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SONIXB chip. + Say Y here if you want support for cameras based on the Sonix + chips with Bayer format (SN9C101, SN9C102 and SN9C103). To compile this driver as a module, choose M here: the module will be called gspca_sonixb. @@ -95,7 +106,8 @@ config USB_GSPCA_SONIXJ tristate "SONIX JPEG USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SONIXJ chip. + Say Y here if you want support for cameras based on the Sonix + chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110). To compile this driver as a module, choose M here: the module will be called gspca_sonixj @@ -171,7 +183,7 @@ config USB_GSPCA_SUNPLUS SPCA504(abc) SPCA533 SPCA536 chips. To compile this driver as a module, choose M here: the - module will be called gspca_spca5xx. + module will be called gspca_sunplus. config USB_GSPCA_T613 tristate "T613 (JPEG Compliance) USB Camera Driver" diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile index 22734f5a6..6c8046e23 100644 --- a/linux/drivers/media/video/gspca/Makefile +++ b/linux/drivers/media/video/gspca/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o +obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o @@ -27,6 +28,7 @@ gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o gspca_mars-objs := mars.o gspca_ov519-objs := ov519.o +gspca_ov534-objs := ov534.o gspca_pac207-objs := pac207.o gspca_pac7311-objs := pac7311.o gspca_sonixb-objs := sonixb.o diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index a9d51ba7c..de28354ea 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -846,10 +846,13 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { int retry = 50; + if (!gspca_dev->present) + return; reg_w_val(gspca_dev, 0x0000, 0x00); reg_r(gspca_dev, 0x0002, 1); reg_w_val(gspca_dev, 0x0053, 0x00); diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c index d3e3f085b..03cb94466 100644 --- a/linux/drivers/media/video/gspca/finepix.c +++ b/linux/drivers/media/video/gspca/finepix.c @@ -276,6 +276,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* Stop the state machine */ if (dev->state != FPIX_NOP) wait_for_completion(&dev->can_close); +} + +/* called on streamoff with alt 0 and disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; usb_free_urb(dev->control_urb); dev->control_urb = NULL; @@ -382,6 +388,7 @@ static int sd_start(struct gspca_dev *gspca_dev) error: /* Free the ressources */ sd_stopN(gspca_dev); + sd_stop0(gspca_dev); return ret; } @@ -422,6 +429,7 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, + .stop0 = sd_stop0, }; /* -- device connect -- */ diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 7a2006c3e..d725663fc 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -30,7 +30,6 @@ #include <linux/string.h> #include <linux/pagemap.h> #include <linux/io.h> -#include <linux/kref.h> #include <asm/page.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #include <asm/uaccess.h> @@ -177,7 +176,6 @@ static void fill_frame(struct gspca_dev *gspca_dev, } /* resubmit the URB */ - urb->status = 0; st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); @@ -213,11 +211,18 @@ static void bulk_irq(struct urb *urb { struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; struct gspca_frame *frame; + int st; PDEBUG(D_PACK, "bulk irq"); if (!gspca_dev->streaming) return; - if (urb->status != 0 && urb->status != -ECONNRESET) { + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + urb->status = 0; + break; + default: #ifdef CONFIG_PM if (!gspca_dev->frozen) #endif @@ -236,6 +241,13 @@ static void bulk_irq(struct urb *urb urb->transfer_buffer, urb->actual_length); } + + /* resubmit the URB */ + if (gspca_dev->cam.bulk_nurbs != 0) { + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); + } } /* @@ -298,7 +310,6 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, frame->v4l2_buf.bytesused = frame->data_end - frame->data; frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED; frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE; - atomic_inc(&gspca_dev->nevent); wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ i = (gspca_dev->fr_i + 1) % gspca_dev->nframes; gspca_dev->fr_i = i; @@ -392,7 +403,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev, gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->sequence = 0; - atomic_set(&gspca_dev->nevent, 0); return 0; } @@ -533,11 +543,14 @@ static int create_urbs(struct gspca_dev *gspca_dev, nurbs = DEF_NURBS; } else { /* bulk */ npkt = 0; - bsize = gspca_dev->cam. bulk_size; + bsize = gspca_dev->cam.bulk_size; if (bsize == 0) bsize = psize; PDEBUG(D_STREAM, "bulk bsize:%d", bsize); - nurbs = 1; + if (gspca_dev->cam.bulk_nurbs != 0) + nurbs = gspca_dev->cam.bulk_nurbs; + else + nurbs = 1; } gspca_dev->nurbs = nurbs; @@ -623,10 +636,9 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) goto out; } gspca_dev->streaming = 1; - atomic_set(&gspca_dev->nevent, 0); - /* bulk transfers are started by the subdriver */ - if (gspca_dev->alt == 0) + /* some bulk transfers are started by the subdriver */ + if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0) break; /* submit the URBs */ @@ -664,16 +676,14 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) static void gspca_stream_off(struct gspca_dev *gspca_dev) { gspca_dev->streaming = 0; - atomic_set(&gspca_dev->nevent, 0); - if (gspca_dev->present) { - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_set_alt0(gspca_dev); - if (gspca_dev->sd_desc->stop0) - gspca_dev->sd_desc->stop0(gspca_dev); - PDEBUG(D_STREAM, "stream off OK"); - } + if (gspca_dev->present + && gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_set_alt0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); + PDEBUG(D_STREAM, "stream off OK"); } static void gspca_set_default_mode(struct gspca_dev *gspca_dev) @@ -747,7 +757,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (fmtdesc->index == index) break; /* new format */ index++; - if (index >= sizeof fmt_tb / sizeof fmt_tb[0]) + if (index >= ARRAY_SIZE(fmt_tb)) return -EINVAL; } } @@ -866,11 +876,11 @@ out: return ret; } -static void gspca_delete(struct kref *kref) +static void gspca_release(struct video_device *vfd) { - struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref); + struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); - PDEBUG(D_STREAM, "device deleted"); + PDEBUG(D_STREAM, "device released"); kfree(gspca_dev->usb_buf); kfree(gspca_dev); @@ -894,10 +904,14 @@ static int dev_open(struct inode *inode, struct file *file) ret = -EBUSY; goto out; } - gspca_dev->users++; - /* one more user */ - kref_get(&gspca_dev->kref); + /* protect the subdriver against rmmod */ + if (!try_module_get(gspca_dev->module)) { + ret = -ENODEV; + goto out; + } + + gspca_dev->users++; file->private_data = gspca_dev; #ifdef GSPCA_DEBUG @@ -940,12 +954,11 @@ static int dev_close(struct inode *inode, struct file *file) gspca_dev->memory = GSPCA_MEMORY_NO; } file->private_data = NULL; + module_put(gspca_dev->module); mutex_unlock(&gspca_dev->queue_lock); PDEBUG(D_STREAM, "close done"); - kref_put(&gspca_dev->kref, gspca_delete); - return 0; } @@ -1248,7 +1261,6 @@ static int vidioc_streamoff(struct file *file, void *priv, gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->sequence = 0; - atomic_set(&gspca_dev->nevent, 0); ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); @@ -1452,33 +1464,22 @@ static int frame_wait(struct gspca_dev *gspca_dev, i = gspca_dev->fr_o; j = gspca_dev->fr_queue[i]; frame = &gspca_dev->frame[j]; - if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) { - atomic_dec(&gspca_dev->nevent); - goto ok; - } - if (nonblock_ing) /* no frame yet */ - return -EAGAIN; - /* wait till a frame is ready */ - for (;;) { + if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) { + if (nonblock_ing) + return -EAGAIN; + + /* wait till a frame is ready */ ret = wait_event_interruptible_timeout(gspca_dev->wq, - atomic_read(&gspca_dev->nevent) > 0, - msecs_to_jiffies(3000)); - if (ret <= 0) { - if (ret < 0) - return ret; /* interrupt */ - return -EIO; /* timeout */ - } - atomic_dec(&gspca_dev->nevent); - if (!gspca_dev->streaming || !gspca_dev->present) + (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) || + !gspca_dev->streaming || !gspca_dev->present, + msecs_to_jiffies(3000)); + if (ret < 0) + return ret; + if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present) return -EIO; - i = gspca_dev->fr_o; - j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; - if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) - break; } -ok: + gspca_dev->fr_o = (i + 1) % gspca_dev->nframes; PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d", gspca_dev->fr_q, @@ -1767,11 +1768,6 @@ out: return ret; } -static void dev_release(struct video_device *vfd) -{ - /* nothing */ -} - static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = dev_open, @@ -1819,7 +1815,7 @@ static struct video_device gspca_template = { .name = "gspca main driver", .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, - .release = dev_release, /* mandatory */ + .release = gspca_release, .minor = -1, }; @@ -1857,7 +1853,6 @@ int gspca_dev_probe(struct usb_interface *intf, err("couldn't kzalloc gspca struct"); return -ENOMEM; } - kref_init(&gspca_dev->kref); gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { err("out of memory"); @@ -1872,10 +1867,10 @@ int gspca_dev_probe(struct usb_interface *intf, gspca_dev->empty_packet = -1; /* don't check the empty packets */ /* configure the subdriver and initialize the USB device */ - ret = gspca_dev->sd_desc->config(gspca_dev, id); + ret = sd_desc->config(gspca_dev, id); if (ret < 0) goto out; - ret = gspca_dev->sd_desc->init(gspca_dev); + ret = sd_desc->init(gspca_dev); if (ret < 0) goto out; ret = gspca_set_alt0(gspca_dev); @@ -1891,9 +1886,7 @@ int gspca_dev_probe(struct usb_interface *intf, /* init video stuff */ memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); gspca_dev->vdev.parent = &dev->dev; - memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); - gspca_dev->vdev.fops = &gspca_dev->fops; - gspca_dev->fops.owner = module; /* module protection */ + gspca_dev->module = module; gspca_dev->present = 1; ret = video_register_device(&gspca_dev->vdev, VFL_TYPE_GRABBER, @@ -1907,7 +1900,8 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probe ok"); return 0; out: - kref_put(&gspca_dev->kref, gspca_delete); + kfree(gspca_dev->usb_buf); + kfree(gspca_dev); return ret; } EXPORT_SYMBOL(gspca_dev_probe); @@ -1922,15 +1916,14 @@ void gspca_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - -/* We don't want people trying to open up the device */ - video_unregister_device(&gspca_dev->vdev); - gspca_dev->present = 0; gspca_dev->streaming = 0; - kref_put(&gspca_dev->kref, gspca_delete); + usb_set_intfdata(intf, NULL); + + /* release the device */ + /* (this will call gspca_release() immediatly or on last close) */ + video_unregister_device(&gspca_dev->vdev); PDEBUG(D_PROBE, "disconnect complete"); } diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 6f097f4a1..15db13296 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -58,6 +58,10 @@ struct cam { int bulk_size; /* buffer size when image transfer by bulk */ struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; + __u8 bulk_nurbs; /* number of URBs in bulk mode + * - cannot be > MAX_NURBS + * - when 0 and bulk_size != 0 means + * 1 URB and submit done by subdriver */ __u8 epaddr; }; @@ -97,7 +101,7 @@ struct sd_desc { cam_pkt_op pkt_scan; /* optional operations */ cam_v_op stopN; /* called on stream off - main alt */ - cam_v_op stop0; /* called on stream off - alt 0 */ + cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_jpg_op get_jcomp; cam_jpg_op set_jcomp; @@ -121,9 +125,8 @@ struct gspca_frame { struct gspca_dev { struct video_device vdev; /* !! must be the first item */ - struct file_operations fops; + struct module *module; /* subdriver handling the device */ struct usb_device *dev; - struct kref kref; struct file *capt_file; /* file doing video capture */ struct cam cam; /* device information */ @@ -152,7 +155,6 @@ struct gspca_dev { __u16 height; __u32 sequence; /* frame sequence number */ - atomic_t nevent; /* number of frames done */ wait_queue_head_t wq; /* wait queue */ struct mutex usb_lock; /* usb exchange protection */ struct mutex read_lock; /* read protection */ diff --git a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h index 1a37ae4bc..c1c7ce524 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h @@ -25,59 +25,59 @@ /*****************************************************************************/ -#define M5602_XB_SENSOR_TYPE 0x00 -#define M5602_XB_SENSOR_CTRL 0x01 -#define M5602_XB_LINE_OF_FRAME_H 0x02 -#define M5602_XB_LINE_OF_FRAME_L 0x03 -#define M5602_XB_PIX_OF_LINE_H 0x04 -#define M5602_XB_PIX_OF_LINE_L 0x05 -#define M5602_XB_VSYNC_PARA 0x06 -#define M5602_XB_HSYNC_PARA 0x07 -#define M5602_XB_TEST_MODE_1 0x08 -#define M5602_XB_TEST_MODE_2 0x09 -#define M5602_XB_SIG_INI 0x0a -#define M5602_XB_DS_PARA 0x0e -#define M5602_XB_TRIG_PARA 0x0f -#define M5602_XB_CLK_PD 0x10 -#define M5602_XB_MCU_CLK_CTRL 0x12 -#define M5602_XB_MCU_CLK_DIV 0x13 -#define M5602_XB_SEN_CLK_CTRL 0x14 -#define M5602_XB_SEN_CLK_DIV 0x15 -#define M5602_XB_AUD_CLK_CTRL 0x16 -#define M5602_XB_AUD_CLK_DIV 0x17 -#define M5602_XB_DEVCTR1 0x41 -#define M5602_XB_EPSETR0 0x42 -#define M5602_XB_EPAFCTR 0x47 -#define M5602_XB_EPBFCTR 0x49 -#define M5602_XB_EPEFCTR 0x4f -#define M5602_XB_TEST_REG 0x53 -#define M5602_XB_ALT2SIZE 0x54 -#define M5602_XB_ALT3SIZE 0x55 -#define M5602_XB_OBSFRAME 0x56 -#define M5602_XB_PWR_CTL 0x59 -#define M5602_XB_ADC_CTRL 0x60 -#define M5602_XB_ADC_DATA 0x61 -#define M5602_XB_MISC_CTRL 0x62 -#define M5602_XB_SNAPSHOT 0x63 -#define M5602_XB_SCRATCH_1 0x64 -#define M5602_XB_SCRATCH_2 0x65 -#define M5602_XB_SCRATCH_3 0x66 -#define M5602_XB_SCRATCH_4 0x67 -#define M5602_XB_I2C_CTRL 0x68 -#define M5602_XB_I2C_CLK_DIV 0x69 -#define M5602_XB_I2C_DEV_ADDR 0x6a -#define M5602_XB_I2C_REG_ADDR 0x6b -#define M5602_XB_I2C_DATA 0x6c -#define M5602_XB_I2C_STATUS 0x6d -#define M5602_XB_GPIO_DAT_H 0x70 -#define M5602_XB_GPIO_DAT_L 0x71 -#define M5602_XB_GPIO_DIR_H 0x72 -#define M5602_XB_GPIO_DIR_L 0x73 -#define M5602_XB_GPIO_EN_H 0x74 -#define M5602_XB_GPIO_EN_L 0x75 -#define M5602_XB_GPIO_DAT 0x76 -#define M5602_XB_GPIO_DIR 0x77 -#define M5602_XB_MISC_CTL 0x70 +#define M5602_XB_SENSOR_TYPE 0x00 +#define M5602_XB_SENSOR_CTRL 0x01 +#define M5602_XB_LINE_OF_FRAME_H 0x02 +#define M5602_XB_LINE_OF_FRAME_L 0x03 +#define M5602_XB_PIX_OF_LINE_H 0x04 +#define M5602_XB_PIX_OF_LINE_L 0x05 +#define M5602_XB_VSYNC_PARA 0x06 +#define M5602_XB_HSYNC_PARA 0x07 +#define M5602_XB_TEST_MODE_1 0x08 +#define M5602_XB_TEST_MODE_2 0x09 +#define M5602_XB_SIG_INI 0x0a +#define M5602_XB_DS_PARA 0x0e +#define M5602_XB_TRIG_PARA 0x0f +#define M5602_XB_CLK_PD 0x10 +#define M5602_XB_MCU_CLK_CTRL 0x12 +#define M5602_XB_MCU_CLK_DIV 0x13 +#define M5602_XB_SEN_CLK_CTRL 0x14 +#define M5602_XB_SEN_CLK_DIV 0x15 +#define M5602_XB_AUD_CLK_CTRL 0x16 +#define M5602_XB_AUD_CLK_DIV 0x17 +#define M5602_XB_DEVCTR1 0x41 +#define M5602_XB_EPSETR0 0x42 +#define M5602_XB_EPAFCTR 0x47 +#define M5602_XB_EPBFCTR 0x49 +#define M5602_XB_EPEFCTR 0x4f +#define M5602_XB_TEST_REG 0x53 +#define M5602_XB_ALT2SIZE 0x54 +#define M5602_XB_ALT3SIZE 0x55 +#define M5602_XB_OBSFRAME 0x56 +#define M5602_XB_PWR_CTL 0x59 +#define M5602_XB_ADC_CTRL 0x60 +#define M5602_XB_ADC_DATA 0x61 +#define M5602_XB_MISC_CTRL 0x62 +#define M5602_XB_SNAPSHOT 0x63 +#define M5602_XB_SCRATCH_1 0x64 +#define M5602_XB_SCRATCH_2 0x65 +#define M5602_XB_SCRATCH_3 0x66 +#define M5602_XB_SCRATCH_4 0x67 +#define M5602_XB_I2C_CTRL 0x68 +#define M5602_XB_I2C_CLK_DIV 0x69 +#define M5602_XB_I2C_DEV_ADDR 0x6a +#define M5602_XB_I2C_REG_ADDR 0x6b +#define M5602_XB_I2C_DATA 0x6c +#define M5602_XB_I2C_STATUS 0x6d +#define M5602_XB_GPIO_DAT_H 0x70 +#define M5602_XB_GPIO_DAT_L 0x71 +#define M5602_XB_GPIO_DIR_H 0x72 +#define M5602_XB_GPIO_DIR_L 0x73 +#define M5602_XB_GPIO_EN_H 0x74 +#define M5602_XB_GPIO_EN_L 0x75 +#define M5602_XB_GPIO_DAT 0x76 +#define M5602_XB_GPIO_DIR 0x77 +#define M5602_XB_MISC_CTL 0x70 #define I2C_BUSY 0x80 @@ -90,13 +90,7 @@ #define M5602_ISOC_ENDPOINT_ADDR 0x81 #define M5602_INTR_ENDPOINT_ADDR 0x82 -#define M5602_MAX_FRAMES 32 -#define M5602_URBS 2 -#define M5602_ISOC_PACKETS 14 - -#define M5602_URB_TIMEOUT msecs_to_jiffies(2 * M5602_ISOC_PACKETS) #define M5602_URB_MSG_TIMEOUT 5000 -#define M5602_FRAME_TIMEOUT 2 /*****************************************************************************/ diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c index 837c7e476..07ef2b3db 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -18,6 +18,44 @@ #include "m5602_ov9650.h" +/* Vertically and horizontally flips the image if matched, needed for machines + where the sensor is mounted upside down */ +static +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + const +#endif + struct dmi_system_id ov9650_flip_dmi_table[] = { + { + .ident = "ASUS A6VC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") + } + }, + { + .ident = "ASUS A6VM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") + } + }, + { + .ident = "ASUS A6JC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") + } + }, + { + .ident = "ASUS A6Kt", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + } + }, + { } +}; + int ov9650_read_sensor(struct sd *sd, const u8 address, u8 *i2c_data, const u8 len) { diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h index e8ede47ce..e0efdb930 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -432,6 +432,7 @@ static const unsigned char init_ov9650[][3] = {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00}, {BRIDGE, M5602_XB_SIG_INI, 0x01}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + /* Moves the view window in a vertical orientation */ {BRIDGE, M5602_XB_VSYNC_PARA, 0x09}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, @@ -463,42 +464,4 @@ static const unsigned char power_down_ov9650[][3] = {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0} }; -/* Vertically and horizontally flips the image if matched, needed for machines - where the sensor is mounted upside down */ -static -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - const -#endif - struct dmi_system_id ov9650_flip_dmi_table[] = { - { - .ident = "ASUS A6VC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") - } - }, - { - .ident = "ASUS A6VM", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") - } - }, - { - .ident = "ASUS A6JC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") - } - }, - { - .ident = "ASUS A6Kt", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") - } - }, - { } -}; - #endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index 14b1eac5b..1f72e7eae 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -18,6 +18,41 @@ #include "m5602_s5k4aa.h" +static +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + const +#endif + struct dmi_system_id s5k4aa_vflip_dmi_table[] = { + { + .ident = "Fujitsu-Siemens Amilo Xa 2528", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") + } + }, { + .ident = "Fujitsu-Siemens Amilo Xi 2550", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") + } + }, { + .ident = "MSI GX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), + DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") + } + }, { + .ident = "MSI GX700/GX705/EX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") + } + }, + { } +}; + + int s5k4aa_probe(struct sd *sd) { u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h index 87167fb92..151c6f530 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -338,34 +338,4 @@ static const unsigned char init_s5k4aa[][4] = {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00} }; -static -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - const -#endif - struct dmi_system_id s5k4aa_vflip_dmi_table[] = { - { - .ident = "Fujitsu-Siemens Amilo Xa 2528", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") - } - }, - { - .ident = "Fujitsu-Siemens Amilo Xi 2550", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") - } - }, - { - .ident = "MSI GX700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), - DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") - } - }, - { } -}; - #endif diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index 277ca34a8..492cdd3b5 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -123,7 +123,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->epaddr = 0x01; cam->cam_mode = vga_mode; - cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + cam->nmodes = ARRAY_SIZE(vga_mode); sd->qindex = 1; /* set the quantization table */ return 0; } diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c new file mode 100644 index 000000000..a574be09b --- /dev/null +++ b/linux/drivers/media/video/gspca/ov534.c @@ -0,0 +1,505 @@ +/* + * ov534/ov772x gspca driver + * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> + * + * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> + * USB protocol reverse engineered by Jim Paris <jim@jtan.com> + * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "ov534" + +#include "gspca.h" + +#define OV534_REG_ADDRESS 0xf1 /* ? */ +#define OV534_REG_SUBADDR 0xf2 +#define OV534_REG_WRITE 0xf3 +#define OV534_REG_READ 0xf4 +#define OV534_REG_OPERATION 0xf5 +#define OV534_REG_STATUS 0xf6 + +#define OV534_OP_WRITE_3 0x37 +#define OV534_OP_WRITE_2 0x33 +#define OV534_OP_READ_2 0xf9 + +#define CTRL_TIMEOUT 500 + +MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); +MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* global parameters */ +static int frame_rate; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + __u8 frame_rate; +}; + +/* V4L2 controls supported by the driver */ +static struct ctrl sd_ctrls[] = { +}; + +static struct v4l2_pix_format vga_mode[] = { + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static void ov534_reg_write(struct usb_device *udev, u16 reg, u16 val) +{ + u16 data = val; + int ret; + + PDEBUG(D_USBO, "reg=0x%04x, val=0%04x", reg, val); + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + 0x1, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, reg, &data, 1, CTRL_TIMEOUT); + if (ret < 0) + PDEBUG(D_ERR, "write failed"); +} + +static u16 ov534_reg_read(struct usb_device *udev, u16 reg) +{ + u16 data; + int ret; + + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0x1, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, reg, &data, 1, CTRL_TIMEOUT); + PDEBUG(D_USBI, "reg=0x%04x, data=0x%04x", reg, data); + if (ret < 0) + PDEBUG(D_ERR, "read failed"); + return data; +} + +static void ov534_reg_verify_write(struct usb_device *udev, u16 reg, u16 val) +{ + u16 data; + + ov534_reg_write(udev, reg, val); + data = ov534_reg_read(udev, reg); + if (data != val) { + PDEBUG(D_ERR | D_USBO, + "unexpected result from read: 0x%04x != 0x%04x", val, + data); + } +} + +/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. + * (direction and output)? */ +static void ov534_set_led(struct usb_device *udev, int status) +{ + u16 data; + + PDEBUG(D_CONF, "led status: %d", status); + + data = ov534_reg_read(udev, 0x21); + data |= 0x80; + ov534_reg_write(udev, 0x21, data); + + data = ov534_reg_read(udev, 0x23); + if (status) + data |= 0x80; + else + data &= ~(0x80); + + ov534_reg_write(udev, 0x23, data); +} + +static int sccb_check_status(struct usb_device *udev) +{ + u16 data; + int i; + + for (i = 0; i < 5; i++) { + data = ov534_reg_read(udev, OV534_REG_STATUS); + + switch (data & 0xFF) { + case 0x00: + return 1; + case 0x04: + return 0; + case 0x03: + break; + default: + PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5\n", + data, i + 1); + } + } + return 0; +} + +static void sccb_reg_write(struct usb_device *udev, u16 reg, u16 val) +{ + PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%04x", reg, val); + ov534_reg_write(udev, OV534_REG_SUBADDR, reg); + ov534_reg_write(udev, OV534_REG_WRITE, val); + ov534_reg_write(udev, OV534_REG_OPERATION, OV534_OP_WRITE_3); + + if (!sccb_check_status(udev)) + PDEBUG(D_ERR, "sccb_reg_write failed"); +} + +/* setup method */ +static void ov534_setup(struct usb_device *udev) +{ + ov534_reg_verify_write(udev, 0xe7, 0x3a); + + ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); + ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); + ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); + ov534_reg_write(udev, OV534_REG_ADDRESS, 0x42); + + ov534_reg_verify_write(udev, 0xc2, 0x0c); + ov534_reg_verify_write(udev, 0x88, 0xf8); + ov534_reg_verify_write(udev, 0xc3, 0x69); + ov534_reg_verify_write(udev, 0x89, 0xff); + ov534_reg_verify_write(udev, 0x76, 0x03); + ov534_reg_verify_write(udev, 0x92, 0x01); + ov534_reg_verify_write(udev, 0x93, 0x18); + ov534_reg_verify_write(udev, 0x94, 0x10); + ov534_reg_verify_write(udev, 0x95, 0x10); + ov534_reg_verify_write(udev, 0xe2, 0x00); + ov534_reg_verify_write(udev, 0xe7, 0x3e); + + ov534_reg_write(udev, 0x1c, 0x0a); + ov534_reg_write(udev, 0x1d, 0x22); + ov534_reg_write(udev, 0x1d, 0x06); + + ov534_reg_verify_write(udev, 0x96, 0x00); + + ov534_reg_write(udev, 0x97, 0x20); + ov534_reg_write(udev, 0x97, 0x20); + ov534_reg_write(udev, 0x97, 0x20); + ov534_reg_write(udev, 0x97, 0x0a); + ov534_reg_write(udev, 0x97, 0x3f); + ov534_reg_write(udev, 0x97, 0x4a); + ov534_reg_write(udev, 0x97, 0x20); + ov534_reg_write(udev, 0x97, 0x15); + ov534_reg_write(udev, 0x97, 0x0b); + + ov534_reg_verify_write(udev, 0x8e, 0x40); + ov534_reg_verify_write(udev, 0x1f, 0x81); + ov534_reg_verify_write(udev, 0x34, 0x05); + ov534_reg_verify_write(udev, 0xe3, 0x04); + ov534_reg_verify_write(udev, 0x88, 0x00); + ov534_reg_verify_write(udev, 0x89, 0x00); + ov534_reg_verify_write(udev, 0x76, 0x00); + ov534_reg_verify_write(udev, 0xe7, 0x2e); + ov534_reg_verify_write(udev, 0x31, 0xf9); + ov534_reg_verify_write(udev, 0x25, 0x42); + ov534_reg_verify_write(udev, 0x21, 0xf0); + + ov534_reg_write(udev, 0x1c, 0x00); + ov534_reg_write(udev, 0x1d, 0x40); + ov534_reg_write(udev, 0x1d, 0x02); + ov534_reg_write(udev, 0x1d, 0x00); + ov534_reg_write(udev, 0x1d, 0x02); + ov534_reg_write(udev, 0x1d, 0x57); + ov534_reg_write(udev, 0x1d, 0xff); + + ov534_reg_verify_write(udev, 0x8d, 0x1c); + ov534_reg_verify_write(udev, 0x8e, 0x80); + ov534_reg_verify_write(udev, 0xe5, 0x04); + + ov534_set_led(udev, 1); + + sccb_reg_write(udev, 0x12, 0x80); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x11, 0x01); + + ov534_set_led(udev, 0); + + sccb_reg_write(udev, 0x3d, 0x03); + sccb_reg_write(udev, 0x17, 0x26); + sccb_reg_write(udev, 0x18, 0xa0); + sccb_reg_write(udev, 0x19, 0x07); + sccb_reg_write(udev, 0x1a, 0xf0); + sccb_reg_write(udev, 0x32, 0x00); + sccb_reg_write(udev, 0x29, 0xa0); + sccb_reg_write(udev, 0x2c, 0xf0); + sccb_reg_write(udev, 0x65, 0x20); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x42, 0x7f); + sccb_reg_write(udev, 0x63, 0xe0); + sccb_reg_write(udev, 0x64, 0xff); + sccb_reg_write(udev, 0x66, 0x00); + sccb_reg_write(udev, 0x13, 0xf0); + sccb_reg_write(udev, 0x0d, 0x41); + sccb_reg_write(udev, 0x0f, 0xc5); + sccb_reg_write(udev, 0x14, 0x11); + + ov534_set_led(udev, 1); + + sccb_reg_write(udev, 0x22, 0x7f); + sccb_reg_write(udev, 0x23, 0x03); + sccb_reg_write(udev, 0x24, 0x40); + sccb_reg_write(udev, 0x25, 0x30); + sccb_reg_write(udev, 0x26, 0xa1); + sccb_reg_write(udev, 0x2a, 0x00); + sccb_reg_write(udev, 0x2b, 0x00); + sccb_reg_write(udev, 0x6b, 0xaa); + sccb_reg_write(udev, 0x13, 0xff); + + ov534_set_led(udev, 0); + + sccb_reg_write(udev, 0x90, 0x05); + sccb_reg_write(udev, 0x91, 0x01); + sccb_reg_write(udev, 0x92, 0x03); + sccb_reg_write(udev, 0x93, 0x00); + sccb_reg_write(udev, 0x94, 0x60); + sccb_reg_write(udev, 0x95, 0x3c); + sccb_reg_write(udev, 0x96, 0x24); + sccb_reg_write(udev, 0x97, 0x1e); + sccb_reg_write(udev, 0x98, 0x62); + sccb_reg_write(udev, 0x99, 0x80); + sccb_reg_write(udev, 0x9a, 0x1e); + sccb_reg_write(udev, 0x9b, 0x08); + sccb_reg_write(udev, 0x9c, 0x20); + sccb_reg_write(udev, 0x9e, 0x81); + + ov534_set_led(udev, 1); + + sccb_reg_write(udev, 0xa6, 0x04); + sccb_reg_write(udev, 0x7e, 0x0c); + sccb_reg_write(udev, 0x7f, 0x16); + sccb_reg_write(udev, 0x80, 0x2a); + sccb_reg_write(udev, 0x81, 0x4e); + sccb_reg_write(udev, 0x82, 0x61); + sccb_reg_write(udev, 0x83, 0x6f); + sccb_reg_write(udev, 0x84, 0x7b); + sccb_reg_write(udev, 0x85, 0x86); + sccb_reg_write(udev, 0x86, 0x8e); + sccb_reg_write(udev, 0x87, 0x97); + sccb_reg_write(udev, 0x88, 0xa4); + sccb_reg_write(udev, 0x89, 0xaf); + sccb_reg_write(udev, 0x8a, 0xc5); + sccb_reg_write(udev, 0x8b, 0xd7); + sccb_reg_write(udev, 0x8c, 0xe8); + sccb_reg_write(udev, 0x8d, 0x20); + + sccb_reg_write(udev, 0x0c, 0x90); + + ov534_reg_verify_write(udev, 0xc0, 0x50); + ov534_reg_verify_write(udev, 0xc1, 0x3c); + ov534_reg_verify_write(udev, 0xc2, 0x0c); + + ov534_set_led(udev, 1); + + sccb_reg_write(udev, 0x2b, 0x00); + sccb_reg_write(udev, 0x22, 0x7f); + sccb_reg_write(udev, 0x23, 0x03); + sccb_reg_write(udev, 0x11, 0x01); + sccb_reg_write(udev, 0x0c, 0xd0); + sccb_reg_write(udev, 0x64, 0xff); + sccb_reg_write(udev, 0x0d, 0x41); + + sccb_reg_write(udev, 0x14, 0x41); + sccb_reg_write(udev, 0x0e, 0xcd); + sccb_reg_write(udev, 0xac, 0xbf); + sccb_reg_write(udev, 0x8e, 0x00); + sccb_reg_write(udev, 0x0c, 0xd0); + + ov534_reg_write(udev, 0xe0, 0x09); + ov534_set_led(udev, 0); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam; + + cam = &gspca_dev->cam; + + cam->epaddr = 0x01; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + cam->bulk_size = vga_mode[0].sizeimage; + cam->bulk_nurbs = 2; + + PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + ov534_setup(gspca_dev->dev); + + if (frame_rate > 0) + sd->frame_rate = frame_rate; + + PDEBUG(D_PROBE, "frame_rate = %d", sd->frame_rate); + + switch (sd->frame_rate) { + case 50: + sccb_reg_write(gspca_dev->dev, 0x11, 0x01); + sccb_check_status(gspca_dev->dev); + sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); + sccb_check_status(gspca_dev->dev); + ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); + break; + case 40: + sccb_reg_write(gspca_dev->dev, 0x11, 0x02); + sccb_check_status(gspca_dev->dev); + sccb_reg_write(gspca_dev->dev, 0x0d, 0xc1); + sccb_check_status(gspca_dev->dev); + ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); + break; + case 30: + default: + sccb_reg_write(gspca_dev->dev, 0x11, 0x04); + sccb_check_status(gspca_dev->dev); + sccb_reg_write(gspca_dev->dev, 0x0d, 0x81); + sccb_check_status(gspca_dev->dev); + ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); + break; + case 15: + sccb_reg_write(gspca_dev->dev, 0x11, 0x03); + sccb_check_status(gspca_dev->dev); + sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); + sccb_check_status(gspca_dev->dev); + ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); + break; + }; + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_PROBE, "width = %d, height = %d", + gspca_dev->width, gspca_dev->height); + + gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height * 2; + + /* start streaming data */ + ov534_set_led(gspca_dev->dev, 1); + ov534_reg_write(gspca_dev->dev, 0xe0, 0x00); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* stop streaming data */ + ov534_reg_write(gspca_dev->dev, 0xe0, 0x09); + ov534_set_led(gspca_dev->dev, 0); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, + __u8 *data, int len) +{ + /* + * The current camera setup doesn't stream the last pixel, so we set it + * to a dummy value + */ + __u8 last_pixel[4] = { 0, 0, 0, 0 }; + int framesize = gspca_dev->cam.bulk_size; + + if (len == framesize - 4) { + frame = + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); + frame = + gspca_frame_add(gspca_dev, LAST_PACKET, frame, last_pixel, + 4); + } else + PDEBUG(D_PACK, "packet len = %d, framesize = %d", len, + framesize); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */ + {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */ + {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */ + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "registered"); + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(frame_rate, int, 0644); +MODULE_PARM_DESC(frame_rate, "Frame rate (15, 30, 40, 50)"); diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index a122634e0..f443df77e 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -763,10 +763,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x78, 0x40); diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 8b5eb91e1..182b84f1c 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -252,13 +252,13 @@ static const __u8 sn_ov7630[] = { static const __u8 sn_ov7648[] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ - 0xa1, 0x6e, 0x18, 0x65, 0x00, 0x00, 0x00, 0x10, + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x82, + 0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00, /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_ov7660[] = { @@ -490,6 +490,53 @@ static const __u8 ov7630_sensor_init[][8] = { /* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ {} }; + +static const __u8 ov7648_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10}, + {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10}, + {0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10}, + {0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10}, + {0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10}, + {0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10}, + {0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10}, + {0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10}, + {0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10}, + {0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10}, + {0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10}, + + {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10}, +/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */ +/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */ + {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, +/*...*/ +/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, jfm done */ + {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, * GAIN - def */ +/* {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10}, * B R - def: 80 */ +/*...*/ + {0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */ +/* {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10}, * B R - def: 80 */ + + {} +}; + static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ @@ -578,64 +625,6 @@ static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, {} }; -/* reg 0x04 reg 0x07 reg 0x10 */ -/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */ - -static const __u8 ov7648_sensor_init[][8] = { - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10}, - {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10}, - {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10}, - {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10}, - {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10}, - {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10}, - {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10}, - {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10}, - {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10}, - {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10}, - {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10}, - {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10}, - {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10}, - {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10}, - {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10}, - {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10}, - /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10}, - * This is currently setting a - * blue tint, and some things more , i leave it here for future test if - * somene is having problems with color on this sensor - {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10}, - {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, - {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */ - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */ - {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */ - {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/ -/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */ - {} -}; static const __u8 qtable4[] = { 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06, @@ -854,18 +843,21 @@ static int configure_gpio(struct gspca_dev *gspca_dev, break; #endif case SENSOR_OV7648: - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0xae); + reg_w1(gspca_dev, 0x01, 0x63); + reg_w1(gspca_dev, 0x17, 0x20); reg_w1(gspca_dev, 0x01, 0x42); break; #if 1 /*jfm: from win trace */ case SENSOR_OV7660: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; + if (sd->bridge == BRIDGE_SN9C120) { + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x60); + reg_w1(gspca_dev, 0x01, 0x40); + break; + } + /* fall thru */ #endif default: reg_w1(gspca_dev, 0x01, 0x43); @@ -951,6 +943,13 @@ static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; + i2c_w8(gspca_dev, ov7648_sensor_init[i]); + i++; +/* win: dble reset */ + i2c_w8(gspca_dev, ov7648_sensor_init[i]); /* reset */ + i++; + msleep(20); +/* win: i2c reg read 00..7f */ while (ov7648_sensor_init[i][0]) { i2c_w8(gspca_dev, ov7648_sensor_init[i]); i++; @@ -1284,19 +1283,23 @@ static int sd_start(struct gspca_dev *gspca_dev) reg17 = 0xe2; break; case SENSOR_OV7648: - reg17 = 0xae; + reg17 = 0x20; break; #if 1 /*jfm: from win trace */ case SENSOR_OV7660: - reg17 = 0xa0; - break; + if (sd->bridge == BRIDGE_SN9C120) { + reg17 = 0xa0; + break; + } + /* fall thru */ #endif default: reg17 = 0x60; break; } reg_w1(gspca_dev, 0x17, reg17); +/* set reg1 was here */ reg_w1(gspca_dev, 0x05, sn9c1xx[5]); reg_w1(gspca_dev, 0x07, sn9c1xx[7]); reg_w1(gspca_dev, 0x06, sn9c1xx[6]); @@ -1305,9 +1308,16 @@ static int sd_start(struct gspca_dev *gspca_dev) for (i = 0; i < 8; i++) reg_w(gspca_dev, 0x84, reg84, sizeof reg84); switch (sd->sensor) { - case SENSOR_OV7660: - reg_w1(gspca_dev, 0x9a, 0x05); + case SENSOR_OV7648: + reg_w1(gspca_dev, 0x9a, 0x0a); + reg_w1(gspca_dev, 0x99, 0x60); break; + case SENSOR_OV7660: + if (sd->bridge == BRIDGE_SN9C120) { + reg_w1(gspca_dev, 0x9a, 0x05); + break; + } + /* fall thru */ default: reg_w1(gspca_dev, 0x9a, 0x08); reg_w1(gspca_dev, 0x99, 0x59); @@ -1316,10 +1326,10 @@ static int sd_start(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; if (mode) - reg1 = 0x46; /* 320 clk 48Mhz */ + reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */ else - reg1 = 0x06; /* 640 clk 24Mz */ - reg17 = 0x61; + reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */ + reg17 = 0x61; /* 0x:20: enable sensor clock */ switch (sd->sensor) { case SENSOR_HV7131R: hv7131R_InitSensor(gspca_dev); @@ -1349,8 +1359,8 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); - reg17 = 0xa2; - reg1 = 0x44; + reg17 = 0x21; +/* reg1 = 0x42; * 42 - 46? */ /* if (mode) ; * 320x2... else @@ -1363,9 +1373,15 @@ static int sd_start(struct gspca_dev *gspca_dev) /* reg17 = 0x21; * 320 */ /* reg1 = 0x44; */ /* reg1 = 0x46; (done) */ - } else { - reg17 = 0xa2; /* 640 */ - reg1 = 0x44; + } else { /* 640 */ + if (sd->bridge == BRIDGE_SN9C120) { + reg17 = 0xa2; + reg1 = 0x44; /* 48 Mhz, video trf eneble */ + } else { + reg17 = 0x22; + reg1 = 0x06; /* 24 Mhz, video trf eneble + * inverse power down */ + } } break; } @@ -1393,6 +1409,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x18, reg18); reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, reg1); switch (sd->sensor) { case SENSOR_MI0360: setinfrared(sd); @@ -1411,7 +1428,6 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } setautogain(gspca_dev); - reg_w1(gspca_dev, 0x01, reg1); return 0; } @@ -1422,6 +1438,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; static const __u8 stopmi0360[] = { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; + static const __u8 stopov7648[] = + { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; __u8 data; const __u8 *sn9c1xx; @@ -1435,8 +1453,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev) i2c_w8(gspca_dev, stopmi0360); data = 0x29; break; - case SENSOR_OV7630: case SENSOR_OV7648: + i2c_w8(gspca_dev, stopov7648); + /* fall thru */ + case SENSOR_OV7630: data = 0x29; break; default: @@ -1691,8 +1711,10 @@ static const __devinitdata struct usb_device_id device_table[] = { #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)}, {USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)}, +#endif {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)}, #endif {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, @@ -1720,7 +1742,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ /*bw600.inf:*/ - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c110?*/ {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)}, /* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ @@ -1728,8 +1750,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, #endif {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, + {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE -/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, /* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index a3f616709..2e1c5e50e 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -650,10 +650,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->subtype = id->driver_info; if (sd->subtype != LogitechClickSmart310) { cam->cam_mode = vga_mode; - cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + cam->nmodes = ARRAY_SIZE(vga_mode); } else { cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + cam->nmodes = ARRAY_SIZE(sif_mode); } sd->qindex = 5; sd->brightness = BRIGHTNESS_DEF; diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index 979344907..17dab9859 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -34,6 +34,8 @@ struct sd { unsigned short contrast; __u8 brightness; __u8 colors; + __u8 blue_balance; + __u8 red_balance; char subtype; #define Arowana300KCMOSCamera 0 @@ -52,6 +54,10 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { #define MY_BRIGHTNESS 0 @@ -63,7 +69,7 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 127, .step = 1, - .default_value = 63, + .default_value = 0, }, .set = sd_setbrightness, .get = sd_getbrightness, @@ -75,9 +81,9 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 0xffff, + .maximum = 64725, .step = 1, - .default_value = 0xaa00, + .default_value = 64725, }, .set = sd_setcontrast, .get = sd_getcontrast, @@ -91,11 +97,39 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 63, .step = 1, - .default_value = 31, + .default_value = 20, }, .set = sd_setcolors, .get = sd_getcolors, }, +#define MY_BLUE_BALANCE 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setblue_balance, + .get = sd_getblue_balance, + }, +#define MY_RED_BALANCE 4 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setred_balance, + .get = sd_getred_balance, + }, }; static struct v4l2_pix_format vga_mode[] = { @@ -1822,6 +1856,7 @@ static int reg_write(struct usb_device *dev, return ret; } +#if 0 /* returns: negative is error, pos or zero is data */ static int reg_read(struct gspca_dev *gspca_dev, __u16 req, /* bRequest */ @@ -1845,6 +1880,7 @@ static int reg_read(struct gspca_dev *gspca_dev, } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; } +#endif static int write_vector(struct gspca_dev *gspca_dev, const __u16 data[][3]) @@ -1869,18 +1905,18 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness); reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness); } static void getbrightness(struct gspca_dev *gspca_dev) { +#if 0 struct sd *sd = (struct sd *) gspca_dev; __u16 brightness; - brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2); - sd->brightness = brightness << 1; + brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x12, 2); + sd->brightness = brightness; +#endif } static void setcontrast(struct gspca_dev *gspca_dev) @@ -1906,7 +1942,6 @@ static void getcontrast(struct gspca_dev *gspca_dev) 0x01, 1) & 0xff); #endif -/* spca50x->contrast = 0xaa01; */ } static void setcolors(struct gspca_dev *gspca_dev) @@ -1918,11 +1953,25 @@ static void setcolors(struct gspca_dev *gspca_dev) static void getcolors(struct gspca_dev *gspca_dev) { +#if 0 struct sd *sd = (struct sd *) gspca_dev; sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2); -/* sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */ -/* 2) & 0xFF) << 8; */ +#endif +} + +static void setblue_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance); +} + +static void setred_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance); } /* this function is called at probe time */ @@ -1941,6 +1990,14 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (sd->subtype) { case Arowana300KCMOSCamera: case SmileIntlCamera: @@ -1959,15 +2016,17 @@ static int sd_config(struct gspca_dev *gspca_dev, goto error; break; } + PDEBUG(D_STREAM, "Initializing SPCA501 finished"); return 0; error: return -EINVAL; } -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int mode; switch (sd->subtype) { case ThreeComHomeConnectLite: @@ -1987,14 +2046,6 @@ static int sd_init(struct gspca_dev *gspca_dev) /* Generic 501 open data */ write_vector(gspca_dev, spca501_open_data); } - PDEBUG(D_STREAM, "Initializing SPCA501 finished"); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - int mode; /* memorize the wanted pixel format */ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; @@ -2033,8 +2084,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { + if (!gspca_dev->present) + return; reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); } @@ -2121,6 +2175,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue_balance = val; + if (gspca_dev->streaming) + setblue_balance(gspca_dev); + return 0; +} + +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue_balance; + return 0; +} + +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red_balance = val; + if (gspca_dev->streaming) + setred_balance(gspca_dev); + return 0; +} + +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red_balance; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index 62bab3cc1..c52598e94 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -811,8 +811,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { + if (!gspca_dev->present) + return; + /* This maybe reset or power control */ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 5b65dd66b..4c0046cc7 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -780,10 +780,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) } } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; if (sd->chip_revision == Rev012A) { reg_w_val(gspca_dev->dev, 0x8118, 0x29); reg_w_val(gspca_dev->dev, 0x8114, 0x08); diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index 95531138e..f6fae60ae 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -1830,10 +1830,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(dev, 0xa0, 0x09, 0xb003); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; + if (!gspca_dev->present) + return; reg_w(dev, 0x89, 0xffff, 0xffff); } diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index b74ce0ef1..adbca6a9d 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -7371,10 +7371,13 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; send_unknown(gspca_dev->dev, sd->sensor); } diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 5a872787e..ab9814144 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -193,7 +193,7 @@ struct s2255_dmaqueue { #define S2255_FW_FAILED 3 #define S2255_FW_DISCONNECTING 4 -#define S2255_FW_MARKER 0x22552f2f +#define S2255_FW_MARKER cpu_to_le32(0x22552f2f) /* 2255 read states */ #define S2255_READ_IDLE 0 #define S2255_READ_FRAME 1 diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 65d3909d4..d4c432cb3 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -6151,7 +6151,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) struct v4l2_priv_tun_config xc2028_cfg; struct xc2028_ctrl ctl; - memset(&xc2028_cfg, 0, sizeof(ctl)); + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); memset(&ctl, 0, sizeof(ctl)); ctl.fname = XC2028_DEFAULT_FIRMWARE; diff --git a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c index f7a3f1d0a..477d9e091 100644 --- a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -161,7 +161,7 @@ static struct saa7134_tvaudio tvaudio[] = { .mode = TVAUDIO_FM_MONO, } }; -#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio)) +#define TVAUDIO ARRAY_SIZE(tvaudio) /* ------------------------------------------------------------------ */ diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index 390722003..8cb3457e7 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -93,8 +93,10 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, /* SN9C105 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, +#endif { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, #if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, @@ -117,7 +119,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 046b98871..0a0ef6611 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -32,6 +32,7 @@ #include <linux/vmalloc.h> #include <linux/wait.h> #include <asm/atomic.h> +#include <asm/unaligned.h> #include <media/v4l2-common.h> @@ -452,20 +453,20 @@ static int uvc_parse_format(struct uvc_device *dev, frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; - frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]); - frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]); - frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]); - frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]); + frame->wWidth = get_unaligned_le16(&buffer[5]); + frame->wHeight = get_unaligned_le16(&buffer[7]); + frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); + frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); if (ftype != VS_FRAME_FRAME_BASED) { frame->dwMaxVideoFrameBufferSize = - le32_to_cpup((__le32 *)&buffer[17]); + get_unaligned_le32(&buffer[17]); frame->dwDefaultFrameInterval = - le32_to_cpup((__le32 *)&buffer[21]); + get_unaligned_le32(&buffer[21]); frame->bFrameIntervalType = buffer[25]; } else { frame->dwMaxVideoFrameBufferSize = 0; frame->dwDefaultFrameInterval = - le32_to_cpup((__le32 *)&buffer[17]); + get_unaligned_le32(&buffer[17]); frame->bFrameIntervalType = buffer[21]; } frame->dwFrameInterval = *intervals; @@ -488,7 +489,7 @@ static int uvc_parse_format(struct uvc_device *dev, * some other divisions by zero which could happen. */ for (i = 0; i < n; ++i) { - interval = le32_to_cpup((__le32 *)&buffer[26+4*i]); + interval = get_unaligned_le32(&buffer[26+4*i]); *(*intervals)++ = interval ? interval : 1; } @@ -832,8 +833,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unit->type = VC_EXTENSION_UNIT; memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; - unit->extension.bNrInPins = - le16_to_cpup((__le16 *)&buffer[21]); + unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; memcpy(unit->extension.baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; @@ -877,8 +877,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]); - dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]); + dev->uvc_version = get_unaligned_le16(&buffer[3]); + dev->clock_frequency = get_unaligned_le32(&buffer[7]); /* Parse all USB Video Streaming interfaces. */ for (i = 0; i < n; ++i) { @@ -905,7 +905,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, /* Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit. */ - type = le16_to_cpup((__le16 *)&buffer[4]); + type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL %d has invalid " @@ -947,11 +947,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev, term->camera.bControlSize = n; term->camera.bmControls = (__u8 *)term + sizeof *term; term->camera.wObjectiveFocalLengthMin = - le16_to_cpup((__le16 *)&buffer[8]); + get_unaligned_le16(&buffer[8]); term->camera.wObjectiveFocalLengthMax = - le16_to_cpup((__le16 *)&buffer[10]); + get_unaligned_le16(&buffer[10]); term->camera.wOcularFocalLength = - le16_to_cpup((__le16 *)&buffer[12]); + get_unaligned_le16(&buffer[12]); memcpy(term->camera.bmControls, &buffer[15], n); } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) { term->media.bControlSize = n; @@ -987,7 +987,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, /* Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit. */ - type = le16_to_cpup((__le16 *)&buffer[4]); + type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d OUTPUT_TERMINAL %d has invalid " @@ -1061,7 +1061,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->type = buffer[2]; unit->processing.bSourceID = buffer[4]; unit->processing.wMaxMultiplier = - le16_to_cpup((__le16 *)&buffer[5]); + get_unaligned_le16(&buffer[5]); unit->processing.bControlSize = buffer[7]; unit->processing.bmControls = (__u8 *)unit + sizeof *unit; memcpy(unit->processing.bmControls, &buffer[8], n); @@ -1096,8 +1096,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->type = buffer[2]; memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; - unit->extension.bNrInPins = - le16_to_cpup((__le16 *)&buffer[21]); + unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; memcpy(unit->extension.baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index 5588698e2..95eb6f3ad 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -252,9 +252,6 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, if (ret < 0) return ret; - if ((ret = uvc_commit_video(video, &probe)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -315,10 +312,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, if ((ret = uvc_probe_video(video, &probe)) < 0) return ret; - /* Commit the new settings. */ - if ((ret = uvc_commit_video(video, &probe)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); /* Return the actual frame period. */ @@ -477,9 +470,6 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct uvc_fh *handle = (struct uvc_fh *)file->private_data; int ret = 0; - if (uvc_trace_param & UVC_TRACE_IOCTL) - v4l_printk_ioctl(cmd); - switch (cmd) { /* Query capabilities */ case VIDIOC_QUERYCAP: @@ -996,7 +986,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) static int uvc_v4l2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n"); + if (uvc_trace_param & UVC_TRACE_IOCTL) { + uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl("); + v4l_printk_ioctl(cmd); + printk(")\n"); + } + return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); } diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 987e110fe..3be776a47 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -142,14 +142,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]); ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]); ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]); - ctrl->dwMaxVideoFrameSize = - le32_to_cpu(get_unaligned((__le32 *)&data[18])); - ctrl->dwMaxPayloadTransferSize = - le32_to_cpu(get_unaligned((__le32 *)&data[22])); + ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); + ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); if (size == 34) { - ctrl->dwClockFrequency = - le32_to_cpu(get_unaligned((__le32 *)&data[26])); + ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); ctrl->bmFramingInfo = data[30]; ctrl->bPreferedVersion = data[31]; ctrl->bMinVersion = data[32]; @@ -197,14 +194,11 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video, /* Note: Some of the fields below are not required for IN devices (see * UVC spec, 4.3.1.1), but we still copy them in case support for OUT * devices is added in the future. */ - put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize), - (__le32 *)&data[18]); - put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize), - (__le32 *)&data[22]); + put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); + put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); if (size == 34) { - put_unaligned(cpu_to_le32(ctrl->dwClockFrequency), - (__le32 *)&data[26]); + put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); data[30] = ctrl->bmFramingInfo; data[31] = ctrl->bPreferedVersion; data[32] = ctrl->bMinVersion; @@ -899,7 +893,7 @@ int uvc_video_resume(struct uvc_video_device *video) video->frozen = 0; - if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) { + if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) { uvc_queue_enable(&video->queue, 0); return ret; } @@ -980,11 +974,8 @@ int uvc_video_init(struct uvc_video_device *video) break; } - /* Commit the default settings. */ probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; - if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0) - return ret; video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -1024,6 +1015,10 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) return ret; + /* Commit the streaming parameters. */ + if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) + return ret; + return uvc_init_video(video, GFP_KERNEL); } |