diff options
Diffstat (limited to 'drivers/media/usb')
26 files changed, 300 insertions, 178 deletions
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index e731243267e4..5d38171b7638 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -15,8 +15,8 @@ /* debug */ #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) +#define dprintk(level, args...) \ + do { if ((debug & (level))) printk(args); } while (0) #define debug_dump(b, l, method) do {\ int i; \ @@ -27,8 +27,8 @@ #define DEBSTATUS "" #else -#define dprintk(level, args...) -#define debug_dump(b, l, method) +#define dprintk(level, args...) no_printk(args) +#define debug_dump(b, l, method) do { } while (0) #define DEBSTATUS " (debugging is not enabled)" #endif @@ -195,7 +195,6 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, break; default: return -EINVAL; - break; } for (i = 0; i < len;) { pagechunk = diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index b32eab641793..6929e4d97067 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -425,8 +425,6 @@ struct cx231xx_audio { u16 end_point_addr; }; -struct cx231xx; - /*****************************************************************/ /* set/get i2c */ /* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */ diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 89a1b204b90c..aa45b5d263f6 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -1171,14 +1171,9 @@ static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, int addr, u8 val) { struct dvb_usb_device *d = ci->data; - int ret; u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, @@ -1200,14 +1195,9 @@ static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, u8 addr, u8 val) { struct dvb_usb_device *d = ci->data; - int ret; u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) @@ -1252,13 +1242,8 @@ static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) { struct dvb_usb_device *d = ci->data; - int ret; - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); - if (ret) - return ret; - - return 0; + return anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); } static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 52bcc2d2efe5..288c15a7d72b 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -100,7 +100,8 @@ struct dvb_usb_device; struct dvb_usb_adapter; /** - * structure for carrying all needed data from the device driver to the general + * struct dvb_usb_driver_info - structure for carrying all needed data from the + * device driver to the general * dvb usb routines * @name: device name * @rc_map: name of rc codes table @@ -113,7 +114,7 @@ struct dvb_usb_driver_info { }; /** - * structure for remote controller configuration + * struct dvb_usb_rc - structure for remote controller configuration * @map_name: name of rc codes table * @allowed_protos: protocol(s) supported by the driver * @change_protocol: callback to change protocol @@ -135,10 +136,11 @@ struct dvb_usb_rc { }; /** - * usb streaming configuration for adapter + * struct usb_data_stream_properties - usb streaming configuration for adapter * @type: urb type * @count: count of used urbs * @endpoint: stream usb endpoint number + * @u: union for @bulk and @isoc */ struct usb_data_stream_properties { #define USB_BULK 1 @@ -160,15 +162,15 @@ struct usb_data_stream_properties { }; /** - * properties of dvb usb device adapter + * struct dvb_usb_adapter_properties - properties of dvb usb device adapter * @caps: adapter capabilities * @pid_filter_count: pid count of adapter pid-filter * @pid_filter_ctrl: called to enable/disable pid-filter * @pid_filter: called to set/unset pid for filtering * @stream: adapter usb stream configuration */ -#define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { +#define MAX_NO_OF_FE_PER_ADAP 3 #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 @@ -208,6 +210,7 @@ struct dvb_usb_adapter_properties { * @frontend_attach: called to attach the possible frontends * @frontend_detach: called to detach the possible frontends * @tuner_attach: called to attach the possible tuners + * @tuner_detach: called to detach the possible tuners * @frontend_ctrl: called to power on/off active frontend * @streaming_ctrl: called to start/stop the usb streaming of adapter * @init: called after adapters are created in order to finalize device @@ -218,8 +221,8 @@ struct dvb_usb_adapter_properties { * of the adapter just before streaming is started. input stream is transport * stream from the demodulator and output stream is usb stream to host. */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 const char *driver_name; struct module *owner; short *adapter_nr; @@ -265,7 +268,12 @@ struct dvb_usb_device_properties { }; /** - * generic object of an usb stream + * struct usb_data_stream - generic object of an usb stream + * @udev: USB device + * @props: properties + * @state: state of the data stream + * @complete: complete callback + * @urb_list: list of URBs * @buf_num: number of buffer allocated * @buf_size: size of each buffer in buf_list * @buf_list: array containing all allocate buffers for streaming @@ -273,9 +281,10 @@ struct dvb_usb_device_properties { * * @urbs_initialized: number of URBs initialized * @urbs_submitted: number of URBs submitted + * @user_priv: private pointer */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { +#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_device *udev; struct usb_data_stream_properties props; @@ -298,7 +307,7 @@ struct usb_data_stream { }; /** - * dvb adapter object on dvb usb device + * struct dvb_usb_adapter - dvb adapter object on dvb usb device * @props: pointer to adapter properties * @stream: adapter the usb data stream * @id: index of this adapter (starting with 0) @@ -307,11 +316,12 @@ struct usb_data_stream { * @pid_filtering: is hardware pid_filtering used or not * @feed_count: current feed count * @max_feed_count: maimum feed count device can handle + * @active_fe: active frontend + * @state_bits: status bits * @dvb_adap: adapter dvb_adapter * @dmxdev: adapter dmxdev * @demux: adapter software demuxer * @dvb_net: adapter dvb_net interfaces - * @sync_mutex: mutex used to sync control and streaming of the adapter * @fe: adapter frontends * @fe_init: rerouted frontend-init function * @fe_sleep: rerouted frontend-sleep function @@ -343,7 +353,7 @@ struct dvb_usb_adapter { }; /** - * dvb usb device object + * struct dvb_usb_device - dvb usb device object * @props: device properties * @name: device name * @rc_map: name of rc codes table @@ -355,7 +365,9 @@ struct dvb_usb_adapter { * @usb_mutex: mutex for usb control messages * @i2c_mutex: mutex for i2c-transfers * @i2c_adap: device's i2c-adapter + * @adapter: adapters * @rc_dev: rc device for the remote control + * @rc_phys: rc path * @rc_query_work: work for polling remote * @priv: private data of the actual driver (allocate by dvb usb, size defined * in size_of_priv of dvb_usb_properties). diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index c1a7634e27b4..28e1fd64dd3c 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -79,11 +79,17 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } } - if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || - (ret = dvb_usb_adapter_frontend_init(adap))) { + ret = dvb_usb_adapter_stream_init(adap); + if (ret) return ret; - } + + ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs); + if (ret) + goto dvb_init_err; + + ret = dvb_usb_adapter_frontend_init(adap); + if (ret) + goto frontend_init_err; /* use exclusive FE lock if there is multiple shared FEs */ if (adap->fe_adap[1].fe) @@ -103,6 +109,12 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } return 0; + +frontend_init_err: + dvb_usb_adapter_dvb_exit(adap); +dvb_init_err: + dvb_usb_adapter_stream_exit(adap); + return ret; } static int dvb_usb_adapter_exit(struct dvb_usb_device *d) @@ -158,22 +170,20 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) if (d->props.priv_init != NULL) { ret = d->props.priv_init(d); - if (ret != 0) { - kfree(d->priv); - d->priv = NULL; - return ret; - } + if (ret != 0) + goto err_priv_init; } } /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); - if ((ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_adapter_init(d, adapter_nums))) { - dvb_usb_exit(d); - return ret; - } + ret = dvb_usb_i2c_init(d); + if (ret) + goto err_i2c_init; + ret = dvb_usb_adapter_init(d, adapter_nums); + if (ret) + goto err_adapter_init; if ((ret = dvb_usb_remote_init(d))) err("could not initialize remote control."); @@ -181,6 +191,17 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) dvb_usb_device_power_ctrl(d, 0); return 0; + +err_adapter_init: + dvb_usb_adapter_exit(d); +err_i2c_init: + dvb_usb_i2c_exit(d); + if (d->priv && d->props.priv_destroy) + d->props.priv_destroy(d); +err_priv_init: + kfree(d->priv); + d->priv = NULL; + return ret; } /* determine the name and the state of the just found USB device */ @@ -255,41 +276,50 @@ int dvb_usb_device_init(struct usb_interface *intf, if (du != NULL) *du = NULL; - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + err("no memory for 'struct dvb_usb_device'"); + return -ENOMEM; + } + + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + + desc = dvb_usb_find_device(udev, &d->props, &cold); + if (!desc) { deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); - return -ENODEV; + ret = -ENODEV; + goto error; } if (cold) { info("found a '%s' in cold state, will try to load a firmware", desc->name); ret = dvb_usb_download_firmware(udev, props); if (!props->no_reconnect || ret != 0) - return ret; + goto error; } info("found a '%s' in warm state.", desc->name); - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); - return -ENOMEM; - } - d->udev = udev; - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); d->desc = desc; d->owner = owner; usb_set_intfdata(intf, d); - if (du != NULL) + ret = dvb_usb_init(d, adapter_nums); + if (ret) { + info("%s error while loading driver (%d)", desc->name, ret); + goto error; + } + + if (du) *du = d; - ret = dvb_usb_init(d, adapter_nums); + info("%s successfully initialized and connected.", desc->name); + return 0; - if (ret == 0) - info("%s successfully initialized and connected.", desc->name); - else - info("%s error while loading driver (%d)", desc->name, ret); + error: + usb_set_intfdata(intf, NULL); + kfree(d); return ret; } EXPORT_SYMBOL(dvb_usb_device_init); diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 741be0e69447..0990aa4a17bb 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -28,18 +28,19 @@ /* debug */ #ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var,level,args...) \ - do { if ((var & level)) { printk(args); } } while (0) +#define dprintk(var, level, args...) \ + do { if (((var) & (level))) { printk(args); } } while (0) -#define debug_dump(b,l,func) {\ +#define debug_dump(b, l, func) {\ int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + for (loop_ = 0; loop_ < (l); loop_++) \ + func("%02x ", b[loop_]); \ func("\n");\ } #define DVB_USB_DEBUG_STATUS #else -#define dprintk(args...) -#define debug_dump(b,l,func) +#define dprintk(var, level, args...) no_printk(args) +#define debug_dump(b, l, func) do { } while (0) #define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" @@ -95,7 +96,7 @@ struct dvb_usb_device; struct dvb_usb_adapter; struct usb_data_stream; -/** +/* * Properties of USB streaming - TODO this structure should be somewhere else * describes the kind of USB transfer used for data-streaming. * (BULK or ISOC) @@ -120,7 +121,7 @@ struct usb_data_stream_properties { }; /** - * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * struct dvb_usb_adapter_fe_properties - properties of a dvb-usb-adapter. * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware @@ -139,6 +140,7 @@ struct usb_data_stream_properties { * @tuner_attach: called to attach the correct tuner and to fill pll_addr, * pll_desc and pll_init_buf of struct dvb_usb_device). * @stream: configuration of the USB streaming + * @size_of_priv: size of the priv memory in struct dvb_usb_adapter */ struct dvb_usb_adapter_fe_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 @@ -191,15 +193,17 @@ struct dvb_rc_legacy { }; /** - * struct dvb_rc properties of remote controller, using rc-core + * struct dvb_rc - properties of remote controller, using rc-core * @rc_codes: name of rc codes table * @protocol: type of protocol(s) currently used by the driver * @allowed_protos: protocol(s) supported by the driver * @driver_type: Used to point if a device supports raw mode * @change_protocol: callback to change protocol + * @module_name: module name * @rc_query: called to query an event event. * @rc_interval: time in ms between two queries. * @bulk_mode: device supports bulk mode for RC (disable polling mode) + * @scancode_mask: scancode mask */ struct dvb_rc { char *rc_codes; @@ -219,6 +223,9 @@ struct dvb_rc { * based on rc-core * This is initialized/used only inside dvb-usb-remote.c. * It shouldn't be set by the drivers. + * + * @DVB_RC_LEGACY: legacy driver + * @DVB_RC_CORE: rc-core driver */ enum dvb_usb_mode { DVB_RC_LEGACY, @@ -227,6 +234,7 @@ enum dvb_usb_mode { /** * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @caps: capabilities * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. @@ -243,6 +251,8 @@ enum dvb_usb_mode { * @priv_destroy: just like priv_init, only called before deallocating * the memory pointed by private field of struct dvb_usb_device. * + * @num_adapters: the number of adapters in @adapters + * @adapter: the adapters * @power_ctrl: called to enable/disable power of the device. * @read_mac_address: called to read the MAC address of the device. * @identify_state: called to determine the state (cold or warm), when it @@ -267,9 +277,8 @@ enum dvb_usb_mode { * @devices: array of struct dvb_usb_device_description compatibles with these * properties. */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { - +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 #define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; @@ -313,6 +322,11 @@ struct dvb_usb_device_properties { /** * struct usb_data_stream - generic object of an USB stream + * @udev: the USB device + * @props: data stream properties + * @state: state of the stream + * @complete: complete callback + * @urb_list: list of URBs * @buf_num: number of buffer allocated. * @buf_size: size of each buffer in buf_list. * @buf_list: array containing all allocate buffers for streaming. @@ -320,9 +334,10 @@ struct dvb_usb_device_properties { * * @urbs_initialized: number of URBs initialized. * @urbs_submitted: number of URBs submitted. + * @user_priv: for private use. */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { +#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_device *udev; struct usb_data_stream_properties props; @@ -345,29 +360,15 @@ struct usb_data_stream { }; /** - * struct dvb_usb_adapter - a DVB adapter on a USB device - * @id: index of this adapter (starting with 0). - * - * @feedcount: number of requested feeds (used for streaming-activation) - * @pid_filtering: is hardware pid_filtering used or not. - * - * @pll_addr: I2C address of the tuner for programming - * @pll_init: array containing the initialization buffer - * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board - * - * @dvb_adap: device's dvb_adapter. - * @dmxdev: device's dmxdev. - * @demux: device's software demuxer. - * @dvb_net: device's dvb_net interfaces. - * @dvb_frontend: device's frontend. - * @max_feed_count: how many feeds can be handled simultaneously by this - * device - * + * struct dvb_usb_fe_adapter - a DVB adapter on a USB device + * @fe: frontend * @fe_init: rerouted frontend-init (wakeup) function. * @fe_sleep: rerouted frontend-sleep function. - * * @stream: the usb data stream. + * @pid_filtering: is hardware pid_filtering used or not. + * @max_feed_count: how many feeds can be handled simultaneously by this + * device + * @priv: private pointer */ struct dvb_usb_fe_adapter { struct dvb_frontend *fe; @@ -383,6 +384,25 @@ struct dvb_usb_fe_adapter { void *priv; }; +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @dev: DVB USB device pointer + * @props: properties + * @state: status + * @id: index of this adapter (starting with 0). + * + * @feedcount: number of requested feeds (used for streaming-activation) + * + * @dvb_adap: device's dvb_adapter. + * @dmxdev: device's dmxdev. + * @demux: device's software demuxer. + * @dvb_net: device's dvb_net interfaces. + * + * @fe_adap: frontend adapters + * @active_fe: active frontend + * @num_frontends_initialized: number of initialized frontends + * @priv: private pointer + */ struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; @@ -427,8 +447,12 @@ struct dvb_usb_adapter { * * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB * + * @num_adapters_initialized: number of initialized adapters + * @adapter: adapters + * * @rc_dev: rc device for the remote control (rc-core mode) * @input_dev: input device for the remote control (legacy mode) + * @rc_phys: rc device path * @rc_query_work: struct work_struct frequent rc queries * @last_event: last triggered event * @last_state: last state (no, pressed, repeat) @@ -487,7 +511,8 @@ extern int __must_check dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ -extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); +int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, u8 keybuf[5], + u32 *event, int *state); /* commonly used firmware download types and function */ struct hexline { diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d6c8ae213914..ba9292e2a587 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2778,8 +2778,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, { USB_DEVICE(0x2013, 0x0258), .driver_info = EM28178_BOARD_PCTV_461E }, + { USB_DEVICE(0x2013, 0x8258), /* Bulk transport 461e */ + .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x0461), .driver_info = EM28178_BOARD_PCTV_461E_V2 }, + { USB_DEVICE(0x2013, 0x8461), /* Bulk transport 461e v2 */ + .driver_info = EM28178_BOARD_PCTV_461E_V2 }, { USB_DEVICE(0x2013, 0x0259), .driver_info = EM28178_BOARD_PCTV_461E_V2 }, { USB_DEVICE(0x2013, 0x025f), diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 526424279637..471bd74667e3 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -2010,6 +2010,7 @@ ret: return result; out_free: + em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); kfree(dvb); dev->dvb = NULL; goto ret; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 6648e11f1271..ab167cd1f400 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -335,7 +335,7 @@ enum em28xx_usb_audio_type { }; /** - * em28xx_amux - describes the type of audio input used by em28xx + * enum em28xx_amux - describes the type of audio input used by em28xx * * @EM28XX_AMUX_UNUSED: * Used only on em28xx dev->map field, in order to mark an entry @@ -628,8 +628,6 @@ struct em28xx_audio { atomic_t stream_started; /* stream should be running if true */ }; -struct em28xx; - enum em28xx_i2c_algo_type { EM28XX_I2C_ALGO_EM28XX = 0, EM28XX_I2C_ALGO_EM2800, diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index a4f7431486f3..d93d384286c1 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -1424,7 +1424,6 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - int ret; sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; reset_camera_params(gspca_dev); @@ -1436,10 +1435,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mode; cam->nmodes = ARRAY_SIZE(mode); - ret = goto_low_power(gspca_dev); - if (ret) - gspca_err(gspca_dev, "Cannot go to low power mode: %d\n", - ret); + goto_low_power(gspca_dev); /* Check the firmware version. */ sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 158c8e28ed2c..47d8f28bfdfc 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1576,6 +1576,8 @@ out: #endif v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); v4l2_device_unregister(&gspca_dev->v4l2_dev); + if (sd_desc->probe_error) + sd_desc->probe_error(gspca_dev); kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index b0ced2e14006..a6554d5e9e1a 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -105,6 +105,7 @@ struct sd_desc { cam_cf_op config; /* called on probe */ cam_op init; /* called on probe and resume */ cam_op init_controls; /* called on probe */ + cam_v_op probe_error; /* called if probe failed, do cleanup here */ cam_op start; /* called on stream on after URBs creation */ cam_pkt_op pkt_scan; /* optional operations */ diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index bfa3b381d8a2..bf1af6ed9131 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -195,7 +195,7 @@ static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; - int i, rc = 0; + int i, err; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -213,18 +213,18 @@ int mt9m111_probe(struct sd *sd) /* Do the preinit */ for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { if (preinit_mt9m111[i][0] == BRIDGE) { - rc |= m5602_write_bridge(sd, - preinit_mt9m111[i][1], - preinit_mt9m111[i][2]); + err = m5602_write_bridge(sd, + preinit_mt9m111[i][1], + preinit_mt9m111[i][2]); } else { data[0] = preinit_mt9m111[i][2]; data[1] = preinit_mt9m111[i][3]; - rc |= m5602_write_sensor(sd, - preinit_mt9m111[i][1], data, 2); + err = m5602_write_sensor(sd, + preinit_mt9m111[i][1], data, 2); } + if (err < 0) + return err; } - if (rc < 0) - return rc; if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) return -ENODEV; diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index d680b777f097..8fd99ceee4b6 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -154,8 +154,8 @@ static const struct v4l2_ctrl_config po1030_greenbal_cfg = { int po1030_probe(struct sd *sd) { - int rc = 0; u8 dev_id_h = 0, i; + int err; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -174,14 +174,14 @@ int po1030_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { u8 data = preinit_po1030[i][2]; if (preinit_po1030[i][0] == SENSOR) - rc |= m5602_write_sensor(sd, - preinit_po1030[i][1], &data, 1); + err = m5602_write_sensor(sd, preinit_po1030[i][1], + &data, 1); else - rc |= m5602_write_bridge(sd, preinit_po1030[i][1], - data); + err = m5602_write_bridge(sd, preinit_po1030[i][1], + data); + if (err < 0) + return err; } - if (rc < 0) - return rc; if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) return -ENODEV; diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index 97799cfb832e..949111070971 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -158,7 +158,7 @@ static int sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) { int ret; - int act_len; + int act_len = 0; gspca_dev->usb_buf[0] = '\0'; if (need_lock) diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 95673fc0a99c..d9bc2aacc885 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -529,12 +529,21 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, static int stv06xx_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id); +static void stv06xx_probe_error(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + + kfree(sd->sensor_priv); + sd->sensor_priv = NULL; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = stv06xx_config, .init = stv06xx_init, .init_controls = stv06xx_init_controls, + .probe_error = stv06xx_probe_error, .start = stv06xx_start, .stopN = stv06xx_stopN, .pkt_scan = stv06xx_pkt_scan, diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index a8350ee9712f..79baa0c1a031 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** - * +/* * GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip. * * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> diff --git a/drivers/media/usb/pwc/pwc-dec23.c b/drivers/media/usb/pwc/pwc-dec23.c index 4e26ada87f7b..a3aa8c7174b9 100644 --- a/drivers/media/usb/pwc/pwc-dec23.c +++ b/drivers/media/usb/pwc/pwc-dec23.c @@ -637,7 +637,7 @@ static void DecompressBand23(struct pwc_dec23_private *pdec, } /** - * Uncompress a pwc23 buffer. + * pwc_dec23_decompress - Uncompress a pwc23 buffer. * @pdev: pointer to pwc device's internal struct * @src: raw data * @dst: image output diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 5e3339cc31c0..e342199711d3 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -861,7 +861,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x069A) { @@ -873,7 +872,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x046d) { @@ -932,7 +930,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x055d) { @@ -958,7 +955,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x041e) { @@ -977,7 +973,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x04cc) { @@ -989,7 +984,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x06be) { @@ -1002,7 +996,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } @@ -1020,7 +1013,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else diff --git a/drivers/media/usb/pwc/pwc-uncompress.c b/drivers/media/usb/pwc/pwc-uncompress.c index abfc88391036..68bc3829c6b3 100644 --- a/drivers/media/usb/pwc/pwc-uncompress.c +++ b/drivers/media/usb/pwc/pwc-uncompress.c @@ -9,9 +9,6 @@ Please send bug reports and support requests to <luc@saillard.org>. The decompression routines have been implemented by reverse-engineering the Nemosoft binary pwcx module. Caveat emptor. - - - vim: set ts=8: */ #include <asm/current.h> diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index df6c5e4a0f05..a852ee5f7ac9 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1102,11 +1102,9 @@ static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TYPE_TS: return ttusb_dec_start_ts_feed(dvbdmxfeed); - break; case DMX_TYPE_SEC: return ttusb_dec_start_sec_feed(dvbdmxfeed); - break; default: dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); @@ -1157,11 +1155,9 @@ static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) switch (dvbdmxfeed->type) { case DMX_TYPE_TS: return ttusb_dec_stop_ts_feed(dvbdmxfeed); - break; case DMX_TYPE_SEC: return ttusb_dec_stop_sec_feed(dvbdmxfeed); - break; } return 0; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 3b4a2e769230..a714ad77ca8e 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -47,7 +47,7 @@ #include "usbtv.h" -static struct usbtv_norm_params norm_params[] = { +static const struct usbtv_norm_params norm_params[] = { { .norm = V4L2_STD_525_60, .cap_width = 720, @@ -63,7 +63,7 @@ static struct usbtv_norm_params norm_params[] = { static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) { int i, ret = 0; - struct usbtv_norm_params *params = NULL; + const struct usbtv_norm_params *params = NULL; for (i = 0; i < ARRAY_SIZE(norm_params); i++) { if (norm_params[i].norm & norm) { @@ -685,7 +685,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i) return usbtv_select_input(usbtv, i); } -static struct v4l2_ioctl_ops usbtv_ioctl_ops = { +static const struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_querycap = usbtv_querycap, .vidioc_enum_input = usbtv_enum_input, .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 30ef2a3110f7..9a791d8ef200 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1712,10 +1712,35 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, if (forward->bNrInPins != 1) { uvc_dbg(chain->dev, DESCR, "Extension unit %d has more than 1 input pin\n", - entity->id); + forward->id); return -EINVAL; } + /* + * Some devices reference an output terminal as the + * source of extension units. This is incorrect, as + * output terminals only have an input pin, and thus + * can't be connected to any entity in the forward + * direction. The resulting topology would cause issues + * when registering the media controller graph. To + * avoid this problem, connect the extension unit to + * the source of the output terminal instead. + */ + if (UVC_ENTITY_IS_OTERM(entity)) { + struct uvc_entity *source; + + source = uvc_entity_by_id(chain->dev, + entity->baSourceID[0]); + if (!source) { + uvc_dbg(chain->dev, DESCR, + "Can't connect extension unit %u in chain\n", + forward->id); + break; + } + + forward->baSourceID[0] = source->id; + } + list_add_tail(&forward->chain, &chain->entities); if (!found) uvc_dbg_cont(PROBE, " (->"); @@ -1735,6 +1760,13 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, return -EINVAL; } + if (UVC_ENTITY_IS_OTERM(entity)) { + uvc_dbg(chain->dev, DESCR, + "Unsupported connection between output terminals %u and %u\n", + entity->id, forward->id); + break; + } + list_add_tail(&forward->chain, &chain->entities); if (!found) uvc_dbg_cont(PROBE, " (->"); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index f2f565281e63..a777b389a66e 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -6,11 +6,14 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <linux/dma-mapping.h> +#include <linux/highmem.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/usb/hcd.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> @@ -1096,6 +1099,29 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return data[0]; } +static inline enum dma_data_direction uvc_stream_dir( + struct uvc_streaming *stream) +{ + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return DMA_FROM_DEVICE; + else + return DMA_TO_DEVICE; +} + +static inline struct device *uvc_stream_to_dmadev(struct uvc_streaming *stream) +{ + return bus_to_hcd(stream->dev->udev->bus)->self.sysdev; +} + +static int uvc_submit_urb(struct uvc_urb *uvc_urb, gfp_t mem_flags) +{ + /* Sync DMA. */ + dma_sync_sgtable_for_device(uvc_stream_to_dmadev(uvc_urb->stream), + uvc_urb->sgt, + uvc_stream_dir(uvc_urb->stream)); + return usb_submit_urb(uvc_urb->urb, mem_flags); +} + /* * uvc_video_decode_data_work: Asynchronous memcpy processing * @@ -1117,7 +1143,7 @@ static void uvc_video_copy_data_work(struct work_struct *work) uvc_queue_buffer_release(op->buf); } - ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); + ret = uvc_submit_urb(uvc_urb, GFP_KERNEL); if (ret < 0) dev_err(&uvc_urb->stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1537,6 +1563,12 @@ static void uvc_video_complete(struct urb *urb) /* Re-initialise the URB async work. */ uvc_urb->async_operations = 0; + /* Sync DMA and invalidate vmap range. */ + dma_sync_sgtable_for_cpu(uvc_stream_to_dmadev(uvc_urb->stream), + uvc_urb->sgt, uvc_stream_dir(stream)); + invalidate_kernel_vmap_range(uvc_urb->buffer, + uvc_urb->stream->urb_size); + /* * Process the URB headers, and optionally queue expensive memcpy tasks * to be deferred to a work queue. @@ -1545,7 +1577,7 @@ static void uvc_video_complete(struct urb *urb) /* If no async work is needed, resubmit the URB immediately. */ if (!uvc_urb->async_operations) { - ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); + ret = uvc_submit_urb(uvc_urb, GFP_ATOMIC); if (ret < 0) dev_err(&stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1560,24 +1592,49 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { + struct device *dma_dev = uvc_stream_to_dmadev(stream); struct uvc_urb *uvc_urb; for_each_uvc_urb(uvc_urb, stream) { if (!uvc_urb->buffer) continue; -#ifndef CONFIG_DMA_NONCOHERENT - usb_free_coherent(stream->dev->udev, stream->urb_size, - uvc_urb->buffer, uvc_urb->dma); -#else - kfree(uvc_urb->buffer); -#endif + dma_vunmap_noncontiguous(dma_dev, uvc_urb->buffer); + dma_free_noncontiguous(dma_dev, stream->urb_size, uvc_urb->sgt, + uvc_stream_dir(stream)); + uvc_urb->buffer = NULL; + uvc_urb->sgt = NULL; } stream->urb_size = 0; } +static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream, + struct uvc_urb *uvc_urb, gfp_t gfp_flags) +{ + struct device *dma_dev = uvc_stream_to_dmadev(stream); + + uvc_urb->sgt = dma_alloc_noncontiguous(dma_dev, stream->urb_size, + uvc_stream_dir(stream), + gfp_flags, 0); + if (!uvc_urb->sgt) + return false; + uvc_urb->dma = uvc_urb->sgt->sgl->dma_address; + + uvc_urb->buffer = dma_vmap_noncontiguous(dma_dev, stream->urb_size, + uvc_urb->sgt); + if (!uvc_urb->buffer) { + dma_free_noncontiguous(dma_dev, stream->urb_size, + uvc_urb->sgt, + uvc_stream_dir(stream)); + uvc_urb->sgt = NULL; + return false; + } + + return true; +} + /* * Allocate transfer buffers. This function can be called with buffers * already allocated when resuming from suspend, in which case it will @@ -1608,19 +1665,12 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, /* Retry allocations until one succeed. */ for (; npackets > 1; npackets /= 2) { + stream->urb_size = psize * npackets; + for (i = 0; i < UVC_URBS; ++i) { struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; - stream->urb_size = psize * npackets; -#ifndef CONFIG_DMA_NONCOHERENT - uvc_urb->buffer = usb_alloc_coherent( - stream->dev->udev, stream->urb_size, - gfp_flags | __GFP_NOWARN, &uvc_urb->dma); -#else - uvc_urb->buffer = - kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN); -#endif - if (!uvc_urb->buffer) { + if (!uvc_alloc_urb_buffer(stream, uvc_urb, gfp_flags)) { uvc_free_urb_buffers(stream); break; } @@ -1730,12 +1780,8 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->context = uvc_urb; urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); -#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; -#else - urb->transfer_flags = URB_ISO_ASAP; -#endif urb->interval = ep->desc.bInterval; urb->transfer_buffer = uvc_urb->buffer; urb->complete = uvc_video_complete; @@ -1795,10 +1841,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer, size, uvc_video_complete, uvc_urb); -#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; -#endif uvc_urb->urb = urb; } @@ -1895,7 +1939,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Submit the URBs. */ for_each_uvc_urb(uvc_urb, stream) { - ret = usb_submit_urb(uvc_urb->urb, gfp_flags); + ret = uvc_submit_urb(uvc_urb, gfp_flags); if (ret < 0) { dev_err(&stream->intf->dev, "Failed to submit URB %u (%d).\n", diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 97df5ecd66c9..cce5e38133cd 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -219,6 +219,7 @@ */ struct gpio_desc; +struct sg_table; struct uvc_device; /* TODO: Put the most frequently accessed fields at the beginning of @@ -545,7 +546,8 @@ struct uvc_copy_op { * @urb: the URB described by this context structure * @stream: UVC streaming context * @buffer: memory storage for the URB - * @dma: DMA coherent addressing for the urb_buffer + * @dma: Allocated DMA handle + * @sgt: sgt_table with the urb locations in memory * @async_operations: counter to indicate the number of copy operations * @copy_operations: work descriptors for asynchronous copy operations * @work: work queue entry for asynchronous decode @@ -556,6 +558,7 @@ struct uvc_urb { char *buffer; dma_addr_t dma; + struct sg_table *sgt; unsigned int async_operations; struct uvc_copy_op copy_operations[UVC_MAX_PACKETS]; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index d29b861367ea..1ef611e08323 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1430,7 +1430,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (hdl->error) { err = hdl->error; dev_err(&udev->dev, "couldn't register control\n"); - goto unregister; + goto free_hdlr_and_unreg_dev; } /* save the init method used by this camera */ cam->method = id->driver_info; @@ -1503,7 +1503,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (!cam->read_endpoint) { err = -ENOMEM; dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - goto unregister; + goto free_hdlr_and_unreg_dev; } /* v4l */ @@ -1515,7 +1515,7 @@ static int zr364xx_probe(struct usb_interface *intf, /* load zr364xx board specific */ err = zr364xx_board_init(cam); if (err) - goto unregister; + goto free_hdlr_and_unreg_dev; err = v4l2_ctrl_handler_setup(hdl); if (err) goto board_uninit; @@ -1533,7 +1533,7 @@ static int zr364xx_probe(struct usb_interface *intf, err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); if (err) { dev_err(&udev->dev, "video_register_device failed\n"); - goto free_handler; + goto board_uninit; } cam->v4l2_dev.release = zr364xx_release; @@ -1541,11 +1541,10 @@ static int zr364xx_probe(struct usb_interface *intf, video_device_node_name(&cam->vdev)); return 0; -free_handler: - v4l2_ctrl_handler_free(hdl); board_uninit: zr364xx_board_uninit(cam); -unregister: +free_hdlr_and_unreg_dev: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&cam->v4l2_dev); free_cam: kfree(cam); |